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