Hi tareqsiraj, arielbernal, Sarcasm, klimek,
Introducing new tool 'migmerge' to merge and apply changes to headers as
found in header change description files generated by the C++11 Migrator.
CMake files updated to build new tool.
Includes a conflict test case.
http://llvm-reviews.chandlerc.com/D1382
Files:
cpp11-migrate/Core/ApplyChangeDescriptions.cpp
cpp11-migrate/Core/ApplyChangeDescriptions.h
cpp11-migrate/Core/CMakeLists.txt
cpp11-migrate/tool/CMakeLists.txt
cpp11-migrate/tool/MergeMain.cpp
test/CMakeLists.txt
test/migmerge/conflict.cpp
test/migmerge/conflict/common.h
test/migmerge/conflict/expected.txt
test/migmerge/conflict/file1.yaml
test/migmerge/conflict/file2.yaml
test/migmerge/conflict/file3.yaml
Index: cpp11-migrate/Core/ApplyChangeDescriptions.cpp
===================================================================
--- /dev/null
+++ cpp11-migrate/Core/ApplyChangeDescriptions.cpp
@@ -0,0 +1,172 @@
+#include "Core/ReplacementsYaml.h"
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+using namespace llvm;
+using namespace clang;
+
+typedef std::vector<HeaderChangeDocument> HeaderChangeDocs;
+typedef std::set<StringRef> UniqueFiles;
+
+void eatDiagnostics(const SMDiagnostic &, void *) {}
+
+error_code collectHeaderChangeDocs(const StringRef Directory,
+ HeaderChangeDocs &ChangeDocs,
+ UniqueFiles &FoundFiles) {
+ using namespace llvm::sys::fs;
+ using namespace llvm::sys::path;
+
+ error_code ErrorCode;
+
+ for (recursive_directory_iterator I(Directory, ErrorCode), E;
+ I != E && !ErrorCode; I.increment(ErrorCode)) {
+ StringRef Filename(filename(I->path()));
+ if (Filename == ".git") {
+ I.no_push();
+ continue;
+ }
+
+ if (extension(I->path()) != ".yaml")
+ continue;
+
+ OwningPtr<MemoryBuffer> Out;
+ error_code BufferError= MemoryBuffer::getFile(I->path(), Out);
+ if (BufferError) {
+ errs() << "Error reading " << I->path() << ": " << BufferError.message()
+ << "\n";
+ continue;
+ }
+
+ yaml::Input yin(Out->getBuffer());
+ yin.setDiagHandler(&eatDiagnostics);
+ HeaderChangeDocument Doc;
+ yin >> Doc;
+ if (yin.error()) {
+ // File doesn't appear to be a header change description. Ignore it.
+ continue;
+ }
+
+ // Only keep files that properly parse.
+ ChangeDocs.push_back(Doc);
+
+ FoundFiles.insert(Doc.HeaderFileName);
+ }
+
+ return ErrorCode;
+}
+
+bool applyChangeDescriptions(const StringRef Directory,
+ DiagnosticsEngine &Diagnostics) {
+
+ // FIXME: Use Diagnostics for output
+
+ HeaderChangeDocs Docs;
+ UniqueFiles FoundFiles;
+
+ error_code ErrorCode;
+ ErrorCode = collectHeaderChangeDocs(Directory, Docs, FoundFiles);
+
+ if (ErrorCode) {
+ errs() << "Trouble iterating over directory '" << Directory
+ << "': " << ErrorCode.message() << "\n";
+ return false;
+ }
+
+ // FIXME: For multi-threading, use contents of FoundFiles to divvy up work
+ // among threads.
+
+ typedef StringMap<std::vector<clang::tooling::Replacement> >
+ GroupedReplacementsTy;
+
+ GroupedReplacementsTy GroupedReplacements(FoundFiles.size());
+
+ // Group all replacements for a single file together.
+ for (HeaderChangeDocs::const_iterator I = Docs.begin(), E = Docs.end();
+ I != E; ++I) {
+ GroupedReplacements[I->HeaderFileName]
+ .insert(GroupedReplacements[I->HeaderFileName].end(),
+ I->Replacements.begin(), I->Replacements.end());
+ }
+
+ FileManager Files((FileSystemOptions()));
+ SourceManager SM(Diagnostics, Files);
+
+ bool conflictsFound = false;
+
+ // Ask clang to deduplicate and report conflicts.
+ for (GroupedReplacementsTy::iterator I = GroupedReplacements.begin(),
+ E = GroupedReplacements.end(); I != E; ++I) {
+
+ const FileEntry *Entry = SM.getFileManager().getFile(I->getKey());
+ if (!Entry) {
+ errs() << "Described file '" << I->getKey()
+ << "' doesn't exist. Ignoring...\n";
+ continue;
+ }
+
+ std::vector<tooling::Range> Conflicts;
+ deduplicate(I->getValue(), Conflicts);
+
+ if (Conflicts.empty())
+ continue;
+
+ conflictsFound = true;
+
+ // Report conflicts
+
+ FileID FID = SM.translateFile(Entry);
+ if (FID.isInvalid())
+ FID = SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+
+ errs() << "There are conflicting changes to " << I->getKey() << ":\n";
+
+ // FIXME: Output something a little more user-friendly (e.g. unified diff?)
+ unsigned conflictCount = 1;
+ for (std::vector<tooling::Range>::const_iterator
+ ConflictI = Conflicts.begin(),
+ ConflictE = Conflicts.end();
+ ConflictI != ConflictE; ++ConflictI, ++conflictCount) {
+ errs() << "Conflict #" << conflictCount << "\n";
+ for (unsigned i = ConflictI->getOffset(),
+ e = ConflictI->getOffset() + ConflictI->getLength();
+ i < e; ++i) {
+ const tooling::Replacement &R = I->getValue()[i];
+ if (R.getLength() == 0) {
+ errs() << " Insert at " << SM.getLineNumber(FID, R.getOffset())
+ << ":" << SM.getColumnNumber(FID, R.getOffset())
+ << " " << R.getReplacementText() << "\n";
+ } else {
+ if (R.getReplacementText().empty())
+ errs() << " Remove ";
+ else
+ errs() << " Replace ";
+
+ errs() << SM.getLineNumber(FID, R.getOffset()) << ":"
+ << SM.getColumnNumber(FID, R.getOffset()) << "-"
+ << SM.getLineNumber(FID, R.getOffset() + R.getLength() - 1)
+ << ":"
+ << SM.getColumnNumber(FID, R.getOffset() + R.getLength() - 1);
+
+ if (R.getReplacementText().empty())
+ errs() << "\n";
+ else
+ errs() << " with \"" << R.getReplacementText() << "\"\n";
+ }
+ }
+ }
+ }
+
+ if (conflictsFound)
+ return false;
+
+ // FIXME: Time to apply
+
+ return true;
+}
Index: cpp11-migrate/Core/ApplyChangeDescriptions.h
===================================================================
--- /dev/null
+++ cpp11-migrate/Core/ApplyChangeDescriptions.h
@@ -0,0 +1,30 @@
+//===-- Core/ApplyChangeDescriptions.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the declaration for the base Transform class from
+/// which all transforms must subclass.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef CPP11_MIGRATE_APPLYCHANGEDESCRIPTIONS_H
+#define CPP11_MIGRATE_APPLYCHANGEDESCRIPTIONS_H
+
+#include "llvm/ADT/StringRef.h"
+
+// Forward declarations
+
+namespace clang {
+class DiagnosticsEngine;
+} // namespace clang
+
+bool applyChangeDescriptions(const llvm::StringRef Directory,
+ clang::DiagnosticsEngine &Diagnostics);
+
+#endif // CPP11_MIGRATE_APPLYCHANGEDESCRIPTIONS_H
Index: cpp11-migrate/Core/CMakeLists.txt
===================================================================
--- cpp11-migrate/Core/CMakeLists.txt
+++ cpp11-migrate/Core/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(migrateCore
+ ApplyChangeDescriptions.cpp
FileOverrides.cpp
SyntaxCheck.cpp
Transforms.cpp
Index: cpp11-migrate/tool/CMakeLists.txt
===================================================================
--- cpp11-migrate/tool/CMakeLists.txt
+++ cpp11-migrate/tool/CMakeLists.txt
@@ -4,6 +4,10 @@
Cpp11Migrate.cpp
)
+set(LLVM_OPTIONAL_SOURCES
+ MergeMain.cpp
+ )
+
# FIXME: Lib-ify the transforms to simplify the build rules.
# For each transform subdirectory.
@@ -36,3 +40,22 @@
install(TARGETS cpp11-migrate
RUNTIME DESTINATION bin)
+
+################################################################################
+
+set(LLVM_OPTIONAL_SOURCES
+ Cpp11Migrate.cpp
+ )
+
+add_clang_executable(migmerge
+ MergeMain.cpp
+ )
+
+add_dependencies(migmerge
+ clang-headers
+ )
+
+target_link_libraries(migmerge
+ migrateCore
+ )
+
Index: cpp11-migrate/tool/MergeMain.cpp
===================================================================
--- /dev/null
+++ cpp11-migrate/tool/MergeMain.cpp
@@ -0,0 +1,26 @@
+#include "Core/ApplyChangeDescriptions.h"
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+using namespace clang;
+
+static cl::opt<std::string>
+Directory(cl::Positional, cl::Required,
+ cl::desc("<Search Root Directory>"));
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+ DiagOpts.getPtr());
+
+ if (applyChangeDescriptions(Directory, Diagnostics))
+ return 0;
+ return 1;
+}
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -27,7 +27,7 @@
clang clang-headers FileCheck count not
# Individual tools we test.
- remove-cstr-calls cpp11-migrate modularize clang-tidy
+ remove-cstr-calls migmerge cpp11-migrate modularize clang-tidy
# Unit tests
ExtraToolsUnitTests
Index: test/migmerge/conflict.cpp
===================================================================
--- /dev/null
+++ test/migmerge/conflict.cpp
@@ -0,0 +1,5 @@
+// RUN: mkdir -p %T/conflict
+// RUN: for f in %S/conflict/*.yaml; do sed "s#\$(path)#%S/conflict#" $f > %T/conflict/`basename $f`; done
+// RUN: sed "s#\$(path)#%S/conflict#" %S/conflict/expected.txt > %T/conflict/expected.txt
+// RUN: not migmerge %T/conflict > %T/conflict/output.txt 2>&1
+// RUN: cmp %T/conflict/output.txt %T/conflict/expected.txt
Index: test/migmerge/conflict/common.h
===================================================================
--- /dev/null
+++ test/migmerge/conflict/common.h
@@ -0,0 +1,17 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+extern void ext(int (&)[5]);
+
+void func(int t) {
+ int ints[5];
+ for (unsigned i = 0; i < 5; ++i) {
+ ints[i] = t;
+ }
+
+ int *i = 0;
+
+ ext(ints);
+}
+
+#endif // COMMON_H
Index: test/migmerge/conflict/expected.txt
===================================================================
--- /dev/null
+++ test/migmerge/conflict/expected.txt
@@ -0,0 +1,11 @@
+There are conflicting changes to $(path)/common.h:
+Conflict #1
+ Replace 8:8-8:33 with "auto & i : ints"
+ Replace 8:8-8:33 with "int & elem : ints"
+Conflict #2
+ Replace 9:5-9:11 with "elem"
+ Replace 9:5-9:11 with "i"
+Conflict #3
+ Remove 12:3-12:14
+ Insert at 12:12 (int*)
+ Replace 12:12-12:12 with "nullptr"
Index: test/migmerge/conflict/file1.yaml
===================================================================
--- /dev/null
+++ test/migmerge/conflict/file1.yaml
@@ -0,0 +1,15 @@
+---
+TransformID: "Blah"
+Replacements:
+ - Offset: 106
+ Length: 26
+ ReplacementText: "auto & i : ints"
+ - Offset: 140
+ Length: 7
+ ReplacementText: "i"
+ - Offset: 160
+ Length: 12
+ ReplacementText: ""
+HeaderFileName: "$(path)/common.h"
+SourceFileName: "source1.cpp"
+...
Index: test/migmerge/conflict/file2.yaml
===================================================================
--- /dev/null
+++ test/migmerge/conflict/file2.yaml
@@ -0,0 +1,15 @@
+---
+TransformID: "Blah"
+Replacements:
+ - Offset: 106
+ Length: 26
+ ReplacementText: "int & elem : ints"
+ - Offset: 140
+ Length: 7
+ ReplacementText: "elem"
+ - Offset: 169
+ Length: 1
+ ReplacementText: "nullptr"
+HeaderFileName: "$(path)/common.h"
+SourceFileName: "source2.cpp"
+...
Index: test/migmerge/conflict/file3.yaml
===================================================================
--- /dev/null
+++ test/migmerge/conflict/file3.yaml
@@ -0,0 +1,9 @@
+---
+TransformID: "Blah"
+Replacements:
+ - Offset: 169
+ Length: 0
+ ReplacementText: "(int*)"
+HeaderFileName: "$(path)/common.h"
+SourceFileName: "source3.cpp"
+...
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits