Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -1,5 +1,5 @@ add_subdirectory(clang-apply-replacements) -add_subdirectory(clang-rename) +add_subdirectory(clang-refactor) add_subdirectory(clang-reorder-fields) add_subdirectory(modularize) if(CLANG_ENABLE_STATIC_ANALYZER) @@ -23,4 +23,3 @@ if( CLANG_TOOLS_EXTRA_INCLUDE_DOCS ) add_subdirectory(docs) endif() - Index: TemplatedClassFunction.cpp =================================================================== --- /dev/null +++ TemplatedClassFunction.cpp @@ -0,0 +1,22 @@ +template +class A { +public: + void foo() /* Test 1 */ {} // CHECK: void bar() /* Test 1 */ {} +}; + +int main(int argc, char **argv) { + A a; + a.foo(); /* Test 2 */ // CHECK: a.bar() /* Test 2 */ + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=162 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// +// Currently unsupported test. +// XFAIL: * + +// To find offsets after modifying the file, use: +// grep -Ubo 'foo.*' Index: clang-refactor/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( + USREngine + modules + ) + +add_subdirectory(driver) +add_subdirectory(USREngine) +add_subdirectory(modules) +add_subdirectory(editor-integrations) Index: clang-refactor/USREngine/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/USREngine/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS Support) + +add_clang_library(clangRefactorUSREngine + USRFinder.cpp + USRFindingAction.cpp + USRLocFinder.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangIndex + clangLex + ) Index: clang-refactor/USREngine/USRFinder.h =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRFinder.h @@ -0,0 +1,81 @@ +//===--- tools/extra/clang-refactor/USRFinder.h - USREngine ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Methods for determining the USR of a symbol at a location in source +/// code. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H + +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include + +using namespace llvm; +using namespace clang::ast_matchers; + +namespace clang { +class ASTContext; +class Decl; +class SourceLocation; +class NamedDecl; + +namespace clang_refactor { + +// Given an AST context and a point, returns a NamedDecl identifying the symbol +// at the point. Returns null if nothing is found at the point. +const NamedDecl *getNamedDeclAt(const ASTContext &Context, + const SourceLocation Point); + +// Given an AST context and a fully qualified name, returns a NamedDecl +// identifying the symbol with a matching name. Returns null if nothing is +// found for the name. +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name); + +// Converts a Decl into a USR. +std::string getUSRForDecl(const Decl *Decl); + +// FIXME: Implement RecursiveASTVisitor::VisitNestedNameSpecifier instead. +class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback { +public: + explicit NestedNameSpecifierLocFinder(ASTContext &Context) + : Context(Context) {} + + std::vector getNestedNameSpecifierLocations() { + addMatchers(); + Finder.matchAST(Context); + return Locations; + } + +private: + void addMatchers() { + const auto NestedNameSpecifierLocMatcher = + nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc"); + Finder.addMatcher(NestedNameSpecifierLocMatcher, this); + } + + virtual void run(const MatchFinder::MatchResult &Result) { + const auto *NNS = Result.Nodes.getNodeAs( + "nestedNameSpecifierLoc"); + Locations.push_back(*NNS); + } + + ASTContext &Context; + std::vector Locations; + MatchFinder Finder; +}; +} +} + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H Index: clang-refactor/USREngine/USRFinder.cpp =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRFinder.cpp @@ -0,0 +1,217 @@ +//===--- tools/extra/clang-refactor/USRFinder.cpp - USREngine -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file Implements a recursive AST visitor that finds the USR of a symbol at a +/// point. +/// +//===----------------------------------------------------------------------===// + +#include "USRFinder.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallVector.h" + +using namespace llvm; + +namespace clang { +namespace clang_refactor { + +// NamedDeclFindingASTVisitor recursively visits each AST node to find the +// symbol underneath the cursor. +// FIXME: move to seperate .h/.cc file if this gets too large. +namespace { +class NamedDeclFindingASTVisitor + : public clang::RecursiveASTVisitor { +public: + // \brief Finds the NamedDecl at a point in the source. + // \param Point the location in the source to search for the NamedDecl. + explicit NamedDeclFindingASTVisitor(const SourceLocation Point, + const ASTContext &Context) + : Result(nullptr), Point(Point), Context(Context) {} + + // \brief Finds the NamedDecl for a name in the source. + // \param Name the fully qualified name. + explicit NamedDeclFindingASTVisitor(const std::string &Name, + const ASTContext &Context) + : Result(nullptr), Name(Name), Context(Context) {} + + // Declaration visitors: + + // \brief Checks if the point falls within the NameDecl. This covers every + // declaration of a named entity that we may come across. Usually, just + // checking if the point lies within the length of the name of the declaration + // and the start location is sufficient. + bool VisitNamedDecl(const NamedDecl *Decl) { + return dyn_cast(Decl) + ? true + : setResult(Decl, Decl->getLocation(), + Decl->getNameAsString().length()); + } + + // Expression visitors: + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + return setResult(Decl, Expr->getLocation(), + Decl->getNameAsString().length()); + } + + bool VisitMemberExpr(const MemberExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); + return setResult(Decl, Expr->getMemberLoc(), + Decl->getNameAsString().length()); + } + + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + const SourceLocation TypeBeginLoc = Loc.getBeginLoc(); + const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken( + TypeBeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); + if (const auto *TemplateTypeParm = + dyn_cast(Loc.getType())) { + return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc); + } + if (const auto *TemplateSpecType = + dyn_cast(Loc.getType())) { + return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(), + TypeBeginLoc, TypeEndLoc); + } + return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, + TypeEndLoc); + } + + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { + for (const auto *Initializer : ConstructorDecl->inits()) { + if (!Initializer->isWritten()) { + // Ignore implicit initializers. + continue; + } + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { + const SourceLocation InitBeginLoc = Initializer->getSourceLocation(), + InitEndLoc = Lexer::getLocForEndOfToken( + InitBeginLoc, 0, Context.getSourceManager(), + Context.getLangOpts()); + if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc)) { + return false; + } + } + } + return true; + } + + // Other: + + const NamedDecl *getNamedDecl() { return Result; } + + // \brief Determines if a namespace qualifier contains the point. + // \returns false on success and sets Result. + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + while (NameLoc) { + const NamespaceDecl *Decl = + NameLoc.getNestedNameSpecifier()->getAsNamespace(); + setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc()); + NameLoc = NameLoc.getPrefix(); + } + } + +private: + // \brief Sets Result to Decl if the Point is within Start and End. + // \returns false on success. + bool setResult(const NamedDecl *Decl, SourceLocation Start, + SourceLocation End) { + if (!Decl) { + return true; + } + if (Name.empty()) { + // Offset is used to find the declaration. + if (!Start.isValid() || !Start.isFileID() || !End.isValid() || + !End.isFileID() || !isPointWithin(Start, End)) { + return true; + } + } else { + // Fully qualified name is used to find the declaration. + if (Name != Decl->getQualifiedNameAsString()) { + return true; + } + } + Result = Decl; + return false; + } + + // \brief Sets Result to Decl if Point is within Loc and Loc + Offset. + // \returns false on success. + bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) { + // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc). + return Offset == 0 || + setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1)); + } + + // \brief Determines if the Point is within Start and End. + bool isPointWithin(const SourceLocation Start, const SourceLocation End) { + // FIXME: Add tests for Point == End. + return Point == Start || Point == End || + (Context.getSourceManager().isBeforeInTranslationUnit(Start, + Point) && + Context.getSourceManager().isBeforeInTranslationUnit(Point, End)); + } + + const NamedDecl *Result; + const SourceLocation Point; // The location to find the NamedDecl. + const std::string Name; + const ASTContext &Context; +}; +} // namespace + +const NamedDecl *getNamedDeclAt(const ASTContext &Context, + const SourceLocation Point) { + StringRef SearchFile = Context.getSourceManager().getFilename(Point); + NamedDeclFindingASTVisitor Visitor(Point, Context); + + // We only want to search the decls that exist in the same file as the point. + for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) { + const SourceLocation FileLoc = CurrDecl->getLocStart(); + StringRef FileName = Context.getSourceManager().getFilename(FileLoc); + // FIXME: Add test. + if (FileName == SearchFile) { + Visitor.TraverseDecl(CurrDecl); + } + } + + NestedNameSpecifierLocFinder Finder(const_cast(Context)); + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { + Visitor.handleNestedNameSpecifierLoc(Location); + } + + return Visitor.getNamedDecl(); +} + +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name) { + NamedDeclFindingASTVisitor Visitor(Name, Context); + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + + return Visitor.getNamedDecl(); +} + +std::string getUSRForDecl(const Decl *Decl) { + llvm::SmallVector Buff; + + // FIXME: Add test for the nullptr case. + if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff)) + return ""; + + return std::string(Buff.data(), Buff.size()); +} + +} // namespace clang_refactor +} // namespace clang Index: clang-refactor/USREngine/USRFindingAction.h =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRFindingAction.h @@ -0,0 +1,50 @@ +//===--- tools/extra/clang-refactor/USRFindingAction.h - USREngine --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to find all relevant USRs at a point. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_USRENGINE_USRFINDINGACTION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_USRENGINE_USRFINDINGACTION_H + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/Frontend/FrontendAction.h" + +#include +#include + +namespace clang { +class ASTConsumer; +class CompilerInstance; +class NamedDecl; + +namespace clang_refactor { + +struct USRFindingAction { + USRFindingAction(ArrayRef SymbolOffsets, + ArrayRef QualifiedNames) + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames) {} + std::unique_ptr newASTConsumer(); + + const std::vector &getUSRSpellings() { return SpellingNames; } + const std::vector> &getUSRList() { return USRList; } + +private: + std::vector SymbolOffsets; + std::vector QualifiedNames; + std::vector SpellingNames; + std::vector> USRList; +}; + +} // namespace clang_refactor +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_USRENGINE_USRFINDINGACTION_H Index: clang-refactor/USREngine/USRFindingAction.cpp =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRFindingAction.cpp @@ -0,0 +1,209 @@ +//===--- tools/extra/clang-refactor/USRFindingAction.cpp - USREngine ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to find USR for the symbol at , as well as +/// all additional USRs. +/// +//===----------------------------------------------------------------------===// + +#include "USRFindingAction.h" +#include "USRFinder.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include +#include + +using namespace llvm; + +namespace clang { +namespace clang_refactor { + +namespace { +// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to +// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given +// Decl refers to class and adds USRs of all overridden methods if Decl refers +// to virtual method. +class AdditionalUSRFinder : public RecursiveASTVisitor { +public: + explicit AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context) + : FoundDecl(FoundDecl), Context(Context) {} + + std::vector Find() { + // Fill OverriddenMethods and PartialSpecs storages. + TraverseDecl(Context.getTranslationUnitDecl()); + if (const auto *MethodDecl = dyn_cast(FoundDecl)) { + addUSRsOfOverridenFunctions(MethodDecl); + for (const auto &OverriddenMethod : OverriddenMethods) { + if (checkIfOverriddenFunctionAscends(OverriddenMethod)) { + USRSet.insert(getUSRForDecl(OverriddenMethod)); + } + } + } else if (const auto *RecordDecl = dyn_cast(FoundDecl)) { + handleCXXRecordDecl(RecordDecl); + } else if (const auto *TemplateDecl = + dyn_cast(FoundDecl)) { + handleClassTemplateDecl(TemplateDecl); + } else { + USRSet.insert(getUSRForDecl(FoundDecl)); + } + return std::vector(USRSet.begin(), USRSet.end()); + } + + bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { + if (MethodDecl->isVirtual()) + OverriddenMethods.push_back(MethodDecl); + return true; + } + + bool VisitClassTemplatePartialSpecializationDecl( + const ClassTemplatePartialSpecializationDecl *PartialSpec) { + PartialSpecs.push_back(PartialSpec); + return true; + } + +private: + void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) { + RecordDecl = RecordDecl->getDefinition(); + if (const auto *ClassTemplateSpecDecl = + dyn_cast(RecordDecl)) + handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate()); + + addUSRsOfCtorDtors(RecordDecl); + } + + void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) { + for (const auto *Specialization : TemplateDecl->specializations()) + addUSRsOfCtorDtors(Specialization); + + for (const auto *PartialSpec : PartialSpecs) + if (PartialSpec->getSpecializedTemplate() == TemplateDecl) + addUSRsOfCtorDtors(PartialSpec); + addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl()); + } + + void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) { + RecordDecl = RecordDecl->getDefinition(); + for (const auto *CtorDecl : RecordDecl->ctors()) + USRSet.insert(getUSRForDecl(CtorDecl)); + USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); + USRSet.insert(getUSRForDecl(RecordDecl)); + } + + void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) { + USRSet.insert(getUSRForDecl(MethodDecl)); + for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) + // Recursively visit each OverridenMethod. + addUSRsOfOverridenFunctions(OverriddenMethod); + } + + bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { + for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { + if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) + return true; + return checkIfOverriddenFunctionAscends(OverriddenMethod); + } + return false; + } + + const Decl *FoundDecl; + ASTContext &Context; + std::set USRSet; + std::vector OverriddenMethods; + std::vector PartialSpecs; +}; +} // namespace + +class NamedDeclFindingConsumer : public ASTConsumer { +public: + explicit NamedDeclFindingConsumer( + ArrayRef SymbolOffsets, ArrayRef QualifiedNames, + std::vector &SpellingNames, + std::vector> &USRList) + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames), + SpellingNames(SpellingNames), USRList(USRList) { + } + +private: + void FindSymbol(ASTContext &Context, const SourceManager &SourceMgr, + unsigned SymbolOffset, const std::string &QualifiedName) { + const SourceLocation Point = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) + .getLocWithOffset(SymbolOffset); + + if (!Point.isValid()) + return; + const NamedDecl *FoundDecl = nullptr; + + if (QualifiedName.empty()) + FoundDecl = getNamedDeclAt(Context, Point); + else + FoundDecl = getNamedDeclFor(Context, QualifiedName); + + if (FoundDecl == nullptr) { + if (QualifiedName.empty()) { + FullSourceLoc FullLoc(Point, SourceMgr); + errs() << "clang-refactor rename: could not find symbol at " + << SourceMgr.getFilename(Point) << ":" + << FullLoc.getSpellingLineNumber() << ":" + << FullLoc.getSpellingColumnNumber() << " (offset " + << SymbolOffset << ").\n"; + exit(1); + } else { + errs() << "USREngine: could not find symbol " << QualifiedName << ".\n"; + exit(1); + } + return; + } + + // If FoundDecl is a constructor or destructor, we want to instead take + // the Decl of the corresponding class. + if (const auto *CtorDecl = dyn_cast(FoundDecl)) + FoundDecl = CtorDecl->getParent(); + else if (const auto *DtorDecl = dyn_cast(FoundDecl)) + FoundDecl = DtorDecl->getParent(); + + SpellingNames.push_back(FoundDecl->getNameAsString()); + AdditionalUSRFinder Finder(FoundDecl, Context); + USRList.push_back(Finder.Find()); + } + + void HandleTranslationUnit(ASTContext &Context) override { + const SourceManager &SourceMgr = Context.getSourceManager(); + for (unsigned Offset : SymbolOffsets) + FindSymbol(Context, SourceMgr, Offset, ""); + for (const std::string &QualifiedName : QualifiedNames) + FindSymbol(Context, SourceMgr, 0, QualifiedName); + } + + ArrayRef SymbolOffsets; + ArrayRef QualifiedNames; + std::vector &SpellingNames; + std::vector> &USRList; +}; + +std::unique_ptr USRFindingAction::newASTConsumer() { + return llvm::make_unique( + SymbolOffsets, QualifiedNames, SpellingNames, USRList); +} + +} // namespace clang_refactor +} // namespace clang Index: clang-refactor/USREngine/USRLocFinder.h =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRLocFinder.h @@ -0,0 +1,35 @@ +//===--- tools/extra/clang-refactor/USRLocFinder.h - USREngine ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides functionality for finding all instances of a USR in a given +/// AST. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H + +#include "clang/AST/AST.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { +namespace clang_refactor { + +// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree! +std::vector +getLocationsOfUSRs(const std::vector &USRs, + llvm::StringRef PrevName, Decl *Decl); + +} // namespace clang_refactor +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H Index: clang-refactor/USREngine/USRLocFinder.cpp =================================================================== --- /dev/null +++ clang-refactor/USREngine/USRLocFinder.cpp @@ -0,0 +1,164 @@ +//===--- tools/extra/clang-refactor/USRLocFinder.cpp - USREngine ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Mehtods for finding all instances of a USR. Our strategy is very +/// simple; we just compare the USR at every relevant AST node with the one +/// provided. +/// +//===----------------------------------------------------------------------===// + +#include "USRLocFinder.h" +#include "USRFinder.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallVector.h" + +using namespace llvm; + +namespace clang { +namespace clang_refactor { + +namespace { +// \brief This visitor recursively searches for all instances of a USR in a +// translation unit and stores them for later usage. +class USRLocFindingASTVisitor + : public clang::RecursiveASTVisitor { +public: + explicit USRLocFindingASTVisitor(const std::vector &USRs, + StringRef PrevName, + const ASTContext &Context) + : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { + } + + // Declaration visitors: + + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { + for (const auto *Initializer : ConstructorDecl->inits()) { + if (!Initializer->isWritten()) { + // Ignore implicit initializers. + continue; + } + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { + if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end()) { + LocationsFound.push_back(Initializer->getSourceLocation()); + } + } + } + return true; + } + + bool VisitNamedDecl(const NamedDecl *Decl) { + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + checkAndAddLocation(Decl->getLocation()); + } + return true; + } + + // Expression visitors: + + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + const SourceManager &Manager = Decl->getASTContext().getSourceManager(); + SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation()); + checkAndAddLocation(Location); + } + + return true; + } + + bool VisitMemberExpr(const MemberExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + const SourceManager &Manager = Decl->getASTContext().getSourceManager(); + SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc()); + checkAndAddLocation(Location); + } + return true; + } + + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl())) != + USRSet.end()) { + checkAndAddLocation(Loc.getBeginLoc()); + } + if (const auto *TemplateTypeParm = + dyn_cast(Loc.getType())) { + if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) != + USRSet.end()) { + checkAndAddLocation(Loc.getBeginLoc()); + } + } + return true; + } + + // Non-visitors: + + // \brief Returns a list of unique locations. Duplicate or overlapping + // locations are erroneous and should be reported! + const std::vector &getLocationsFound() const { + return LocationsFound; + } + + // Namespace traversal: + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + while (NameLoc) { + const NamespaceDecl *Decl = + NameLoc.getNestedNameSpecifier()->getAsNamespace(); + if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { + checkAndAddLocation(NameLoc.getLocalBeginLoc()); + } + NameLoc = NameLoc.getPrefix(); + } + } + +private: + void checkAndAddLocation(SourceLocation Loc) { + const SourceLocation BeginLoc = Loc; + const SourceLocation EndLoc = Lexer::getLocForEndOfToken( + BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); + StringRef TokenName = + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + Context.getSourceManager(), Context.getLangOpts()); + size_t Offset = TokenName.find(PrevName); + if (Offset != StringRef::npos) { + // The token of the source location we find actually has the old + // name. + LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); + } + } + + const std::set USRSet; + const std::string PrevName; + std::vector LocationsFound; + const ASTContext &Context; +}; +} // namespace + +std::vector +getLocationsOfUSRs(const std::vector &USRs, StringRef PrevName, + Decl *Decl) { + USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); + Visitor.TraverseDecl(Decl); + NestedNameSpecifierLocFinder Finder(Decl->getASTContext()); + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { + Visitor.handleNestedNameSpecifierLoc(Location); + } + return Visitor.getLocationsFound(); +} + +} // namespace clang_refactor +} // namespace clang Index: clang-refactor/driver/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/driver/CMakeLists.txt @@ -0,0 +1,18 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_executable(clang-refactor + Driver.cpp + ) + +target_link_libraries(clang-refactor + clangAST + clangBasic + clangFrontend + clangTooling + + clangRefactorRenameModule + + clangRefactorUSREngine + ) Index: clang-refactor/driver/ClangRefactorOptions.h =================================================================== --- /dev/null +++ clang-refactor/driver/ClangRefactorOptions.h @@ -0,0 +1,67 @@ +//===--- tools/extra/clang-refactor/ClangRefactorOptions.h ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines common options for clang-refactor subtools. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/CommonOptionsParser.h" + +#ifndef CLANG_REFACTOR_OPTIONS_H +#define CLANG_REFACTOR_OPTIONS_H + +using namespace llvm; + +namespace clang { +namespace clang_refactor { + +// FIXME: Adjust libTooling so that these options would be displayed, too. +static cl::OptionCategory + ClangRefactorCommonOptions("clang-refactor common options"); + +static cl::list SymbolOffsets( + "offset", + cl::desc("Locates the symbol by offset as opposed to :."), + cl::ZeroOrMore, cl::cat(ClangRefactorCommonOptions)); +static cl::opt Inplace("i", cl::desc("Overwrite edited s."), + cl::cat(ClangRefactorCommonOptions)); +static cl::list + QualifiedNames("qualified-name", + cl::desc("The fully qualified name of the symbol."), + cl::ZeroOrMore, cl::cat(ClangRefactorCommonOptions)); + +namespace rename_module { + +static cl::OptionCategory + ClangRefactorRenameCategory("clang-refactor rename options"); + +static cl::list + NewNames("new-name", cl::desc("The new name to change the symbol to."), + cl::ZeroOrMore, cl::cat(ClangRefactorRenameCategory)); +static cl::opt PrintName( + "pn", + cl::desc("Print the found symbol's name prior to renaming to stderr."), + cl::cat(ClangRefactorRenameCategory)); +static cl::opt PrintLocations( + "pl", cl::desc("Print the locations affected by renaming to stderr."), + cl::cat(ClangRefactorRenameCategory)); +static cl::opt ExportFixes( + "export-fixes", cl::desc("YAML file to store suggested fixes in."), + cl::value_desc("filename"), cl::cat(ClangRefactorRenameCategory)); +static cl::opt + Input("input", cl::desc("YAML file to load oldname-newname pairs from."), + cl::Optional, cl::cat(ClangRefactorRenameCategory)); + +} // namespace rename_module + +} // namespace clang_refactor +} // namespace clang + +#endif // CLANG_REFACTOR_OPTIONS_H Index: clang-refactor/driver/Driver.cpp =================================================================== --- /dev/null +++ clang-refactor/driver/Driver.cpp @@ -0,0 +1,53 @@ +//===---- tools/extra/clang-refactor/Driver.cpp - clang-refactor driver ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// \file This file implements clang-refactor driver. +// +//===----------------------------------------------------------------------===// + +#include "Rename.h" + +#include "llvm/ADT/StringSwitch.h" + +#include +#include + +using namespace clang; +using namespace llvm; + +const char HelpMessage[] = + "USAGE: clang-refactor [subcommand] [options] [... ]\n" + "\n" + "Subcommands:\n" + " rename: rename the symbol found at s or by s in " + ".\n"; + +static int printHelpMessage(int argc, const char *argv[]) { + outs() << HelpMessage; + return 0; +} + +int main(int argc, const char **argv) { + if (argc > 1) { + using MainFunction = std::function; + MainFunction Func = + StringSwitch(argv[1]) + .Cases("-help", "--help", printHelpMessage) + .Case("rename", clang_refactor::rename_module::RenameModuleMain) + .Default(nullptr); + if (Func) { + std::string Invocation = std::string(argv[0]) + " " + argv[1]; + argv[1] = Invocation.c_str(); + return Func(argc - 1, argv + 1); + } + } + + printHelpMessage(argc, argv); + return 0; +} Index: clang-refactor/driver/Rename.h =================================================================== --- /dev/null +++ clang-refactor/driver/Rename.h @@ -0,0 +1,203 @@ +//===--- tools/extra/clang-refactor/Rename.h - rename module driver -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements driver of rename module of clang-refactor. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_RENAME_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_RENAME_H + +#include "USRFindingAction.h" +#include "rename/RenamingAction.h" +#include "ClangRefactorOptions.h" + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/ReplacementsYaml.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; +using namespace clang; + +/// \brief An oldname -> newname rename. +struct RenameAllInfo { + unsigned Offset = 0; + std::string OldName; + std::string NewName; +}; + +LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo) + +namespace llvm { +namespace yaml { + +/// \brief Specialized MappingTraits to describe how a RenameAllInfo is +/// (de)serialized. +template <> struct MappingTraits { + static void mapping(IO &IO, RenameAllInfo &Info) { + IO.mapOptional("Offset", Info.Offset); + IO.mapOptional("OldName", Info.OldName); + IO.mapRequired("NewName", Info.NewName); + } +}; + +} // end namespace yaml +} // end namespace llvm + +namespace clang { +namespace clang_refactor { +namespace rename_module { + +int RenameModuleMain(int argc, const char **argv) { + tooling::CommonOptionsParser OP(argc, argv, ClangRefactorRenameCategory); + + if (!Input.empty()) { + // Populate QualifiedNames and NewNames from a YAML file. + ErrorOr> Buffer = + llvm::MemoryBuffer::getFile(Input); + if (!Buffer) { + errs() << "clang-refactor rename: failed to read " << Input << ": " + << Buffer.getError().message() << "\n"; + return 1; + } + + std::vector Infos; + llvm::yaml::Input YAML(Buffer.get()->getBuffer()); + YAML >> Infos; + for (const auto &Info : Infos) { + if (!Info.OldName.empty()) + QualifiedNames.push_back(Info.OldName); + else + SymbolOffsets.push_back(Info.Offset); + NewNames.push_back(Info.NewName); + } + } + + // Check the arguments for correctness. + if (NewNames.empty()) { + errs() << "clang-refactor rename: -new-name or -input is required.\n\n"; + exit(1); + } + + // Check if NewNames is a valid identifier in C++17. + LangOptions Options; + Options.CPlusPlus = true; + Options.CPlusPlus1z = true; + IdentifierTable Table(Options); + for (const auto &NewName : NewNames) { + auto NewNameTokKind = Table.get(NewName).getTokenID(); + if (!tok::isAnyIdentifier(NewNameTokKind)) { + errs() << "ERROR: new name is not a valid identifier in C++17.\n\n"; + exit(1); + } + } + + if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) { + errs() << "clang-refactor rename: number of symbol offsets(" + << SymbolOffsets.size() << ") + number of qualified names (" + << QualifiedNames.size() << ") must be equal to number of new names(" + << NewNames.size() << ").\n\n"; + cl::PrintHelpMessage(); + exit(1); + } + + auto Files = OP.getSourcePathList(); + tooling::RefactoringTool Tool(OP.getCompilations(), Files); + USRFindingAction FindingAction(SymbolOffsets, QualifiedNames); + Tool.run(tooling::newFrontendActionFactory(&FindingAction).get()); + const std::vector> &USRList = + FindingAction.getUSRList(); + const std::vector &PrevNames = FindingAction.getUSRSpellings(); + if (PrintName) { + for (const auto &PrevName : PrevNames) { + outs() << "clang-refactor rename found name: " << PrevName << '\n'; + } + } + + // Perform the renaming. + RenamingAction RenameAction(NewNames, PrevNames, USRList, + Tool.getReplacements(), PrintLocations); + std::unique_ptr Factory = + tooling::newFrontendActionFactory(&RenameAction); + int ExitCode; + + if (Inplace) { + ExitCode = Tool.runAndSave(Factory.get()); + } else { + ExitCode = Tool.run(Factory.get()); + + if (!ExportFixes.empty()) { + std::error_code EC; + llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None); + if (EC) { + llvm::errs() << "Error opening output file: " << EC.message() << '\n'; + exit(1); + } + + // Export replacements. + tooling::TranslationUnitReplacements TUR; + const auto &FileToReplacements = Tool.getReplacements(); + for (const auto &Entry : FileToReplacements) + TUR.Replacements.insert(TUR.Replacements.end(), Entry.second.begin(), + Entry.second.end()); + + yaml::Output YAML(OS); + YAML << TUR; + OS.close(); + exit(0); + } + + // Write every file to stdout. Right now we just barf the files without any + // indication of which files start where, other than that we print the files + // in the same order we see them. + LangOptions DefaultLangOptions; + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + &DiagnosticPrinter, false); + auto &FileMgr = Tool.getFiles(); + SourceManager Sources(Diagnostics, FileMgr); + Rewriter Rewrite(Sources, DefaultLangOptions); + + Tool.applyAllReplacements(Rewrite); + for (const auto &File : Files) { + const auto *Entry = FileMgr.getFile(File); + auto ID = Sources.translateFile(Entry); + Rewrite.getEditBuffer(ID).write(outs()); + } + } + + exit(ExitCode); +} + +} // namespace rename_module +} // namespace clang_refactor +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_RENAME_H Index: clang-refactor/editor-integrations/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/editor-integrations/CMakeLists.txt @@ -0,0 +1,6 @@ +install(PROGRAMS clang-refactor-rename.py + DESTINATION share/clang + COMPONENT clang-refactor) +install(PROGRAMS clang-refactor-rename.el + DESTINATION share/clang + COMPONENT clang-refactor) Index: clang-refactor/editor-integrations/clang-refactor-rename.el =================================================================== --- /dev/null +++ clang-refactor/editor-integrations/clang-refactor-rename.el @@ -0,0 +1,44 @@ +;;; clang-refactor-rename.el --- Renames symbols found at . + +;; Keywords: tools, c + +;;; Commentary: + +;; To install clang-refactor-rename.el make sure the directory of this file is +;; in your 'load-path' and add +;; +;; (require 'clang-refactor-rename) +;; +;; to your .emacs configuration. + +;;; Code: + +(defcustom clang-refactor "clang-refactor" + "Path to clang-refactor executable." + :type 'hook + :options '(turn-on-auto-fill flyspell-mode) + :group 'wp) + +(defun clang-refactor-rename (new-name) + "Rename all instances of the symbol at the point using clang-refactor rename" + (interactive "sEnter a new name: ") + (let (;; Emacs offset is 1-based. + (offset (- (point) 1)) + (orig-buf (current-buffer)) + (file-name (buffer-file-name))) + + (let ((rename-command + (format "bash -f -c '%s -offset=%s -new-name=%s -i %s'" + clang-refactor-binary offset new-name file-name))) + (message (format "Running clang-refactor command %s" rename-command)) + ;; Run clang-refactor via bash. + (shell-command rename-command) + ;; Reload buffer. + (revert-buffer t t) + ) + ) +) + +(provide 'clang-refactor) + +;;; clang-refactor.el ends here Index: clang-refactor/editor-integrations/clang-refactor-rename.py =================================================================== --- /dev/null +++ clang-refactor/editor-integrations/clang-refactor-rename.py @@ -0,0 +1,63 @@ +''' +Minimal clang-refactor rename integration with Vim. + +Before installing make sure one of the following is satisfied: + +* clang-refactor is in your PATH +* `g:clang_rename_path` in ~/.vimrc points to valid clang-refactor executable +* `binary` in clang-refactor rename.py points to valid to clang-refactor +executable + +To install, simply put this into your ~/.vimrc + + noremap cr :pyf /clang-refactor-rename.py + +IMPORTANT NOTE: Before running the tool, make sure you saved the file. + +All you have to do now is to place a cursor on a variable/function/class which +you would like to rename and press 'cr'. You will be prompted for a new +name if the cursor points to a valid symbol. +''' + +import vim +import subprocess +import sys + +def main(): + binary = 'clang-refactor' + if vim.eval('exists("g:clang_rename_path")') == "1": + binary = vim.eval('g:clang_rename_path') + + # Get arguments for clang-refactor binary. + offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2 + if offset < 0: + print >> sys.stderr, '''Couldn\'t determine cursor position. + Is your file empty?''' + return + filename = vim.current.buffer.name + + new_name_request_message = 'type new name:' + new_name = vim.eval("input('{}\n')".format(new_name_request_message)) + + # Call clang-refactor rename module. + command = [binary, + filename, + 'rename', + '-i', + '-offset', str(offset), + '-new-name', str(new_name)] + # FIXME: make it possible to run the tool on unsaved file. + p = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + + if stderr: + print stderr + + # Reload all buffers in Vim. + vim.command("bufdo edit") + + +if __name__ == '__main__': + main() Index: clang-refactor/modules/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/modules/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(rename) Index: clang-refactor/modules/rename/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/modules/rename/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_LINK_COMPONENTS Support) + +add_clang_library(clangRefactorRenameModule + RenamingAction.cpp + + LINK_LIBS + clangAST + clangBasic + clangFrontend + clangToolingCore + + clangRefactorUSREngine + ) Index: clang-refactor/modules/rename/RenamingAction.h =================================================================== --- /dev/null +++ clang-refactor/modules/rename/RenamingAction.h @@ -0,0 +1,50 @@ +//===--- tools/extra/clang-refactor/RenamingAction.h ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to rename every symbol at a point. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H + +#include "clang/Tooling/Refactoring.h" + +namespace clang { +class ASTConsumer; +class CompilerInstance; + +namespace clang_refactor { +namespace rename_module { + +class RenamingAction { +public: + RenamingAction(const std::vector &NewNames, + const std::vector &PrevNames, + const std::vector> &USRList, + std::map &FileToReplaces, + bool PrintLocations = false) + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} + + std::unique_ptr newASTConsumer(); + +private: + const std::vector &NewNames, &PrevNames; + const std::vector> &USRList; + std::map &FileToReplaces; + bool PrintLocations; +}; + +} // namespace rename_module +} // namespace clang_refactor +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H Index: clang-refactor/modules/rename/RenamingAction.cpp =================================================================== --- /dev/null +++ clang-refactor/modules/rename/RenamingAction.cpp @@ -0,0 +1,97 @@ +//===--- tools/extra/clang-refactor/RenamingAction.cpp --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Provides an action to rename every symbol at a point. +/// +//===----------------------------------------------------------------------===// + +#include "RenamingAction.h" +#include "USRLocFinder.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include +#include + +using namespace llvm; + +namespace clang { +namespace clang_refactor { +namespace rename_module { + +class RenamingASTConsumer : public ASTConsumer { +public: + RenamingASTConsumer( + const std::vector &NewNames, + const std::vector &PrevNames, + const std::vector> &USRList, + std::map &FileToReplaces, + bool PrintLocations) + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} + + void HandleTranslationUnit(ASTContext &Context) override { + for (unsigned I = 0; I < NewNames.size(); ++I) { + HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]); + } + } + + void HandleOneRename(ASTContext &Context, const std::string &NewName, + const std::string &PrevName, + const std::vector &USRs) { + const SourceManager &SourceMgr = Context.getSourceManager(); + std::vector RenamingCandidates; + std::vector NewCandidates; + + NewCandidates = + getLocationsOfUSRs(USRs, PrevName, Context.getTranslationUnitDecl()); + RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), + NewCandidates.end()); + + unsigned PrevNameLen = PrevName.length(); + for (const auto &Loc : RenamingCandidates) { + if (PrintLocations) { + FullSourceLoc FullLoc(Loc, SourceMgr); + errs() << "clang-refactor rename: renamed at: " + << SourceMgr.getFilename(Loc) << ":" + << FullLoc.getSpellingLineNumber() << ":" + << FullLoc.getSpellingColumnNumber() << "\n"; + } + // FIXME: better error handling. + tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); + llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); + if (Err) + llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " + << llvm::toString(std::move(Err)) << "\n"; + } + } + +private: + const std::vector &NewNames, &PrevNames; + const std::vector> &USRList; + std::map &FileToReplaces; + bool PrintLocations; +}; + +std::unique_ptr RenamingAction::newASTConsumer() { + return llvm::make_unique(NewNames, PrevNames, USRList, + FileToReplaces, PrintLocations); +} + +} // namespace rename_module +} // namespace clang_refactor +} // namespace clang Index: clang-rename/CMakeLists.txt =================================================================== --- clang-rename/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -add_clang_library(clangRename - USRFinder.cpp - USRFindingAction.cpp - USRLocFinder.cpp - RenamingAction.cpp - - LINK_LIBS - clangAST - clangASTMatchers - clangBasic - clangIndex - clangLex - clangToolingCore - ) - -add_subdirectory(tool) Index: clang-rename/RenamingAction.h =================================================================== --- clang-rename/RenamingAction.h +++ /dev/null @@ -1,47 +0,0 @@ -//===--- tools/extra/clang-rename/RenamingAction.h - Clang rename tool ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provides an action to rename every symbol at a point. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H - -#include "clang/Tooling/Refactoring.h" - -namespace clang { -class ASTConsumer; -class CompilerInstance; - -namespace rename { - -class RenamingAction { -public: - RenamingAction(const std::vector &NewNames, - const std::vector &PrevNames, - const std::vector> &USRList, - std::map &FileToReplaces, - bool PrintLocations = false) - : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), - FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} - - std::unique_ptr newASTConsumer(); - -private: - const std::vector &NewNames, &PrevNames; - const std::vector> &USRList; - std::map &FileToReplaces; - bool PrintLocations; -}; -} -} - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_RENAMING_ACTION_H Index: clang-rename/RenamingAction.cpp =================================================================== --- clang-rename/RenamingAction.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===--- tools/extra/clang-rename/RenamingAction.cpp - Clang rename tool --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provides an action to rename every symbol at a point. -/// -//===----------------------------------------------------------------------===// - -#include "RenamingAction.h" -#include "USRLocFinder.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/Basic/FileManager.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" -#include -#include - -using namespace llvm; - -namespace clang { -namespace rename { - -class RenamingASTConsumer : public ASTConsumer { -public: - RenamingASTConsumer( - const std::vector &NewNames, - const std::vector &PrevNames, - const std::vector> &USRList, - std::map &FileToReplaces, - bool PrintLocations) - : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), - FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} - - void HandleTranslationUnit(ASTContext &Context) override { - for (unsigned I = 0; I < NewNames.size(); ++I) { - HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]); - } - } - - void HandleOneRename(ASTContext &Context, const std::string &NewName, - const std::string &PrevName, - const std::vector &USRs) { - const SourceManager &SourceMgr = Context.getSourceManager(); - std::vector RenamingCandidates; - std::vector NewCandidates; - - NewCandidates = - getLocationsOfUSRs(USRs, PrevName, Context.getTranslationUnitDecl()); - RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), - NewCandidates.end()); - - unsigned PrevNameLen = PrevName.length(); - for (const auto &Loc : RenamingCandidates) { - if (PrintLocations) { - FullSourceLoc FullLoc(Loc, SourceMgr); - errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) - << ":" << FullLoc.getSpellingLineNumber() << ":" - << FullLoc.getSpellingColumnNumber() << "\n"; - } - // FIXME: better error handling. - tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); - llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); - if (Err) - llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " - << llvm::toString(std::move(Err)) << "\n"; - } - } - -private: - const std::vector &NewNames, &PrevNames; - const std::vector> &USRList; - std::map &FileToReplaces; - bool PrintLocations; -}; - -std::unique_ptr RenamingAction::newASTConsumer() { - return llvm::make_unique(NewNames, PrevNames, USRList, - FileToReplaces, PrintLocations); -} - -} // namespace rename -} // namespace clang Index: clang-rename/USRFinder.h =================================================================== --- clang-rename/USRFinder.h +++ /dev/null @@ -1,80 +0,0 @@ -//===--- tools/extra/clang-rename/USRFinder.h - Clang rename tool ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Methods for determining the USR of a symbol at a location in source -/// code. -/// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H - -#include "clang/AST/AST.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include - -using namespace llvm; -using namespace clang::ast_matchers; - -namespace clang { -class ASTContext; -class Decl; -class SourceLocation; -class NamedDecl; - -namespace rename { - -// Given an AST context and a point, returns a NamedDecl identifying the symbol -// at the point. Returns null if nothing is found at the point. -const NamedDecl *getNamedDeclAt(const ASTContext &Context, - const SourceLocation Point); - -// Given an AST context and a fully qualified name, returns a NamedDecl -// identifying the symbol with a matching name. Returns null if nothing is -// found for the name. -const NamedDecl *getNamedDeclFor(const ASTContext &Context, - const std::string &Name); - -// Converts a Decl into a USR. -std::string getUSRForDecl(const Decl *Decl); - -// FIXME: Implement RecursiveASTVisitor::VisitNestedNameSpecifier instead. -class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback { -public: - explicit NestedNameSpecifierLocFinder(ASTContext &Context) - : Context(Context) {} - - std::vector getNestedNameSpecifierLocations() { - addMatchers(); - Finder.matchAST(Context); - return Locations; - } - -private: - void addMatchers() { - const auto NestedNameSpecifierLocMatcher = - nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc"); - Finder.addMatcher(NestedNameSpecifierLocMatcher, this); - } - - virtual void run(const MatchFinder::MatchResult &Result) { - const auto *NNS = Result.Nodes.getNodeAs( - "nestedNameSpecifierLoc"); - Locations.push_back(*NNS); - } - - ASTContext &Context; - std::vector Locations; - MatchFinder Finder; -}; -} -} - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H Index: clang-rename/USRFinder.cpp =================================================================== --- clang-rename/USRFinder.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//===--- tools/extra/clang-rename/USRFinder.cpp - Clang rename tool -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file Implements a recursive AST visitor that finds the USR of a symbol at a -/// point. -/// -//===----------------------------------------------------------------------===// - -#include "USRFinder.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Index/USRGeneration.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallVector.h" - -using namespace llvm; - -namespace clang { -namespace rename { - -// NamedDeclFindingASTVisitor recursively visits each AST node to find the -// symbol underneath the cursor. -// FIXME: move to seperate .h/.cc file if this gets too large. -namespace { -class NamedDeclFindingASTVisitor - : public clang::RecursiveASTVisitor { -public: - // \brief Finds the NamedDecl at a point in the source. - // \param Point the location in the source to search for the NamedDecl. - explicit NamedDeclFindingASTVisitor(const SourceLocation Point, - const ASTContext &Context) - : Result(nullptr), Point(Point), Context(Context) {} - - // \brief Finds the NamedDecl for a name in the source. - // \param Name the fully qualified name. - explicit NamedDeclFindingASTVisitor(const std::string &Name, - const ASTContext &Context) - : Result(nullptr), Name(Name), Context(Context) {} - - // Declaration visitors: - - // \brief Checks if the point falls within the NameDecl. This covers every - // declaration of a named entity that we may come across. Usually, just - // checking if the point lies within the length of the name of the declaration - // and the start location is sufficient. - bool VisitNamedDecl(const NamedDecl *Decl) { - return dyn_cast(Decl) - ? true - : setResult(Decl, Decl->getLocation(), - Decl->getNameAsString().length()); - } - - // Expression visitors: - - bool VisitDeclRefExpr(const DeclRefExpr *Expr) { - const NamedDecl *Decl = Expr->getFoundDecl(); - return setResult(Decl, Expr->getLocation(), - Decl->getNameAsString().length()); - } - - bool VisitMemberExpr(const MemberExpr *Expr) { - const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); - return setResult(Decl, Expr->getMemberLoc(), - Decl->getNameAsString().length()); - } - - // Other visitors: - - bool VisitTypeLoc(const TypeLoc Loc) { - const SourceLocation TypeBeginLoc = Loc.getBeginLoc(); - const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken( - TypeBeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); - if (const auto *TemplateTypeParm = - dyn_cast(Loc.getType())) { - return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc); - } - if (const auto *TemplateSpecType = - dyn_cast(Loc.getType())) { - return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(), - TypeBeginLoc, TypeEndLoc); - } - return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, - TypeEndLoc); - } - - bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { - for (const auto *Initializer : ConstructorDecl->inits()) { - if (!Initializer->isWritten()) { - // Ignore implicit initializers. - continue; - } - if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { - const SourceLocation InitBeginLoc = Initializer->getSourceLocation(), - InitEndLoc = Lexer::getLocForEndOfToken( - InitBeginLoc, 0, Context.getSourceManager(), - Context.getLangOpts()); - if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc)) { - return false; - } - } - } - return true; - } - - // Other: - - const NamedDecl *getNamedDecl() { return Result; } - - // \brief Determines if a namespace qualifier contains the point. - // \returns false on success and sets Result. - void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { - while (NameLoc) { - const NamespaceDecl *Decl = - NameLoc.getNestedNameSpecifier()->getAsNamespace(); - setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc()); - NameLoc = NameLoc.getPrefix(); - } - } - -private: - // \brief Sets Result to Decl if the Point is within Start and End. - // \returns false on success. - bool setResult(const NamedDecl *Decl, SourceLocation Start, - SourceLocation End) { - if (!Decl) { - return true; - } - if (Name.empty()) { - // Offset is used to find the declaration. - if (!Start.isValid() || !Start.isFileID() || !End.isValid() || - !End.isFileID() || !isPointWithin(Start, End)) { - return true; - } - } else { - // Fully qualified name is used to find the declaration. - if (Name != Decl->getQualifiedNameAsString()) { - return true; - } - } - Result = Decl; - return false; - } - - // \brief Sets Result to Decl if Point is within Loc and Loc + Offset. - // \returns false on success. - bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) { - // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc). - return Offset == 0 || - setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1)); - } - - // \brief Determines if the Point is within Start and End. - bool isPointWithin(const SourceLocation Start, const SourceLocation End) { - // FIXME: Add tests for Point == End. - return Point == Start || Point == End || - (Context.getSourceManager().isBeforeInTranslationUnit(Start, - Point) && - Context.getSourceManager().isBeforeInTranslationUnit(Point, End)); - } - - const NamedDecl *Result; - const SourceLocation Point; // The location to find the NamedDecl. - const std::string Name; - const ASTContext &Context; -}; -} // namespace - -const NamedDecl *getNamedDeclAt(const ASTContext &Context, - const SourceLocation Point) { - StringRef SearchFile = Context.getSourceManager().getFilename(Point); - NamedDeclFindingASTVisitor Visitor(Point, Context); - - // We only want to search the decls that exist in the same file as the point. - for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) { - const SourceLocation FileLoc = CurrDecl->getLocStart(); - StringRef FileName = Context.getSourceManager().getFilename(FileLoc); - // FIXME: Add test. - if (FileName == SearchFile) { - Visitor.TraverseDecl(CurrDecl); - } - } - - NestedNameSpecifierLocFinder Finder(const_cast(Context)); - for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { - Visitor.handleNestedNameSpecifierLoc(Location); - } - - return Visitor.getNamedDecl(); -} - -const NamedDecl *getNamedDeclFor(const ASTContext &Context, - const std::string &Name) { - NamedDeclFindingASTVisitor Visitor(Name, Context); - Visitor.TraverseDecl(Context.getTranslationUnitDecl()); - - return Visitor.getNamedDecl(); -} - -std::string getUSRForDecl(const Decl *Decl) { - llvm::SmallVector Buff; - - // FIXME: Add test for the nullptr case. - if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff)) - return ""; - - return std::string(Buff.data(), Buff.size()); -} - -} // namespace rename -} // namespace clang Index: clang-rename/USRFindingAction.h =================================================================== --- clang-rename/USRFindingAction.h +++ /dev/null @@ -1,47 +0,0 @@ -//===--- tools/extra/clang-rename/USRFindingAction.h - Clang rename tool --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provides an action to find all relevant USRs at a point. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H - -#include "clang/Frontend/FrontendAction.h" - -namespace clang { -class ASTConsumer; -class CompilerInstance; -class NamedDecl; - -namespace rename { - -struct USRFindingAction { - USRFindingAction(unsigned Offset, const std::string &Name) - : SymbolOffset(Offset), OldName(Name) {} - std::unique_ptr newASTConsumer(); - - // \brief get the spelling of the USR(s) as it would appear in source files. - const std::string &getUSRSpelling() { return SpellingName; } - - const std::vector &getUSRs() { return USRs; } - -private: - unsigned SymbolOffset; - std::string OldName; - std::string SpellingName; - std::vector USRs; -}; - -} // namespace rename -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDING_ACTION_H Index: clang-rename/USRFindingAction.cpp =================================================================== --- clang-rename/USRFindingAction.cpp +++ /dev/null @@ -1,203 +0,0 @@ -//===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provides an action to find USR for the symbol at , as well as -/// all additional USRs. -/// -//===----------------------------------------------------------------------===// - -#include "USRFindingAction.h" -#include "USRFinder.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/FileManager.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" -#include -#include -#include -#include - -using namespace llvm; - -namespace clang { -namespace rename { - -namespace { -// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to -// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given -// Decl refers to class and adds USRs of all overridden methods if Decl refers -// to virtual method. -class AdditionalUSRFinder : public RecursiveASTVisitor { -public: - explicit AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context, - std::vector *USRs) - : FoundDecl(FoundDecl), Context(Context), USRs(USRs) {} - - void Find() { - // Fill OverriddenMethods and PartialSpecs storages. - TraverseDecl(Context.getTranslationUnitDecl()); - if (const auto *MethodDecl = dyn_cast(FoundDecl)) { - addUSRsOfOverridenFunctions(MethodDecl); - for (const auto &OverriddenMethod : OverriddenMethods) { - if (checkIfOverriddenFunctionAscends(OverriddenMethod)) { - USRSet.insert(getUSRForDecl(OverriddenMethod)); - } - } - } else if (const auto *RecordDecl = dyn_cast(FoundDecl)) { - handleCXXRecordDecl(RecordDecl); - } else if (const auto *TemplateDecl = - dyn_cast(FoundDecl)) { - handleClassTemplateDecl(TemplateDecl); - } else { - USRSet.insert(getUSRForDecl(FoundDecl)); - } - USRs->insert(USRs->end(), USRSet.begin(), USRSet.end()); - } - - bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { - if (MethodDecl->isVirtual()) { - OverriddenMethods.push_back(MethodDecl); - } - return true; - } - - bool VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *PartialSpec) { - PartialSpecs.push_back(PartialSpec); - return true; - } - -private: - void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) { - RecordDecl = RecordDecl->getDefinition(); - if (const auto *ClassTemplateSpecDecl = - dyn_cast(RecordDecl)) { - handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate()); - } - addUSRsOfCtorDtors(RecordDecl); - } - - void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) { - for (const auto *Specialization : TemplateDecl->specializations()) { - addUSRsOfCtorDtors(Specialization); - } - for (const auto *PartialSpec : PartialSpecs) { - if (PartialSpec->getSpecializedTemplate() == TemplateDecl) { - addUSRsOfCtorDtors(PartialSpec); - } - } - addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl()); - } - - void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) { - RecordDecl = RecordDecl->getDefinition(); - for (const auto *CtorDecl : RecordDecl->ctors()) { - USRSet.insert(getUSRForDecl(CtorDecl)); - } - USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); - USRSet.insert(getUSRForDecl(RecordDecl)); - } - - void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) { - USRSet.insert(getUSRForDecl(MethodDecl)); - for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { - // Recursively visit each OverridenMethod. - addUSRsOfOverridenFunctions(OverriddenMethod); - } - } - - bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { - for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { - if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) { - return true; - } - return checkIfOverriddenFunctionAscends(OverriddenMethod); - } - return false; - } - - const Decl *FoundDecl; - ASTContext &Context; - std::vector *USRs; - std::set USRSet; - std::vector OverriddenMethods; - std::vector PartialSpecs; -}; -} // namespace - -struct NamedDeclFindingConsumer : public ASTConsumer { - void HandleTranslationUnit(ASTContext &Context) override { - const SourceManager &SourceMgr = Context.getSourceManager(); - // The file we look for the USR in will always be the main source file. - const SourceLocation Point = - SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) - .getLocWithOffset(SymbolOffset); - if (!Point.isValid()) - return; - const NamedDecl *FoundDecl = nullptr; - if (OldName.empty()) { - FoundDecl = getNamedDeclAt(Context, Point); - } else { - FoundDecl = getNamedDeclFor(Context, OldName); - } - if (FoundDecl == nullptr) { - if (OldName.empty()) { - FullSourceLoc FullLoc(Point, SourceMgr); - errs() << "clang-rename: could not find symbol at " - << SourceMgr.getFilename(Point) << ":" - << FullLoc.getSpellingLineNumber() << ":" - << FullLoc.getSpellingColumnNumber() << " (offset " - << SymbolOffset << ").\n"; - } else - errs() << "clang-rename: could not find symbol " << OldName << ".\n"; - return; - } - - // If FoundDecl is a constructor or destructor, we want to instead take the - // Decl of the corresponding class. - if (const auto *CtorDecl = dyn_cast(FoundDecl)) { - FoundDecl = CtorDecl->getParent(); - } else if (const auto *DtorDecl = dyn_cast(FoundDecl)) { - FoundDecl = DtorDecl->getParent(); - } - *SpellingName = FoundDecl->getNameAsString(); - - AdditionalUSRFinder Finder(FoundDecl, Context, USRs); - Finder.Find(); - } - - unsigned SymbolOffset; - std::string OldName; - std::string *SpellingName; - std::vector *USRs; -}; - -std::unique_ptr USRFindingAction::newASTConsumer() { - std::unique_ptr Consumer( - new NamedDeclFindingConsumer); - SpellingName = ""; - Consumer->SymbolOffset = SymbolOffset; - Consumer->OldName = OldName; - Consumer->USRs = &USRs; - Consumer->SpellingName = &SpellingName; - return std::move(Consumer); -} - -} // namespace rename -} // namespace clang Index: clang-rename/USRLocFinder.h =================================================================== --- clang-rename/USRLocFinder.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- tools/extra/clang-rename/USRLocFinder.h - Clang rename tool ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provides functionality for finding all instances of a USR in a given -/// AST. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H - -#include "clang/AST/AST.h" -#include "llvm/ADT/StringRef.h" -#include -#include - -namespace clang { -namespace rename { - -// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree! -std::vector -getLocationsOfUSRs(const std::vector &USRs, - llvm::StringRef PrevName, Decl *Decl); - -} // namespace rename -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_LOC_FINDER_H Index: clang-rename/USRLocFinder.cpp =================================================================== --- clang-rename/USRLocFinder.cpp +++ /dev/null @@ -1,164 +0,0 @@ -//===--- tools/extra/clang-rename/USRLocFinder.cpp - Clang rename tool ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Mehtods for finding all instances of a USR. Our strategy is very -/// simple; we just compare the USR at every relevant AST node with the one -/// provided. -/// -//===----------------------------------------------------------------------===// - -#include "USRLocFinder.h" -#include "USRFinder.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Index/USRGeneration.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallVector.h" - -using namespace llvm; - -namespace clang { -namespace rename { - -namespace { -// \brief This visitor recursively searches for all instances of a USR in a -// translation unit and stores them for later usage. -class USRLocFindingASTVisitor - : public clang::RecursiveASTVisitor { -public: - explicit USRLocFindingASTVisitor(const std::vector &USRs, - StringRef PrevName, - const ASTContext &Context) - : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { - } - - // Declaration visitors: - - bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { - for (const auto *Initializer : ConstructorDecl->inits()) { - if (!Initializer->isWritten()) { - // Ignore implicit initializers. - continue; - } - if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) { - if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end()) { - LocationsFound.push_back(Initializer->getSourceLocation()); - } - } - } - return true; - } - - bool VisitNamedDecl(const NamedDecl *Decl) { - if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { - checkAndAddLocation(Decl->getLocation()); - } - return true; - } - - // Expression visitors: - - bool VisitDeclRefExpr(const DeclRefExpr *Expr) { - const NamedDecl *Decl = Expr->getFoundDecl(); - - if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { - const SourceManager &Manager = Decl->getASTContext().getSourceManager(); - SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation()); - checkAndAddLocation(Location); - } - - return true; - } - - bool VisitMemberExpr(const MemberExpr *Expr) { - const NamedDecl *Decl = Expr->getFoundDecl().getDecl(); - if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { - const SourceManager &Manager = Decl->getASTContext().getSourceManager(); - SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc()); - checkAndAddLocation(Location); - } - return true; - } - - // Other visitors: - - bool VisitTypeLoc(const TypeLoc Loc) { - if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl())) != - USRSet.end()) { - checkAndAddLocation(Loc.getBeginLoc()); - } - if (const auto *TemplateTypeParm = - dyn_cast(Loc.getType())) { - if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) != - USRSet.end()) { - checkAndAddLocation(Loc.getBeginLoc()); - } - } - return true; - } - - // Non-visitors: - - // \brief Returns a list of unique locations. Duplicate or overlapping - // locations are erroneous and should be reported! - const std::vector &getLocationsFound() const { - return LocationsFound; - } - - // Namespace traversal: - void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { - while (NameLoc) { - const NamespaceDecl *Decl = - NameLoc.getNestedNameSpecifier()->getAsNamespace(); - if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) { - checkAndAddLocation(NameLoc.getLocalBeginLoc()); - } - NameLoc = NameLoc.getPrefix(); - } - } - -private: - void checkAndAddLocation(SourceLocation Loc) { - const SourceLocation BeginLoc = Loc; - const SourceLocation EndLoc = Lexer::getLocForEndOfToken( - BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); - StringRef TokenName = - Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), - Context.getSourceManager(), Context.getLangOpts()); - size_t Offset = TokenName.find(PrevName); - if (Offset != StringRef::npos) { - // The token of the source location we find actually has the old - // name. - LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); - } - } - - const std::set USRSet; - const std::string PrevName; - std::vector LocationsFound; - const ASTContext &Context; -}; -} // namespace - -std::vector -getLocationsOfUSRs(const std::vector &USRs, StringRef PrevName, - Decl *Decl) { - USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); - Visitor.TraverseDecl(Decl); - NestedNameSpecifierLocFinder Finder(Decl->getASTContext()); - for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { - Visitor.handleNestedNameSpecifierLoc(Location); - } - return Visitor.getLocationsFound(); -} - -} // namespace rename -} // namespace clang Index: clang-rename/tool/CMakeLists.txt =================================================================== --- clang-rename/tool/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -add_clang_executable(clang-rename ClangRename.cpp) - -target_link_libraries(clang-rename - clangBasic - clangFrontend - clangRename - clangRewrite - clangTooling - clangToolingCore - ) - -install(TARGETS clang-rename RUNTIME DESTINATION bin) - -install(PROGRAMS clang-rename.py - DESTINATION share/clang - COMPONENT clang-rename) -install(PROGRAMS clang-rename.el - DESTINATION share/clang - COMPONENT clang-rename) Index: clang-rename/tool/ClangRename.cpp =================================================================== --- clang-rename/tool/ClangRename.cpp +++ /dev/null @@ -1,310 +0,0 @@ -//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief This file implements a clang-rename tool that automatically finds and -/// renames symbols in C++ code. -/// -//===----------------------------------------------------------------------===// - -#include "../RenamingAction.h" -#include "../USRFindingAction.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TokenKinds.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -using namespace llvm; - -using namespace clang; - -cl::OptionCategory ClangRenameAtCategory("clang-rename rename-at options"); -cl::OptionCategory ClangRenameAllCategory("clang-rename rename-all options"); - -const char RenameAtUsage[] = "A tool to rename symbols in C/C++ code.\n\ -clang-rename renames every occurrence of a symbol found at in\n\ -. If -i is specified, the edited files are overwritten to disk.\n\ -Otherwise, the results are written to stdout.\n"; - -const char RenameAllUsage[] = "A tool to rename symbols in C/C++ code.\n\ -clang-rename performs renaming given pairs {offset | old-name} -> new-name.\n"; - -static int renameAtMain(int argc, const char *argv[]); -static int renameAllMain(int argc, const char *argv[]); -static int helpMain(int argc, const char *argv[]); - -/// \brief An oldname -> newname rename. -struct RenameAllInfo { - std::string OldName; - unsigned Offset = 0; - std::string NewName; -}; - -LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo) - -namespace llvm { -namespace yaml { - -/// \brief Specialized MappingTraits to describe how a RenameAllInfo is -/// (de)serialized. -template <> struct MappingTraits { - static void mapping(IO &IO, RenameAllInfo &Info) { - IO.mapOptional("OldName", Info.OldName); - IO.mapOptional("Offset", Info.Offset); - IO.mapRequired("NewName", Info.NewName); - } -}; - -} // end namespace yaml -} // end namespace llvm - -int main(int argc, const char **argv) { - if (argc > 1) { - using MainFunction = std::function; - MainFunction Func = StringSwitch(argv[1]) - .Case("rename-at", renameAtMain) - .Case("rename-all", renameAllMain) - .Cases("-help", "--help", helpMain) - .Default(nullptr); - - if (Func) { - std::string Invocation = std::string(argv[0]) + " " + argv[1]; - argv[1] = Invocation.c_str(); - return Func(argc - 1, argv + 1); - } else { - return renameAtMain(argc, argv); - } - } - - helpMain(argc, argv); - return 1; -} - -int subcommandMain(bool isRenameAll, int argc, const char **argv) { - cl::OptionCategory *Category = nullptr; - const char *Usage = nullptr; - if (isRenameAll) { - Category = &ClangRenameAllCategory; - Usage = RenameAllUsage; - } else { - Category = &ClangRenameAtCategory; - Usage = RenameAtUsage; - } - - cl::list NewNames( - "new-name", cl::desc("The new name to change the symbol to."), - (isRenameAll ? cl::ZeroOrMore : cl::Required), cl::cat(*Category)); - cl::list SymbolOffsets( - "offset", - cl::desc("Locates the symbol by offset as opposed to :."), - (isRenameAll ? cl::ZeroOrMore : cl::Required), cl::cat(*Category)); - cl::list OldNames( - "old-name", - cl::desc( - "The fully qualified name of the symbol, if -offset is not used."), - (isRenameAll ? cl::ZeroOrMore : cl::Optional), - cl::cat(ClangRenameAllCategory)); - cl::opt Inplace("i", cl::desc("Overwrite edited s."), - cl::cat(*Category)); - cl::opt PrintName( - "pn", - cl::desc("Print the found symbol's name prior to renaming to stderr."), - cl::cat(ClangRenameAtCategory)); - cl::opt PrintLocations( - "pl", cl::desc("Print the locations affected by renaming to stderr."), - cl::cat(ClangRenameAtCategory)); - cl::opt ExportFixes( - "export-fixes", cl::desc("YAML file to store suggested fixes in."), - cl::value_desc("filename"), cl::cat(*Category)); - cl::opt Input( - "input", cl::desc("YAML file to load oldname-newname pairs from."), - cl::Optional, cl::cat(ClangRenameAllCategory)); - - tooling::CommonOptionsParser OP(argc, argv, *Category, Usage); - - if (!Input.empty()) { - // Populate OldNames and NewNames from a YAML file. - ErrorOr> Buffer = - llvm::MemoryBuffer::getFile(Input); - if (!Buffer) { - errs() << "clang-rename: failed to read " << Input << ": " - << Buffer.getError().message() << "\n"; - return 1; - } - - std::vector Infos; - llvm::yaml::Input YAML(Buffer.get()->getBuffer()); - YAML >> Infos; - for (const auto &Info : Infos) { - if (!Info.OldName.empty()) - OldNames.push_back(Info.OldName); - else - SymbolOffsets.push_back(Info.Offset); - NewNames.push_back(Info.NewName); - } - } - - // Check the arguments for correctness. - - if (NewNames.empty()) { - errs() << "clang-rename: either -new-name or -input is required.\n\n"; - exit(1); - } - - // Check if NewNames is a valid identifier in C++17. - for (const auto &NewName : NewNames) { - LangOptions Options; - Options.CPlusPlus = true; - Options.CPlusPlus1z = true; - IdentifierTable Table(Options); - auto NewNameTokKind = Table.get(NewName).getTokenID(); - if (!tok::isAnyIdentifier(NewNameTokKind)) { - errs() << "ERROR: new name is not a valid identifier in C++17.\n\n"; - exit(1); - } - } - - if (!OldNames.empty() && OldNames.size() != NewNames.size()) { - errs() << "clang-rename: number of old names (" << OldNames.size() - << ") do not equal to number of new names (" << NewNames.size() - << ").\n\n"; - cl::PrintHelpMessage(); - exit(1); - } - - if (!SymbolOffsets.empty() && SymbolOffsets.size() != NewNames.size()) { - errs() << "clang-rename: number of symbol offsets (" << SymbolOffsets.size() - << ") do not equal to number of new names (" << NewNames.size() - << ").\n\n"; - cl::PrintHelpMessage(); - exit(1); - } - - std::vector> USRList; - std::vector PrevNames; - auto Files = OP.getSourcePathList(); - tooling::RefactoringTool Tool(OP.getCompilations(), Files); - unsigned Count = OldNames.size() ? OldNames.size() : SymbolOffsets.size(); - for (unsigned I = 0; I < Count; ++I) { - unsigned SymbolOffset = SymbolOffsets.empty() ? 0 : SymbolOffsets[I]; - const std::string &OldName = OldNames.empty() ? std::string() : OldNames[I]; - - // Get the USRs. - rename::USRFindingAction USRAction(SymbolOffset, OldName); - - // Find the USRs. - Tool.run(tooling::newFrontendActionFactory(&USRAction).get()); - const auto &USRs = USRAction.getUSRs(); - USRList.push_back(USRs); - const auto &PrevName = USRAction.getUSRSpelling(); - PrevNames.push_back(PrevName); - - if (PrevName.empty()) { - // An error should have already been printed. - exit(1); - } - - if (PrintName) { - errs() << "clang-rename: found name: " << PrevName << '\n'; - } - } - - // Perform the renaming. - rename::RenamingAction RenameAction(NewNames, PrevNames, USRList, - Tool.getReplacements(), PrintLocations); - auto Factory = tooling::newFrontendActionFactory(&RenameAction); - int ExitCode; - - if (Inplace) { - ExitCode = Tool.runAndSave(Factory.get()); - } else { - ExitCode = Tool.run(Factory.get()); - - if (!ExportFixes.empty()) { - std::error_code EC; - llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None); - if (EC) { - llvm::errs() << "Error opening output file: " << EC.message() << '\n'; - exit(1); - } - - // Export replacements. - tooling::TranslationUnitReplacements TUR; - const auto &FileToReplacements = Tool.getReplacements(); - for (const auto &Entry : FileToReplacements) - TUR.Replacements.insert(TUR.Replacements.end(), Entry.second.begin(), - Entry.second.end()); - - yaml::Output YAML(OS); - YAML << TUR; - OS.close(); - exit(0); - } - - // Write every file to stdout. Right now we just barf the files without any - // indication of which files start where, other than that we print the files - // in the same order we see them. - LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, - &DiagnosticPrinter, false); - auto &FileMgr = Tool.getFiles(); - SourceManager Sources(Diagnostics, FileMgr); - Rewriter Rewrite(Sources, DefaultLangOptions); - - Tool.applyAllReplacements(Rewrite); - for (const auto &File : Files) { - const auto *Entry = FileMgr.getFile(File); - auto ID = Sources.translateFile(Entry); - Rewrite.getEditBuffer(ID).write(outs()); - } - } - - exit(ExitCode); -} - -/// \brief Top level help. -/// FIXME It would be better if this could be auto-generated. -static int helpMain(int argc, const char *argv[]) { - errs() << "Usage: clang-rename {rename-at|rename-all} [OPTION]...\n\n" - "A tool to rename symbols in C/C++ code.\n\n" - "Subcommands:\n" - " rename-at: Perform rename off of a location in a file. (This " - "is the default.)\n" - " rename-all: Perform rename of all symbols matching one or more " - "fully qualified names.\n"; - return 0; -} - -static int renameAtMain(int argc, const char *argv[]) { - return subcommandMain(false, argc, argv); -} - -static int renameAllMain(int argc, const char *argv[]) { - return subcommandMain(true, argc, argv); -} Index: clang-rename/tool/clang-rename.el =================================================================== --- clang-rename/tool/clang-rename.el +++ /dev/null @@ -1,44 +0,0 @@ -;;; clang-rename.el --- Renames every occurrence of a symbol found at . - -;; Keywords: tools, c - -;;; Commentary: - -;; To install clang-rename.el make sure the directory of this file is in your -;; 'load-path' and add -;; -;; (require 'clang-rename) -;; -;; to your .emacs configuration. - -;;; Code: - -(defcustom clang-rename-binary "clang-rename" - "Path to clang-rename executable." - :type 'hook - :options '(turn-on-auto-fill flyspell-mode) - :group 'wp) - -(defun clang-rename (new-name) - "Rename all instances of the symbol at the point using clang-rename" - (interactive "sEnter a new name: ") - (let (;; Emacs offset is 1-based. - (offset (- (point) 1)) - (orig-buf (current-buffer)) - (file-name (buffer-file-name))) - - (let ((rename-command - (format "bash -f -c '%s -offset=%s -new-name=%s -i %s'" - clang-rename-binary offset new-name file-name))) - (message (format "Running clang-rename command %s" rename-command)) - ;; Run clang-rename via bash. - (shell-command rename-command) - ;; Reload buffer. - (revert-buffer t t) - ) - ) -) - -(provide 'clang-rename) - -;;; clang-rename.el ends here Index: clang-rename/tool/clang-rename.py =================================================================== --- clang-rename/tool/clang-rename.py +++ /dev/null @@ -1,61 +0,0 @@ -''' -Minimal clang-rename integration with Vim. - -Before installing make sure one of the following is satisfied: - -* clang-rename is in your PATH -* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable -* `binary` in clang-rename.py points to valid to clang-rename executable - -To install, simply put this into your ~/.vimrc - - noremap cr :pyf /clang-rename.py - -IMPORTANT NOTE: Before running the tool, make sure you saved the file. - -All you have to do now is to place a cursor on a variable/function/class which -you would like to rename and press 'cr'. You will be prompted for a new -name if the cursor points to a valid symbol. -''' - -import vim -import subprocess -import sys - -def main(): - binary = 'clang-rename' - if vim.eval('exists("g:clang_rename_path")') == "1": - binary = vim.eval('g:clang_rename_path') - - # Get arguments for clang-rename binary. - offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2 - if offset < 0: - print >> sys.stderr, '''Couldn\'t determine cursor position. - Is your file empty?''' - return - filename = vim.current.buffer.name - - new_name_request_message = 'type new name:' - new_name = vim.eval("input('{}\n')".format(new_name_request_message)) - - # Call clang-rename. - command = [binary, - filename, - '-i', - '-offset', str(offset), - '-new-name', str(new_name)] - # FIXME: make it possible to run the tool on unsaved file. - p = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - - if stderr: - print stderr - - # Reload all buffers in Vim. - vim.command("bufdo edit") - - -if __name__ == '__main__': - main() Index: docs/clang-refactor/index.rst =================================================================== --- /dev/null +++ docs/clang-refactor/index.rst @@ -0,0 +1,32 @@ +============== +Clang-Refactor +============== + +.. contents:: + +See also: + +.. toctree:: + :maxdepth: 1 + +:program:`clang-refactor` is a Clang-based refactoring "master" tool. It is home +for refactoring submodules, such as `rename`. :program:`clang-refactor` is only +a prototype at the moment and most of its parts may significantly change. + +.. code-block:: console + + $ clang-refactor --help + + USAGE: clang-refactor [subcommand] [options] [... ] + + Subcommands: + rename: rename the symbol found at s or by s in . + +======= +Modules +======= + +.. toctree:: + :maxdepth: 1 + + rename.rst Index: docs/clang-refactor/rename.rst =================================================================== --- /dev/null +++ docs/clang-refactor/rename.rst @@ -0,0 +1,112 @@ +====== +Rename +====== + +.. contents:: + +See also: + +.. toctree:: + :maxdepth: 1 + + +`rename` is a module of `clang-refactor`, a C++ "master" refactoring tool. Its +purpose is to perform efficient renaming actions in large-scale projects such as +renaming classes, functions, variables, arguments, namespaces etc. + +The tool is in a very early development stage, so you might encounter bugs and +crashes. Submitting reports with information about how to reproduce the issue +to `the LLVM bugtracker `_ will definitely help the +project. If you have any ideas or suggestions, you might want to put a feature +request there. + +Using Rename module +=================== + +:program:`clang-refactor` is a `LibTooling +`_-based tool, and it's easier to +work with if you set up a compile command database for your project (for an +example of how to do this see `How To Setup Tooling For LLVM +`_). You can also +specify compilation options on the command line after `--`: + +.. code-block:: console + + $ clang-refactor rename -offset=42 -new-name=foo test.cpp -- -Imy_project/include -DMY_DEFINES ... + + +To get an offset of a symbol in a file run + +.. code-block:: console + + $ grep -FUbo 'foo' file.cpp + + +The tool currently supports renaming actions inside a single translation unit +only. It is planned to extend the tool's functionality to support multi-TU +renaming actions in the future. + +:program:`clang-refactor` also aims to be easily integrated into popular text +editors, such as Vim and Emacs, and improve the workflow of users. + +Although a command line interface exists, it is highly recommended to use the +text editor interface instead for better experience. + +You can also identify one or more symbols to be renamed by giving the fully +qualified name: + +.. code-block:: console + + $ clang-refactor rename-old-name=foo -new-name=bar test.cpp + + +Alternatively, { offset | old name } -> new name pairs can be put into a YAML +file: + +.. code-block:: yaml + + --- + - OldName: foo + NewName: bar + - Offset: 42 + NewName: baz + ... + + +That way you can avoid spelling out all the names as command line arguments: + +.. code-block:: console + + $ clang-refactor rename -input=test.yaml test.cpp + + +Vim Integration +=============== + +You can call :program:`clang-refactor rename` directly from Vim! To set up +:program:`clang-refactor-rename` integration for Vim see +`clang-refactor/editor-integrations/clang-refactor-rename.py +`_. + +Please note that **you have to save all buffers, in which the replacement will +happen before running the tool**. + +Once installed, you can point your cursor to symbols you want to rename, press +`cr` and type new desired name. The ` key +`_ +is a reference to a specific key defined by the mapleader variable and is bound +to backslash by default. + +Emacs Integration +================= + +You can also use :program:`clang-refactor` while using Emacs! To set up +:program:`clang-refactor rename` integration for Emacs see +`clang-refactor/editor-integrations/clang-refactor-rename.el +`_. + +Once installed, you can point your cursor to symbols you want to rename, press +`M-X`, type `clang-refactor rename` and new desired name. + +Please note that **you have to save all buffers, in which the replacement will +happen before running the tool**. Index: docs/clang-rename.rst =================================================================== --- docs/clang-rename.rst +++ /dev/null @@ -1,193 +0,0 @@ -============ -Clang-Rename -============ - -.. contents:: - -See also: - -.. toctree:: - :maxdepth: 1 - - -:program:`clang-rename` is a C++ refactoring tool. Its purpose is to perform -efficient renaming actions in large-scale projects such as renaming classes, -functions, variables, arguments, namespaces etc. - -The tool is in a very early development stage, so you might encounter bugs and -crashes. Submitting reports with information about how to reproduce the issue -to `the LLVM bugtracker `_ will definitely help the -project. If you have any ideas or suggestions, you might want to put a feature -request there. - -Using Clang-Rename -================== - -:program:`clang-rename` is a `LibTooling -`_-based tool, and it's easier to -work with if you set up a compile command database for your project (for an -example of how to do this see `How To Setup Tooling For LLVM -`_). You can also -specify compilation options on the command line after `--`: - -.. code-block:: console - - $ clang-rename -offset=42 -new-name=foo test.cpp -- -Imy_project/include -DMY_DEFINES ... - - -To get an offset of a symbol in a file run - -.. code-block:: console - - $ grep -FUbo 'foo' file.cpp - - -The tool currently supports renaming actions inside a single translation unit -only. It is planned to extend the tool's functionality to support multi-TU -renaming actions in the future. - -:program:`clang-rename` also aims to be easily integrated into popular text -editors, such as Vim and Emacs, and improve the workflow of users. - -Although a command line interface exists, it is highly recommended to use the -text editor interface instead for better experience. - -You can also identify one or more symbols to be renamed by giving the fully qualified -name: - -.. code-block:: console - - $ clang-rename rename-all -old-name=foo -new-name=bar test.cpp - - -Alternatively, old name / new name pairs can be put into a YAML file: - -.. code-block:: yaml - - --- - - OldName: foo - NewName: bar - ... - - -That way you can avoid spelling out all the names as command line arguments: - -.. code-block:: console - - $ clang-rename rename-all -input=test.yaml test.cpp - - -The YAML file also supports offsets: - -.. code-block:: yaml - - --- - - Offset: 42 - NewName: foo - ... - - -:program:`clang-rename` offers the following options: - -.. code-block:: console - - $ clang-rename -help - Usage: clang-rename {rename-at|rename-all} [OPTION]... - - A tool to rename symbols in C/C++ code. - - Subcommands: - rename-at: Perform rename off of a location in a file. (This is the default.) - rename-all: Perform rename of all symbols matching one or more fully qualified names. - - -.. code-block:: console - - $ clang-rename rename-at -help - OVERVIEW: A tool to rename symbols in C/C++ code. - clang-rename renames every occurrence of a symbol found at in - . If -i is specified, the edited files are overwritten to disk. - Otherwise, the results are written to stdout. - - USAGE: clang-rename rename-at [subcommand] [options] [... ] - - OPTIONS: - - Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program - - clang-rename rename-at options: - - -export-fixes= - YAML file to store suggested fixes in. - -extra-arg= - Additional argument to append to the compiler command line. - -extra-arg-before= - Additional argument to prepend to the compiler command line. - -i - Overwrite edited s. - -new-name= - The new name to change the symbol to. - -offset= - Locates the symbol by offset as opposed to :. - -p= - Build path. - -pl - Print the locations affected by renaming to stderr. - -pn - Print the found symbol's name prior to renaming to stderr. - - -.. code-block:: console - - $ clang-rename rename-all -help - OVERVIEW: A tool to rename symbols in C/C++ code. - clang-rename renames every occurrence of a symbol named . - - USAGE: clang-rename rename-all [subcommand] [options] [... ] - - OPTIONS: - - Generic Options: - - -help - Display available options (-help-hidden for more). - -help-list - Display list of available options (-help-list-hidden for more). - -version - Display the version of this program. - - clang-rename rename-all options: - - -export-fixes= - YAML file to store suggested fixes in. - -extra-arg= - Additional argument to append to the compiler command line. - -extra-arg-before= - Additional argument to prepend to the compiler command line. - -i - Overwrite edited s. - -input= - YAML file to load oldname-newname pairs from. - -new-name= - The new name to change the symbol to. - -offset= - Locates the symbol by offset as opposed to :. - -old-name= - The fully qualified name of the symbol, if -offset is not used. - -p= - Build path. - - -Vim Integration -=============== - -You can call :program:`clang-rename` directly from Vim! To set up -:program:`clang-rename` integration for Vim see -`clang-rename/tool/clang-rename.py -`_. - -Please note that **you have to save all buffers, in which the replacement will -happen before running the tool**. - -Once installed, you can point your cursor to symbols you want to rename, press -`cr` and type new desired name. The ` key -`_ -is a reference to a specific key defined by the mapleader variable and is bound -to backslash by default. - -Emacs Integration -================= - -You can also use :program:`clang-rename` while using Emacs! To set up -:program:`clang-rename` integration for Emacs see -`clang-rename/tool/clang-rename.el -`_. - -Once installed, you can point your cursor to symbols you want to rename, press -`M-X`, type `clang-rename` and new desired name. - -Please note that **you have to save all buffers, in which the replacement will -happen before running the tool**. Index: docs/index.rst =================================================================== --- docs/index.rst +++ docs/index.rst @@ -24,7 +24,7 @@ include-fixer modularize pp-trace - clang-rename + clang-refactor/index Doxygen Documentation Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -44,7 +44,7 @@ clang-apply-replacements clang-include-fixer clang-query - clang-rename + clang-refactor clang-reorder-fields clang-tidy find-all-symbols Index: test/clang-refactor/rename/ClassAsTemplateArgument.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassAsTemplateArgument.cpp @@ -0,0 +1,21 @@ +class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {}; + +template +void func() {} + +template +class Baz {}; + +int main() { + func(); // CHECK: func(); + Baz /* Test 2 */ obj; // CHECK: Baz /* Test 2 */ obj; + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/ClassFindByName.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassFindByName.cpp @@ -0,0 +1,10 @@ +class Foo { // CHECK: class Bar { +}; + +int main() { + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-refactor/rename/ClassReplacements.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassReplacements.cpp @@ -0,0 +1,11 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t/fixes +// RUN: cat %s > %t.cpp +// RUN: clang-refactor rename -offset=273 -new-name=Bar -export-fixes=%t/fixes/clang-refactor-rename.yaml %t.cpp -- +// RUN: clang-apply-replacements %t +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +class Foo {}; // CHECK: class Bar {}; + +// Use grep -FUbo 'Foo' to get the correct offset of Cla when changing +// this file. Index: test/clang-refactor/rename/ClassSimpleRenaming.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassSimpleRenaming.cpp @@ -0,0 +1,14 @@ +class Foo /* Test 1 */ { // CHECK: class Bar /* Test 1 */ { +public: + void foo(int x); +}; + +void Foo::foo(int x) /* Test 2 */ {} // CHECK: void Bar::foo(int x) /* Test 2 */ {} + +// Test 1. +// RUN: clang-refactor rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/ClassTestMulti.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassTestMulti.cpp @@ -0,0 +1,11 @@ +class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ { +}; + +class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ { +}; + +// Test 1. +// RUN: clang-refactor rename -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/ClassTestMultiByName.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassTestMultiByName.cpp @@ -0,0 +1,8 @@ +class Foo1 { // CHECK: class Bar1 +}; + +class Foo2 { // CHECK: class Bar2 +}; + +// Test 1. +// RUN: clang-refactor rename -qualified-name=Foo1 -new-name=Bar1 -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-refactor/rename/ClassTestMultiByNameYAML.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ClassTestMultiByNameYAML.cpp @@ -0,0 +1,10 @@ +class Foo1 { // CHECK: class Bar1 +}; + +class Foo2 { // CHECK: class Bar2 +}; + +// Test 1. +// RUN: clang-refactor rename -input %S/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -input %S/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-refactor/rename/ComplexFunctionOverride.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ComplexFunctionOverride.cpp @@ -0,0 +1,47 @@ +struct A { + virtual void foo() {} /* Test 1 */ // CHECK: virtual void bar() {} +}; + +struct B : A { + void foo() override {} /* Test 2 */ // CHECK: void bar() override {} +}; + +struct C : B { + void foo() override {} /* Test 3 */ // CHECK: void bar() override {} +}; + +struct D : B { + void foo() override {} /* Test 4 */ // CHECK: void bar() override {} +}; + +struct E : D { + void foo() override {} /* Test 5 */ // CHECK: void bar() override {} +}; + +int main() { + A a; + a.foo(); // CHECK: a.bar(); + B b; + b.foo(); // CHECK: b.bar(); + C c; + c.foo(); // CHECK: c.bar(); + D d; + d.foo(); // CHECK: d.bar(); + E e; + e.foo(); // CHECK: e.bar(); + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 4. +// RUN: clang-refactor rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 5. +// RUN: clang-refactor rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'foo.*' Index: test/clang-refactor/rename/ComplicatedClassType.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/ComplicatedClassType.cpp @@ -0,0 +1,63 @@ +// Forward declaration. +class Foo; /* Test 1 */ // CHECK: class Bar; /* Test 1 */ + +class Baz { + virtual int getValue() const = 0; +}; + +class Foo : public Baz { /* Test 2 */// CHECK: class Bar : public Baz { +public: + Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {} + + Foo &operator++(int) { // CHECK: Bar &operator++(int) { + x++; + return *this; + } + + bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) { + return this->x < rhs.x; + } + + int getValue() const { + return 0; + } + +private: + int x; +}; + +int main() { + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; + Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10); + for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) { + } + const Foo *C = new Foo(); // CHECK: const Bar *C = new Bar(); + const_cast(C)->getValue(); // CHECK: const_cast(C)->getValue(); + Foo foo; // CHECK: Bar foo; + const Baz &BazReference = foo; + const Baz *BazPointer = &foo; + dynamic_cast(BazReference).getValue(); /* Test 3 */ // CHECK: dynamic_cast(BazReference).getValue(); + dynamic_cast(BazPointer)->getValue(); /* Test 4 */ // CHECK: dynamic_cast(BazPointer)->getValue(); + reinterpret_cast(BazPointer)->getValue(); /* Test 5 */ // CHECK: reinterpret_cast(BazPointer)->getValue(); + static_cast(BazReference).getValue(); /* Test 6 */ // CHECK: static_cast(BazReference).getValue(); + static_cast(BazPointer)->getValue(); /* Test 7 */ // CHECK: static_cast(BazPointer)->getValue(); + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=30 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=155 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=1133 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 4. +// RUN: clang-refactor rename -offset=1266 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 5. +// RUN: clang-refactor rename -offset=1402 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 6. +// RUN: clang-refactor rename -offset=1533 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s +// Test 7. +// RUN: clang-refactor rename -offset=1665 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/Ctor.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/Ctor.cpp @@ -0,0 +1,14 @@ +class Foo { // CHECK: class Bar { +public: + Foo(); /* Test 1 */ // CHECK: Bar(); +}; + +Foo::Foo() /* Test 2 */ {} // CHECK: Bar::Bar() /* Test 2 */ {} + +// Test 1. +// RUN: clang-refactor rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/CtorInitializer.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/CtorInitializer.cpp @@ -0,0 +1,17 @@ +class Baz {}; + +class Qux { + Baz Foo; /* Test 1 */ // CHECK: Baz Bar; +public: + Qux(); +}; + +Qux::Qux() : Foo() /* Test 2 */ {} // CHECK: Qux::Qux() : Bar() /* Test 2 */ {} + +// Test 1. +// RUN: clang-refactor rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/DeclRefExpr.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/DeclRefExpr.cpp @@ -0,0 +1,24 @@ +class C { +public: + static int Foo; /* Test 1 */ // CHECK: static int Bar; +}; + +int foo(int x) { return 0; } +#define MACRO(a) foo(a) + +int main() { + C::Foo = 1; /* Test 2 */ // CHECK: C::Bar = 1; + MACRO(C::Foo); // CHECK: MACRO(C::Bar); + int y = C::Foo; /* Test 3 */ // CHECK: int y = C::Bar; + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/Field.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/Field.cpp @@ -0,0 +1,15 @@ +class Baz { + int Foo; /* Test 1 */ // CHECK: int Bar; +public: + Baz(); +}; + +Baz::Baz() : Foo(0) /* Test 2 */ {} // CHECK: Baz::Baz() : Bar(0) + +// Test 1. +// RUN: clang-refactor rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=89 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/FunctionMacro.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/FunctionMacro.cpp @@ -0,0 +1,20 @@ +#define moo foo // CHECK: #define moo macro_function + +int foo() /* Test 1 */ { // CHECK: int macro_function() /* Test 1 */ { + return 42; +} + +void boo(int value) {} + +void qoo() { + foo(); // CHECK: macro_function(); + boo(foo()); // CHECK: boo(macro_function()); + moo(); + boo(moo()); +} + +// Test 1. +// RUN: clang-refactor rename -offset=68 -new-name=macro_function %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'foo.*' Index: test/clang-refactor/rename/FunctionOverride.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/FunctionOverride.cpp @@ -0,0 +1,13 @@ +class A { virtual void foo(); /* Test 1 */ }; // CHECK: class A { virtual void bar(); +class B : public A { void foo(); /* Test 2 */ }; // CHECK: class B : public A { void bar(); +class C : public B { void foo(); /* Test 3 */ }; // CHECK: class C : public B { void bar(); + +// Test 1. +// RUN: clang-refactor rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'foo.*' Index: test/clang-refactor/rename/FunctionWithClassFindByName.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/FunctionWithClassFindByName.cpp @@ -0,0 +1,12 @@ +void foo() { +} + +class Foo { // CHECK: class Bar +}; + +int main() { + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; + return 0; +} + +// RUN: clang-refactor rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-refactor/rename/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml =================================================================== --- /dev/null +++ test/clang-refactor/rename/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml @@ -0,0 +1,6 @@ +--- +- OldName: Foo1 + NewName: Bar1 +- OldName: Foo2 + NewName: Bar2 +... Index: test/clang-refactor/rename/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml =================================================================== --- /dev/null +++ test/clang-refactor/rename/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml @@ -0,0 +1,6 @@ +--- +- Offset: 6 + NewName: Bar1 +- Offset: 44 + NewName: Bar2 +... Index: test/clang-refactor/rename/InvalidNewName.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/InvalidNewName.cpp @@ -0,0 +1,2 @@ +// RUN: not clang-refactor rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s +// CHECK: ERROR: new name is not a valid identifier in C++17. Index: test/clang-refactor/rename/MemberExprMacro.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/MemberExprMacro.cpp @@ -0,0 +1,22 @@ +class Baz { +public: + int Foo; /* Test 1 */ // CHECK: int Bar; +}; + +int qux(int x) { return 0; } +#define MACRO(a) qux(a) + +int main() { + Baz baz; + baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1; + MACRO(baz.Foo); // CHECK: MACRO(baz.Bar); + int y = baz.Foo; // CHECK: int y = baz.Bar; +} + +// Test 1. +// RUN: clang-refactor rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/Namespace.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/Namespace.cpp @@ -0,0 +1,13 @@ +namespace gcc /* Test 1 */ { // CHECK: namespace clang /* Test 1 */ { + int x; +} + +void boo() { + gcc::x = 42; // CHECK: clang::x = 42; +} + +// Test 1. +// RUN: clang-refactor rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/NoNewName.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/NoNewName.cpp @@ -0,0 +1,4 @@ +// Check for an error while -new-name argument has not been passed to +// clang-refactor rename. +// RUN: not clang-refactor rename -offset=133 %s 2>&1 | FileCheck %s +// CHECK: clang-refactor rename: -new-name or -input is required. Index: test/clang-refactor/rename/QualifiedNameNotFound.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/QualifiedNameNotFound.cpp @@ -0,0 +1,2 @@ +// RUN: not clang-refactor rename -new-name=Foo -qualified-name=Bar %s -- 2>&1 | FileCheck %s +// CHECK: USREngine: could not find symbol Bar. Index: test/clang-refactor/rename/TemplateClassInstantiation.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/TemplateClassInstantiation.cpp @@ -0,0 +1,42 @@ +template +class Foo { /* Test 1 */ // CHECK: class Bar { /* Test 1 */ +public: + T foo(T arg, T& ref, T* ptr) { + T value; + int number = 42; + value = (T)number; + value = static_cast(number); + return value; + } + static void foo(T value) {} + T member; +}; + +template +void func() { + Foo obj; /* Test 2 */ // CHECK: Bar obj; + obj.member = T(); + Foo::foo(); // CHECK: Bar::foo(); +} + +int main() { + Foo i; /* Test 3 */ // CHECK: Bar i; + i.member = 0; + Foo::foo(0); // CHECK: Bar::foo(0); + + Foo b; // CHECK: Bar b; + b.member = false; + Foo::foo(false); // CHECK: Bar::foo(false); + + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=29 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=324 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=463 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/TemplateTypename.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/TemplateTypename.cpp @@ -0,0 +1,24 @@ +template // CHECK: template +class Foo { +T foo(T arg, T& ref, T* /* Test 2 */ ptr) { // CHECK: U foo(U arg, U& ref, U* /* Test 2 */ ptr) { + T value; // CHECK: U value; + int number = 42; + value = (T)number; // CHECK: value = (U)number; + value = static_cast(number); // CHECK: value = static_cast(number); + return value; +} + +static void foo(T value) {} // CHECK: static void foo(U value) {} + +T member; // CHECK: U member; +}; + +// Test 1. +// RUN: clang-refactor rename -offset=19 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=126 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=392 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'T.*' Index: test/clang-refactor/rename/UserDefinedConversion.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/UserDefinedConversion.cpp @@ -0,0 +1,26 @@ +class Foo { /* Test 1 */ // CHECK: class Bar { +public: + Foo() {} // CHECK: Bar() {} +}; + +class Baz { +public: + operator Foo() /* Test 2 */ const { // CHECK: operator Bar() /* Test 2 */ const { + Foo foo; // CHECK: Bar foo; + return foo; + } +}; + +int main() { + Baz boo; + Foo foo = static_cast(boo); // CHECK: Bar foo = static_cast(boo); + return 0; +} + +// Test 1. +// RUN: clang-refactor rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/Variable.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/Variable.cpp @@ -0,0 +1,32 @@ +namespace A { +int Foo; /* Test 1 */ // CHECK: int Bar; +} +int Foo; // CHECK: int Foo; +int Qux = Foo; // CHECK: int Qux = Foo; +int Baz = A::Foo; /* Test 2 */ // CHECK: Baz = A::Bar; +void fun() { + struct { + int Foo; // CHECK: int Foo; + } b = {100}; + int Foo = 100; // CHECK: int Foo = 100; + Baz = Foo; // CHECK: Baz = Foo; + { + extern int Foo; // CHECK: extern int Foo; + Baz = Foo; // CHECK: Baz = Foo; + Foo = A::Foo /* Test 3 */ + Baz; // CHECK: Foo = A::Bar /* Test 3 */ + Baz; + A::Foo /* Test 4 */ = b.Foo; // CHECK: A::Bar /* Test 4 */ = b.Foo; + } + Foo = b.Foo; // Foo = b.Foo; +} + +// Test 1. +// RUN: clang-refactor rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=206 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=613 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 4. +// RUN: clang-refactor rename -offset=688 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-refactor/rename/VariableMacro.cpp =================================================================== --- /dev/null +++ test/clang-refactor/rename/VariableMacro.cpp @@ -0,0 +1,21 @@ +#define Baz Foo // CHECK: #define Baz Bar + +void foo(int value) {} + +void macro() { + int Foo; /* Test 1 */ // CHECK: int Bar; + Foo = 42; /* Test 2 */ // CHECK: Bar = 42; + Baz -= 0; + foo(Foo); /* Test 3 */ // CHECK: foo(Bar); + foo(Baz); +} + +// Test 1. +// RUN: clang-refactor rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 2. +// RUN: clang-refactor rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-refactor rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s + +// To find offsets after modifying the file, use: +// grep -Ubo 'Foo.*' Index: test/clang-rename/ClassAsTemplateArgument.cpp =================================================================== --- test/clang-rename/ClassAsTemplateArgument.cpp +++ /dev/null @@ -1,21 +0,0 @@ -class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {}; - -template -void func() {} - -template -class Baz {}; - -int main() { - func(); // CHECK: func(); - Baz /* Test 2 */ obj; // CHECK: Baz /* Test 2 */ obj; - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/ClassFindByName.cpp =================================================================== --- test/clang-rename/ClassFindByName.cpp +++ /dev/null @@ -1,10 +0,0 @@ -class Foo { // CHECK: class Bar { -}; - -int main() { - Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; - return 0; -} - -// Test 1. -// RUN: clang-rename rename-all -old-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-rename/ClassReplacements.cpp =================================================================== --- test/clang-rename/ClassReplacements.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t/fixes -// RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=254 -new-name=Bar -export-fixes=%t/fixes/clang-rename.yaml %t.cpp -- -// RUN: clang-apply-replacements %t -// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s - -class Foo {}; // CHECK: class Bar {}; - -// Use grep -FUbo 'Foo' to get the correct offset of Cla when changing -// this file. Index: test/clang-rename/ClassSimpleRenaming.cpp =================================================================== --- test/clang-rename/ClassSimpleRenaming.cpp +++ /dev/null @@ -1,14 +0,0 @@ -class Foo /* Test 1 */ { // CHECK: class Bar /* Test 1 */ { -public: - void foo(int x); -}; - -void Foo::foo(int x) /* Test 2 */ {} // CHECK: void Bar::foo(int x) /* Test 2 */ {} - -// Test 1. -// RUN: clang-rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/ClassTestMulti.cpp =================================================================== --- test/clang-rename/ClassTestMulti.cpp +++ /dev/null @@ -1,11 +0,0 @@ -class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ { -}; - -class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ { -}; - -// Test 1. -// RUN: clang-rename rename-all -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/ClassTestMultiByName.cpp =================================================================== --- test/clang-rename/ClassTestMultiByName.cpp +++ /dev/null @@ -1,8 +0,0 @@ -class Foo1 { // CHECK: class Bar1 -}; - -class Foo2 { // CHECK: class Bar2 -}; - -// Test 1. -// RUN: clang-rename rename-all -old-name=Foo1 -new-name=Bar1 -old-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-rename/ClassTestMultiByNameYAML.cpp =================================================================== --- test/clang-rename/ClassTestMultiByNameYAML.cpp +++ /dev/null @@ -1,10 +0,0 @@ -class Foo1 { // CHECK: class Bar1 -}; - -class Foo2 { // CHECK: class Bar2 -}; - -// Test 1. -// RUN: clang-rename rename-all -input %S/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename rename-all -input %S/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-rename/ComplexFunctionOverride.cpp =================================================================== --- test/clang-rename/ComplexFunctionOverride.cpp +++ /dev/null @@ -1,47 +0,0 @@ -struct A { - virtual void foo() {} /* Test 1 */ // CHECK: virtual void bar() {} -}; - -struct B : A { - void foo() override {} /* Test 2 */ // CHECK: void bar() override {} -}; - -struct C : B { - void foo() override {} /* Test 3 */ // CHECK: void bar() override {} -}; - -struct D : B { - void foo() override {} /* Test 4 */ // CHECK: void bar() override {} -}; - -struct E : D { - void foo() override {} /* Test 5 */ // CHECK: void bar() override {} -}; - -int main() { - A a; - a.foo(); // CHECK: a.bar(); - B b; - b.foo(); // CHECK: b.bar(); - C c; - c.foo(); // CHECK: c.bar(); - D d; - d.foo(); // CHECK: d.bar(); - E e; - e.foo(); // CHECK: e.bar(); - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 4. -// RUN: clang-rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 5. -// RUN: clang-rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'foo.*' Index: test/clang-rename/ComplicatedClassType.cpp =================================================================== --- test/clang-rename/ComplicatedClassType.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Forward declaration. -class Foo; /* Test 1 */ // CHECK: class Bar; /* Test 1 */ - -class Baz { - virtual int getValue() const = 0; -}; - -class Foo : public Baz { /* Test 2 */// CHECK: class Bar : public Baz { -public: - Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {} - - Foo &operator++(int) { // CHECK: Bar &operator++(int) { - x++; - return *this; - } - - bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) { - return this->x < rhs.x; - } - - int getValue() const { - return 0; - } - -private: - int x; -}; - -int main() { - Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; - Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10); - for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) { - } - const Foo *C = new Foo(); // CHECK: const Bar *C = new Bar(); - const_cast(C)->getValue(); // CHECK: const_cast(C)->getValue(); - Foo foo; // CHECK: Bar foo; - const Baz &BazReference = foo; - const Baz *BazPointer = &foo; - dynamic_cast(BazReference).getValue(); /* Test 3 */ // CHECK: dynamic_cast(BazReference).getValue(); - dynamic_cast(BazPointer)->getValue(); /* Test 4 */ // CHECK: dynamic_cast(BazPointer)->getValue(); - reinterpret_cast(BazPointer)->getValue(); /* Test 5 */ // CHECK: reinterpret_cast(BazPointer)->getValue(); - static_cast(BazReference).getValue(); /* Test 6 */ // CHECK: static_cast(BazReference).getValue(); - static_cast(BazPointer)->getValue(); /* Test 7 */ // CHECK: static_cast(BazPointer)->getValue(); - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=30 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=155 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=1133 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 4. -// RUN: clang-rename -offset=1266 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 5. -// RUN: clang-rename -offset=1402 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 6. -// RUN: clang-rename -offset=1533 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s -// Test 7. -// RUN: clang-rename -offset=1665 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/Ctor.cpp =================================================================== --- test/clang-rename/Ctor.cpp +++ /dev/null @@ -1,14 +0,0 @@ -class Foo { // CHECK: class Bar { -public: - Foo(); /* Test 1 */ // CHECK: Bar(); -}; - -Foo::Foo() /* Test 2 */ {} // CHECK: Bar::Bar() /* Test 2 */ {} - -// Test 1. -// RUN: clang-rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/CtorInitializer.cpp =================================================================== --- test/clang-rename/CtorInitializer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -class Baz {}; - -class Qux { - Baz Foo; /* Test 1 */ // CHECK: Baz Bar; -public: - Qux(); -}; - -Qux::Qux() : Foo() /* Test 2 */ {} // CHECK: Qux::Qux() : Bar() /* Test 2 */ {} - -// Test 1. -// RUN: clang-rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/DeclRefExpr.cpp =================================================================== --- test/clang-rename/DeclRefExpr.cpp +++ /dev/null @@ -1,24 +0,0 @@ -class C { -public: - static int Foo; /* Test 1 */ // CHECK: static int Bar; -}; - -int foo(int x) { return 0; } -#define MACRO(a) foo(a) - -int main() { - C::Foo = 1; /* Test 2 */ // CHECK: C::Bar = 1; - MACRO(C::Foo); // CHECK: MACRO(C::Bar); - int y = C::Foo; /* Test 3 */ // CHECK: int y = C::Bar; - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/Field.cpp =================================================================== --- test/clang-rename/Field.cpp +++ /dev/null @@ -1,15 +0,0 @@ -class Baz { - int Foo; /* Test 1 */ // CHECK: int Bar; -public: - Baz(); -}; - -Baz::Baz() : Foo(0) /* Test 2 */ {} // CHECK: Baz::Baz() : Bar(0) - -// Test 1. -// RUN: clang-rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=89 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/FunctionMacro.cpp =================================================================== --- test/clang-rename/FunctionMacro.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#define moo foo // CHECK: #define moo macro_function - -int foo() /* Test 1 */ { // CHECK: int macro_function() /* Test 1 */ { - return 42; -} - -void boo(int value) {} - -void qoo() { - foo(); // CHECK: macro_function(); - boo(foo()); // CHECK: boo(macro_function()); - moo(); - boo(moo()); -} - -// Test 1. -// RUN: clang-rename -offset=68 -new-name=macro_function %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'foo.*' Index: test/clang-rename/FunctionOverride.cpp =================================================================== --- test/clang-rename/FunctionOverride.cpp +++ /dev/null @@ -1,13 +0,0 @@ -class A { virtual void foo(); /* Test 1 */ }; // CHECK: class A { virtual void bar(); -class B : public A { void foo(); /* Test 2 */ }; // CHECK: class B : public A { void bar(); -class C : public B { void foo(); /* Test 3 */ }; // CHECK: class C : public B { void bar(); - -// Test 1. -// RUN: clang-rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'foo.*' Index: test/clang-rename/FunctionWithClassFindByName.cpp =================================================================== --- test/clang-rename/FunctionWithClassFindByName.cpp +++ /dev/null @@ -1,12 +0,0 @@ -void foo() { -} - -class Foo { // CHECK: class Bar -}; - -int main() { - Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; - return 0; -} - -// RUN: clang-rename rename-all -old-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s Index: test/clang-rename/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml =================================================================== --- test/clang-rename/Inputs/ClassTestMultiByNameYAMLRenameAll.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- OldName: Foo1 - NewName: Bar1 -- OldName: Foo2 - NewName: Bar2 -... Index: test/clang-rename/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml =================================================================== --- test/clang-rename/Inputs/ClassTestMultiByNameYAMLRenameAt.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- Offset: 6 - NewName: Bar1 -- Offset: 44 - NewName: Bar2 -... Index: test/clang-rename/InvalidNewName.cpp =================================================================== --- test/clang-rename/InvalidNewName.cpp +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s -// CHECK: ERROR: new name is not a valid identifier in C++17. Index: test/clang-rename/InvalidOldName.cpp =================================================================== --- test/clang-rename/InvalidOldName.cpp +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: not clang-rename rename-all -new-name=Foo -old-name=Bar %s -- 2>&1 | FileCheck %s -// CHECK: clang-rename: could not find symbol Bar. Index: test/clang-rename/MemberExprMacro.cpp =================================================================== --- test/clang-rename/MemberExprMacro.cpp +++ /dev/null @@ -1,22 +0,0 @@ -class Baz { -public: - int Foo; /* Test 1 */ // CHECK: int Bar; -}; - -int qux(int x) { return 0; } -#define MACRO(a) qux(a) - -int main() { - Baz baz; - baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1; - MACRO(baz.Foo); // CHECK: MACRO(baz.Bar); - int y = baz.Foo; // CHECK: int y = baz.Bar; -} - -// Test 1. -// RUN: clang-rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/Namespace.cpp =================================================================== --- test/clang-rename/Namespace.cpp +++ /dev/null @@ -1,13 +0,0 @@ -namespace gcc /* Test 1 */ { // CHECK: namespace clang /* Test 1 */ { - int x; -} - -void boo() { - gcc::x = 42; // CHECK: clang::x = 42; -} - -// Test 1. -// RUN: clang-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/NoNewName.cpp =================================================================== --- test/clang-rename/NoNewName.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Check for an error while -new-name argument has not been passed to -// clang-rename. -// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s -// CHECK: clang-rename: for the -new-name option: must be specified Index: test/clang-rename/TemplateClassInstantiation.cpp =================================================================== --- test/clang-rename/TemplateClassInstantiation.cpp +++ /dev/null @@ -1,42 +0,0 @@ -template -class Foo { /* Test 1 */ // CHECK: class Bar { /* Test 1 */ -public: - T foo(T arg, T& ref, T* ptr) { - T value; - int number = 42; - value = (T)number; - value = static_cast(number); - return value; - } - static void foo(T value) {} - T member; -}; - -template -void func() { - Foo obj; /* Test 2 */ // CHECK: Bar obj; - obj.member = T(); - Foo::foo(); // CHECK: Bar::foo(); -} - -int main() { - Foo i; /* Test 3 */ // CHECK: Bar i; - i.member = 0; - Foo::foo(0); // CHECK: Bar::foo(0); - - Foo b; // CHECK: Bar b; - b.member = false; - Foo::foo(false); // CHECK: Bar::foo(false); - - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=29 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=324 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=463 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/TemplateTypename.cpp =================================================================== --- test/clang-rename/TemplateTypename.cpp +++ /dev/null @@ -1,24 +0,0 @@ -template // CHECK: template -class Foo { -T foo(T arg, T& ref, T* /* Test 2 */ ptr) { // CHECK: U foo(U arg, U& ref, U* /* Test 2 */ ptr) { - T value; // CHECK: U value; - int number = 42; - value = (T)number; // CHECK: value = (U)number; - value = static_cast(number); // CHECK: value = static_cast(number); - return value; -} - -static void foo(T value) {} // CHECK: static void foo(U value) {} - -T member; // CHECK: U member; -}; - -// Test 1. -// RUN: clang-rename -offset=19 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=126 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=392 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'T.*' Index: test/clang-rename/UserDefinedConversion.cpp =================================================================== --- test/clang-rename/UserDefinedConversion.cpp +++ /dev/null @@ -1,26 +0,0 @@ -class Foo { /* Test 1 */ // CHECK: class Bar { -public: - Foo() {} // CHECK: Bar() {} -}; - -class Baz { -public: - operator Foo() /* Test 2 */ const { // CHECK: operator Bar() /* Test 2 */ const { - Foo foo; // CHECK: Bar foo; - return foo; - } -}; - -int main() { - Baz boo; - Foo foo = static_cast(boo); // CHECK: Bar foo = static_cast(boo); - return 0; -} - -// Test 1. -// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/Variable.cpp =================================================================== --- test/clang-rename/Variable.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace A { -int Foo; /* Test 1 */ // CHECK: int Bar; -} -int Foo; // CHECK: int Foo; -int Qux = Foo; // CHECK: int Qux = Foo; -int Baz = A::Foo; /* Test 2 */ // CHECK: Baz = A::Bar; -void fun() { - struct { - int Foo; // CHECK: int Foo; - } b = {100}; - int Foo = 100; // CHECK: int Foo = 100; - Baz = Foo; // CHECK: Baz = Foo; - { - extern int Foo; // CHECK: extern int Foo; - Baz = Foo; // CHECK: Baz = Foo; - Foo = A::Foo /* Test 3 */ + Baz; // CHECK: Foo = A::Bar /* Test 3 */ + Baz; - A::Foo /* Test 4 */ = b.Foo; // CHECK: A::Bar /* Test 4 */ = b.Foo; - } - Foo = b.Foo; // Foo = b.Foo; -} - -// Test 1. -// RUN: clang-rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=206 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=613 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 4. -// RUN: clang-rename -offset=688 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: test/clang-rename/VariableMacro.cpp =================================================================== --- test/clang-rename/VariableMacro.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#define Baz Foo // CHECK: #define Baz Bar - -void foo(int value) {} - -void macro() { - int Foo; /* Test 1 */ // CHECK: int Bar; - Foo = 42; /* Test 2 */ // CHECK: Bar = 42; - Baz -= 0; - foo(Foo); /* Test 3 */ // CHECK: foo(Bar); - foo(Baz); -} - -// Test 1. -// RUN: clang-rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 2. -// RUN: clang-rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s -// Test 3. -// RUN: clang-rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s - -// To find offsets after modifying the file, use: -// grep -Ubo 'Foo.*' Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -6,7 +6,6 @@ endfunction() add_subdirectory(clang-apply-replacements) -add_subdirectory(clang-rename) add_subdirectory(clang-query) add_subdirectory(clang-tidy) add_subdirectory(include-fixer) Index: unittests/clang-rename/CMakeLists.txt =================================================================== --- unittests/clang-rename/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -set(LLVM_LINK_COMPONENTS - support - ) - -get_filename_component(CLANG_RENAME_SOURCE_DIR - ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-rename REALPATH) -include_directories( - ${CLANG_RENAME_SOURCE_DIR} - ) - -add_extra_unittest(ClangRenameTests - USRLocFindingTest.cpp - ${CLANG_RENAME_SOURCE_DIR}/USRFinder.cpp - ${CLANG_RENAME_SOURCE_DIR}/USRFindingAction.cpp - ) - -target_link_libraries(ClangRenameTests - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangIndex - clangLex - clangTooling - ) Index: unittests/clang-rename/USRLocFindingTest.cpp =================================================================== --- unittests/clang-rename/USRLocFindingTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "USRFindingAction.h" -#include "clang/Tooling/Tooling.h" -#include "gtest/gtest.h" -#include -#include -#include - -namespace clang { -namespace rename { -namespace test { - -// Determines if the symbol group invariants hold. To recap, those invariants -// are: -// (1) All symbols in the same symbol group share the same USR. -// (2) Two symbols from two different groups do not share the same USR. -static void testOffsetGroups(const char *Code, - const std::vector> Groups) { - std::set AllUSRs, CurrUSR; - - for (const auto &Group : Groups) { - // Groups the invariants do not hold then the value of USR is also invalid, - // but at that point the test has already failed and USR ceases to be - // useful. - std::string USR; - for (const auto &Offset : Group) { - USRFindingAction Action(Offset, std::string()); - auto Factory = tooling::newFrontendActionFactory(&Action); - EXPECT_TRUE(tooling::runToolOnCode(Factory->create(), Code)); - const auto &USRs = Action.getUSRs(); - EXPECT_EQ(1u, USRs.size()); - USR = USRs[0]; - CurrUSR.insert(USR); - } - EXPECT_EQ(1u, CurrUSR.size()); - CurrUSR.clear(); - AllUSRs.insert(USR); - } - - EXPECT_EQ(Groups.size(), AllUSRs.size()); -} - - -TEST(USRLocFinding, FindsVarUSR) { - const char VarTest[] = "\n\ -namespace A {\n\ -int foo;\n\ -}\n\ -int foo;\n\ -int bar = foo;\n\ -int baz = A::foo;\n\ -void fun1() {\n\ - struct {\n\ - int foo;\n\ - } b = { 100 };\n\ - int foo = 100;\n\ - baz = foo;\n\ - {\n\ - extern int foo;\n\ - baz = foo;\n\ - foo = A::foo + baz;\n\ - A::foo = b.foo;\n\ - }\n\ - foo = b.foo;\n\ -}\n"; - std::vector> VarTestOffsets(3); - VarTestOffsets[0].push_back(19); - VarTestOffsets[0].push_back(63); - VarTestOffsets[0].push_back(205); - VarTestOffsets[0].push_back(223); - VarTestOffsets[1].push_back(30); - VarTestOffsets[1].push_back(45); - VarTestOffsets[1].push_back(172); - VarTestOffsets[1].push_back(187); - VarTestOffsets[2].push_back(129); - VarTestOffsets[2].push_back(148); - VarTestOffsets[2].push_back(242); - - testOffsetGroups(VarTest, VarTestOffsets); -} - -} // namespace test -} // namespace rename -} // namespace clang