r306840 - [refactor] Move clang-rename into the clang repository
Evgenii Stepanov via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 30 13:14:00 PDT 2017
Hi,
there are new memory leaks related to this change:
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/6072/steps/check-clang%20asan/logs/stdio
On Fri, Jun 30, 2017 at 9:36 AM, Alex Lorenz via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: arphaman
> Date: Fri Jun 30 09:36:09 2017
> New Revision: 306840
>
> URL: http://llvm.org/viewvc/llvm-project?rev=306840&view=rev
> Log:
> [refactor] Move clang-rename into the clang repository
>
> The core engine of clang-rename will be used for local and global renames
> in the
> new refactoring engine, as mentioned in
> http://lists.llvm.org/pipermail/cfe-dev/2017-June/054286.html.
>
> The clang-rename tool is still supported but might get deprecated in the
> future.
>
> Differential Revision: https://reviews.llvm.org/D34696
>
> Added:
> cfe/trunk/include/clang/Tooling/Refactoring/Rename/
> cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
> cfe/trunk/lib/Tooling/Refactoring/Rename/
> cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
> cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
> cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
> cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
> cfe/trunk/test/clang-rename/
> cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
> cfe/trunk/test/clang-rename/ClassFindByName.cpp
> cfe/trunk/test/clang-rename/ClassReplacements.cpp
> cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
> cfe/trunk/test/clang-rename/ClassTestMulti.cpp
> cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
> cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
> cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
> cfe/trunk/test/clang-rename/Ctor.cpp
> cfe/trunk/test/clang-rename/CtorInitializer.cpp
> cfe/trunk/test/clang-rename/DeclRefExpr.cpp
> cfe/trunk/test/clang-rename/Field.cpp
> cfe/trunk/test/clang-rename/FunctionMacro.cpp
> cfe/trunk/test/clang-rename/FunctionOverride.cpp
> cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
> cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
> cfe/trunk/test/clang-rename/Inputs/
> cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
> cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
> cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
> cfe/trunk/test/clang-rename/InvalidNewName.cpp
> cfe/trunk/test/clang-rename/InvalidOffset.cpp
> cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
> cfe/trunk/test/clang-rename/MemberExprMacro.cpp
> cfe/trunk/test/clang-rename/Namespace.cpp
> cfe/trunk/test/clang-rename/NoNewName.cpp
> cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
> cfe/trunk/test/clang-rename/TemplateTypename.cpp
> cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
> cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
> cfe/trunk/test/clang-rename/Variable.cpp
> cfe/trunk/test/clang-rename/VariableMacro.cpp
> cfe/trunk/test/clang-rename/YAMLInput.cpp
> cfe/trunk/tools/clang-rename/
> cfe/trunk/tools/clang-rename/CMakeLists.txt
> cfe/trunk/tools/clang-rename/ClangRename.cpp
> cfe/trunk/tools/clang-rename/clang-rename.el
> cfe/trunk/tools/clang-rename/clang-rename.py
> cfe/trunk/unittests/Rename/
> cfe/trunk/unittests/Rename/CMakeLists.txt
> cfe/trunk/unittests/Rename/ClangRenameTest.h
> cfe/trunk/unittests/Rename/RenameClassTest.cpp
> Modified:
> cfe/trunk/include/clang/module.modulemap
> cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
> cfe/trunk/test/CMakeLists.txt
> cfe/trunk/tools/CMakeLists.txt
> cfe/trunk/unittests/CMakeLists.txt
>
> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Tooling/Refactoring/Rename/RenamingAction.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
> (added)
> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
> Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,70 @@
> +//===--- RenamingAction.h - Clang refactoring library
> ---------------------===//
> +//
> +// 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_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
> +
> +#include "clang/Tooling/Refactoring.h"
> +
> +namespace clang {
> +class ASTConsumer;
> +class CompilerInstance;
> +
> +namespace tooling {
> +
> +class RenamingAction {
> +public:
> + RenamingAction(const std::vector<std::string> &NewNames,
> + const std::vector<std::string> &PrevNames,
> + const std::vector<std::vector<std::string>> &USRList,
> + std::map<std::string, tooling::Replacements>
> &FileToReplaces,
> + bool PrintLocations = false)
> + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
> + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
> +
> + std::unique_ptr<ASTConsumer> newASTConsumer();
> +
> +private:
> + const std::vector<std::string> &NewNames, &PrevNames;
> + const std::vector<std::vector<std::string>> &USRList;
> + std::map<std::string, tooling::Replacements> &FileToReplaces;
> + bool PrintLocations;
> +};
> +
> +/// Rename all symbols identified by the given USRs.
> +class QualifiedRenamingAction {
> +public:
> + QualifiedRenamingAction(
> + const std::vector<std::string> &NewNames,
> + const std::vector<std::vector<std::string>> &USRList,
> + std::map<std::string, tooling::Replacements> &FileToReplaces)
> + : NewNames(NewNames), USRList(USRList),
> FileToReplaces(FileToReplaces) {}
> +
> + std::unique_ptr<ASTConsumer> newASTConsumer();
> +
> +private:
> + /// New symbol names.
> + const std::vector<std::string> &NewNames;
> +
> + /// A list of USRs. Each element represents USRs of a symbol being
> renamed.
> + const std::vector<std::vector<std::string>> &USRList;
> +
> + /// A file path to replacements map.
> + std::map<std::string, tooling::Replacements> &FileToReplaces;
> +};
> +
> +} // end namespace tooling
> +} // end namespace clang
> +
> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
>
> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Tooling/Refactoring/Rename/USRFinder.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h (added)
> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h Fri
> Jun 30 09:36:09 2017
> @@ -0,0 +1,84 @@
> +//===--- USRFinder.h - Clang refactoring library
> --------------------------===//
> +//
> +// 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_TOOLING_REFACTOR_RENAME_USR_FINDER_H
> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
> +
> +#include "clang/AST/AST.h"
> +#include "clang/AST/ASTContext.h"
> +#include "clang/ASTMatchers/ASTMatchFinder.h"
> +#include <string>
> +#include <vector>
> +
> +using namespace llvm;
> +using namespace clang::ast_matchers;
> +
> +namespace clang {
> +
> +class ASTContext;
> +class Decl;
> +class SourceLocation;
> +class NamedDecl;
> +
> +namespace tooling {
> +
> +// 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<T>::VisitNestedNameSpecifier
> instead.
> +class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback {
> +public:
> + explicit NestedNameSpecifierLocFinder(ASTContext &Context)
> + : Context(Context) {}
> +
> + std::vector<NestedNameSpecifierLoc> getNestedNameSpecifierLocations() {
> + addMatchers();
> + Finder.matchAST(Context);
> + return Locations;
> + }
> +
> +private:
> + void addMatchers() {
> + const auto NestedNameSpecifierLocMatcher =
> + nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc");
> + Finder.addMatcher(NestedNameSpecifierLocMatcher, this);
> + }
> +
> + void run(const MatchFinder::MatchResult &Result) override {
> + const auto *NNS = Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
> + "nestedNameSpecifierLoc");
> + Locations.push_back(*NNS);
> + }
> +
> + ASTContext &Context;
> + std::vector<NestedNameSpecifierLoc> Locations;
> + MatchFinder Finder;
> +};
> +
> +} // end namespace tooling
> +} // end namespace clang
> +
> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
>
> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/
> USRFindingAction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Tooling/Refactoring/Rename/USRFindingAction.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
> (added)
> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
> Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,54 @@
> +//===--- USRFindingAction.h - Clang refactoring library
> -------------------===//
> +//
> +// 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_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
> +
> +#include "clang/Basic/LLVM.h"
> +#include "llvm/ADT/ArrayRef.h"
> +
> +#include <string>
> +#include <vector>
> +
> +namespace clang {
> +class ASTConsumer;
> +class CompilerInstance;
> +class NamedDecl;
> +
> +namespace tooling {
> +
> +struct USRFindingAction {
> + USRFindingAction(ArrayRef<unsigned> SymbolOffsets,
> + ArrayRef<std::string> QualifiedNames, bool Force)
> + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
> + ErrorOccurred(false), Force(Force) {}
> + std::unique_ptr<ASTConsumer> newASTConsumer();
> +
> + ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }
> + ArrayRef<std::vector<std::string>> getUSRList() { return USRList; }
> + bool errorOccurred() { return ErrorOccurred; }
> +
> +private:
> + std::vector<unsigned> SymbolOffsets;
> + std::vector<std::string> QualifiedNames;
> + std::vector<std::string> SpellingNames;
> + std::vector<std::vector<std::string>> USRList;
> + bool ErrorOccurred;
> + bool Force;
> +};
> +
> +} // end namespace tooling
> +} // end namespace clang
> +
> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
>
> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Tooling/Refactoring/Rename/USRLocFinder.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
> (added)
> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h Fri
> Jun 30 09:36:09 2017
> @@ -0,0 +1,49 @@
> +//===--- USRLocFinder.h - Clang refactoring library
> -----------------------===//
> +//
> +// 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_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
> +
> +#include "clang/AST/AST.h"
> +#include "clang/Tooling/Core/Replacement.h"
> +#include "clang/Tooling/Refactoring/AtomicChange.h"
> +#include "llvm/ADT/StringRef.h"
> +#include <string>
> +#include <vector>
> +
> +namespace clang {
> +namespace tooling {
> +
> +/// Create atomic changes for renaming all symbol references which are
> +/// identified by the USRs set to a given new name.
> +///
> +/// \param USRs The set containing USRs of a particular old symbol.
> +/// \param NewName The new name to replace old symbol name.
> +/// \param TranslationUnitDecl The translation unit declaration.
> +///
> +/// \return Atomic changes for renaming.
> +std::vector<tooling::AtomicChange>
> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
> + llvm::StringRef NewName, Decl
> *TranslationUnitDecl);
> +
> +// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!
> +std::vector<SourceLocation>
> +getLocationsOfUSRs(const std::vector<std::string> &USRs,
> + llvm::StringRef PrevName, Decl *Decl);
> +
> +} // end namespace tooling
> +} // end namespace clang
> +
> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
>
> Modified: cfe/trunk/include/clang/module.modulemap
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/module.modulemap?rev=306840&r1=306839&r2=306840&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/module.modulemap (original)
> +++ cfe/trunk/include/clang/module.modulemap Fri Jun 30 09:36:09 2017
> @@ -133,9 +133,10 @@ module Clang_StaticAnalyzer_Frontend {
>
> module Clang_Tooling {
> requires cplusplus umbrella "Tooling" module * { export * }
> - // FIXME: Exclude this header to avoid pulling all of the AST matchers
> + // FIXME: Exclude these headers to avoid pulling all of the AST matchers
> // library into clang-format. Due to inline key functions in the
> headers,
> // importing the AST matchers library gives a link dependency on the AST
> // matchers (and thus the AST), which clang-format should not have.
> exclude header "Tooling/RefactoringCallbacks.h"
> + exclude header "Tooling/Refactoring/Rename/USRFinder.h"
> }
>
> Modified: cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/
> Refactoring/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt Fri Jun 30 09:36:09
> 2017
> @@ -5,8 +5,16 @@ set(LLVM_LINK_COMPONENTS
>
> add_clang_library(clangToolingRefactor
> AtomicChange.cpp
> + Rename/RenamingAction.cpp
> + Rename/USRFinder.cpp
> + Rename/USRFindingAction.cpp
> + Rename/USRLocFinder.cpp
>
> LINK_LIBS
> + clangAST
> + clangASTMatchers
> clangBasic
> + clangIndex
> + clangLex
> clangToolingCore
> )
>
> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/
> Refactoring/Rename/RenamingAction.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp (added)
> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp Fri Jun
> 30 09:36:09 2017
> @@ -0,0 +1,134 @@
> +//===--- RenamingAction.cpp - Clang refactoring library
> -------------------===//
> +//
> +// 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 "clang/Tooling/Refactoring/Rename/RenamingAction.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/Refactoring/Rename/USRLocFinder.h"
> +#include "clang/Tooling/Tooling.h"
> +#include <string>
> +#include <vector>
> +
> +using namespace llvm;
> +
> +namespace clang {
> +namespace tooling {
> +
> +class RenamingASTConsumer : public ASTConsumer {
> +public:
> + RenamingASTConsumer(
> + const std::vector<std::string> &NewNames,
> + const std::vector<std::string> &PrevNames,
> + const std::vector<std::vector<std::string>> &USRList,
> + std::map<std::string, tooling::Replacements> &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<std::string> &USRs) {
> + const SourceManager &SourceMgr = Context.getSourceManager();
> + std::vector<SourceLocation> RenamingCandidates;
> + std::vector<SourceLocation> NewCandidates;
> +
> + NewCandidates = tooling::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<std::string> &NewNames, &PrevNames;
> + const std::vector<std::vector<std::string>> &USRList;
> + std::map<std::string, tooling::Replacements> &FileToReplaces;
> + bool PrintLocations;
> +};
> +
> +// A renamer to rename symbols which are identified by a give USRList to
> +// new name.
> +//
> +// FIXME: Merge with the above RenamingASTConsumer.
> +class USRSymbolRenamer : public ASTConsumer {
> +public:
> + USRSymbolRenamer(const std::vector<std::string> &NewNames,
> + const std::vector<std::vector<std::string>> &USRList,
> + std::map<std::string, tooling::Replacements>
> &FileToReplaces)
> + : NewNames(NewNames), USRList(USRList),
> FileToReplaces(FileToReplaces) {
> + assert(USRList.size() == NewNames.size());
> + }
> +
> + void HandleTranslationUnit(ASTContext &Context) override {
> + for (unsigned I = 0; I < NewNames.size(); ++I) {
> + // FIXME: Apply AtomicChanges directly once the refactoring APIs are
> + // ready.
> + auto AtomicChanges = tooling::createRenameAtomicChanges(
> + USRList[I], NewNames[I], Context.getTranslationUnitDecl());
> + for (const auto AtomicChange : AtomicChanges) {
> + for (const auto &Replace : AtomicChange.getReplacements()) {
> + 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<std::string> &NewNames;
> + const std::vector<std::vector<std::string>> &USRList;
> + std::map<std::string, tooling::Replacements> &FileToReplaces;
> +};
> +
> +std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
> + return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames,
> USRList,
> + FileToReplaces,
> PrintLocations);
> +}
> +
> +std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
> + return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList,
> FileToReplaces);
> +}
> +
> +} // end namespace tooling
> +} // end namespace clang
>
> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/
> Refactoring/Rename/USRFinder.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp (added)
> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,213 @@
> +//===--- USRFinder.cpp - Clang refactoring library
> ------------------------===//
> +//
> +// 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 "clang/Tooling/Refactoring/Rename/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 tooling {
> +
> +// NamedDeclFindingASTVisitor recursively visits each AST node to find the
> +// symbol underneath the cursor.
> +// FIXME: move to separate .h/.cc file if this gets too large.
> +namespace {
> +class NamedDeclFindingASTVisitor
> + : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
> +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<CXXConversionDecl>(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<TemplateTypeParmType>(Loc.getType()))
> + return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc,
> TypeEndLoc);
> + if (const auto *TemplateSpecType =
> + dyn_cast<TemplateSpecializationType>(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()) {
> + // Ignore implicit initializers.
> + if (!Initializer->isWritten())
> + 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() &&
> + 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) {
> + const SourceManager &SM = Context.getSourceManager();
> + NamedDeclFindingASTVisitor Visitor(Point, Context);
> +
> + // Try to be clever about pruning down the number of top-level
> declarations we
> + // see. If both start and end is either before or after the point we're
> + // looking for the point cannot be inside of this decl. Don't even look
> at it.
> + for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
> + SourceLocation StartLoc = CurrDecl->getLocStart();
> + SourceLocation EndLoc = CurrDecl->getLocEnd();
> + if (StartLoc.isValid() && EndLoc.isValid() &&
> + SM.isBeforeInTranslationUnit(StartLoc, Point) !=
> + SM.isBeforeInTranslationUnit(EndLoc, Point))
> + Visitor.TraverseDecl(CurrDecl);
> + }
> +
> + NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(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<char, 128> Buff;
> +
> + // FIXME: Add test for the nullptr case.
> + if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
> + return "";
> +
> + return std::string(Buff.data(), Buff.size());
> +}
> +
> +} // end namespace tooling
> +} // end namespace clang
>
> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/
> Refactoring/Rename/USRFindingAction.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp (added)
> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp Fri Jun
> 30 09:36:09 2017
> @@ -0,0 +1,236 @@
> +//===--- USRFindingAction.cpp - Clang refactoring library
> -----------------===//
> +//
> +// 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 <offset>, as
> well as
> +/// all additional USRs.
> +///
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.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/Refactoring/Rename/USRFinder.h"
> +#include "clang/Tooling/Tooling.h"
> +
> +#include <algorithm>
> +#include <set>
> +#include <string>
> +#include <vector>
> +
> +using namespace llvm;
> +
> +namespace clang {
> +namespace tooling {
> +
> +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<AdditionalUSRFinder>
> {
> +public:
> + AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
> + : FoundDecl(FoundDecl), Context(Context) {}
> +
> + std::vector<std::string> Find() {
> + // Fill OverriddenMethods and PartialSpecs storages.
> + TraverseDecl(Context.getTranslationUnitDecl());
> + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
> + addUSRsOfOverridenFunctions(MethodDecl);
> + for (const auto &OverriddenMethod : OverriddenMethods) {
> + if (checkIfOverriddenFunctionAscends(OverriddenMethod))
> + USRSet.insert(getUSRForDecl(OverriddenMethod));
> + }
> + } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl))
> {
> + handleCXXRecordDecl(RecordDecl);
> + } else if (const auto *TemplateDecl =
> + dyn_cast<ClassTemplateDecl>(FoundDecl)) {
> + handleClassTemplateDecl(TemplateDecl);
> + } else {
> + USRSet.insert(getUSRForDecl(FoundDecl));
> + }
> + return std::vector<std::string>(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<ClassTemplateSpecializationDecl>(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();
> +
> + // Skip if the CXXRecordDecl doesn't have definition.
> + if (!RecordDecl)
> + return;
> +
> + 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));
> + // Recursively visit each OverridenMethod.
> + for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
> + 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<std::string> USRSet;
> + std::vector<const CXXMethodDecl *> OverriddenMethods;
> + std::vector<const ClassTemplatePartialSpecializationDecl *>
> PartialSpecs;
> +};
> +} // namespace
> +
> +class NamedDeclFindingConsumer : public ASTConsumer {
> +public:
> + NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
> + ArrayRef<std::string> QualifiedNames,
> + std::vector<std::string> &SpellingNames,
> + std::vector<std::vector<std::string>>
> &USRList,
> + bool Force, bool &ErrorOccurred)
> + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
> + SpellingNames(SpellingNames), USRList(USRList), Force(Force),
> + ErrorOccurred(ErrorOccurred) {}
> +
> +private:
> + bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
> + unsigned SymbolOffset, const std::string
> &QualifiedName) {
> + DiagnosticsEngine &Engine = Context.getDiagnostics();
> + const FileID MainFileID = SourceMgr.getMainFileID();
> +
> + if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
> + ErrorOccurred = true;
> + unsigned InvalidOffset = Engine.getCustomDiagID(
> + DiagnosticsEngine::Error,
> + "SourceLocation in file %0 at offset %1 is invalid");
> + Engine.Report(SourceLocation(), InvalidOffset)
> + << SourceMgr.getFileEntryForID(MainFileID)->getName() <<
> SymbolOffset;
> + return false;
> + }
> +
> + const SourceLocation Point = SourceMgr.getLocForStartOfFile(
> MainFileID)
> + .getLocWithOffset(SymbolOffset);
> + const NamedDecl *FoundDecl = QualifiedName.empty()
> + ? getNamedDeclAt(Context, Point)
> + : getNamedDeclFor(Context,
> QualifiedName);
> +
> + if (FoundDecl == nullptr) {
> + if (QualifiedName.empty()) {
> + FullSourceLoc FullLoc(Point, SourceMgr);
> + unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
> + DiagnosticsEngine::Error,
> + "clang-rename could not find symbol (offset %0)");
> + Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
> + ErrorOccurred = true;
> + return false;
> + }
> +
> + if (Force)
> + return true;
> +
> + unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
> + DiagnosticsEngine::Error, "clang-rename could not find symbol
> %0");
> + Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
> + ErrorOccurred = true;
> + return false;
> + }
> +
> + // If FoundDecl is a constructor or destructor, we want to instead
> take
> + // the Decl of the corresponding class.
> + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
> + FoundDecl = CtorDecl->getParent();
> + else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(
> FoundDecl))
> + FoundDecl = DtorDecl->getParent();
> +
> + SpellingNames.push_back(FoundDecl->getNameAsString());
> + AdditionalUSRFinder Finder(FoundDecl, Context);
> + USRList.push_back(Finder.Find());
> + return true;
> + }
> +
> + void HandleTranslationUnit(ASTContext &Context) override {
> + const SourceManager &SourceMgr = Context.getSourceManager();
> + for (unsigned Offset : SymbolOffsets) {
> + if (!FindSymbol(Context, SourceMgr, Offset, ""))
> + return;
> + }
> + for (const std::string &QualifiedName : QualifiedNames) {
> + if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
> + return;
> + }
> + }
> +
> + ArrayRef<unsigned> SymbolOffsets;
> + ArrayRef<std::string> QualifiedNames;
> + std::vector<std::string> &SpellingNames;
> + std::vector<std::vector<std::string>> &USRList;
> + bool Force;
> + bool &ErrorOccurred;
> +};
> +
> +std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
> + return llvm::make_unique<NamedDeclFindingConsumer>(
> + SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
> + ErrorOccurred);
> +}
> +
> +} // end namespace tooling
> +} // end namespace clang
>
> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/
> Refactoring/Rename/USRLocFinder.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (added)
> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,509 @@
> +//===--- USRLocFinder.cpp - Clang refactoring library
> ---------------------===//
> +//
> +// 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 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 "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/RecursiveASTVisitor.h"
> +#include "clang/Basic/LLVM.h"
> +#include "clang/Basic/SourceLocation.h"
> +#include "clang/Basic/SourceManager.h"
> +#include "clang/Lex/Lexer.h"
> +#include "clang/Tooling/Core/Lookup.h"
> +#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/Casting.h"
> +#include <cstddef>
> +#include <set>
> +#include <string>
> +#include <vector>
> +
> +using namespace llvm;
> +
> +namespace clang {
> +namespace tooling {
> +
> +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<USRLocFindingASTVisitor> {
> +public:
> + explicit USRLocFindingASTVisitor(const std::vector<std::string> &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()) {
> + // Ignore implicit initializers.
> + if (!Initializer->isWritten())
> + 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<TemplateTypeParmType>(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<clang::SourceLocation> &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);
> +
> + // The token of the source location we find actually has the old
> + // name.
> + if (Offset != StringRef::npos)
> + LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
> + }
> +
> + const std::set<std::string> USRSet;
> + const std::string PrevName;
> + std::vector<clang::SourceLocation> LocationsFound;
> + const ASTContext &Context;
> +};
> +
> +SourceLocation StartLocationForType(TypeLoc TL) {
> + // For elaborated types (e.g. `struct a::A`) we want the portion after
> the
> + // `struct` but including the namespace qualifier, `a::`.
> + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
> + NestedNameSpecifierLoc NestedNameSpecifier =
> + ElaboratedTypeLoc.getQualifierLoc();
> + if (NestedNameSpecifier.getNestedNameSpecifier())
> + return NestedNameSpecifier.getBeginLoc();
> + TL = TL.getNextTypeLoc();
> + }
> + return TL.getLocStart();
> +}
> +
> +SourceLocation EndLocationForType(TypeLoc TL) {
> + // Dig past any namespace or keyword qualifications.
> + while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
> + TL.getTypeLocClass() == TypeLoc::Qualified)
> + TL = TL.getNextTypeLoc();
> +
> + // The location for template specializations (e.g. Foo<int>) includes
> the
> + // templated types in its location range. We want to restrict this to
> just
> + // before the `<` character.
> + if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
> + return TL.castAs<TemplateSpecializationTypeLoc>()
> + .getLAngleLoc()
> + .getLocWithOffset(-1);
> + }
> + return TL.getEndLoc();
> +}
> +
> +NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
> + // Dig past any keyword qualifications.
> + while (TL.getTypeLocClass() == TypeLoc::Qualified)
> + TL = TL.getNextTypeLoc();
> +
> + // For elaborated types (e.g. `struct a::A`) we want the portion after
> the
> + // `struct` but including the namespace qualifier, `a::`.
> + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
> + return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
> + return nullptr;
> +}
> +
> +// Find all locations identified by the given USRs for rename.
> +//
> +// This class will traverse the AST and find every AST node whose USR is
> in the
> +// given USRs' set.
> +class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
> +public:
> + RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
> + : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
> +
> + // A structure records all information of a symbol reference being
> renamed.
> + // We try to add as few prefix qualifiers as possible.
> + struct RenameInfo {
> + // The begin location of a symbol being renamed.
> + SourceLocation Begin;
> + // The end location of a symbol being renamed.
> + SourceLocation End;
> + // The declaration of a symbol being renamed (can be nullptr).
> + const NamedDecl *FromDecl;
> + // The declaration in which the nested name is contained (can be
> nullptr).
> + const Decl *Context;
> + // The nested name being replaced (can be nullptr).
> + const NestedNameSpecifier *Specifier;
> + };
> +
> + // FIXME: Currently, prefix qualifiers will be added to the renamed
> symbol
> + // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming
> + // "a::Foo" to "b::Bar").
> + // For renaming declarations/definitions, prefix qualifiers should be
> filtered
> + // out.
> + bool VisitNamedDecl(const NamedDecl *Decl) {
> + // UsingDecl has been handled in other place.
> + if (llvm::isa<UsingDecl>(Decl))
> + return true;
> +
> + // DestructorDecl has been handled in Typeloc.
> + if (llvm::isa<CXXDestructorDecl>(Decl))
> + return true;
> +
> + if (Decl->isImplicit())
> + return true;
> +
> + if (isInUSRSet(Decl)) {
> + RenameInfo Info = {Decl->getLocation(), Decl->getLocation(),
> nullptr,
> + nullptr, nullptr};
> + RenameInfos.push_back(Info);
> + }
> + return true;
> + }
> +
> + bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
> + const NamedDecl *Decl = Expr->getFoundDecl();
> + if (isInUSRSet(Decl)) {
> + RenameInfo Info = {Expr->getSourceRange().getBegin(),
> + Expr->getSourceRange().getEnd(), Decl,
> + getClosestAncestorDecl(*Expr),
> Expr->getQualifier()};
> + RenameInfos.push_back(Info);
> + }
> +
> + return true;
> + }
> +
> + bool VisitUsingDecl(const UsingDecl *Using) {
> + for (const auto *UsingShadow : Using->shadows()) {
> + if (isInUSRSet(UsingShadow->getTargetDecl())) {
> + UsingDecls.push_back(Using);
> + break;
> + }
> + }
> + return true;
> + }
> +
> + bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc
> NestedLoc) {
> + if (!NestedLoc.getNestedNameSpecifier()->getAsType())
> + return true;
> + if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
> + return true;
> +
> + if (const auto *TargetDecl =
> + getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
> + if (isInUSRSet(TargetDecl)) {
> + RenameInfo Info = {NestedLoc.getBeginLoc(),
> + EndLocationForType(NestedLoc.getTypeLoc()),
> + TargetDecl, getClosestAncestorDecl(NestedLoc),
> + NestedLoc.getNestedNameSpecifier()->
> getPrefix()};
> + RenameInfos.push_back(Info);
> + }
> + }
> + return true;
> + }
> +
> + bool VisitTypeLoc(TypeLoc Loc) {
> + if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
> + return true;
> +
> + auto Parents = Context.getParents(Loc);
> + TypeLoc ParentTypeLoc;
> + if (!Parents.empty()) {
> + // Handle cases of nested name specificier locations.
> + //
> + // The VisitNestedNameSpecifierLoc interface is not impelmented in
> + // RecursiveASTVisitor, we have to handle it explicitly.
> + if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
> + VisitNestedNameSpecifierLocations(*NSL);
> + return true;
> + }
> +
> + if (const auto *TL = Parents[0].get<TypeLoc>())
> + ParentTypeLoc = *TL;
> + }
> +
> + // Handle the outermost TypeLoc which is directly linked to the
> interesting
> + // declaration and don't handle nested name specifier locations.
> + if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
> + if (isInUSRSet(TargetDecl)) {
> + // Only handle the outermost typeLoc.
> + //
> + // For a type like "a::Foo", there will be two typeLocs for it.
> + // One ElaboratedType, the other is RecordType:
> + //
> + // ElaboratedType 0x33b9390 'a::Foo' sugar
> + // `-RecordType 0x338fef0 'class a::Foo'
> + // `-CXXRecord 0x338fe58 'Foo'
> + //
> + // Skip if this is an inner typeLoc.
> + if (!ParentTypeLoc.isNull() &&
> + isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
> + return true;
> + RenameInfo Info = {StartLocationForType(Loc),
> EndLocationForType(Loc),
> + TargetDecl, getClosestAncestorDecl(Loc),
> + GetNestedNameForType(Loc)};
> + RenameInfos.push_back(Info);
> + return true;
> + }
> + }
> +
> + // Handle specific template class specialiation cases.
> + if (const auto *TemplateSpecType =
> + dyn_cast<TemplateSpecializationType>(Loc.getType())) {
> + TypeLoc TargetLoc = Loc;
> + if (!ParentTypeLoc.isNull()) {
> + if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
> + TargetLoc = ParentTypeLoc;
> + }
> +
> + if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl()))
> {
> + TypeLoc TargetLoc = Loc;
> + // FIXME: Find a better way to handle this case.
> + // For the qualified template class specification type like
> + // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent
> typeLoc
> + // (ElaboratedType) of the TemplateSpecializationType in order to
> + // catch the prefix qualifiers "ns::".
> + if (!ParentTypeLoc.isNull() &&
> + llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
> + TargetLoc = ParentTypeLoc;
> + RenameInfo Info = {
> + StartLocationForType(TargetLoc),
> EndLocationForType(TargetLoc),
> + TemplateSpecType->getTemplateName().getAsTemplateDecl(),
> + getClosestAncestorDecl(
> + ast_type_traits::DynTypedNode::create(TargetLoc)),
> + GetNestedNameForType(TargetLoc)};
> + RenameInfos.push_back(Info);
> + }
> + }
> + return true;
> + }
> +
> + // Returns a list of RenameInfo.
> + const std::vector<RenameInfo> &getRenameInfos() const { return
> RenameInfos; }
> +
> + // Returns a list of using declarations which are needed to update.
> + const std::vector<const UsingDecl *> &getUsingDecls() const {
> + return UsingDecls;
> + }
> +
> +private:
> + // FIXME: This method may not be suitable for renaming other types like
> alias
> + // types. Need to figure out a way to handle it.
> + bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const {
> + while (!TL.isNull()) {
> + // SubstTemplateTypeParm is the TypeLocation class for a
> substituted type
> + // inside a template expansion so we ignore these. For example:
> + //
> + // template<typename T> struct S {
> + // T t; // <-- this T becomes a TypeLoc(int) with class
> + // // SubstTemplateTypeParm when S<int> is instantiated
> + // }
> + if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
> + return true;
> +
> + // Typedef is the TypeLocation class for a type which is a typedef
> to the
> + // type we want to replace. We ignore the use of the typedef as we
> will
> + // replace the definition of it. For example:
> + //
> + // typedef int T;
> + // T a; // <--- This T is a TypeLoc(int) with class Typedef.
> + if (TL.getTypeLocClass() == TypeLoc::Typedef)
> + return true;
> + TL = TL.getNextTypeLoc();
> + }
> + return false;
> + }
> +
> + // Get the supported declaration from a given typeLoc. If the
> declaration type
> + // is not supported, returns nullptr.
> + //
> + // FIXME: support more types, e.g. enum, type alias.
> + const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
> + if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
> + return RD;
> + return nullptr;
> + }
> +
> + // Get the closest ancester which is a declaration of a given AST node.
> + template <typename ASTNodeType>
> + const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
> + auto Parents = Context.getParents(Node);
> + // FIXME: figure out how to handle it when there are multiple parents.
> + if (Parents.size() != 1)
> + return nullptr;
> + if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
> + Parents[0].getNodeKind()))
> + return Parents[0].template get<Decl>();
> + return getClosestAncestorDecl(Parents[0]);
> + }
> +
> + // Get the parent typeLoc of a given typeLoc. If there is no such
> parent,
> + // return nullptr.
> + const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
> + auto Parents = Context.getParents(Loc);
> + // FIXME: figure out how to handle it when there are multiple parents.
> + if (Parents.size() != 1)
> + return nullptr;
> + return Parents[0].get<TypeLoc>();
> + }
> +
> + // Check whether the USR of a given Decl is in the USRSet.
> + bool isInUSRSet(const Decl *Decl) const {
> + auto USR = getUSRForDecl(Decl);
> + if (USR.empty())
> + return false;
> + return llvm::is_contained(USRSet, USR);
> + }
> +
> + const std::set<std::string> USRSet;
> + ASTContext &Context;
> + std::vector<RenameInfo> RenameInfos;
> + // Record all interested using declarations which contains the
> using-shadow
> + // declarations of the symbol declarations being renamed.
> + std::vector<const UsingDecl *> UsingDecls;
> +};
> +
> +} // namespace
> +
> +std::vector<SourceLocation>
> +getLocationsOfUSRs(const std::vector<std::string> &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();
> +}
> +
> +std::vector<tooling::AtomicChange>
> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
> + llvm::StringRef NewName, Decl
> *TranslationUnitDecl) {
> + RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
> + Finder.TraverseDecl(TranslationUnitDecl);
> +
> + const SourceManager &SM =
> + TranslationUnitDecl->getASTContext().getSourceManager();
> +
> + std::vector<tooling::AtomicChange> AtomicChanges;
> + auto Replace = [&](SourceLocation Start, SourceLocation End,
> + llvm::StringRef Text) {
> + tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM,
> Start);
> + llvm::Error Err = ReplaceChange.replace(
> + SM, CharSourceRange::getTokenRange(Start, End), Text);
> + if (Err) {
> + llvm::errs() << "Faile to add replacement to AtomicChange: "
> + << llvm::toString(std::move(Err)) << "\n";
> + return;
> + }
> + AtomicChanges.push_back(std::move(ReplaceChange));
> + };
> +
> + for (const auto &RenameInfo : Finder.getRenameInfos()) {
> + std::string ReplacedName = NewName.str();
> + if (RenameInfo.FromDecl && RenameInfo.Context) {
> + if (!llvm::isa<clang::TranslationUnitDecl>(
> + RenameInfo.Context->getDeclContext())) {
> + ReplacedName = tooling::replaceNestedName(
> + RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
> + RenameInfo.FromDecl,
> + NewName.startswith("::") ? NewName.str() : ("::" +
> NewName).str());
> + }
> + }
> + // If the NewName contains leading "::", add it back.
> + if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
> + ReplacedName = NewName.str();
> + Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
> + }
> +
> + // Hanlde using declarations explicitly as "using a::Foo" don't trigger
> + // typeLoc for "a::Foo".
> + for (const auto *Using : Finder.getUsingDecls())
> + Replace(Using->getLocStart(), Using->getLocEnd(), "using " +
> NewName.str());
> +
> + return AtomicChanges;
> +}
> +
> +} // end namespace tooling
> +} // end namespace clang
>
> Modified: cfe/trunk/test/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/CMakeLists.txt (original)
> +++ cfe/trunk/test/CMakeLists.txt Fri Jun 30 09:36:09 2017
> @@ -47,6 +47,7 @@ list(APPEND CLANG_TEST_DEPS
> clang-tblgen
> clang-offload-bundler
> clang-import-test
> + clang-rename
> )
>
> if(CLANG_ENABLE_STATIC_ANALYZER)
>
> Added: cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/
> ClassAsTemplateArgument.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,21 @@
> +class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {};
> +
> +template <typename T>
> +void func() {}
> +
> +template <typename T>
> +class Baz {};
> +
> +int main() {
> + func<Foo>(); // CHECK: func<Bar>();
> + Baz<Foo> /* Test 2 */ obj; // CHECK: Baz<Bar> /* 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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/ClassFindByName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ClassFindByName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassFindByName.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassFindByName.cpp Fri Jun 30 09:36:09
> 2017
> @@ -0,0 +1,10 @@
> +class Foo { // CHECK: class Bar {
> +};
> +
> +int main() {
> + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
> + return 0;
> +}
> +
> +// Test 1.
> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed
> 's,//.*,,' | FileCheck %s
>
> Added: cfe/trunk/test/clang-rename/ClassReplacements.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ClassReplacements.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassReplacements.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassReplacements.cpp Fri Jun 30 09:36:09
> 2017
> @@ -0,0 +1,11 @@
> +// 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' <file> to get the correct offset of Cla when
> changing
> +// this file.
>
> Added: cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ClassSimpleRenaming.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp Fri Jun 30
> 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/ClassTestMulti.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ClassTestMulti.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassTestMulti.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassTestMulti.cpp Fri Jun 30 09:36:09
> 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ClassTestMultiByName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp (added)
> +++ cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,8 @@
> +class Foo1 { // CHECK: class Bar1
> +};
> +
> +class Foo2 { // CHECK: class Bar2
> +};
> +
> +// Test 1.
> +// RUN: clang-rename -qualified-name=Foo1 -new-name=Bar1
> -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s
>
> Added: cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/
> ComplexFunctionOverride.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp (added)
> +++ cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp Fri Jun 30
> 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/ComplicatedClassType.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/ComplicatedClassType.cpp (added)
> +++ cfe/trunk/test/clang-rename/ComplicatedClassType.cpp Fri Jun 30
> 09:36:09 2017
> @@ -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<Foo *>(C)->getValue(); // CHECK: const_cast<Bar
> *>(C)->getValue();
> + Foo foo; // CHECK: Bar foo;
> + const Baz &BazReference = foo;
> + const Baz *BazPointer = &foo;
> + dynamic_cast<const Foo &>(BazReference).getValue(); /* Test 3 */ //
> CHECK: dynamic_cast<const Bar &>(BazReference).getValue();
> + dynamic_cast<const Foo *>(BazPointer)->getValue(); /* Test 4 */ //
> CHECK: dynamic_cast<const Bar *>(BazPointer)->getValue();
> + reinterpret_cast<const Foo *>(BazPointer)->getValue(); /* Test 5 */ //
> CHECK: reinterpret_cast<const Bar *>(BazPointer)->getValue();
> + static_cast<const Foo &>(BazReference).getValue(); /* Test 6 */ //
> CHECK: static_cast<const Bar &>(BazReference).getValue();
> + static_cast<const Foo *>(BazPointer)->getValue(); /* Test 7 */ //
> CHECK: static_cast<const Bar *>(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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/Ctor.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Ctor.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Ctor.cpp (added)
> +++ cfe/trunk/test/clang-rename/Ctor.cpp Fri Jun 30 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/CtorInitializer.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/CtorInitializer.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/CtorInitializer.cpp (added)
> +++ cfe/trunk/test/clang-rename/CtorInitializer.cpp Fri Jun 30 09:36:09
> 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/DeclRefExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/DeclRefExpr.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/DeclRefExpr.cpp (added)
> +++ cfe/trunk/test/clang-rename/DeclRefExpr.cpp Fri Jun 30 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/Field.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Field.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Field.cpp (added)
> +++ cfe/trunk/test/clang-rename/Field.cpp Fri Jun 30 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/FunctionMacro.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/FunctionMacro.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/FunctionMacro.cpp (added)
> +++ cfe/trunk/test/clang-rename/FunctionMacro.cpp Fri Jun 30 09:36:09 2017
> @@ -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-rename -offset=68 -new-name=macro_function %s -- | sed
> 's,//.*,,' | FileCheck %s
> +
> +// To find offsets after modifying the file, use:
> +// grep -Ubo 'foo.*' <file>
>
> Added: cfe/trunk/test/clang-rename/FunctionOverride.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/FunctionOverride.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/FunctionOverride.cpp (added)
> +++ cfe/trunk/test/clang-rename/FunctionOverride.cpp Fri Jun 30 09:36:09
> 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/
> FunctionWithClassFindByName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp (added)
> +++ cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp Fri Jun
> 30 09:36:09 2017
> @@ -0,0 +1,12 @@
> +void foo() {
> +}
> +
> +class Foo { // CHECK: class Bar
> +};
> +
> +int main() {
> + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
> + return 0;
> +}
> +
> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed
> 's,//.*,,' | FileCheck %s
>
> Added: cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/
> IncludeHeaderWithSymbol.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp (added)
> +++ cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,10 @@
> +#include "Inputs/HeaderWithSymbol.h"
> +
> +int main() {
> + return 0; // CHECK: {{^ return 0;}}
> +}
> +
> +// Test 1.
> +// The file IncludeHeaderWithSymbol.cpp doesn't contain the symbol Foo
> +// and is expected to be written to stdout without modifications
> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | FileCheck
> %s
>
> Added: cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Inputs/HeaderWithSymbol.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h (added)
> +++ cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1 @@
> +struct Foo {};
>
> Added: cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Inputs/OffsetToNewName.yaml?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml (added)
> +++ cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,6 @@
> +---
> +- Offset: 6
> + NewName: Bar1
> +- Offset: 44
> + NewName: Bar2
> +...
>
> Added: cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Inputs/QualifiedNameToNewName.yaml?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml (added)
> +++ cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml Fri
> Jun 30 09:36:09 2017
> @@ -0,0 +1,6 @@
> +---
> +- QualifiedName: Foo1
> + NewName: Bar1
> +- QualifiedName: Foo2
> + NewName: Bar2
> +...
>
> Added: cfe/trunk/test/clang-rename/InvalidNewName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/InvalidNewName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/InvalidNewName.cpp (added)
> +++ cfe/trunk/test/clang-rename/InvalidNewName.cpp Fri Jun 30 09:36:09
> 2017
> @@ -0,0 +1,2 @@
> +// 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.
>
> Added: cfe/trunk/test/clang-rename/InvalidOffset.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/InvalidOffset.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/InvalidOffset.cpp (added)
> +++ cfe/trunk/test/clang-rename/InvalidOffset.cpp Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,9 @@
> +#include "Inputs/HeaderWithSymbol.h"
> +#define FOO int bar;
> +FOO
> +
> +int foo;
> +
> +// RUN: not clang-rename -new-name=qux -offset=259 %s -- 2>&1 | FileCheck
> %s
> +// CHECK-NOT: CHECK
> +// CHECK: error: SourceLocation in file {{.*}}InvalidOffset.cpp at offset
> 259 is invalid
>
> Added: cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/InvalidQualifiedName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp (added)
> +++ cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,4 @@
> +struct S {
> +};
> +
> +// RUN: clang-rename -force -qualified-name S2 -new-name=T %s --
>
> Added: cfe/trunk/test/clang-rename/MemberExprMacro.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/MemberExprMacro.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/MemberExprMacro.cpp (added)
> +++ cfe/trunk/test/clang-rename/MemberExprMacro.cpp Fri Jun 30 09:36:09
> 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/Namespace.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Namespace.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Namespace.cpp (added)
> +++ cfe/trunk/test/clang-rename/Namespace.cpp Fri Jun 30 09:36:09 2017
> @@ -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-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' |
> FileCheck %s
> +
> +// To find offsets after modifying the file, use:
> +// grep -Ubo 'Foo.*' <file>
>
> Added: cfe/trunk/test/clang-rename/NoNewName.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/NoNewName.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/NoNewName.cpp (added)
> +++ cfe/trunk/test/clang-rename/NoNewName.cpp Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,4 @@
> +// 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: -new-name must be specified.
>
> Added: cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/
> TemplateClassInstantiation.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp (added)
> +++ cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,42 @@
> +template <typename T>
> +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<T>(number);
> + return value;
> + }
> + static void foo(T value) {}
> + T member;
> +};
> +
> +template <typename T>
> +void func() {
> + Foo<T> obj; /* Test 2 */ // CHECK: Bar<T> obj;
> + obj.member = T();
> + Foo<T>::foo(); // CHECK: Bar<T>::foo();
> +}
> +
> +int main() {
> + Foo<int> i; /* Test 3 */ // CHECK: Bar<int> i;
> + i.member = 0;
> + Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);
> +
> + Foo<bool> b; // CHECK: Bar<bool> b;
> + b.member = false;
> + Foo<bool>::foo(false); // CHECK: Bar<bool>::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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/TemplateTypename.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/TemplateTypename.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/TemplateTypename.cpp (added)
> +++ cfe/trunk/test/clang-rename/TemplateTypename.cpp Fri Jun 30 09:36:09
> 2017
> @@ -0,0 +1,24 @@
> +template <typename T /* Test 1 */> // CHECK: template
> <typename U /* Test 1 */>
> +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<T /* Test 3 */>(number); // CHECK: value =
> static_cast<U /* Test 3 */>(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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/TemplatedClassFunction.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp (added)
> +++ cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp Fri Jun 30
> 09:36:09 2017
> @@ -0,0 +1,22 @@
> +template <typename T>
> +class A {
> +public:
> + void foo() /* Test 1 */ {} // CHECK: void bar() /* Test 1 */ {}
> +};
> +
> +int main(int argc, char **argv) {
> + A<int> 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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/UserDefinedConversion.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/UserDefinedConversion.cpp (added)
> +++ cfe/trunk/test/clang-rename/UserDefinedConversion.cpp Fri Jun 30
> 09:36:09 2017
> @@ -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<Foo>(boo); // CHECK: Bar foo =
> static_cast<Bar>(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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/Variable.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/Variable.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/Variable.cpp (added)
> +++ cfe/trunk/test/clang-rename/Variable.cpp Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,33 @@
> +#define NAMESPACE namespace A
> +NAMESPACE {
> +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=46 -new-name=Bar %s -- | sed 's,//.*,,' |
> FileCheck %s
> +// Test 2.
> +// RUN: clang-rename -offset=234 -new-name=Bar %s -- | sed 's,//.*,,' |
> FileCheck %s
> +// Test 3.
> +// RUN: clang-rename -offset=641 -new-name=Bar %s -- | sed 's,//.*,,' |
> FileCheck %s
> +// Test 4.
> +// RUN: clang-rename -offset=716 -new-name=Bar %s -- | sed 's,//.*,,' |
> FileCheck %s
> +
> +// To find offsets after modifying the file, use:
> +// grep -Ubo 'Foo.*' <file>
>
> Added: cfe/trunk/test/clang-rename/VariableMacro.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/VariableMacro.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/VariableMacro.cpp (added)
> +++ cfe/trunk/test/clang-rename/VariableMacro.cpp Fri Jun 30 09:36:09 2017
> @@ -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-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.*' <file>
>
> Added: cfe/trunk/test/clang-rename/YAMLInput.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-
> rename/YAMLInput.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/clang-rename/YAMLInput.cpp (added)
> +++ cfe/trunk/test/clang-rename/YAMLInput.cpp Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,10 @@
> +class Foo1 { // CHECK: class Bar1
> +};
> +
> +class Foo2 { // CHECK: class Bar2
> +};
> +
> +// Test 1.
> +// RUN: clang-rename -input %S/Inputs/OffsetToNewName.yaml %s -- | sed
> 's,//.*,,' | FileCheck %s
> +// Test 2.
> +// RUN: clang-rename -input %S/Inputs/QualifiedNameToNewName.yaml %s --
> | sed 's,//.*,,' | FileCheck %s
>
> Modified: cfe/trunk/tools/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/
> CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
> ============================================================
> ==================
> --- cfe/trunk/tools/CMakeLists.txt (original)
> +++ cfe/trunk/tools/CMakeLists.txt Fri Jun 30 09:36:09 2017
> @@ -10,6 +10,8 @@ add_clang_subdirectory(clang-offload-bun
>
> add_clang_subdirectory(c-index-test)
>
> +add_clang_subdirectory(clang-rename)
> +
> if(CLANG_ENABLE_ARCMT)
> add_clang_subdirectory(arcmt-test)
> add_clang_subdirectory(c-arcmt-test)
>
> Added: cfe/trunk/tools/clang-rename/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-
> rename/CMakeLists.txt?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/tools/clang-rename/CMakeLists.txt (added)
> +++ cfe/trunk/tools/clang-rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,19 @@
> +add_clang_executable(clang-rename ClangRename.cpp)
> +
> +target_link_libraries(clang-rename
> + clangBasic
> + clangFrontend
> + clangRewrite
> + clangTooling
> + clangToolingCore
> + clangToolingRefactor
> + )
> +
> +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)
>
> Added: cfe/trunk/tools/clang-rename/ClangRename.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-
> rename/ClangRename.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/tools/clang-rename/ClangRename.cpp (added)
> +++ cfe/trunk/tools/clang-rename/ClangRename.cpp Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,240 @@
> +//===--- 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 "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/Refactoring/Rename/RenamingAction.h"
> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.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 <cstdlib>
> +#include <string>
> +#include <system_error>
> +
> +using namespace llvm;
> +using namespace clang;
> +
> +/// \brief An oldname -> newname rename.
> +struct RenameAllInfo {
> + unsigned Offset = 0;
> + std::string QualifiedName;
> + 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<RenameAllInfo> {
> + static void mapping(IO &IO, RenameAllInfo &Info) {
> + IO.mapOptional("Offset", Info.Offset);
> + IO.mapOptional("QualifiedName", Info.QualifiedName);
> + IO.mapRequired("NewName", Info.NewName);
> + }
> +};
> +
> +} // end namespace yaml
> +} // end namespace llvm
> +
> +static cl::OptionCategory ClangRenameOptions("clang-rename common
> options");
> +
> +static cl::list<unsigned> SymbolOffsets(
> + "offset",
> + cl::desc("Locates the symbol by offset as opposed to
> <line>:<column>."),
> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
> +static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
> + cl::cat(ClangRenameOptions));
> +static cl::list<std::string>
> + QualifiedNames("qualified-name",
> + cl::desc("The fully qualified name of the symbol."),
> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
> +
> +static cl::list<std::string>
> + NewNames("new-name", cl::desc("The new name to change the symbol
> to."),
> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
> +static cl::opt<bool> PrintName(
> + "pn",
> + cl::desc("Print the found symbol's name prior to renaming to
> stderr."),
> + cl::cat(ClangRenameOptions));
> +static cl::opt<bool> PrintLocations(
> + "pl", cl::desc("Print the locations affected by renaming to stderr."),
> + cl::cat(ClangRenameOptions));
> +static cl::opt<std::string>
> + ExportFixes("export-fixes",
> + cl::desc("YAML file to store suggested fixes in."),
> + cl::value_desc("filename"), cl::cat(ClangRenameOptions));
> +static cl::opt<std::string>
> + Input("input", cl::desc("YAML file to load oldname-newname pairs
> from."),
> + cl::Optional, cl::cat(ClangRenameOptions));
> +static cl::opt<bool> Force("force",
> + cl::desc("Ignore nonexistent qualified
> names."),
> + cl::cat(ClangRenameOptions));
> +
> +int main(int argc, const char **argv) {
> + tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);
> +
> + if (!Input.empty()) {
> + // Populate QualifiedNames and NewNames from a YAML file.
> + ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
> + llvm::MemoryBuffer::getFile(Input);
> + if (!Buffer) {
> + errs() << "clang-rename: failed to read " << Input << ": "
> + << Buffer.getError().message() << "\n";
> + return 1;
> + }
> +
> + std::vector<RenameAllInfo> Infos;
> + llvm::yaml::Input YAML(Buffer.get()->getBuffer());
> + YAML >> Infos;
> + for (const auto &Info : Infos) {
> + if (!Info.QualifiedName.empty())
> + QualifiedNames.push_back(Info.QualifiedName);
> + else
> + SymbolOffsets.push_back(Info.Offset);
> + NewNames.push_back(Info.NewName);
> + }
> + }
> +
> + // Check the arguments for correctness.
> + if (NewNames.empty()) {
> + errs() << "clang-rename: -new-name must be specified.\n\n";
> + exit(1);
> + }
> +
> + if (SymbolOffsets.empty() == QualifiedNames.empty()) {
> + errs() << "clang-rename: -offset and -qualified-name can't be present
> at "
> + "the same time.\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-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);
> + tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames,
> Force);
> + Tool.run(tooling::newFrontendActionFactory(&FindingAction).get());
> + const std::vector<std::vector<std::string>> &USRList =
> + FindingAction.getUSRList();
> + const std::vector<std::string> &PrevNames =
> FindingAction.getUSRSpellings();
> + if (PrintName) {
> + for (const auto &PrevName : PrevNames) {
> + outs() << "clang-rename found name: " << PrevName << '\n';
> + }
> + }
> +
> + if (FindingAction.errorOccurred()) {
> + // Diagnostics are already issued at this point.
> + exit(1);
> + }
> +
> + if (Force && PrevNames.size() < NewNames.size()) {
> + // No matching PrevName for all NewNames. Without Force this is an
> error
> + // above already.
> + exit(0);
> + }
> +
> + // Perform the renaming.
> + tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,
> + Tool.getReplacements(),
> PrintLocations);
> + std::unique_ptr<tooling::FrontendActionFactory> 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<DiagnosticOptions> DiagOpts = new
> DiagnosticOptions();
> + TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
> + DiagnosticsEngine Diagnostics(
> + IntrusiveRefCntPtr<DiagnosticIDs>(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);
> + const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
> + Rewrite.getEditBuffer(ID).write(outs());
> + }
> + }
> +
> + exit(ExitCode);
> +}
>
> Added: cfe/trunk/tools/clang-rename/clang-rename.el
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-
> rename/clang-rename.el?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/tools/clang-rename/clang-rename.el (added)
> +++ cfe/trunk/tools/clang-rename/clang-rename.el Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,79 @@
> +;;; clang-rename.el --- Renames every occurrence of a symbol found at
> <offset>. -*- lexical-binding: t; -*-
> +
> +;; 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:
> +
> +(defgroup clang-rename nil
> + "Integration with clang-rename"
> + :group 'c)
> +
> +(defcustom clang-rename-binary "clang-rename"
> + "Path to clang-rename executable."
> + :type '(file :must-match t)
> + :group 'clang-rename)
> +
> +;;;###autoload
> +(defun clang-rename (new-name)
> + "Rename all instances of the symbol at point to NEW-NAME using
> clang-rename."
> + (interactive "sEnter a new name: ")
> + (save-some-buffers :all)
> + ;; clang-rename should not be combined with other operations when
> undoing.
> + (undo-boundary)
> + (let ((output-buffer (get-buffer-create "*clang-rename*")))
> + (with-current-buffer output-buffer (erase-buffer))
> + (let ((exit-code (call-process
> + clang-rename-binary nil output-buffer nil
> + (format "-offset=%d"
> + ;; clang-rename wants file (byte) offsets,
> not
> + ;; buffer (character) positions.
> + (clang-rename--bufferpos-to-filepos
> + ;; Emacs treats one character after a
> symbol as
> + ;; part of the symbol, but clang-rename
> doesn’t.
> + ;; Use the beginning of the current
> symbol, if
> + ;; available, to resolve the inconsistency.
> + (or (car (bounds-of-thing-at-point
> 'symbol))
> + (point))
> + 'exact))
> + (format "-new-name=%s" new-name)
> + "-i" (buffer-file-name))))
> + (if (and (integerp exit-code) (zerop exit-code))
> + ;; Success; revert current buffer so it gets the modifications.
> + (progn
> + (kill-buffer output-buffer)
> + (revert-buffer :ignore-auto :noconfirm :preserve-modes))
> + ;; Failure; append exit code to output buffer and display it.
> + (let ((message (clang-rename--format-message
> + "clang-rename failed with %s %s"
> + (if (integerp exit-code) "exit status" "signal")
> + exit-code)))
> + (with-current-buffer output-buffer
> + (insert ?\n message ?\n))
> + (message "%s" message)
> + (display-buffer output-buffer))))))
> +
> +(defalias 'clang-rename--bufferpos-to-filepos
> + (if (fboundp 'bufferpos-to-filepos)
> + 'bufferpos-to-filepos
> + ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it
> using
> + ;; ‘position-bytes’.
> + (lambda (position &optional _quality _coding-system)
> + (1- (position-bytes position)))))
> +
> +;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for
> older
> +;; versions.
> +(defalias 'clang-rename--format-message
> + (if (fboundp 'format-message) 'format-message 'format))
> +
> +(provide 'clang-rename)
> +
> +;;; clang-rename.el ends here
>
> Added: cfe/trunk/tools/clang-rename/clang-rename.py
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-
> rename/clang-rename.py?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/tools/clang-rename/clang-rename.py (added)
> +++ cfe/trunk/tools/clang-rename/clang-rename.py Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,61 @@
> +'''
> +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 <leader>cr :pyf <path-to>/clang-rename.py<cr>
> +
> +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 '<leader>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("checktime")
> +
> +
> +if __name__ == '__main__':
> + main()
>
> Modified: cfe/trunk/unittests/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
> ============================================================
> ==================
> --- cfe/trunk/unittests/CMakeLists.txt (original)
> +++ cfe/trunk/unittests/CMakeLists.txt Fri Jun 30 09:36:09 2017
> @@ -29,3 +29,4 @@ add_subdirectory(CodeGen)
> if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)
> add_subdirectory(libclang)
> endif()
> +add_subdirectory(Rename)
>
> Added: cfe/trunk/unittests/Rename/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Rename/CMakeLists.txt?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/unittests/Rename/CMakeLists.txt (added)
> +++ cfe/trunk/unittests/Rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,22 @@
> +set(LLVM_LINK_COMPONENTS
> + support
> + )
> +
> +# We'd like clang/unittests/Tooling/RewriterTestContext.h in the test.
> +include_directories(${CLANG_SOURCE_DIR})
> +
> +add_extra_unittest(ClangRenameTests
> + RenameClassTest.cpp
> + )
> +
> +target_link_libraries(ClangRenameTests
> + clangAST
> + clangASTMatchers
> + clangBasic
> + clangFormat
> + clangFrontend
> + clangRewrite
> + clangTooling
> + clangToolingCore
> + clangToolingRefactor
> + )
>
> Added: cfe/trunk/unittests/Rename/ClangRenameTest.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Rename/ClangRenameTest.h?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/unittests/Rename/ClangRenameTest.h (added)
> +++ cfe/trunk/unittests/Rename/ClangRenameTest.h Fri Jun 30 09:36:09 2017
> @@ -0,0 +1,112 @@
> +//===-- ClangRenameTests.cpp - clang-rename unit tests
> --------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "unittests/Tooling/RewriterTestContext.h"
> +#include "clang/ASTMatchers/ASTMatchFinder.h"
> +#include "clang/Basic/FileManager.h"
> +#include "clang/Basic/FileSystemOptions.h"
> +#include "clang/Basic/VirtualFileSystem.h"
> +#include "clang/Format/Format.h"
> +#include "clang/Frontend/CompilerInstance.h"
> +#include "clang/Frontend/PCHContainerOperations.h"
> +#include "clang/Tooling/Refactoring.h"
> +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
> +#include "clang/Tooling/Tooling.h"
> +#include "llvm/ADT/IntrusiveRefCntPtr.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "gtest/gtest.h"
> +#include <memory>
> +#include <string>
> +#include <vector>
> +
> +namespace clang {
> +namespace clang_rename {
> +namespace test {
> +
> +struct Case {
> + std::string Before;
> + std::string After;
> + std::string OldName;
> + std::string NewName;
> +};
> +
> +class ClangRenameTest : public testing::Test,
> + public testing::WithParamInterface<Case> {
> +protected:
> + void AppendToHeader(StringRef Code) { HeaderContent += Code.str(); }
> +
> + std::string runClangRenameOnCode(llvm::StringRef Code,
> + llvm::StringRef OldName,
> + llvm::StringRef NewName) {
> + std::string NewCode;
> + llvm::raw_string_ostream(NewCode) << llvm::format(
> + "#include \"%s\"\n%s", HeaderName.c_str(), Code.str().c_str());
> + tooling::FileContentMappings FileContents = {{HeaderName,
> HeaderContent},
> + {CCName, NewCode}};
> + clang::RewriterTestContext Context;
> + Context.createInMemoryFile(HeaderName, HeaderContent);
> + clang::FileID InputFileID = Context.createInMemoryFile(CCName,
> NewCode);
> +
> + tooling::USRFindingAction FindingAction({}, {OldName}, false);
> + std::unique_ptr<tooling::FrontendActionFactory>
> USRFindingActionFactory =
> + tooling::newFrontendActionFactory(&FindingAction);
> +
> + if (!tooling::runToolOnCodeWithArgs(
> + USRFindingActionFactory->create(), NewCode, {"-std=c++11"},
> CCName,
> + "clang-rename", std::make_shared<PCHContainerOperations>(),
> + FileContents))
> + return "";
> +
> + const std::vector<std::vector<std::string>> &USRList =
> + FindingAction.getUSRList();
> + std::vector<std::string> NewNames = {NewName};
> + std::map<std::string, tooling::Replacements> FileToReplacements;
> + tooling::QualifiedRenamingAction RenameAction(NewNames, USRList,
> + FileToReplacements);
> + auto RenameActionFactory = tooling::newFrontendActionFactory(&
> RenameAction);
> + if (!tooling::runToolOnCodeWithArgs(
> + RenameActionFactory->create(), NewCode, {"-std=c++11"},
> CCName,
> + "clang-rename", std::make_shared<PCHContainerOperations>(),
> + FileContents))
> + return "";
> +
> + formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite,
> "llvm");
> + return Context.getRewrittenText(InputFileID);
> + }
> +
> + void CompareSnippets(StringRef Expected, StringRef Actual) {
> + std::string ExpectedCode;
> + llvm::raw_string_ostream(ExpectedCode) << llvm::format(
> + "#include \"%s\"\n%s", HeaderName.c_str(),
> Expected.str().c_str());
> + EXPECT_EQ(format(ExpectedCode), format(Actual));
> + }
> +
> + std::string format(llvm::StringRef Code) {
> + tooling::Replacements Replaces = format::reformat(
> + format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
> + auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
> + EXPECT_TRUE(static_cast<bool>(ChangedCode));
> + if (!ChangedCode) {
> + llvm::errs() << llvm::toString(ChangedCode.takeError());
> + return "";
> + }
> + return *ChangedCode;
> + }
> +
> + std::string HeaderContent;
> + std::string HeaderName = "header.h";
> + std::string CCName = "input.cc";
> +};
> +
> +} // namespace test
> +} // namespace clang_rename
> +} // namesdpace clang
>
> Added: cfe/trunk/unittests/Rename/RenameClassTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Rename/RenameClassTest.cpp?rev=306840&view=auto
> ============================================================
> ==================
> --- cfe/trunk/unittests/Rename/RenameClassTest.cpp (added)
> +++ cfe/trunk/unittests/Rename/RenameClassTest.cpp Fri Jun 30 09:36:09
> 2017
> @@ -0,0 +1,684 @@
> +//===-- RenameClassTest.cpp - unit tests for renaming classes
> -------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "ClangRenameTest.h"
> +
> +namespace clang {
> +namespace clang_rename {
> +namespace test {
> +namespace {
> +
> +class RenameClassTest : public ClangRenameTest {
> +public:
> + RenameClassTest() {
> + AppendToHeader(R"(
> + namespace a {
> + class Foo {
> + public:
> + struct Nested {
> + enum NestedEnum {E1, E2};
> + };
> + void func() {}
> + static int Constant;
> + };
> + class Goo {
> + public:
> + struct Nested {
> + enum NestedEnum {E1, E2};
> + };
> + };
> + int Foo::Constant = 1;
> + } // namespace a
> + namespace b {
> + class Foo {};
> + } // namespace b
> +
> + #define MACRO(x) x
> +
> + template<typename T> class ptr {};
> + )");
> + }
> +};
> +
> +INSTANTIATE_TEST_CASE_P(
> + RenameClassTests, RenameClassTest,
> + testing::ValuesIn(std::vector<Case>({
> + // basic classes
> + {"a::Foo f;", "b::Bar f;", "", ""},
> + {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
> + {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
> + {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return
> b::Bar(); }",
> + "", ""},
> + {"namespace a {a::Foo f() { return Foo(); }}",
> + "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
> + {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}",
> "", ""},
> + {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}",
> "", ""},
> + {"namespace a { void f(Foo a1) {} }",
> + "namespace a { void f(b::Bar a1) {} }", "", ""},
> + {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}",
> "", ""},
> + {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}",
> "", ""},
> + {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
> + {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "",
> ""},
> + {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
> + "a::Foo::Nested2"},
> +
> + // use namespace and typedefs
> + {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
> + {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA)
> {}",
> + "", ""},
> + {"using a::Foo; namespace x { Foo gA; }",
> + "using b::Bar; namespace x { Bar gA; }", "", ""},
> + {"struct S { using T = a::Foo; T a_; };",
> + "struct S { using T = b::Bar; T a_; };", "", ""},
> + {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
> + {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
> + {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T
> gA;", "",
> + ""},
> +
> + // struct members and other oddities
> + {"struct S : public a::Foo {};", "struct S : public b::Bar {};",
> "",
> + ""},
> + {"struct F { void f(a::Foo a1) {} };",
> + "struct F { void f(b::Bar a1) {} };", "", ""},
> + {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
> + {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_;
> };", "",
> + ""},
> +
> + {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested
> ne; }",
> + "", ""},
> + {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested
> ne; }",
> + "", ""},
> + {"void f() { a::Foo::Nested::NestedEnum e; }",
> + "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
> + {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
> + "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "",
> ""},
> + {"void f() { auto e = a::Foo::Nested::E1; }",
> + "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
> +
> + // templates
> + {"template <typename T> struct Foo { T t; };\n"
> + "void f() { Foo<a::Foo> foo; }",
> + "template <typename T> struct Foo { T t; };\n"
> + "void f() { Foo<b::Bar> foo; }",
> + "", ""},
> + {"template <typename T> struct Foo { a::Foo a; };",
> + "template <typename T> struct Foo { b::Bar a; };", "", ""},
> + {"template <typename T> void f(T t) {}\n"
> + "void g() { f<a::Foo>(a::Foo()); }",
> + "template <typename T> void f(T t) {}\n"
> + "void g() { f<b::Bar>(b::Bar()); }",
> + "", ""},
> + {"template <typename T> int f() { return 1; }\n"
> + "template <> int f<a::Foo>() { return 2; }\n"
> + "int g() { return f<a::Foo>(); }",
> + "template <typename T> int f() { return 1; }\n"
> + "template <> int f<b::Bar>() { return 2; }\n"
> + "int g() { return f<b::Bar>(); }",
> + "", ""},
> + {"struct Foo { template <typename T> T foo(); };\n"
> + "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
> + "struct Foo { template <typename T> T foo(); };\n"
> + "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",
> + "", ""},
> +
> + // The following two templates are distilled from regressions
> found in
> + // unique_ptr<> and type_traits.h
> + {"template <typename T> struct outer {\n"
> + " typedef T type;\n"
> + " type Baz();\n"
> + " };\n"
> + " outer<a::Foo> g_A;",
> + "template <typename T> struct outer {\n"
> + " typedef T type;\n"
> + " type Baz();\n"
> + " };\n"
> + " outer<b::Bar> g_A;",
> + "", ""},
> + {"template <typename T> struct nested { typedef T type; };\n"
> + "template <typename T> struct outer { typename nested<T>::type
> Foo(); "
> + "};\n"
> + "outer<a::Foo> g_A;",
> + "template <typename T> struct nested { typedef T type; };\n"
> + "template <typename T> struct outer { typename nested<T>::type
> Foo(); "
> + "};\n"
> + "outer<b::Bar> g_A;",
> + "", ""},
> +
> + // macros
> + {"#define FOO(T, t) T t\n"
> + "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
> + "#define FOO(T, t) T t\n"
> + "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
> + "", ""},
> + {"#define FOO(n) a::Foo n\n"
> + " void f() { FOO(a1); FOO(a2); }",
> + "#define FOO(n) b::Bar n\n"
> + " void f() { FOO(a1); FOO(a2); }",
> + "", ""},
> +
> + // Pointer to member functions
> + {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
> + {"using a::Foo; auto gA = &Foo::func;",
> + "using b::Bar; auto gA = &b::Bar::func;", "", ""},
> + {"using a::Foo; namespace x { auto gA = &Foo::func; }",
> + "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
> + {"typedef a::Foo T; auto gA = &T::func;",
> + "typedef b::Bar T; auto gA = &T::func;", "", ""},
> + {"auto gA = &MACRO(a::Foo)::func;", "auto gA =
> &MACRO(b::Bar)::func;",
> + "", ""},
> +
> + // Short match inside a namespace
> + {"namespace a { void f(Foo a1) {} }",
> + "namespace a { void f(b::Bar a1) {} }", "", ""},
> +
> + // Correct match.
> + {"using a::Foo; struct F { ptr<Foo> a_; };",
> + "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
> +
> + // avoid false positives
> + {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
> + {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a)
> {} }",
> + "", ""},
> +
> + // friends, everyone needs friends.
> + {"class Foo { int i; friend class a::Foo; };",
> + "class Foo { int i; friend class b::Bar; };", "", ""},
> + })), );
> +
> +TEST_P(RenameClassTest, RenameClasses) {
> + auto Param = GetParam();
> + std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
> + std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
> + std::string Actual = runClangRenameOnCode(Param.Before, OldName,
> NewName);
> + CompareSnippets(Param.After, Actual);
> +}
> +
> +class NamespaceDetectionTest : public ClangRenameTest {
> +protected:
> + NamespaceDetectionTest() {
> + AppendToHeader(R"(
> + class Old {};
> + namespace o1 {
> + class Old {};
> + namespace o2 {
> + class Old {};
> + namespace o3 {
> + class Old {};
> + } // namespace o3
> + } // namespace o2
> + } // namespace o1
> + )");
> + }
> +};
> +
> +INSTANTIATE_TEST_CASE_P(
> + RenameClassTest, NamespaceDetectionTest,
> + ::testing::ValuesIn(std::vector<Case>({
> + // Test old and new namespace overlap.
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
> + "o1::o2::o3::Old", "o1::o2::o3::New"},
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } }
> }",
> + "o1::o2::o3::Old", "o1::o2::n3::New"},
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; }
> } }",
> + "o1::o2::o3::Old", "o1::n2::n3::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
> + "::o1::o2::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { n2::New moo; } }",
> "::o1::o2::Old",
> + "::o1::n2::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
> + "::o1::o2::Old", "::n1::n2::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { n1::n2::New moo; } }",
> "::o1::o2::Old",
> + "n1::n2::New"},
> +
> + // Test old and new namespace with differing depths.
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
> + "o1::o2::o3::Old", "::o1::New"},
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
> + "o1::o2::o3::Old", "::o1::o2::New"},
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
> + "o1::o2::o3::Old", "o1::New"},
> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
> + "o1::o2::o3::Old", "o1::o2::New"},
> + {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
> + {"Old moo;", "o1::New moo;", "Old", "o1::New"},
> + {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }",
> "Old",
> + "o1::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",
> + "::New"},
> + {"namespace o1 { namespace o2 { Old moo; } }",
> + "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
> "New"},
> +
> + // Test moving into the new namespace at different levels.
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
> + "::n1::n2::New"},
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
> + "n1::n2::New"},
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { o2::New moo; } }",
> "::o1::o2::Old",
> + "::n1::o2::New"},
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { o2::New moo; } }",
> "::o1::o2::Old",
> + "n1::o2::New"},
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
> + "::o1::o2::Old", "::o1::o2::New"},
> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
> + "namespace n1 { namespace n2 { o1::o2::New moo; } }",
> "::o1::o2::Old",
> + "o1::o2::New"},
> +
> + // Test friends declarations.
> + {"class Foo { friend class o1::Old; };",
> + "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
> + {"class Foo { int i; friend class o1::Old; };",
> + "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
> + "::o1::New"},
> + {"namespace o1 { class Foo { int i; friend class Old; }; }",
> + "namespace o1 { class Foo { int i; friend class New; }; }",
> "o1::Old",
> + "o1::New"},
> + {"namespace o1 { class Foo { int i; friend class Old; }; }",
> + "namespace o1 { class Foo { int i; friend class New; }; }",
> + "::o1::Old", "::o1::New"},
> + })), );
> +
> +TEST_P(NamespaceDetectionTest, RenameClasses) {
> + auto Param = GetParam();
> + std::string Actual =
> + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
> + CompareSnippets(Param.After, Actual);
> +}
> +
> +class TemplatedClassRenameTest : public ClangRenameTest {
> +protected:
> + TemplatedClassRenameTest() {
> + AppendToHeader(R"(
> + template <typename T> struct Old {
> + T t_;
> + T f() { return T(); };
> + static T s(T t) { return t; }
> + };
> + namespace ns {
> + template <typename T> struct Old {
> + T t_;
> + T f() { return T(); };
> + static T s(T t) { return t; }
> + };
> + } // namespace ns
> +
> + namespace o1 {
> + namespace o2 {
> + namespace o3 {
> + template <typename T> struct Old {
> + T t_;
> + T f() { return T(); };
> + static T s(T t) { return t; }
> + };
> + } // namespace o3
> + } // namespace o2
> + } // namespace o1
> + )");
> + }
> +};
> +
> +INSTANTIATE_TEST_CASE_P(
> + RenameClassTests, TemplatedClassRenameTest,
> + ::testing::ValuesIn(std::vector<Case>({
> + {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;",
> "Old",
> + "New"},
> + {"ns::Old<int> gI; ns::Old<bool> gB;",
> + "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
> + {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
> + "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old",
> "New"},
> + {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
> + "ns::Old", "ns::New"},
> +
> + {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
> + "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
> + "New"},
> + {"int gI = ns::Old<int>::s(0); bool gB =
> ns::Old<bool>::s(false);",
> + "int gI = ns::New<int>::s(0); bool gB =
> ns::New<bool>::s(false);",
> + "ns::Old", "ns::New"},
> +
> + {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };",
> "Old",
> + "New"},
> + {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_;
> };",
> + "ns::Old", "ns::New"},
> +
> + {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
> + "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old",
> "New"},
> + {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
> + "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
> + "ns::Old", "ns::New"},
> + {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
> + "auto a = reinterpret_cast<const New<int>*>(new New<int>);",
> "Old",
> + "New"},
> + {"auto a = reinterpret_cast<const ns::Old<int>*>(new
> ns::Old<int>);",
> + "auto a = reinterpret_cast<const ns::New<int>*>(new
> ns::New<int>);",
> + "ns::Old", "ns::New"},
> +
> + {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
> + {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
> + "ns::New"},
> + {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
> + "o1::o2::o3::Old", "o1::o2::o3::New"},
> + {"namespace ns { Old<bool>& foo(); }",
> + "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
> + {"const Old<bool>& foo();", "const New<bool>& foo();", "Old",
> "New"},
> + {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
> + "ns::Old", "ns::New"},
> +
> + // FIXME: figure out why this only works when Moo gets
> + // specialized at some point.
> + {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
> + "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;",
> "Old",
> + "New"},
> + {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int>
> m;",
> + "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int>
> m;",
> + "ns::Old", "ns::New"},
> + })), );
> +
> +TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
> + auto Param = GetParam();
> + std::string Actual =
> + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
> + CompareSnippets(Param.After, Actual);
> +}
> +
> +TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
> + std::string Before = R"(
> + class Old {
> + public:
> + Old();
> + ~Old();
> +
> + Old* next();
> +
> + private:
> + Old* next_;
> + };
> +
> + Old::Old() {}
> + Old::~Old() {}
> + Old* Old::next() { return next_; }
> + )";
> + std::string Expected = R"(
> + class New {
> + public:
> + New();
> + ~New();
> +
> + New* next();
> +
> + private:
> + New* next_;
> + };
> +
> + New::New() {}
> + New::~New() {}
> + New* New::next() { return next_; }
> + )";
> + std::string After = runClangRenameOnCode(Before, "Old", "New");
> + CompareSnippets(Expected, After);
> +}
> +
> +TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
> + std::string Before = R"(
> + class Old {
> + public:
> + Old() {}
> + ~Old() {}
> +
> + Old* next() { return next_; }
> +
> + private:
> + Old* next_;
> + };
> + )";
> + std::string Expected = R"(
> + class New {
> + public:
> + New() {}
> + ~New() {}
> +
> + New* next() { return next_; }
> +
> + private:
> + New* next_;
> + };
> + )";
> + std::string After = runClangRenameOnCode(Before, "Old", "New");
> + CompareSnippets(Expected, After);
> +}
> +
> +// FIXME: no prefix qualifiers being added to the class definition and
> +// constructor.
> +TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
> + std::string Before = R"(
> + namespace ns {
> + class Old {
> + public:
> + Old() {}
> + ~Old() {}
> +
> + Old* next() { return next_; }
> +
> + private:
> + Old* next_;
> + };
> + } // namespace ns
> + )";
> + std::string Expected = R"(
> + namespace ns {
> + class ns::New {
> + public:
> + ns::New() {}
> + ~New() {}
> +
> + New* next() { return next_; }
> +
> + private:
> + New* next_;
> + };
> + } // namespace ns
> + )";
> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
> + CompareSnippets(Expected, After);
> +}
> +
> +// FIXME: no prefix qualifiers being added to the class definition and
> +// constructor.
> +TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
> + std::string Before = R"(
> + namespace ns {
> + class Old {
> + public:
> + Old();
> + ~Old();
> +
> + Old* next();
> +
> + private:
> + Old* next_;
> + };
> +
> + Old::Old() {}
> + Old::~Old() {}
> + Old* Old::next() { return next_; }
> + } // namespace ns
> + )";
> + std::string Expected = R"(
> + namespace ns {
> + class ns::New {
> + public:
> + ns::New();
> + ~New();
> +
> + New* next();
> +
> + private:
> + New* next_;
> + };
> +
> + New::ns::New() {}
> + New::~New() {}
> + New* New::next() { return next_; }
> + } // namespace ns
> + )";
> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
> + CompareSnippets(Expected, After);
> +}
> +
> +// FIXME: no prefix qualifiers being added to the definition.
> +TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
> + // `using Base::Base;` will generate an implicit constructor containing
> usage
> + // of `::ns::Old` which should not be matched.
> + std::string Before = R"(
> + namespace ns {
> + class Old {
> + int x;
> + };
> + class Base {
> + protected:
> + Old *moo_;
> + public:
> + Base(Old *moo) : moo_(moo) {}
> + };
> + class Derived : public Base {
> + public:
> + using Base::Base;
> + };
> + } // namespace ns
> + int main() {
> + ::ns::Old foo;
> + ::ns::Derived d(&foo);
> + return 0;
> + })";
> + std::string Expected = R"(
> + namespace ns {
> + class ns::New {
> + int x;
> + };
> + class Base {
> + protected:
> + New *moo_;
> + public:
> + Base(New *moo) : moo_(moo) {}
> + };
> + class Derived : public Base {
> + public:
> + using Base::Base;
> + };
> + } // namespace ns
> + int main() {
> + ::ns::New foo;
> + ::ns::Derived d(&foo);
> + return 0;
> + })";
> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
> + CompareSnippets(Expected, After);
> +}
> +
> +TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
> + std::string Before = R"(
> + namespace ns {
> + class Old {
> + };
> + } // namespace ns
> + struct S {
> + int y;
> + ns::Old old;
> + };
> + void f() {
> + S s1, s2, s3;
> + // This causes an implicit assignment operator to be created.
> + s1 = s2 = s3;
> + }
> + )";
> + std::string Expected = R"(
> + namespace ns {
> + class ::new_ns::New {
> + };
> + } // namespace ns
> + struct S {
> + int y;
> + ::new_ns::New old;
> + };
> + void f() {
> + S s1, s2, s3;
> + // This causes an implicit assignment operator to be created.
> + s1 = s2 = s3;
> + }
> + )";
> + std::string After = runClangRenameOnCode(Before, "ns::Old",
> "::new_ns::New");
> + CompareSnippets(Expected, After);
> +}
> +
> +// FIXME: no prefix qualifiers being adding to the definition.
> +TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
> + std::string Before = R"(
> + template <class T>
> + class function;
> + template <class R, class... ArgTypes>
> + class function<R(ArgTypes...)> {
> + public:
> + template <typename Functor>
> + function(Functor f) {}
> +
> + function() {}
> +
> + R operator()(ArgTypes...) const {}
> + };
> +
> + namespace ns {
> + class Old {};
> + void f() {
> + function<void(Old)> func;
> + }
> + } // namespace ns)";
> + std::string Expected = R"(
> + template <class T>
> + class function;
> + template <class R, class... ArgTypes>
> + class function<R(ArgTypes...)> {
> + public:
> + template <typename Functor>
> + function(Functor f) {}
> +
> + function() {}
> +
> + R operator()(ArgTypes...) const {}
> + };
> +
> + namespace ns {
> + class ::new_ns::New {};
> + void f() {
> + function<void(::new_ns::New)> func;
> + }
> + } // namespace ns)";
> + std::string After = runClangRenameOnCode(Before, "ns::Old",
> "::new_ns::New");
> + CompareSnippets(Expected, After);
> +}
> +
> +} // anonymous namespace
> +} // namespace test
> +} // namespace clang_rename
> +} // namesdpace clang
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170630/72218213/attachment-0001.html>
More information about the cfe-commits
mailing list