r306840 - [refactor] Move clang-rename into the clang repository

Alex L via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 30 13:54:45 PDT 2017


Thanks! I'll take a look.

On 30 June 2017 at 21:14, Evgenii Stepanov <eugeni.stepanov at gmail.com>
wrote:

> 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/RenamingA
>> ction.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/USRFindin
>> gAction.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/Re
>> factoring/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/Re
>> factoring/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.getFile
>> Path()].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.getFile
>> Path()].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/Re
>> factoring/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->ge
>> tTemplateName().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/Re
>> factoring/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->getSpecialize
>> dTemplate());
>> +    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>(Fo
>> undDecl))
>> +      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/Re
>> factoring/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().getSourc
>> eManager();
>> +      SourceLocation Location = Manager.getSpellingLoc(Expr->g
>> etLocation());
>> +      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().getSourc
>> eManager();
>> +      SourceLocation Location = Manager.getSpellingLoc(Expr->g
>> etMemberLoc());
>> +      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(NestedL
>> oc),
>> +                           NestedLoc.getNestedNameSpecif
>> ier()->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/CMakeList
>> s.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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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-ren
>> ame/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/CMakeLis
>> ts.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-re
>> name/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-re
>> name/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-re
>> name/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-re
>> name/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')".forma
>> t(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/CMak
>> eLists.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/Rena
>> me/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/Rena
>> me/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::newFrontendActionFact
>> ory(&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/Rena
>> me/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/65ce1f8d/attachment-0001.html>


More information about the cfe-commits mailing list