summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Tooling/Core/Replacement.cpp15
-rw-r--r--clang/unittests/Tooling/RefactoringTest.cpp20
2 files changed, 28 insertions, 7 deletions
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index b990ed2083a..d498f433521 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -159,15 +159,16 @@ llvm::Error Replacements::add(const Replacement &R) {
// replacement cannot overlap.
Replacement AtEnd(R.getFilePath(), R.getOffset() + R.getLength(), 0, "");
- // Find the first entry that starts after the end of R.
- // We cannot use upper_bound for that, as there might be an element equal to
- // AtEnd in Replaces, and AtEnd does not overlap.
- // Instead, we use lower_bound and special-case finding AtEnd below.
+ // Find the first entry that starts after or at the end of R. Note that
+ // entries that start at the end can still be conflicting if R is an
+ // insertion.
auto I = Replaces.lower_bound(AtEnd);
- // If *I == R (which can only happen if R == AtEnd) the first entry that
- // starts after R is (I+1).
- if (I != Replaces.end() && *I == R)
+ // If it starts at the same offset as R (can only happen if R is an
+ // insertion), we have a conflict. In that case, increase I to fall through
+ // to the conflict check.
+ if (I != Replaces.end() && R.getOffset() == I->getOffset())
++I;
+
// I is the smallest iterator whose entry cannot overlap.
// If that is begin(), there are no overlaps.
if (I == Replaces.begin()) {
diff --git a/clang/unittests/Tooling/RefactoringTest.cpp b/clang/unittests/Tooling/RefactoringTest.cpp
index b06123ed62d..5dd5c02c577 100644
--- a/clang/unittests/Tooling/RefactoringTest.cpp
+++ b/clang/unittests/Tooling/RefactoringTest.cpp
@@ -157,6 +157,26 @@ TEST_F(ReplacementTest, FailAddRegression) {
llvm::consumeError(std::move(Err));
}
+TEST_F(ReplacementTest, FailAddInsertAtOffsetOfReplacement) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+}
+
+TEST_F(ReplacementTest, FailAddInsertAtOtherInsert) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+}
+
TEST_F(ReplacementTest, CanApplyReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
OpenPOWER on IntegriCloud