diff options
| -rw-r--r-- | clang/include/clang/Tooling/Core/Replacement.h | 32 | ||||
| -rw-r--r-- | clang/lib/Tooling/Core/Replacement.cpp | 17 | ||||
| -rw-r--r-- | clang/unittests/Tooling/RefactoringTest.cpp | 25 |
3 files changed, 54 insertions, 20 deletions
diff --git a/clang/include/clang/Tooling/Core/Replacement.h b/clang/include/clang/Tooling/Core/Replacement.h index 30a7036c2bb..f189e125012 100644 --- a/clang/include/clang/Tooling/Core/Replacement.h +++ b/clang/include/clang/Tooling/Core/Replacement.h @@ -19,6 +19,7 @@ #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H +#include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringRef.h" #include <set> @@ -77,22 +78,24 @@ public: /// \param FilePath A source file accessible via a SourceManager. /// \param Offset The byte offset of the start of the range in the file. /// \param Length The length of the range in bytes. - Replacement(StringRef FilePath, unsigned Offset, - unsigned Length, StringRef ReplacementText); + Replacement(StringRef FilePath, unsigned Offset, unsigned Length, + StringRef ReplacementText); /// \brief Creates a Replacement of the range [Start, Start+Length) with /// ReplacementText. - Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length, - StringRef ReplacementText); + Replacement(const SourceManager &Sources, SourceLocation Start, + unsigned Length, StringRef ReplacementText); /// \brief Creates a Replacement of the given range with ReplacementText. Replacement(const SourceManager &Sources, const CharSourceRange &Range, - StringRef ReplacementText); + StringRef ReplacementText, + const LangOptions &LangOpts = LangOptions()); /// \brief Creates a Replacement of the node with ReplacementText. template <typename Node> Replacement(const SourceManager &Sources, const Node &NodeToReplace, - StringRef ReplacementText); + StringRef ReplacementText, + const LangOptions &LangOpts = LangOptions()); /// \brief Returns whether this replacement can be applied to a file. /// @@ -114,11 +117,13 @@ public: std::string toString() const; private: - void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start, - unsigned Length, StringRef ReplacementText); - void setFromSourceRange(const SourceManager &Sources, - const CharSourceRange &Range, - StringRef ReplacementText); + void setFromSourceLocation(const SourceManager &Sources, + SourceLocation Start, unsigned Length, + StringRef ReplacementText); + void setFromSourceRange(const SourceManager &Sources, + const CharSourceRange &Range, + StringRef ReplacementText, + const LangOptions &LangOpts); std::string FilePath; Range ReplacementRange; @@ -217,10 +222,11 @@ std::string applyAllReplacements(StringRef Code, const Replacements &Replaces); template <typename Node> Replacement::Replacement(const SourceManager &Sources, - const Node &NodeToReplace, StringRef ReplacementText) { + const Node &NodeToReplace, StringRef ReplacementText, + const LangOptions &LangOpts) { const CharSourceRange Range = CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); - setFromSourceRange(Sources, Range, ReplacementText); + setFromSourceRange(Sources, Range, ReplacementText, LangOpts); } } // end namespace tooling diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp index b9fc92bb6c7..32e8e5bd6b9 100644 --- a/clang/lib/Tooling/Core/Replacement.cpp +++ b/clang/lib/Tooling/Core/Replacement.cpp @@ -43,8 +43,9 @@ Replacement::Replacement(const SourceManager &Sources, SourceLocation Start, Replacement::Replacement(const SourceManager &Sources, const CharSourceRange &Range, - StringRef ReplacementText) { - setFromSourceRange(Sources, Range, ReplacementText); + StringRef ReplacementText, + const LangOptions &LangOpts) { + setFromSourceRange(Sources, Range, ReplacementText, LangOpts); } bool Replacement::isApplicable() const { @@ -124,23 +125,25 @@ void Replacement::setFromSourceLocation(const SourceManager &Sources, // to handle ranges for refactoring in general first - there is no obvious // good way how to integrate this into the Lexer yet. static int getRangeSize(const SourceManager &Sources, - const CharSourceRange &Range) { + const CharSourceRange &Range, + const LangOptions &LangOpts) { SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin()); SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd()); std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin); std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd); if (Start.first != End.first) return -1; if (Range.isTokenRange()) - End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, - LangOptions()); + End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOpts); return End.second - Start.second; } void Replacement::setFromSourceRange(const SourceManager &Sources, const CharSourceRange &Range, - StringRef ReplacementText) { + StringRef ReplacementText, + const LangOptions &LangOpts) { setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()), - getRangeSize(Sources, Range), ReplacementText); + getRangeSize(Sources, Range, LangOpts), + ReplacementText); } unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) { diff --git a/clang/unittests/Tooling/RefactoringTest.cpp b/clang/unittests/Tooling/RefactoringTest.cpp index 7e643fa66d9..6c2c16b484d 100644 --- a/clang/unittests/Tooling/RefactoringTest.cpp +++ b/clang/unittests/Tooling/RefactoringTest.cpp @@ -281,6 +281,7 @@ public: protected: clang::SourceManager *SM; + clang::ASTContext *Context; private: class FindConsumer : public clang::ASTConsumer { @@ -303,6 +304,7 @@ private: CreateASTConsumer(clang::CompilerInstance &compiler, llvm::StringRef dummy) override { Visitor->SM = &compiler.getSourceManager(); + Visitor->Context = &compiler.getASTContext(); /// TestConsumer will be deleted by the framework calling us. return llvm::make_unique<FindConsumer>(Visitor); } @@ -368,6 +370,29 @@ TEST(Replacement, TemplatedFunctionCall) { expectReplacementAt(CallToF.Replace, "input.cc", 43, 8); } +class NestedNameSpecifierAVisitor + : public TestVisitor<NestedNameSpecifierAVisitor> { +public: + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) { + if (NNSLoc.getNestedNameSpecifier()) { + if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) { + if (NS->getName() == "a") { + Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts()); + } + } + } + return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc( + NNSLoc); + } + Replacement Replace; +}; + +TEST(Replacement, ColonColon) { + NestedNameSpecifierAVisitor VisitNNSA; + EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }")); + expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5); +} + TEST(Range, overlaps) { EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11))); EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10))); |

