Sockke created this revision. Sockke added reviewers: malcolm.parsons, hokein, alexfh. Herald added a project: All. Sockke requested review of this revision. Herald added projects: clang, clang-tools-extra. Herald added a subscriber: cfe-commits.
If two different texts are inserted at the same offset, clang-apply-replacements prints the conflict error and discard all fixes. This patch adds support for adjusting conflict offset and running to fix them continually. https://godbolt.org/z/P938EGoxj doesn't have any fixes when I run run-clang-tidy.py to generate a YAML file with clang-tidy and fix them with clang-apply-replacements. The YAML file has two different header texts insertions at the same offset, unlike clang-tidy with '-fix', clang-apply-replacements does not adjust for this conflict. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D123924 Files: clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/conflict-offset.cpp clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/file1.yaml clang-tools-extra/test/clang-apply-replacements/conflict-offset.cpp clang/include/clang/Tooling/Refactoring/AtomicChange.h Index: clang/include/clang/Tooling/Refactoring/AtomicChange.h =================================================================== --- clang/include/clang/Tooling/Refactoring/AtomicChange.h +++ clang/include/clang/Tooling/Refactoring/AtomicChange.h @@ -116,6 +116,8 @@ /// Returns a const reference to existing replacements. const Replacements &getReplacements() const { return Replaces; } + Replacements &getRefReplacements() { return Replaces; } + llvm::ArrayRef<std::string> getInsertedHeaders() const { return InsertedHeaders; } Index: clang-tools-extra/test/clang-apply-replacements/conflict-offset.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/conflict-offset.cpp @@ -0,0 +1,5 @@ +// RUN: mkdir -p %T/Inputs/conflict-offset +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/conflict-offset/conflict-offset.cpp > %T/Inputs/conflict-offset/conflict-offset.cpp +// RUN: sed "s#\$(path)#%/T/Inputs/conflict-offset#" %S/Inputs/conflict-offset/file1.yaml > %T/Inputs/conflict-offset/file1.yaml +// RUN: clang-apply-replacements %T/Inputs/conflict-offset +// RUN: FileCheck -input-file=%T/Inputs/conflict-offset/conflict-offset.cpp %S/Inputs/conflict-offset/conflict-offset.cpp Index: clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/file1.yaml =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/file1.yaml @@ -0,0 +1,24 @@ +--- +MainSourceFile: conflict-offset.cpp +Diagnostics: + - DiagnosticName: test-conflict-offset-insertion + DiagnosticMessage: + Message: Fix + FilePath: $(path)/conflict-offset.cpp + FileOffset: 0 + Replacements: + - FilePath: $(path)/conflict-offset.cpp + Offset: 0 + Length: 0 + ReplacementText: "#include <a.h>\n" + - DiagnosticName: test-conflict-offset-insertion + DiagnosticMessage: + Message: Fix + FilePath: $(path)/conflict-offset.cpp + FileOffset: 0 + Replacements: + - FilePath: $(path)/conflict-offset.cpp + Offset: 0 + Length: 0 + ReplacementText: "#include <b.h>\n" +... Index: clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/conflict-offset.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/conflict-offset.cpp @@ -0,0 +1,4 @@ +class MyType {}; +// CHECK: #include <a.h> +// CHECK-NEXT: #include <b.h> +// CEHCK-NEXT: class MyType {}; Index: clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp =================================================================== --- clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp +++ clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp @@ -231,7 +231,19 @@ // For now, printing directly the error reported by `AtomicChange` is // the easiest solution. errs() << llvm::toString(std::move(Err)) << "\n"; - ConflictDetected = true; + tooling::Replacements &Replacements = FileChange.getRefReplacements(); + unsigned NewOffset = Replacements.getShiftedCodePosition(R.getOffset()); + unsigned NewLength = + Replacements.getShiftedCodePosition(R.getOffset() + R.getLength()) - + NewOffset; + if (NewLength == R.getLength()) { + tooling::Replacement RR = tooling::Replacement( + R.getFilePath(), NewOffset, NewLength, R.getReplacementText()); + Replacements = Replacements.merge(tooling::Replacements(RR)); + } else { + llvm::errs() << "Can't resolve conflict, skipping the replacement.\n"; + ConflictDetected = true; + } } } FileChanges.try_emplace(Entry,
Index: clang/include/clang/Tooling/Refactoring/AtomicChange.h =================================================================== --- clang/include/clang/Tooling/Refactoring/AtomicChange.h +++ clang/include/clang/Tooling/Refactoring/AtomicChange.h @@ -116,6 +116,8 @@ /// Returns a const reference to existing replacements. const Replacements &getReplacements() const { return Replaces; } + Replacements &getRefReplacements() { return Replaces; } + llvm::ArrayRef<std::string> getInsertedHeaders() const { return InsertedHeaders; } Index: clang-tools-extra/test/clang-apply-replacements/conflict-offset.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/conflict-offset.cpp @@ -0,0 +1,5 @@ +// RUN: mkdir -p %T/Inputs/conflict-offset +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/conflict-offset/conflict-offset.cpp > %T/Inputs/conflict-offset/conflict-offset.cpp +// RUN: sed "s#\$(path)#%/T/Inputs/conflict-offset#" %S/Inputs/conflict-offset/file1.yaml > %T/Inputs/conflict-offset/file1.yaml +// RUN: clang-apply-replacements %T/Inputs/conflict-offset +// RUN: FileCheck -input-file=%T/Inputs/conflict-offset/conflict-offset.cpp %S/Inputs/conflict-offset/conflict-offset.cpp Index: clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/file1.yaml =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/file1.yaml @@ -0,0 +1,24 @@ +--- +MainSourceFile: conflict-offset.cpp +Diagnostics: + - DiagnosticName: test-conflict-offset-insertion + DiagnosticMessage: + Message: Fix + FilePath: $(path)/conflict-offset.cpp + FileOffset: 0 + Replacements: + - FilePath: $(path)/conflict-offset.cpp + Offset: 0 + Length: 0 + ReplacementText: "#include <a.h>\n" + - DiagnosticName: test-conflict-offset-insertion + DiagnosticMessage: + Message: Fix + FilePath: $(path)/conflict-offset.cpp + FileOffset: 0 + Replacements: + - FilePath: $(path)/conflict-offset.cpp + Offset: 0 + Length: 0 + ReplacementText: "#include <b.h>\n" +... Index: clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/conflict-offset.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-apply-replacements/Inputs/conflict-offset/conflict-offset.cpp @@ -0,0 +1,4 @@ +class MyType {}; +// CHECK: #include <a.h> +// CHECK-NEXT: #include <b.h> +// CEHCK-NEXT: class MyType {}; Index: clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp =================================================================== --- clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp +++ clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp @@ -231,7 +231,19 @@ // For now, printing directly the error reported by `AtomicChange` is // the easiest solution. errs() << llvm::toString(std::move(Err)) << "\n"; - ConflictDetected = true; + tooling::Replacements &Replacements = FileChange.getRefReplacements(); + unsigned NewOffset = Replacements.getShiftedCodePosition(R.getOffset()); + unsigned NewLength = + Replacements.getShiftedCodePosition(R.getOffset() + R.getLength()) - + NewOffset; + if (NewLength == R.getLength()) { + tooling::Replacement RR = tooling::Replacement( + R.getFilePath(), NewOffset, NewLength, R.getReplacementText()); + Replacements = Replacements.merge(tooling::Replacements(RR)); + } else { + llvm::errs() << "Can't resolve conflict, skipping the replacement.\n"; + ConflictDetected = true; + } } } FileChanges.try_emplace(Entry,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits