Index: lib/Tooling/ASTDiff/ASTPatch.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTPatch.cpp +++ lib/Tooling/ASTDiff/ASTPatch.cpp @@ -79,12 +79,19 @@ void addInsertion(PatchedTreeNode &PatchedNode, SourceLocation InsertionLoc) { addChildAt(PatchedNode, InsertionLoc); + SplitAt.emplace_back(InsertionLoc); } void addChild(PatchedTreeNode &PatchedNode) { SourceLocation InsertionLoc = PatchedNode.getSourceRange().getBegin(); addChildAt(PatchedNode, InsertionLoc); } + // This returns an array of source ranges identical to the input, + // except whenever a SourceRange contains any of the locations in + // SplitAt, it is split up in two ranges at that location. + SmallVector + splitSourceRanges(ArrayRef SourceRanges); + private: void addChildAt(PatchedTreeNode &PatchedNode, SourceLocation InsertionLoc) { auto Less = makeTolerantLess(getTree().getSourceManager()); @@ -94,6 +101,8 @@ Children.insert(Children.begin() + Offset, &PatchedNode); ChildrenLocations.insert(It, InsertionLoc); } + + SmallVector SplitAt; }; } // end anonymous namespace @@ -501,7 +510,7 @@ unsigned ChildIndex = 0; auto MySourceRanges = PatchedNode.getOwnedSourceRanges(); BeforeThanCompare MyLess(Tree.getSourceManager()); - for (auto &MySubRange : MySourceRanges) { + for (auto &MySubRange : PatchedNode.splitSourceRanges(MySourceRanges)) { SourceLocation ChildBegin; SourceLocation InsertionBegin; while (ChildIndex < NumChildren && @@ -555,6 +564,36 @@ return {-1, true}; } +static bool onlyWhitespace(StringRef Str) { + return std::all_of(Str.begin(), Str.end(), + [](char C) { return std::isspace(C); }); +} + +SmallVector +PatchedTreeNode::splitSourceRanges(ArrayRef SourceRanges) { + SourceManager &SM = getTree().getSourceManager(); + const LangOptions &LangOpts = getTree().getLangOpts(); + SmallVector Result; + BeforeThanCompare Less(SM); + std::sort(SplitAt.begin(), SplitAt.end(), Less); + for (auto &Range : SourceRanges) { + SourceLocation Begin = Range.getBegin(), End = Range.getEnd(); + for (auto SplitPoint : SplitAt) { + if (SM.isPointWithin(SplitPoint, Begin, End)) { + auto SplitRange = CharSourceRange::getCharRange(Begin, SplitPoint); + StringRef Text = Lexer::getSourceText(SplitRange, SM, LangOpts); + if (onlyWhitespace(Text)) + continue; + Result.emplace_back(SplitRange); + Begin = SplitPoint; + } + } + if (Less(Begin, End)) + Result.emplace_back(CharSourceRange::getCharRange(Begin, End)); + } + return Result; +} + Error patch(RefactoringTool &TargetTool, SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options, bool Debug) { std::vector> TargetASTs; Index: unittests/Tooling/ASTPatchTest.cpp =================================================================== --- unittests/Tooling/ASTPatchTest.cpp +++ unittests/Tooling/ASTPatchTest.cpp @@ -262,4 +262,8 @@ R"(void f() { })", R"(void f() { { int x = 2; } })", R"(void f() { })"); + PATCH(R"(void f() {;;} namespace {})", + R"(namespace { void f() {;;} })", + R"(void g() {;;} namespace {})", + R"(namespace { void g() {;;} })"); }