diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-27 10:56:34 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2017-03-27 10:56:34 +0200 |
commit | 2a6a16bd178844e4c835e4e505ede3645b18e16c (patch) | |
tree | 963aac784551f1f858cb4f2fdc005238a4255789 | |
parent | 27cb24a38aa9550f5b6011464c38717eb45c1924 (diff) |
clang-rename: handle C -> ns::C rename for class declarations / definitions
-rw-r--r-- | clang/Makefile | 2 | ||||
-rw-r--r-- | clang/rename.cxx | 62 |
2 files changed, 62 insertions, 2 deletions
diff --git a/clang/Makefile b/clang/Makefile index 7bdbec8..b50b32b 100644 --- a/clang/Makefile +++ b/clang/Makefile @@ -3,7 +3,7 @@ CLANGDEFS=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fno-rtti CLANGWARNS=-Werror -Wall -Wno-missing-braces -Wnon-virtual-dtor -Wendif-labels -Wextra -Wundef -Wunused-macros -Wshadow -Woverloaded-virtual CLANGFLAGS = $(CLANGDEFS) $(CLANGWARNS) -g -std=c++11 -CLANGLIBS = -lclangAST -lclangBasic -lclangFrontend -lclangRewrite -lclangTooling -lLLVMSupport +CLANGLIBS = -lclangAST -lclangBasic -lclangFrontend -lclangRewrite -lclangTooling -lclangLex -lLLVMSupport ifneq ($(GCOV),) CLANGFLAGS += --coverage endif diff --git a/clang/rename.cxx b/clang/rename.cxx index a4b3231..2ec5cd0 100644 --- a/clang/rename.cxx +++ b/clang/rename.cxx @@ -9,6 +9,36 @@ #include <clang/Rewrite/Core/Rewriter.h> #include <clang/Tooling/CommonOptionsParser.h> #include <clang/Tooling/Tooling.h> +#include <clang/Lex/Lexer.h> + +namespace +{ +/// From clang-tools-extra.git's clang-move/ClangMove.cpp. +clang::SourceLocation getLocForEndOfDecl(const clang::Decl *D, const clang::LangOptions &LangOpts = clang::LangOptions()) { + const auto &SM = D->getASTContext().getSourceManager(); + auto EndExpansionLoc = SM.getExpansionLoc(D->getLocEnd()); + std::pair<clang::FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc); + // Try to load the file buffer. + bool InvalidTemp = false; + llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp); + if (InvalidTemp) + return clang::SourceLocation(); + + const char *TokBegin = File.data() + LocInfo.second; + // Lex from the start of the given location. + clang::Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),TokBegin, File.end()); + + llvm::SmallVector<char, 16> Line; + // FIXME: this is a bit hacky to get ReadToEndOfLine work. + Lex.setParsingPreprocessorDirective(true); + Lex.ReadToEndOfLine(&Line); + clang::SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size()); + // If we already reach EOF, just return the EOF SourceLocation; + // otherwise, move 1 offset ahead to include the trailing newline character + // '\n'. + return SM.getLocForEndOfFile(LocInfo.first) == EndLoc ? EndLoc : EndLoc.getLocWithOffset(1); +} +} class RenameRewriter : public clang::Rewriter { @@ -70,6 +100,27 @@ class RenameVisitor : public clang::RecursiveASTVisitor<RenameVisitor> } } + /// Get the namespace part of a new name. + std::string GetNamespace(const std::string& rOldName) + { + auto it = mrRewriter.getNameMap().find(rOldName); + if (it == mrRewriter.getNameMap().end()) + return std::string(); + + std::string aNewName = it->second; + std::string::size_type nPos = aNewName.find("::"); + if (nPos == std::string::npos) + return std::string(); + + return aNewName.substr(0, nPos); + } + + /// If a new name has a namespace part. + bool HasNamespace(const std::string& rOldName) + { + return !GetNamespace(rOldName).empty(); + } + public: explicit RenameVisitor(RenameRewriter& rRewriter) : mrRewriter(rRewriter) @@ -245,7 +296,16 @@ public: bool VisitCXXRecordDecl(const clang::CXXRecordDecl* pDecl) { std::string aName = pDecl->getQualifiedNameAsString(); - RewriteText(pDecl->getLocation(), pDecl->getNameAsString().length(), aName); + if (HasNamespace(aName)) + { + std::string aInsert = "namespace "; + aInsert += GetNamespace(aName); + aInsert += "\n{\n"; + mrRewriter.ReplaceText(pDecl->getLocStart(), 0, aInsert); + mrRewriter.ReplaceText(getLocForEndOfDecl(pDecl), 0, "}\n"); + } + else + RewriteText(pDecl->getLocation(), pDecl->getNameAsString().length(), aName); return true; } |