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

Alex Lorenz via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 30 09:36:09 PDT 2017


Author: arphaman
Date: Fri Jun 30 09:36:09 2017
New Revision: 306840

URL: http://llvm.org/viewvc/llvm-project?rev=306840&view=rev
Log:
[refactor] Move clang-rename into the clang repository

The core engine of clang-rename will be used for local and global renames in the
new refactoring engine, as mentioned in
http://lists.llvm.org/pipermail/cfe-dev/2017-June/054286.html.

The clang-rename tool is still supported but might get deprecated in the future.

Differential Revision: https://reviews.llvm.org/D34696

Added:
    cfe/trunk/include/clang/Tooling/Refactoring/Rename/
    cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
    cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
    cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
    cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
    cfe/trunk/lib/Tooling/Refactoring/Rename/
    cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
    cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
    cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
    cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
    cfe/trunk/test/clang-rename/
    cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
    cfe/trunk/test/clang-rename/ClassFindByName.cpp
    cfe/trunk/test/clang-rename/ClassReplacements.cpp
    cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
    cfe/trunk/test/clang-rename/ClassTestMulti.cpp
    cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
    cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
    cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
    cfe/trunk/test/clang-rename/Ctor.cpp
    cfe/trunk/test/clang-rename/CtorInitializer.cpp
    cfe/trunk/test/clang-rename/DeclRefExpr.cpp
    cfe/trunk/test/clang-rename/Field.cpp
    cfe/trunk/test/clang-rename/FunctionMacro.cpp
    cfe/trunk/test/clang-rename/FunctionOverride.cpp
    cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
    cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
    cfe/trunk/test/clang-rename/Inputs/
    cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
    cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
    cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
    cfe/trunk/test/clang-rename/InvalidNewName.cpp
    cfe/trunk/test/clang-rename/InvalidOffset.cpp
    cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
    cfe/trunk/test/clang-rename/MemberExprMacro.cpp
    cfe/trunk/test/clang-rename/Namespace.cpp
    cfe/trunk/test/clang-rename/NoNewName.cpp
    cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
    cfe/trunk/test/clang-rename/TemplateTypename.cpp
    cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
    cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
    cfe/trunk/test/clang-rename/Variable.cpp
    cfe/trunk/test/clang-rename/VariableMacro.cpp
    cfe/trunk/test/clang-rename/YAMLInput.cpp
    cfe/trunk/tools/clang-rename/
    cfe/trunk/tools/clang-rename/CMakeLists.txt
    cfe/trunk/tools/clang-rename/ClangRename.cpp
    cfe/trunk/tools/clang-rename/clang-rename.el
    cfe/trunk/tools/clang-rename/clang-rename.py
    cfe/trunk/unittests/Rename/
    cfe/trunk/unittests/Rename/CMakeLists.txt
    cfe/trunk/unittests/Rename/ClangRenameTest.h
    cfe/trunk/unittests/Rename/RenameClassTest.cpp
Modified:
    cfe/trunk/include/clang/module.modulemap
    cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
    cfe/trunk/test/CMakeLists.txt
    cfe/trunk/tools/CMakeLists.txt
    cfe/trunk/unittests/CMakeLists.txt

Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h (added)
+++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1,70 @@
+//===--- RenamingAction.h - Clang refactoring library ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+class ASTConsumer;
+class CompilerInstance;
+
+namespace tooling {
+
+class RenamingAction {
+public:
+  RenamingAction(const std::vector<std::string> &NewNames,
+                 const std::vector<std::string> &PrevNames,
+                 const std::vector<std::vector<std::string>> &USRList,
+                 std::map<std::string, tooling::Replacements> &FileToReplaces,
+                 bool PrintLocations = false)
+      : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+        FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+  std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+  const std::vector<std::string> &NewNames, &PrevNames;
+  const std::vector<std::vector<std::string>> &USRList;
+  std::map<std::string, tooling::Replacements> &FileToReplaces;
+  bool PrintLocations;
+};
+
+/// Rename all symbols identified by the given USRs.
+class QualifiedRenamingAction {
+public:
+  QualifiedRenamingAction(
+      const std::vector<std::string> &NewNames,
+      const std::vector<std::vector<std::string>> &USRList,
+      std::map<std::string, tooling::Replacements> &FileToReplaces)
+      : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {}
+
+  std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+  /// New symbol names.
+  const std::vector<std::string> &NewNames;
+
+  /// A list of USRs. Each element represents USRs of a symbol being renamed.
+  const std::vector<std::vector<std::string>> &USRList;
+
+  /// A file path to replacements map.
+  std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H

Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h (added)
+++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1,84 @@
+//===--- USRFinder.h - Clang refactoring library --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for determining the USR of a symbol at a location in source
+/// code.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace clang::ast_matchers;
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class SourceLocation;
+class NamedDecl;
+
+namespace tooling {
+
+// Given an AST context and a point, returns a NamedDecl identifying the symbol
+// at the point. Returns null if nothing is found at the point.
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+                                const SourceLocation Point);
+
+// Given an AST context and a fully qualified name, returns a NamedDecl
+// identifying the symbol with a matching name. Returns null if nothing is
+// found for the name.
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+                                 const std::string &Name);
+
+// Converts a Decl into a USR.
+std::string getUSRForDecl(const Decl *Decl);
+
+// FIXME: Implement RecursiveASTVisitor<T>::VisitNestedNameSpecifier instead.
+class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback {
+public:
+  explicit NestedNameSpecifierLocFinder(ASTContext &Context)
+      : Context(Context) {}
+
+  std::vector<NestedNameSpecifierLoc> getNestedNameSpecifierLocations() {
+    addMatchers();
+    Finder.matchAST(Context);
+    return Locations;
+  }
+
+private:
+  void addMatchers() {
+    const auto NestedNameSpecifierLocMatcher =
+        nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc");
+    Finder.addMatcher(NestedNameSpecifierLocMatcher, this);
+  }
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    const auto *NNS = Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
+        "nestedNameSpecifierLoc");
+    Locations.push_back(*NNS);
+  }
+
+  ASTContext &Context;
+  std::vector<NestedNameSpecifierLoc> Locations;
+  MatchFinder Finder;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H

Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h (added)
+++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1,54 @@
+//===--- USRFindingAction.h - Clang refactoring library -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find all relevant USRs at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+class ASTConsumer;
+class CompilerInstance;
+class NamedDecl;
+
+namespace tooling {
+
+struct USRFindingAction {
+  USRFindingAction(ArrayRef<unsigned> SymbolOffsets,
+                   ArrayRef<std::string> QualifiedNames, bool Force)
+      : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+        ErrorOccurred(false), Force(Force) {}
+  std::unique_ptr<ASTConsumer> newASTConsumer();
+
+  ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }
+  ArrayRef<std::vector<std::string>> getUSRList() { return USRList; }
+  bool errorOccurred() { return ErrorOccurred; }
+
+private:
+  std::vector<unsigned> SymbolOffsets;
+  std::vector<std::string> QualifiedNames;
+  std::vector<std::string> SpellingNames;
+  std::vector<std::vector<std::string>> USRList;
+  bool ErrorOccurred;
+  bool Force;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H

Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h (added)
+++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1,49 @@
+//===--- USRLocFinder.h - Clang refactoring library -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides functionality for finding all instances of a USR in a given
+/// AST.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// Create atomic changes for renaming all symbol references which are
+/// identified by the USRs set to a given new name.
+///
+/// \param USRs The set containing USRs of a particular old symbol.
+/// \param NewName The new name to replace old symbol name.
+/// \param TranslationUnitDecl The translation unit declaration.
+///
+/// \return Atomic changes for renaming.
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+                          llvm::StringRef NewName, Decl *TranslationUnitDecl);
+
+// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!
+std::vector<SourceLocation>
+getLocationsOfUSRs(const std::vector<std::string> &USRs,
+                   llvm::StringRef PrevName, Decl *Decl);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H

Modified: cfe/trunk/include/clang/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/module.modulemap?rev=306840&r1=306839&r2=306840&view=diff
==============================================================================
--- cfe/trunk/include/clang/module.modulemap (original)
+++ cfe/trunk/include/clang/module.modulemap Fri Jun 30 09:36:09 2017
@@ -133,9 +133,10 @@ module Clang_StaticAnalyzer_Frontend {
 
 module Clang_Tooling {
   requires cplusplus umbrella "Tooling" module * { export * }
-  // FIXME: Exclude this header to avoid pulling all of the AST matchers
+  // FIXME: Exclude these headers to avoid pulling all of the AST matchers
   // library into clang-format. Due to inline key functions in the headers,
   // importing the AST matchers library gives a link dependency on the AST
   // matchers (and thus the AST), which clang-format should not have.
   exclude header "Tooling/RefactoringCallbacks.h"
+  exclude header "Tooling/Refactoring/Rename/USRFinder.h"
 }

Modified: cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt (original)
+++ cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -5,8 +5,16 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangToolingRefactor
   AtomicChange.cpp
+  Rename/RenamingAction.cpp
+  Rename/USRFinder.cpp
+  Rename/USRFindingAction.cpp
+  Rename/USRLocFinder.cpp
 
   LINK_LIBS
+  clangAST
+  clangASTMatchers
   clangBasic
+  clangIndex
+  clangLex
   clangToolingCore
   )

Added: cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp (added)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,134 @@
+//===--- RenamingAction.cpp - Clang refactoring library -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+class RenamingASTConsumer : public ASTConsumer {
+public:
+  RenamingASTConsumer(
+      const std::vector<std::string> &NewNames,
+      const std::vector<std::string> &PrevNames,
+      const std::vector<std::vector<std::string>> &USRList,
+      std::map<std::string, tooling::Replacements> &FileToReplaces,
+      bool PrintLocations)
+      : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+        FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+  void HandleTranslationUnit(ASTContext &Context) override {
+    for (unsigned I = 0; I < NewNames.size(); ++I)
+      HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);
+  }
+
+  void HandleOneRename(ASTContext &Context, const std::string &NewName,
+                       const std::string &PrevName,
+                       const std::vector<std::string> &USRs) {
+    const SourceManager &SourceMgr = Context.getSourceManager();
+    std::vector<SourceLocation> RenamingCandidates;
+    std::vector<SourceLocation> NewCandidates;
+
+    NewCandidates = tooling::getLocationsOfUSRs(
+        USRs, PrevName, Context.getTranslationUnitDecl());
+    RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(),
+                              NewCandidates.end());
+
+    unsigned PrevNameLen = PrevName.length();
+    for (const auto &Loc : RenamingCandidates) {
+      if (PrintLocations) {
+        FullSourceLoc FullLoc(Loc, SourceMgr);
+        errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc)
+               << ":" << FullLoc.getSpellingLineNumber() << ":"
+               << FullLoc.getSpellingColumnNumber() << "\n";
+      }
+      // FIXME: better error handling.
+      tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName);
+      llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace);
+      if (Err)
+        llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! "
+                     << llvm::toString(std::move(Err)) << "\n";
+    }
+  }
+
+private:
+  const std::vector<std::string> &NewNames, &PrevNames;
+  const std::vector<std::vector<std::string>> &USRList;
+  std::map<std::string, tooling::Replacements> &FileToReplaces;
+  bool PrintLocations;
+};
+
+// A renamer to rename symbols which are identified by a give USRList to
+// new name.
+//
+// FIXME: Merge with the above RenamingASTConsumer.
+class USRSymbolRenamer : public ASTConsumer {
+public:
+  USRSymbolRenamer(const std::vector<std::string> &NewNames,
+                   const std::vector<std::vector<std::string>> &USRList,
+                   std::map<std::string, tooling::Replacements> &FileToReplaces)
+      : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {
+    assert(USRList.size() == NewNames.size());
+  }
+
+  void HandleTranslationUnit(ASTContext &Context) override {
+    for (unsigned I = 0; I < NewNames.size(); ++I) {
+      // FIXME: Apply AtomicChanges directly once the refactoring APIs are
+      // ready.
+      auto AtomicChanges = tooling::createRenameAtomicChanges(
+          USRList[I], NewNames[I], Context.getTranslationUnitDecl());
+      for (const auto AtomicChange : AtomicChanges) {
+        for (const auto &Replace : AtomicChange.getReplacements()) {
+          llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace);
+          if (Err) {
+            llvm::errs() << "Renaming failed in " << Replace.getFilePath()
+                         << "! " << llvm::toString(std::move(Err)) << "\n";
+          }
+        }
+      }
+    }
+  }
+
+private:
+  const std::vector<std::string> &NewNames;
+  const std::vector<std::vector<std::string>> &USRList;
+  std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
+  return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
+                                                FileToReplaces, PrintLocations);
+}
+
+std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
+  return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
+}
+
+} // end namespace tooling
+} // end namespace clang

Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp (added)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,213 @@
+//===--- USRFinder.cpp - Clang refactoring library ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
+/// point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+// NamedDeclFindingASTVisitor recursively visits each AST node to find the
+// symbol underneath the cursor.
+// FIXME: move to separate .h/.cc file if this gets too large.
+namespace {
+class NamedDeclFindingASTVisitor
+    : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
+public:
+  // \brief Finds the NamedDecl at a point in the source.
+  // \param Point the location in the source to search for the NamedDecl.
+  explicit NamedDeclFindingASTVisitor(const SourceLocation Point,
+                                      const ASTContext &Context)
+      : Result(nullptr), Point(Point), Context(Context) {}
+
+  // \brief Finds the NamedDecl for a name in the source.
+  // \param Name the fully qualified name.
+  explicit NamedDeclFindingASTVisitor(const std::string &Name,
+                                      const ASTContext &Context)
+      : Result(nullptr), Name(Name), Context(Context) {}
+
+  // Declaration visitors:
+
+  // \brief Checks if the point falls within the NameDecl. This covers every
+  // declaration of a named entity that we may come across. Usually, just
+  // checking if the point lies within the length of the name of the declaration
+  // and the start location is sufficient.
+  bool VisitNamedDecl(const NamedDecl *Decl) {
+    return dyn_cast<CXXConversionDecl>(Decl)
+               ? true
+               : setResult(Decl, Decl->getLocation(),
+                           Decl->getNameAsString().length());
+  }
+
+  // Expression visitors:
+
+  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl();
+    return setResult(Decl, Expr->getLocation(),
+                     Decl->getNameAsString().length());
+  }
+
+  bool VisitMemberExpr(const MemberExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
+    return setResult(Decl, Expr->getMemberLoc(),
+                     Decl->getNameAsString().length());
+  }
+
+  // Other visitors:
+
+  bool VisitTypeLoc(const TypeLoc Loc) {
+    const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
+    const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(
+        TypeBeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
+    if (const auto *TemplateTypeParm =
+            dyn_cast<TemplateTypeParmType>(Loc.getType()))
+      return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc);
+    if (const auto *TemplateSpecType =
+            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+      return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+                       TypeBeginLoc, TypeEndLoc);
+    }
+    return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
+                     TypeEndLoc);
+  }
+
+  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
+    for (const auto *Initializer : ConstructorDecl->inits()) {
+      // Ignore implicit initializers.
+      if (!Initializer->isWritten())
+        continue;
+      if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
+        const SourceLocation InitBeginLoc = Initializer->getSourceLocation(),
+                             InitEndLoc = Lexer::getLocForEndOfToken(
+                                 InitBeginLoc, 0, Context.getSourceManager(),
+                                 Context.getLangOpts());
+        if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc))
+          return false;
+      }
+    }
+    return true;
+  }
+
+  // Other:
+
+  const NamedDecl *getNamedDecl() { return Result; }
+
+  // \brief Determines if a namespace qualifier contains the point.
+  // \returns false on success and sets Result.
+  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
+    while (NameLoc) {
+      const NamespaceDecl *Decl =
+          NameLoc.getNestedNameSpecifier()->getAsNamespace();
+      setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
+      NameLoc = NameLoc.getPrefix();
+    }
+  }
+
+private:
+  // \brief Sets Result to Decl if the Point is within Start and End.
+  // \returns false on success.
+  bool setResult(const NamedDecl *Decl, SourceLocation Start,
+                 SourceLocation End) {
+    if (!Decl)
+      return true;
+    if (Name.empty()) {
+      // Offset is used to find the declaration.
+      if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
+          !End.isFileID() || !isPointWithin(Start, End))
+        return true;
+    } else {
+      // Fully qualified name is used to find the declaration.
+      if (Name != Decl->getQualifiedNameAsString() &&
+          Name != "::" + Decl->getQualifiedNameAsString())
+        return true;
+    }
+    Result = Decl;
+    return false;
+  }
+
+  // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
+  // \returns false on success.
+  bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {
+    // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
+    return Offset == 0 ||
+           setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
+  }
+
+  // \brief Determines if the Point is within Start and End.
+  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
+    // FIXME: Add tests for Point == End.
+    return Point == Start || Point == End ||
+           (Context.getSourceManager().isBeforeInTranslationUnit(Start,
+                                                                 Point) &&
+            Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
+  }
+
+  const NamedDecl *Result;
+  const SourceLocation Point; // The location to find the NamedDecl.
+  const std::string Name;
+  const ASTContext &Context;
+};
+} // namespace
+
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+                                const SourceLocation Point) {
+  const SourceManager &SM = Context.getSourceManager();
+  NamedDeclFindingASTVisitor Visitor(Point, Context);
+
+  // Try to be clever about pruning down the number of top-level declarations we
+  // see. If both start and end is either before or after the point we're
+  // looking for the point cannot be inside of this decl. Don't even look at it.
+  for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
+    SourceLocation StartLoc = CurrDecl->getLocStart();
+    SourceLocation EndLoc = CurrDecl->getLocEnd();
+    if (StartLoc.isValid() && EndLoc.isValid() &&
+        SM.isBeforeInTranslationUnit(StartLoc, Point) !=
+            SM.isBeforeInTranslationUnit(EndLoc, Point))
+      Visitor.TraverseDecl(CurrDecl);
+  }
+
+  NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
+  for (const auto &Location : Finder.getNestedNameSpecifierLocations())
+    Visitor.handleNestedNameSpecifierLoc(Location);
+
+  return Visitor.getNamedDecl();
+}
+
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+                                 const std::string &Name) {
+  NamedDeclFindingASTVisitor Visitor(Name, Context);
+  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+
+  return Visitor.getNamedDecl();
+}
+
+std::string getUSRForDecl(const Decl *Decl) {
+  llvm::SmallVector<char, 128> Buff;
+
+  // FIXME: Add test for the nullptr case.
+  if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
+    return "";
+
+  return std::string(Buff.data(), Buff.size());
+}
+
+} // end namespace tooling
+} // end namespace clang

Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp (added)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,236 @@
+//===--- USRFindingAction.cpp - Clang refactoring library -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find USR for the symbol at <offset>, as well as
+/// all additional USRs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Tooling.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to
+// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
+// Decl refers to class and adds USRs of all overridden methods if Decl refers
+// to virtual method.
+class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
+public:
+  AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
+      : FoundDecl(FoundDecl), Context(Context) {}
+
+  std::vector<std::string> Find() {
+    // Fill OverriddenMethods and PartialSpecs storages.
+    TraverseDecl(Context.getTranslationUnitDecl());
+    if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
+      addUSRsOfOverridenFunctions(MethodDecl);
+      for (const auto &OverriddenMethod : OverriddenMethods) {
+        if (checkIfOverriddenFunctionAscends(OverriddenMethod))
+          USRSet.insert(getUSRForDecl(OverriddenMethod));
+      }
+    } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
+      handleCXXRecordDecl(RecordDecl);
+    } else if (const auto *TemplateDecl =
+                   dyn_cast<ClassTemplateDecl>(FoundDecl)) {
+      handleClassTemplateDecl(TemplateDecl);
+    } else {
+      USRSet.insert(getUSRForDecl(FoundDecl));
+    }
+    return std::vector<std::string>(USRSet.begin(), USRSet.end());
+  }
+
+  bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
+    if (MethodDecl->isVirtual())
+      OverriddenMethods.push_back(MethodDecl);
+    return true;
+  }
+
+  bool VisitClassTemplatePartialSpecializationDecl(
+      const ClassTemplatePartialSpecializationDecl *PartialSpec) {
+    PartialSpecs.push_back(PartialSpec);
+    return true;
+  }
+
+private:
+  void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
+    RecordDecl = RecordDecl->getDefinition();
+    if (const auto *ClassTemplateSpecDecl =
+            dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
+      handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
+    addUSRsOfCtorDtors(RecordDecl);
+  }
+
+  void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
+    for (const auto *Specialization : TemplateDecl->specializations())
+      addUSRsOfCtorDtors(Specialization);
+
+    for (const auto *PartialSpec : PartialSpecs) {
+      if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
+        addUSRsOfCtorDtors(PartialSpec);
+    }
+    addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
+  }
+
+  void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
+    RecordDecl = RecordDecl->getDefinition();
+
+    // Skip if the CXXRecordDecl doesn't have definition.
+    if (!RecordDecl)
+      return;
+
+    for (const auto *CtorDecl : RecordDecl->ctors())
+      USRSet.insert(getUSRForDecl(CtorDecl));
+
+    USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
+    USRSet.insert(getUSRForDecl(RecordDecl));
+  }
+
+  void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
+    USRSet.insert(getUSRForDecl(MethodDecl));
+    // Recursively visit each OverridenMethod.
+    for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
+      addUSRsOfOverridenFunctions(OverriddenMethod);
+  }
+
+  bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
+    for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
+      if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
+        return true;
+      return checkIfOverriddenFunctionAscends(OverriddenMethod);
+    }
+    return false;
+  }
+
+  const Decl *FoundDecl;
+  ASTContext &Context;
+  std::set<std::string> USRSet;
+  std::vector<const CXXMethodDecl *> OverriddenMethods;
+  std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
+};
+} // namespace
+
+class NamedDeclFindingConsumer : public ASTConsumer {
+public:
+  NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
+                           ArrayRef<std::string> QualifiedNames,
+                           std::vector<std::string> &SpellingNames,
+                           std::vector<std::vector<std::string>> &USRList,
+                           bool Force, bool &ErrorOccurred)
+      : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+        SpellingNames(SpellingNames), USRList(USRList), Force(Force),
+        ErrorOccurred(ErrorOccurred) {}
+
+private:
+  bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
+                  unsigned SymbolOffset, const std::string &QualifiedName) {
+    DiagnosticsEngine &Engine = Context.getDiagnostics();
+    const FileID MainFileID = SourceMgr.getMainFileID();
+
+    if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
+      ErrorOccurred = true;
+      unsigned InvalidOffset = Engine.getCustomDiagID(
+          DiagnosticsEngine::Error,
+          "SourceLocation in file %0 at offset %1 is invalid");
+      Engine.Report(SourceLocation(), InvalidOffset)
+          << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
+      return false;
+    }
+
+    const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
+                                     .getLocWithOffset(SymbolOffset);
+    const NamedDecl *FoundDecl = QualifiedName.empty()
+                                     ? getNamedDeclAt(Context, Point)
+                                     : getNamedDeclFor(Context, QualifiedName);
+
+    if (FoundDecl == nullptr) {
+      if (QualifiedName.empty()) {
+        FullSourceLoc FullLoc(Point, SourceMgr);
+        unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
+            DiagnosticsEngine::Error,
+            "clang-rename could not find symbol (offset %0)");
+        Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
+        ErrorOccurred = true;
+        return false;
+      }
+
+      if (Force)
+        return true;
+
+      unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
+          DiagnosticsEngine::Error, "clang-rename could not find symbol %0");
+      Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
+      ErrorOccurred = true;
+      return false;
+    }
+
+    // If FoundDecl is a constructor or destructor, we want to instead take
+    // the Decl of the corresponding class.
+    if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
+      FoundDecl = CtorDecl->getParent();
+    else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
+      FoundDecl = DtorDecl->getParent();
+
+    SpellingNames.push_back(FoundDecl->getNameAsString());
+    AdditionalUSRFinder Finder(FoundDecl, Context);
+    USRList.push_back(Finder.Find());
+    return true;
+  }
+
+  void HandleTranslationUnit(ASTContext &Context) override {
+    const SourceManager &SourceMgr = Context.getSourceManager();
+    for (unsigned Offset : SymbolOffsets) {
+      if (!FindSymbol(Context, SourceMgr, Offset, ""))
+        return;
+    }
+    for (const std::string &QualifiedName : QualifiedNames) {
+      if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
+        return;
+    }
+  }
+
+  ArrayRef<unsigned> SymbolOffsets;
+  ArrayRef<std::string> QualifiedNames;
+  std::vector<std::string> &SpellingNames;
+  std::vector<std::vector<std::string>> &USRList;
+  bool Force;
+  bool &ErrorOccurred;
+};
+
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
+  return llvm::make_unique<NamedDeclFindingConsumer>(
+      SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
+      ErrorOccurred);
+}
+
+} // end namespace tooling
+} // end namespace clang

Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (added)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,509 @@
+//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for finding all instances of a USR. Our strategy is very
+/// simple; we just compare the USR at every relevant AST node with the one
+/// provided.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Lookup.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <cstddef>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// \brief This visitor recursively searches for all instances of a USR in a
+// translation unit and stores them for later usage.
+class USRLocFindingASTVisitor
+    : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
+public:
+  explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
+                                   StringRef PrevName,
+                                   const ASTContext &Context)
+      : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
+  }
+
+  // Declaration visitors:
+
+  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
+    for (const auto *Initializer : ConstructorDecl->inits()) {
+      // Ignore implicit initializers.
+      if (!Initializer->isWritten())
+        continue;
+      if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
+        if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end())
+          LocationsFound.push_back(Initializer->getSourceLocation());
+      }
+    }
+    return true;
+  }
+
+  bool VisitNamedDecl(const NamedDecl *Decl) {
+    if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
+      checkAndAddLocation(Decl->getLocation());
+    return true;
+  }
+
+  // Expression visitors:
+
+  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl();
+
+    if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
+      const SourceManager &Manager = Decl->getASTContext().getSourceManager();
+      SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
+      checkAndAddLocation(Location);
+    }
+
+    return true;
+  }
+
+  bool VisitMemberExpr(const MemberExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
+    if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
+      const SourceManager &Manager = Decl->getASTContext().getSourceManager();
+      SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
+      checkAndAddLocation(Location);
+    }
+    return true;
+  }
+
+  // Other visitors:
+
+  bool VisitTypeLoc(const TypeLoc Loc) {
+    if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl())) !=
+        USRSet.end())
+      checkAndAddLocation(Loc.getBeginLoc());
+    if (const auto *TemplateTypeParm =
+            dyn_cast<TemplateTypeParmType>(Loc.getType())) {
+      if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) !=
+          USRSet.end())
+        checkAndAddLocation(Loc.getBeginLoc());
+    }
+    return true;
+  }
+
+  // Non-visitors:
+
+  // \brief Returns a list of unique locations. Duplicate or overlapping
+  // locations are erroneous and should be reported!
+  const std::vector<clang::SourceLocation> &getLocationsFound() const {
+    return LocationsFound;
+  }
+
+  // Namespace traversal:
+  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
+    while (NameLoc) {
+      const NamespaceDecl *Decl =
+          NameLoc.getNestedNameSpecifier()->getAsNamespace();
+      if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
+        checkAndAddLocation(NameLoc.getLocalBeginLoc());
+      NameLoc = NameLoc.getPrefix();
+    }
+  }
+
+private:
+  void checkAndAddLocation(SourceLocation Loc) {
+    const SourceLocation BeginLoc = Loc;
+    const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+        BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
+    StringRef TokenName =
+        Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
+                             Context.getSourceManager(), Context.getLangOpts());
+    size_t Offset = TokenName.find(PrevName);
+
+    // The token of the source location we find actually has the old
+    // name.
+    if (Offset != StringRef::npos)
+      LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
+  }
+
+  const std::set<std::string> USRSet;
+  const std::string PrevName;
+  std::vector<clang::SourceLocation> LocationsFound;
+  const ASTContext &Context;
+};
+
+SourceLocation StartLocationForType(TypeLoc TL) {
+  // For elaborated types (e.g. `struct a::A`) we want the portion after the
+  // `struct` but including the namespace qualifier, `a::`.
+  if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
+    NestedNameSpecifierLoc NestedNameSpecifier =
+        ElaboratedTypeLoc.getQualifierLoc();
+    if (NestedNameSpecifier.getNestedNameSpecifier())
+      return NestedNameSpecifier.getBeginLoc();
+    TL = TL.getNextTypeLoc();
+  }
+  return TL.getLocStart();
+}
+
+SourceLocation EndLocationForType(TypeLoc TL) {
+  // Dig past any namespace or keyword qualifications.
+  while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
+         TL.getTypeLocClass() == TypeLoc::Qualified)
+    TL = TL.getNextTypeLoc();
+
+  // The location for template specializations (e.g. Foo<int>) includes the
+  // templated types in its location range.  We want to restrict this to just
+  // before the `<` character.
+  if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
+    return TL.castAs<TemplateSpecializationTypeLoc>()
+        .getLAngleLoc()
+        .getLocWithOffset(-1);
+  }
+  return TL.getEndLoc();
+}
+
+NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
+  // Dig past any keyword qualifications.
+  while (TL.getTypeLocClass() == TypeLoc::Qualified)
+    TL = TL.getNextTypeLoc();
+
+  // For elaborated types (e.g. `struct a::A`) we want the portion after the
+  // `struct` but including the namespace qualifier, `a::`.
+  if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
+    return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
+  return nullptr;
+}
+
+// Find all locations identified by the given USRs for rename.
+//
+// This class will traverse the AST and find every AST node whose USR is in the
+// given USRs' set.
+class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
+public:
+  RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
+      : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
+
+  // A structure records all information of a symbol reference being renamed.
+  // We try to add as few prefix qualifiers as possible.
+  struct RenameInfo {
+    // The begin location of a symbol being renamed.
+    SourceLocation Begin;
+    // The end location of a symbol being renamed.
+    SourceLocation End;
+    // The declaration of a symbol being renamed (can be nullptr).
+    const NamedDecl *FromDecl;
+    // The declaration in which the nested name is contained (can be nullptr).
+    const Decl *Context;
+    // The nested name being replaced (can be nullptr).
+    const NestedNameSpecifier *Specifier;
+  };
+
+  // FIXME: Currently, prefix qualifiers will be added to the renamed symbol
+  // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming
+  // "a::Foo" to "b::Bar").
+  // For renaming declarations/definitions, prefix qualifiers should be filtered
+  // out.
+  bool VisitNamedDecl(const NamedDecl *Decl) {
+    // UsingDecl has been handled in other place.
+    if (llvm::isa<UsingDecl>(Decl))
+      return true;
+
+    // DestructorDecl has been handled in Typeloc.
+    if (llvm::isa<CXXDestructorDecl>(Decl))
+      return true;
+
+    if (Decl->isImplicit())
+      return true;
+
+    if (isInUSRSet(Decl)) {
+      RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr,
+                         nullptr, nullptr};
+      RenameInfos.push_back(Info);
+    }
+    return true;
+  }
+
+  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+    const NamedDecl *Decl = Expr->getFoundDecl();
+    if (isInUSRSet(Decl)) {
+      RenameInfo Info = {Expr->getSourceRange().getBegin(),
+                         Expr->getSourceRange().getEnd(), Decl,
+                         getClosestAncestorDecl(*Expr), Expr->getQualifier()};
+      RenameInfos.push_back(Info);
+    }
+
+    return true;
+  }
+
+  bool VisitUsingDecl(const UsingDecl *Using) {
+    for (const auto *UsingShadow : Using->shadows()) {
+      if (isInUSRSet(UsingShadow->getTargetDecl())) {
+        UsingDecls.push_back(Using);
+        break;
+      }
+    }
+    return true;
+  }
+
+  bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
+    if (!NestedLoc.getNestedNameSpecifier()->getAsType())
+      return true;
+    if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
+      return true;
+
+    if (const auto *TargetDecl =
+            getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
+      if (isInUSRSet(TargetDecl)) {
+        RenameInfo Info = {NestedLoc.getBeginLoc(),
+                           EndLocationForType(NestedLoc.getTypeLoc()),
+                           TargetDecl, getClosestAncestorDecl(NestedLoc),
+                           NestedLoc.getNestedNameSpecifier()->getPrefix()};
+        RenameInfos.push_back(Info);
+      }
+    }
+    return true;
+  }
+
+  bool VisitTypeLoc(TypeLoc Loc) {
+    if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
+      return true;
+
+    auto Parents = Context.getParents(Loc);
+    TypeLoc ParentTypeLoc;
+    if (!Parents.empty()) {
+      // Handle cases of nested name specificier locations.
+      //
+      // The VisitNestedNameSpecifierLoc interface is not impelmented in
+      // RecursiveASTVisitor, we have to handle it explicitly.
+      if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
+        VisitNestedNameSpecifierLocations(*NSL);
+        return true;
+      }
+
+      if (const auto *TL = Parents[0].get<TypeLoc>())
+        ParentTypeLoc = *TL;
+    }
+
+    // Handle the outermost TypeLoc which is directly linked to the interesting
+    // declaration and don't handle nested name specifier locations.
+    if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
+      if (isInUSRSet(TargetDecl)) {
+        // Only handle the outermost typeLoc.
+        //
+        // For a type like "a::Foo", there will be two typeLocs for it.
+        // One ElaboratedType, the other is RecordType:
+        //
+        //   ElaboratedType 0x33b9390 'a::Foo' sugar
+        //   `-RecordType 0x338fef0 'class a::Foo'
+        //     `-CXXRecord 0x338fe58 'Foo'
+        //
+        // Skip if this is an inner typeLoc.
+        if (!ParentTypeLoc.isNull() &&
+            isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
+          return true;
+        RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc),
+                           TargetDecl, getClosestAncestorDecl(Loc),
+                           GetNestedNameForType(Loc)};
+        RenameInfos.push_back(Info);
+        return true;
+      }
+    }
+
+    // Handle specific template class specialiation cases.
+    if (const auto *TemplateSpecType =
+            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+      TypeLoc TargetLoc = Loc;
+      if (!ParentTypeLoc.isNull()) {
+        if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+          TargetLoc = ParentTypeLoc;
+      }
+
+      if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
+        TypeLoc TargetLoc = Loc;
+        // FIXME: Find a better way to handle this case.
+        // For the qualified template class specification type like
+        // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
+        // (ElaboratedType) of the TemplateSpecializationType in order to
+        // catch the prefix qualifiers "ns::".
+        if (!ParentTypeLoc.isNull() &&
+            llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+          TargetLoc = ParentTypeLoc;
+        RenameInfo Info = {
+            StartLocationForType(TargetLoc), EndLocationForType(TargetLoc),
+            TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+            getClosestAncestorDecl(
+                ast_type_traits::DynTypedNode::create(TargetLoc)),
+            GetNestedNameForType(TargetLoc)};
+        RenameInfos.push_back(Info);
+      }
+    }
+    return true;
+  }
+
+  // Returns a list of RenameInfo.
+  const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
+
+  // Returns a list of using declarations which are needed to update.
+  const std::vector<const UsingDecl *> &getUsingDecls() const {
+    return UsingDecls;
+  }
+
+private:
+  // FIXME: This method may not be suitable for renaming other types like alias
+  // types. Need to figure out a way to handle it.
+  bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const {
+    while (!TL.isNull()) {
+      // SubstTemplateTypeParm is the TypeLocation class for a substituted type
+      // inside a template expansion so we ignore these.  For example:
+      //
+      // template<typename T> struct S {
+      //   T t;  // <-- this T becomes a TypeLoc(int) with class
+      //         //     SubstTemplateTypeParm when S<int> is instantiated
+      // }
+      if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
+        return true;
+
+      // Typedef is the TypeLocation class for a type which is a typedef to the
+      // type we want to replace.  We ignore the use of the typedef as we will
+      // replace the definition of it.  For example:
+      //
+      // typedef int T;
+      // T a;  // <---  This T is a TypeLoc(int) with class Typedef.
+      if (TL.getTypeLocClass() == TypeLoc::Typedef)
+        return true;
+      TL = TL.getNextTypeLoc();
+    }
+    return false;
+  }
+
+  // Get the supported declaration from a given typeLoc. If the declaration type
+  // is not supported, returns nullptr.
+  //
+  // FIXME: support more types, e.g. enum, type alias.
+  const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
+    if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
+      return RD;
+    return nullptr;
+  }
+
+  // Get the closest ancester which is a declaration of a given AST node.
+  template <typename ASTNodeType>
+  const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
+    auto Parents = Context.getParents(Node);
+    // FIXME: figure out how to handle it when there are multiple parents.
+    if (Parents.size() != 1)
+      return nullptr;
+    if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
+            Parents[0].getNodeKind()))
+      return Parents[0].template get<Decl>();
+    return getClosestAncestorDecl(Parents[0]);
+  }
+
+  // Get the parent typeLoc of a given typeLoc. If there is no such parent,
+  // return nullptr.
+  const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
+    auto Parents = Context.getParents(Loc);
+    // FIXME: figure out how to handle it when there are multiple parents.
+    if (Parents.size() != 1)
+      return nullptr;
+    return Parents[0].get<TypeLoc>();
+  }
+
+  // Check whether the USR of a given Decl is in the USRSet.
+  bool isInUSRSet(const Decl *Decl) const {
+    auto USR = getUSRForDecl(Decl);
+    if (USR.empty())
+      return false;
+    return llvm::is_contained(USRSet, USR);
+  }
+
+  const std::set<std::string> USRSet;
+  ASTContext &Context;
+  std::vector<RenameInfo> RenameInfos;
+  // Record all interested using declarations which contains the using-shadow
+  // declarations of the symbol declarations being renamed.
+  std::vector<const UsingDecl *> UsingDecls;
+};
+
+} // namespace
+
+std::vector<SourceLocation>
+getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName,
+                   Decl *Decl) {
+  USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
+  Visitor.TraverseDecl(Decl);
+  NestedNameSpecifierLocFinder Finder(Decl->getASTContext());
+
+  for (const auto &Location : Finder.getNestedNameSpecifierLocations())
+    Visitor.handleNestedNameSpecifierLoc(Location);
+
+  return Visitor.getLocationsFound();
+}
+
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+                          llvm::StringRef NewName, Decl *TranslationUnitDecl) {
+  RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
+  Finder.TraverseDecl(TranslationUnitDecl);
+
+  const SourceManager &SM =
+      TranslationUnitDecl->getASTContext().getSourceManager();
+
+  std::vector<tooling::AtomicChange> AtomicChanges;
+  auto Replace = [&](SourceLocation Start, SourceLocation End,
+                     llvm::StringRef Text) {
+    tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
+    llvm::Error Err = ReplaceChange.replace(
+        SM, CharSourceRange::getTokenRange(Start, End), Text);
+    if (Err) {
+      llvm::errs() << "Faile to add replacement to AtomicChange: "
+                   << llvm::toString(std::move(Err)) << "\n";
+      return;
+    }
+    AtomicChanges.push_back(std::move(ReplaceChange));
+  };
+
+  for (const auto &RenameInfo : Finder.getRenameInfos()) {
+    std::string ReplacedName = NewName.str();
+    if (RenameInfo.FromDecl && RenameInfo.Context) {
+      if (!llvm::isa<clang::TranslationUnitDecl>(
+              RenameInfo.Context->getDeclContext())) {
+        ReplacedName = tooling::replaceNestedName(
+            RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
+            RenameInfo.FromDecl,
+            NewName.startswith("::") ? NewName.str() : ("::" + NewName).str());
+      }
+    }
+    // If the NewName contains leading "::", add it back.
+    if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
+      ReplacedName = NewName.str();
+    Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
+  }
+
+  // Hanlde using declarations explicitly as "using a::Foo" don't trigger
+  // typeLoc for "a::Foo".
+  for (const auto *Using : Finder.getUsingDecls())
+    Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());
+
+  return AtomicChanges;
+}
+
+} // end namespace tooling
+} // end namespace clang

Modified: cfe/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
==============================================================================
--- cfe/trunk/test/CMakeLists.txt (original)
+++ cfe/trunk/test/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -47,6 +47,7 @@ list(APPEND CLANG_TEST_DEPS
   clang-tblgen
   clang-offload-bundler
   clang-import-test
+  clang-rename
   )
   
 if(CLANG_ENABLE_STATIC_ANALYZER)

Added: cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,21 @@
+class Foo /* Test 1 */ {};    // CHECK: class Bar /* Test 1 */ {};
+
+template <typename T>
+void func() {}
+
+template <typename T>
+class Baz {};
+
+int main() {
+  func<Foo>();                // CHECK: func<Bar>();
+  Baz<Foo> /* Test 2 */ obj;  // CHECK: Baz<Bar> /* Test 2 */ obj;
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/ClassFindByName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassFindByName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassFindByName.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassFindByName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,10 @@
+class Foo {         // CHECK: class Bar {
+};
+
+int main() {
+  Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s

Added: cfe/trunk/test/clang-rename/ClassReplacements.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassReplacements.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassReplacements.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassReplacements.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/fixes
+// RUN: cat %s > %t.cpp
+// RUN: clang-rename -offset=254 -new-name=Bar -export-fixes=%t/fixes/clang-rename.yaml %t.cpp --
+// RUN: clang-apply-replacements %t
+// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
+
+class Foo {}; // CHECK: class Bar {};
+
+// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when changing
+// this file.

Added: cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,14 @@
+class Foo /* Test 1 */ {              // CHECK: class Bar /* Test 1 */ {
+public:
+  void foo(int x);
+};
+
+void Foo::foo(int x) /* Test 2 */ {}  // CHECK: void Bar::foo(int x) /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/ClassTestMulti.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassTestMulti.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassTestMulti.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassTestMulti.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,11 @@
+class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ {
+};
+
+class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ {
+};
+
+// Test 1.
+// RUN: clang-rename -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp (added)
+++ cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,8 @@
+class Foo1 { // CHECK: class Bar1
+};
+
+class Foo2 { // CHECK: class Bar2
+};
+
+// Test 1.
+// RUN: clang-rename -qualified-name=Foo1 -new-name=Bar1 -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s

Added: cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp (added)
+++ cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,47 @@
+struct A {
+  virtual void foo() {} /* Test 1 */    // CHECK: virtual void bar() {}
+};
+
+struct B : A {
+  void foo() override {} /* Test 2 */   // CHECK: void bar() override {}
+};
+
+struct C : B {
+  void foo() override {} /* Test 3 */   // CHECK: void bar() override {}
+};
+
+struct D : B {
+  void foo() override {} /* Test 4 */   // CHECK: void bar() override {}
+};
+
+struct E : D {
+  void foo() override {} /* Test 5 */   // CHECK: void bar() override {}
+};
+
+int main() {
+  A a;
+  a.foo();                              // CHECK: a.bar();
+  B b;
+  b.foo();                              // CHECK: b.bar();
+  C c;
+  c.foo();                              // CHECK: c.bar();
+  D d;
+  d.foo();                              // CHECK: d.bar();
+  E e;
+  e.foo();                              // CHECK: e.bar();
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 5.
+// RUN: clang-rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'foo.*' <file>

Added: cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ComplicatedClassType.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/ComplicatedClassType.cpp (added)
+++ cfe/trunk/test/clang-rename/ComplicatedClassType.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,63 @@
+// Forward declaration.
+class Foo; /* Test 1 */               // CHECK: class Bar; /* Test 1 */
+
+class Baz {
+  virtual int getValue() const = 0;
+};
+
+class Foo : public Baz  { /* Test 2 */// CHECK: class Bar : public Baz {
+public:
+  Foo(int value = 0) : x(value) {}    // CHECK: Bar(int value = 0) : x(value) {}
+
+  Foo &operator++(int) {              // CHECK: Bar &operator++(int) {
+    x++;
+    return *this;
+  }
+
+  bool operator<(Foo const &rhs) {    // CHECK: bool operator<(Bar const &rhs) {
+    return this->x < rhs.x;
+  }
+
+  int getValue() const {
+    return 0;
+  }
+
+private:
+  int x;
+};
+
+int main() {
+  Foo *Pointer = 0;                   // CHECK: Bar *Pointer = 0;
+  Foo Variable = Foo(10);             // CHECK: Bar Variable = Bar(10);
+  for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) {
+  }
+  const Foo *C = new Foo();           // CHECK: const Bar *C = new Bar();
+  const_cast<Foo *>(C)->getValue();   // CHECK: const_cast<Bar *>(C)->getValue();
+  Foo foo;                            // CHECK: Bar foo;
+  const Baz &BazReference = foo;
+  const Baz *BazPointer = &foo;
+  dynamic_cast<const Foo &>(BazReference).getValue();     /* Test 3 */ // CHECK: dynamic_cast<const Bar &>(BazReference).getValue();
+  dynamic_cast<const Foo *>(BazPointer)->getValue();      /* Test 4 */ // CHECK: dynamic_cast<const Bar *>(BazPointer)->getValue();
+  reinterpret_cast<const Foo *>(BazPointer)->getValue();  /* Test 5 */ // CHECK: reinterpret_cast<const Bar *>(BazPointer)->getValue();
+  static_cast<const Foo &>(BazReference).getValue();      /* Test 6 */ // CHECK: static_cast<const Bar &>(BazReference).getValue();
+  static_cast<const Foo *>(BazPointer)->getValue();       /* Test 7 */ // CHECK: static_cast<const Bar *>(BazPointer)->getValue();
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=30 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=1133 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=1266 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 5.
+// RUN: clang-rename -offset=1402 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 6.
+// RUN: clang-rename -offset=1533 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 7.
+// RUN: clang-rename -offset=1665 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/Ctor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Ctor.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Ctor.cpp (added)
+++ cfe/trunk/test/clang-rename/Ctor.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,14 @@
+class Foo {                   // CHECK: class Bar {
+public:
+  Foo();    /* Test 1 */      // CHECK: Bar();
+};
+
+Foo::Foo()  /* Test 2 */ {}   // CHECK: Bar::Bar()  /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/CtorInitializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/CtorInitializer.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/CtorInitializer.cpp (added)
+++ cfe/trunk/test/clang-rename/CtorInitializer.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,17 @@
+class Baz {};
+
+class Qux {
+  Baz Foo;         /* Test 1 */       // CHECK: Baz Bar;
+public:
+  Qux();
+};
+
+Qux::Qux() : Foo() /* Test 2 */ {}    // CHECK: Qux::Qux() : Bar() /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/DeclRefExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/DeclRefExpr.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/DeclRefExpr.cpp (added)
+++ cfe/trunk/test/clang-rename/DeclRefExpr.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,24 @@
+class C {
+public:
+  static int Foo; /* Test 1 */  // CHECK: static int Bar;
+};
+
+int foo(int x) { return 0; }
+#define MACRO(a) foo(a)
+
+int main() {
+  C::Foo = 1;     /* Test 2 */  // CHECK: C::Bar = 1;
+  MACRO(C::Foo);                // CHECK: MACRO(C::Bar);
+  int y = C::Foo; /* Test 3 */  // CHECK: int y = C::Bar;
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/Field.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Field.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Field.cpp (added)
+++ cfe/trunk/test/clang-rename/Field.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,15 @@
+class Baz {
+  int Foo; /* Test 1 */ // CHECK: int Bar;
+public:
+  Baz();
+};
+
+Baz::Baz() : Foo(0) /* Test 2 */ {}  // CHECK: Baz::Baz() : Bar(0)
+
+// Test 1.
+// RUN: clang-rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=89 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/FunctionMacro.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionMacro.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/FunctionMacro.cpp (added)
+++ cfe/trunk/test/clang-rename/FunctionMacro.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,20 @@
+#define moo foo           // CHECK: #define moo macro_function
+
+int foo() /* Test 1 */ {  // CHECK: int macro_function() /* Test 1 */ {
+  return 42;
+}
+
+void boo(int value) {}
+
+void qoo() {
+  foo();                  // CHECK: macro_function();
+  boo(foo());             // CHECK: boo(macro_function());
+  moo();
+  boo(moo());
+}
+
+// Test 1.
+// RUN: clang-rename -offset=68 -new-name=macro_function %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'foo.*' <file>

Added: cfe/trunk/test/clang-rename/FunctionOverride.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionOverride.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/FunctionOverride.cpp (added)
+++ cfe/trunk/test/clang-rename/FunctionOverride.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,13 @@
+class A { virtual void foo();     /* Test 1 */ }; // CHECK: class A { virtual void bar();
+class B : public A { void foo();  /* Test 2 */ }; // CHECK: class B : public A { void bar();
+class C : public B { void foo();  /* Test 3 */ }; // CHECK: class C : public B { void bar();
+
+// Test 1.
+// RUN: clang-rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'foo.*' <file>

Added: cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp (added)
+++ cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,12 @@
+void foo() {
+}
+
+class Foo {         // CHECK: class Bar
+};
+
+int main() {
+  Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
+  return 0;
+}
+
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s

Added: cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp (added)
+++ cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,10 @@
+#include "Inputs/HeaderWithSymbol.h"
+
+int main() {
+  return 0; // CHECK: {{^  return 0;}}
+}
+
+// Test 1.
+// The file IncludeHeaderWithSymbol.cpp doesn't contain the symbol Foo
+// and is expected to be written to stdout without modifications
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | FileCheck %s

Added: cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h (added)
+++ cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1 @@
+struct Foo {};

Added: cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml (added)
+++ cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml Fri Jun 30 09:36:09 2017
@@ -0,0 +1,6 @@
+---
+- Offset:         6
+  NewName:        Bar1
+- Offset:         44
+  NewName:        Bar2
+...

Added: cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml (added)
+++ cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml Fri Jun 30 09:36:09 2017
@@ -0,0 +1,6 @@
+---
+- QualifiedName:  Foo1
+  NewName:        Bar1
+- QualifiedName:  Foo2
+  NewName:        Bar2
+...

Added: cfe/trunk/test/clang-rename/InvalidNewName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidNewName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/InvalidNewName.cpp (added)
+++ cfe/trunk/test/clang-rename/InvalidNewName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,2 @@
+// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s
+// CHECK: ERROR: new name is not a valid identifier in C++17.

Added: cfe/trunk/test/clang-rename/InvalidOffset.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidOffset.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/InvalidOffset.cpp (added)
+++ cfe/trunk/test/clang-rename/InvalidOffset.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,9 @@
+#include "Inputs/HeaderWithSymbol.h"
+#define FOO int bar;
+FOO
+
+int foo;
+
+// RUN: not clang-rename -new-name=qux -offset=259 %s -- 2>&1 | FileCheck %s
+// CHECK-NOT: CHECK
+// CHECK: error: SourceLocation in file {{.*}}InvalidOffset.cpp at offset 259 is invalid

Added: cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp (added)
+++ cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,4 @@
+struct S {
+};
+
+// RUN: clang-rename -force -qualified-name S2 -new-name=T %s --

Added: cfe/trunk/test/clang-rename/MemberExprMacro.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/MemberExprMacro.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/MemberExprMacro.cpp (added)
+++ cfe/trunk/test/clang-rename/MemberExprMacro.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,22 @@
+class Baz {
+public:
+  int Foo;  /* Test 1 */    // CHECK: int Bar;
+};
+
+int qux(int x) { return 0; }
+#define MACRO(a) qux(a)
+
+int main() {
+  Baz baz;
+  baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1;
+  MACRO(baz.Foo);           // CHECK: MACRO(baz.Bar);
+  int y = baz.Foo;          // CHECK: int y = baz.Bar;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/Namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Namespace.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Namespace.cpp (added)
+++ cfe/trunk/test/clang-rename/Namespace.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,13 @@
+namespace gcc /* Test 1 */ {  // CHECK: namespace clang /* Test 1 */ {
+  int x;
+}
+
+void boo() {
+  gcc::x = 42;                // CHECK: clang::x = 42;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/NoNewName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/NoNewName.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/NoNewName.cpp (added)
+++ cfe/trunk/test/clang-rename/NoNewName.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,4 @@
+// Check for an error while -new-name argument has not been passed to
+// clang-rename.
+// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s
+// CHECK: clang-rename: -new-name must be specified.

Added: cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp (added)
+++ cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,42 @@
+template <typename T>
+class Foo { /* Test 1 */   // CHECK: class Bar { /* Test 1 */
+public:
+  T foo(T arg, T& ref, T* ptr) {
+    T value;
+    int number = 42;
+    value = (T)number;
+    value = static_cast<T>(number);
+    return value;
+  }
+  static void foo(T value) {}
+  T member;
+};
+
+template <typename T>
+void func() {
+  Foo<T> obj; /* Test 2 */  // CHECK: Bar<T> obj;
+  obj.member = T();
+  Foo<T>::foo();            // CHECK: Bar<T>::foo();
+}
+
+int main() {
+  Foo<int> i; /* Test 3 */  // CHECK: Bar<int> i;
+  i.member = 0;
+  Foo<int>::foo(0);         // CHECK: Bar<int>::foo(0);
+
+  Foo<bool> b;              // CHECK: Bar<bool> b;
+  b.member = false;
+  Foo<bool>::foo(false);    // CHECK: Bar<bool>::foo(false);
+
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=29 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=324 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=463 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/TemplateTypename.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplateTypename.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/TemplateTypename.cpp (added)
+++ cfe/trunk/test/clang-rename/TemplateTypename.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,24 @@
+template <typename T /* Test 1 */>              // CHECK: template <typename U /* Test 1 */>
+class Foo {
+T foo(T arg, T& ref, T* /* Test 2 */ ptr) {     // CHECK: U foo(U arg, U& ref, U* /* Test 2 */ ptr) {
+  T value;                                      // CHECK: U value;
+  int number = 42;
+  value = (T)number;                            // CHECK: value = (U)number;
+  value = static_cast<T /* Test 3 */>(number);  // CHECK: value = static_cast<U /* Test 3 */>(number);
+  return value;
+}
+
+static void foo(T value) {}                     // CHECK: static void foo(U value) {}
+
+T member;                                       // CHECK: U member;
+};
+
+// Test 1.
+// RUN: clang-rename -offset=19 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=126 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=392 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'T.*' <file>

Added: cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp (added)
+++ cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,22 @@
+template <typename T>
+class A {
+public:
+  void foo() /* Test 1 */ {}  // CHECK: void bar() /* Test 1 */ {}
+};
+
+int main(int argc, char **argv) {
+  A<int> a;
+  a.foo();   /* Test 2 */     // CHECK: a.bar()   /* Test 2 */
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-refactor rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-refactor rename -offset=162 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+//
+// Currently unsupported test.
+// XFAIL: *
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'foo.*' <file>

Added: cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/UserDefinedConversion.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/UserDefinedConversion.cpp (added)
+++ cfe/trunk/test/clang-rename/UserDefinedConversion.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,26 @@
+class Foo {       /* Test 1 */          // CHECK: class Bar {
+public:
+  Foo() {}                              // CHECK: Bar() {}
+};
+
+class Baz {
+public:
+  operator Foo()  /* Test 2 */ const {  // CHECK: operator Bar()  /* Test 2 */ const {
+    Foo foo;                            // CHECK: Bar foo;
+    return foo;
+  }
+};
+
+int main() {
+  Baz boo;
+  Foo foo = static_cast<Foo>(boo);      // CHECK: Bar foo = static_cast<Bar>(boo);
+  return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/Variable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Variable.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/Variable.cpp (added)
+++ cfe/trunk/test/clang-rename/Variable.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,33 @@
+#define NAMESPACE namespace A
+NAMESPACE {
+int Foo;          /* Test 1 */        // CHECK: int Bar;
+}
+int Foo;                              // CHECK: int Foo;
+int Qux = Foo;                        // CHECK: int Qux = Foo;
+int Baz = A::Foo; /* Test 2 */        // CHECK: Baz = A::Bar;
+void fun() {
+  struct {
+    int Foo;                          // CHECK: int Foo;
+  } b = {100};
+  int Foo = 100;                      // CHECK: int Foo = 100;
+  Baz = Foo;                          // CHECK: Baz = Foo;
+  {
+    extern int Foo;                   // CHECK: extern int Foo;
+    Baz = Foo;                        // CHECK: Baz = Foo;
+    Foo = A::Foo /* Test 3 */ + Baz;  // CHECK: Foo = A::Bar /* Test 3 */ + Baz;
+    A::Foo /* Test 4 */ = b.Foo;      // CHECK: A::Bar /* Test 4 */ = b.Foo;
+  }
+  Foo = b.Foo;                        // Foo = b.Foo;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=46 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=234 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=641 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=716 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/VariableMacro.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/VariableMacro.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/VariableMacro.cpp (added)
+++ cfe/trunk/test/clang-rename/VariableMacro.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,21 @@
+#define Baz Foo // CHECK: #define Baz Bar
+
+void foo(int value) {}
+
+void macro() {
+  int Foo;  /* Test 1 */  // CHECK: int Bar;
+  Foo = 42; /* Test 2 */  // CHECK: Bar = 42;
+  Baz -= 0;
+  foo(Foo); /* Test 3 */  // CHECK: foo(Bar);
+  foo(Baz);
+}
+
+// Test 1.
+// RUN: clang-rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+//   grep -Ubo 'Foo.*' <file>

Added: cfe/trunk/test/clang-rename/YAMLInput.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/YAMLInput.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/test/clang-rename/YAMLInput.cpp (added)
+++ cfe/trunk/test/clang-rename/YAMLInput.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,10 @@
+class Foo1 { // CHECK: class Bar1
+};
+
+class Foo2 { // CHECK: class Bar2
+};
+
+// Test 1.
+// RUN: clang-rename -input %S/Inputs/OffsetToNewName.yaml %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -input %S/Inputs/QualifiedNameToNewName.yaml %s -- | sed 's,//.*,,' | FileCheck %s

Modified: cfe/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
==============================================================================
--- cfe/trunk/tools/CMakeLists.txt (original)
+++ cfe/trunk/tools/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -10,6 +10,8 @@ add_clang_subdirectory(clang-offload-bun
 
 add_clang_subdirectory(c-index-test)
 
+add_clang_subdirectory(clang-rename)
+
 if(CLANG_ENABLE_ARCMT)
   add_clang_subdirectory(arcmt-test)
   add_clang_subdirectory(c-arcmt-test)

Added: cfe/trunk/tools/clang-rename/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/CMakeLists.txt?rev=306840&view=auto
==============================================================================
--- cfe/trunk/tools/clang-rename/CMakeLists.txt (added)
+++ cfe/trunk/tools/clang-rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -0,0 +1,19 @@
+add_clang_executable(clang-rename ClangRename.cpp)
+
+target_link_libraries(clang-rename
+  clangBasic
+  clangFrontend
+  clangRewrite
+  clangTooling
+  clangToolingCore
+  clangToolingRefactor
+  )
+
+install(TARGETS clang-rename RUNTIME DESTINATION bin)
+
+install(PROGRAMS clang-rename.py
+  DESTINATION share/clang
+  COMPONENT clang-rename)
+install(PROGRAMS clang-rename.el
+  DESTINATION share/clang
+  COMPONENT clang-rename)

Added: cfe/trunk/tools/clang-rename/ClangRename.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/ClangRename.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/tools/clang-rename/ClangRename.cpp (added)
+++ cfe/trunk/tools/clang-rename/ClangRename.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,240 @@
+//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a clang-rename tool that automatically finds and
+/// renames symbols in C++ code.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace clang;
+
+/// \brief An oldname -> newname rename.
+struct RenameAllInfo {
+  unsigned Offset = 0;
+  std::string QualifiedName;
+  std::string NewName;
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo)
+
+namespace llvm {
+namespace yaml {
+
+/// \brief Specialized MappingTraits to describe how a RenameAllInfo is
+/// (de)serialized.
+template <> struct MappingTraits<RenameAllInfo> {
+  static void mapping(IO &IO, RenameAllInfo &Info) {
+    IO.mapOptional("Offset", Info.Offset);
+    IO.mapOptional("QualifiedName", Info.QualifiedName);
+    IO.mapRequired("NewName", Info.NewName);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+static cl::OptionCategory ClangRenameOptions("clang-rename common options");
+
+static cl::list<unsigned> SymbolOffsets(
+    "offset",
+    cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
+    cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
+                             cl::cat(ClangRenameOptions));
+static cl::list<std::string>
+    QualifiedNames("qualified-name",
+                   cl::desc("The fully qualified name of the symbol."),
+                   cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+
+static cl::list<std::string>
+    NewNames("new-name", cl::desc("The new name to change the symbol to."),
+             cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+static cl::opt<bool> PrintName(
+    "pn",
+    cl::desc("Print the found symbol's name prior to renaming to stderr."),
+    cl::cat(ClangRenameOptions));
+static cl::opt<bool> PrintLocations(
+    "pl", cl::desc("Print the locations affected by renaming to stderr."),
+    cl::cat(ClangRenameOptions));
+static cl::opt<std::string>
+    ExportFixes("export-fixes",
+                cl::desc("YAML file to store suggested fixes in."),
+                cl::value_desc("filename"), cl::cat(ClangRenameOptions));
+static cl::opt<std::string>
+    Input("input", cl::desc("YAML file to load oldname-newname pairs from."),
+          cl::Optional, cl::cat(ClangRenameOptions));
+static cl::opt<bool> Force("force",
+                           cl::desc("Ignore nonexistent qualified names."),
+                           cl::cat(ClangRenameOptions));
+
+int main(int argc, const char **argv) {
+  tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);
+
+  if (!Input.empty()) {
+    // Populate QualifiedNames and NewNames from a YAML file.
+    ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+        llvm::MemoryBuffer::getFile(Input);
+    if (!Buffer) {
+      errs() << "clang-rename: failed to read " << Input << ": "
+             << Buffer.getError().message() << "\n";
+      return 1;
+    }
+
+    std::vector<RenameAllInfo> Infos;
+    llvm::yaml::Input YAML(Buffer.get()->getBuffer());
+    YAML >> Infos;
+    for (const auto &Info : Infos) {
+      if (!Info.QualifiedName.empty())
+        QualifiedNames.push_back(Info.QualifiedName);
+      else
+        SymbolOffsets.push_back(Info.Offset);
+      NewNames.push_back(Info.NewName);
+    }
+  }
+
+  // Check the arguments for correctness.
+  if (NewNames.empty()) {
+    errs() << "clang-rename: -new-name must be specified.\n\n";
+    exit(1);
+  }
+
+  if (SymbolOffsets.empty() == QualifiedNames.empty()) {
+    errs() << "clang-rename: -offset and -qualified-name can't be present at "
+              "the same time.\n";
+    exit(1);
+  }
+
+  // Check if NewNames is a valid identifier in C++17.
+  LangOptions Options;
+  Options.CPlusPlus = true;
+  Options.CPlusPlus1z = true;
+  IdentifierTable Table(Options);
+  for (const auto &NewName : NewNames) {
+    auto NewNameTokKind = Table.get(NewName).getTokenID();
+    if (!tok::isAnyIdentifier(NewNameTokKind)) {
+      errs() << "ERROR: new name is not a valid identifier in C++17.\n\n";
+      exit(1);
+    }
+  }
+
+  if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) {
+    errs() << "clang-rename: number of symbol offsets(" << SymbolOffsets.size()
+           << ") + number of qualified names (" << QualifiedNames.size()
+           << ") must be equal to number of new names(" << NewNames.size()
+           << ").\n\n";
+    cl::PrintHelpMessage();
+    exit(1);
+  }
+
+  auto Files = OP.getSourcePathList();
+  tooling::RefactoringTool Tool(OP.getCompilations(), Files);
+  tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames, Force);
+  Tool.run(tooling::newFrontendActionFactory(&FindingAction).get());
+  const std::vector<std::vector<std::string>> &USRList =
+      FindingAction.getUSRList();
+  const std::vector<std::string> &PrevNames = FindingAction.getUSRSpellings();
+  if (PrintName) {
+    for (const auto &PrevName : PrevNames) {
+      outs() << "clang-rename found name: " << PrevName << '\n';
+    }
+  }
+
+  if (FindingAction.errorOccurred()) {
+    // Diagnostics are already issued at this point.
+    exit(1);
+  }
+
+  if (Force && PrevNames.size() < NewNames.size()) {
+    // No matching PrevName for all NewNames. Without Force this is an error
+    // above already.
+    exit(0);
+  }
+
+  // Perform the renaming.
+  tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,
+                                       Tool.getReplacements(), PrintLocations);
+  std::unique_ptr<tooling::FrontendActionFactory> Factory =
+      tooling::newFrontendActionFactory(&RenameAction);
+  int ExitCode;
+
+  if (Inplace) {
+    ExitCode = Tool.runAndSave(Factory.get());
+  } else {
+    ExitCode = Tool.run(Factory.get());
+
+    if (!ExportFixes.empty()) {
+      std::error_code EC;
+      llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
+      if (EC) {
+        llvm::errs() << "Error opening output file: " << EC.message() << '\n';
+        exit(1);
+      }
+
+      // Export replacements.
+      tooling::TranslationUnitReplacements TUR;
+      const auto &FileToReplacements = Tool.getReplacements();
+      for (const auto &Entry : FileToReplacements)
+        TUR.Replacements.insert(TUR.Replacements.end(), Entry.second.begin(),
+                                Entry.second.end());
+
+      yaml::Output YAML(OS);
+      YAML << TUR;
+      OS.close();
+      exit(0);
+    }
+
+    // Write every file to stdout. Right now we just barf the files without any
+    // indication of which files start where, other than that we print the files
+    // in the same order we see them.
+    LangOptions DefaultLangOptions;
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+    TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+    DiagnosticsEngine Diagnostics(
+        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+        &DiagnosticPrinter, false);
+    auto &FileMgr = Tool.getFiles();
+    SourceManager Sources(Diagnostics, FileMgr);
+    Rewriter Rewrite(Sources, DefaultLangOptions);
+
+    Tool.applyAllReplacements(Rewrite);
+    for (const auto &File : Files) {
+      const auto *Entry = FileMgr.getFile(File);
+      const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+      Rewrite.getEditBuffer(ID).write(outs());
+    }
+  }
+
+  exit(ExitCode);
+}

Added: cfe/trunk/tools/clang-rename/clang-rename.el
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/clang-rename.el?rev=306840&view=auto
==============================================================================
--- cfe/trunk/tools/clang-rename/clang-rename.el (added)
+++ cfe/trunk/tools/clang-rename/clang-rename.el Fri Jun 30 09:36:09 2017
@@ -0,0 +1,79 @@
+;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>.  -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+
+;;; Commentary:
+
+;; To install clang-rename.el make sure the directory of this file is in your
+;; `load-path' and add
+;;
+;;   (require 'clang-rename)
+;;
+;; to your .emacs configuration.
+
+;;; Code:
+
+(defgroup clang-rename nil
+  "Integration with clang-rename"
+  :group 'c)
+
+(defcustom clang-rename-binary "clang-rename"
+  "Path to clang-rename executable."
+  :type '(file :must-match t)
+  :group 'clang-rename)
+
+;;;###autoload
+(defun clang-rename (new-name)
+  "Rename all instances of the symbol at point to NEW-NAME using clang-rename."
+  (interactive "sEnter a new name: ")
+  (save-some-buffers :all)
+  ;; clang-rename should not be combined with other operations when undoing.
+  (undo-boundary)
+  (let ((output-buffer (get-buffer-create "*clang-rename*")))
+    (with-current-buffer output-buffer (erase-buffer))
+    (let ((exit-code (call-process
+                      clang-rename-binary nil output-buffer nil
+                      (format "-offset=%d"
+                              ;; clang-rename wants file (byte) offsets, not
+                              ;; buffer (character) positions.
+                              (clang-rename--bufferpos-to-filepos
+                               ;; Emacs treats one character after a symbol as
+                               ;; part of the symbol, but clang-rename doesn’t.
+                               ;; Use the beginning of the current symbol, if
+                               ;; available, to resolve the inconsistency.
+                               (or (car (bounds-of-thing-at-point 'symbol))
+                                   (point))
+                               'exact))
+                      (format "-new-name=%s" new-name)
+                      "-i" (buffer-file-name))))
+      (if (and (integerp exit-code) (zerop exit-code))
+          ;; Success; revert current buffer so it gets the modifications.
+          (progn
+            (kill-buffer output-buffer)
+            (revert-buffer :ignore-auto :noconfirm :preserve-modes))
+        ;; Failure; append exit code to output buffer and display it.
+        (let ((message (clang-rename--format-message
+                        "clang-rename failed with %s %s"
+                        (if (integerp exit-code) "exit status" "signal")
+                        exit-code)))
+          (with-current-buffer output-buffer
+            (insert ?\n message ?\n))
+          (message "%s" message)
+          (display-buffer output-buffer))))))
+
+(defalias 'clang-rename--bufferpos-to-filepos
+  (if (fboundp 'bufferpos-to-filepos)
+      'bufferpos-to-filepos
+    ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it using
+    ;; ‘position-bytes’.
+    (lambda (position &optional _quality _coding-system)
+      (1- (position-bytes position)))))
+
+;; ‘format-message’ is new in Emacs 25.1.  Provide a fallback for older
+;; versions.
+(defalias 'clang-rename--format-message
+  (if (fboundp 'format-message) 'format-message 'format))
+
+(provide 'clang-rename)
+
+;;; clang-rename.el ends here

Added: cfe/trunk/tools/clang-rename/clang-rename.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/clang-rename.py?rev=306840&view=auto
==============================================================================
--- cfe/trunk/tools/clang-rename/clang-rename.py (added)
+++ cfe/trunk/tools/clang-rename/clang-rename.py Fri Jun 30 09:36:09 2017
@@ -0,0 +1,61 @@
+'''
+Minimal clang-rename integration with Vim.
+
+Before installing make sure one of the following is satisfied:
+
+* clang-rename is in your PATH
+* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable
+* `binary` in clang-rename.py points to valid to clang-rename executable
+
+To install, simply put this into your ~/.vimrc
+
+    noremap <leader>cr :pyf <path-to>/clang-rename.py<cr>
+
+IMPORTANT NOTE: Before running the tool, make sure you saved the file.
+
+All you have to do now is to place a cursor on a variable/function/class which
+you would like to rename and press '<leader>cr'. You will be prompted for a new
+name if the cursor points to a valid symbol.
+'''
+
+import vim
+import subprocess
+import sys
+
+def main():
+    binary = 'clang-rename'
+    if vim.eval('exists("g:clang_rename_path")') == "1":
+        binary = vim.eval('g:clang_rename_path')
+
+    # Get arguments for clang-rename binary.
+    offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2
+    if offset < 0:
+        print >> sys.stderr, '''Couldn\'t determine cursor position.
+                                Is your file empty?'''
+        return
+    filename = vim.current.buffer.name
+
+    new_name_request_message = 'type new name:'
+    new_name = vim.eval("input('{}\n')".format(new_name_request_message))
+
+    # Call clang-rename.
+    command = [binary,
+               filename,
+               '-i',
+               '-offset', str(offset),
+               '-new-name', str(new_name)]
+    # FIXME: make it possible to run the tool on unsaved file.
+    p = subprocess.Popen(command,
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+
+    if stderr:
+        print stderr
+
+    # Reload all buffers in Vim.
+    vim.command("checktime")
+
+
+if __name__ == '__main__':
+    main()

Modified: cfe/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
==============================================================================
--- cfe/trunk/unittests/CMakeLists.txt (original)
+++ cfe/trunk/unittests/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -29,3 +29,4 @@ add_subdirectory(CodeGen)
 if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD) 
   add_subdirectory(libclang)
 endif()
+add_subdirectory(Rename)

Added: cfe/trunk/unittests/Rename/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/CMakeLists.txt?rev=306840&view=auto
==============================================================================
--- cfe/trunk/unittests/Rename/CMakeLists.txt (added)
+++ cfe/trunk/unittests/Rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
@@ -0,0 +1,22 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+# We'd like clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(ClangRenameTests
+  RenameClassTest.cpp
+  )
+
+target_link_libraries(ClangRenameTests
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFormat
+  clangFrontend
+  clangRewrite
+  clangTooling
+  clangToolingCore
+  clangToolingRefactor
+  )

Added: cfe/trunk/unittests/Rename/ClangRenameTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/ClangRenameTest.h?rev=306840&view=auto
==============================================================================
--- cfe/trunk/unittests/Rename/ClangRenameTest.h (added)
+++ cfe/trunk/unittests/Rename/ClangRenameTest.h Fri Jun 30 09:36:09 2017
@@ -0,0 +1,112 @@
+//===-- ClangRenameTests.cpp - clang-rename unit tests --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+
+struct Case {
+  std::string Before;
+  std::string After;
+  std::string OldName;
+  std::string NewName;
+};
+
+class ClangRenameTest : public testing::Test,
+                        public testing::WithParamInterface<Case> {
+protected:
+  void AppendToHeader(StringRef Code) { HeaderContent += Code.str(); }
+
+  std::string runClangRenameOnCode(llvm::StringRef Code,
+                                   llvm::StringRef OldName,
+                                   llvm::StringRef NewName) {
+    std::string NewCode;
+    llvm::raw_string_ostream(NewCode) << llvm::format(
+        "#include \"%s\"\n%s", HeaderName.c_str(), Code.str().c_str());
+    tooling::FileContentMappings FileContents = {{HeaderName, HeaderContent},
+                                                 {CCName, NewCode}};
+    clang::RewriterTestContext Context;
+    Context.createInMemoryFile(HeaderName, HeaderContent);
+    clang::FileID InputFileID = Context.createInMemoryFile(CCName, NewCode);
+
+    tooling::USRFindingAction FindingAction({}, {OldName}, false);
+    std::unique_ptr<tooling::FrontendActionFactory> USRFindingActionFactory =
+        tooling::newFrontendActionFactory(&FindingAction);
+
+    if (!tooling::runToolOnCodeWithArgs(
+            USRFindingActionFactory->create(), NewCode, {"-std=c++11"}, CCName,
+            "clang-rename", std::make_shared<PCHContainerOperations>(),
+            FileContents))
+      return "";
+
+    const std::vector<std::vector<std::string>> &USRList =
+        FindingAction.getUSRList();
+    std::vector<std::string> NewNames = {NewName};
+    std::map<std::string, tooling::Replacements> FileToReplacements;
+    tooling::QualifiedRenamingAction RenameAction(NewNames, USRList,
+                                                  FileToReplacements);
+    auto RenameActionFactory = tooling::newFrontendActionFactory(&RenameAction);
+    if (!tooling::runToolOnCodeWithArgs(
+            RenameActionFactory->create(), NewCode, {"-std=c++11"}, CCName,
+            "clang-rename", std::make_shared<PCHContainerOperations>(),
+            FileContents))
+      return "";
+
+    formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
+    return Context.getRewrittenText(InputFileID);
+  }
+
+  void CompareSnippets(StringRef Expected, StringRef Actual) {
+    std::string ExpectedCode;
+    llvm::raw_string_ostream(ExpectedCode) << llvm::format(
+        "#include \"%s\"\n%s", HeaderName.c_str(), Expected.str().c_str());
+    EXPECT_EQ(format(ExpectedCode), format(Actual));
+  }
+
+  std::string format(llvm::StringRef Code) {
+    tooling::Replacements Replaces = format::reformat(
+        format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
+    auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
+    EXPECT_TRUE(static_cast<bool>(ChangedCode));
+    if (!ChangedCode) {
+      llvm::errs() << llvm::toString(ChangedCode.takeError());
+      return "";
+    }
+    return *ChangedCode;
+  }
+
+  std::string HeaderContent;
+  std::string HeaderName = "header.h";
+  std::string CCName = "input.cc";
+};
+
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang

Added: cfe/trunk/unittests/Rename/RenameClassTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/RenameClassTest.cpp?rev=306840&view=auto
==============================================================================
--- cfe/trunk/unittests/Rename/RenameClassTest.cpp (added)
+++ cfe/trunk/unittests/Rename/RenameClassTest.cpp Fri Jun 30 09:36:09 2017
@@ -0,0 +1,684 @@
+//===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameClassTest : public ClangRenameTest {
+public:
+  RenameClassTest() {
+    AppendToHeader(R"(
+      namespace a {
+        class Foo {
+          public:
+            struct Nested {
+              enum NestedEnum {E1, E2};
+            };
+            void func() {}
+          static int Constant;
+        };
+        class Goo {
+          public:
+            struct Nested {
+              enum NestedEnum {E1, E2};
+            };
+        };
+        int Foo::Constant = 1;
+      } // namespace a
+      namespace b {
+      class Foo {};
+      } // namespace b
+
+      #define MACRO(x) x
+
+      template<typename T> class ptr {};
+    )");
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    RenameClassTests, RenameClassTest,
+    testing::ValuesIn(std::vector<Case>({
+        // basic classes
+        {"a::Foo f;", "b::Bar f;", "", ""},
+        {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
+        {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
+        {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",
+         "", ""},
+        {"namespace a {a::Foo f() { return Foo(); }}",
+         "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
+        {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}", "", ""},
+        {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}", "", ""},
+        {"namespace a { void f(Foo a1) {} }",
+         "namespace a { void f(b::Bar a1) {} }", "", ""},
+        {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}", "", ""},
+        {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}", "", ""},
+        {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
+        {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "", ""},
+        {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
+         "a::Foo::Nested2"},
+
+        // use namespace and typedefs
+        {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
+        {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}",
+         "", ""},
+        {"using a::Foo; namespace x { Foo gA; }",
+         "using b::Bar; namespace x { Bar gA; }", "", ""},
+        {"struct S { using T = a::Foo; T a_; };",
+         "struct S { using T = b::Bar; T a_; };", "", ""},
+        {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
+        {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
+        {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;", "",
+         ""},
+
+        // struct members and other oddities
+        {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",
+         ""},
+        {"struct F { void f(a::Foo a1) {} };",
+         "struct F { void f(b::Bar a1) {} };", "", ""},
+        {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
+        {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };", "",
+         ""},
+
+        {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }",
+         "", ""},
+        {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }",
+         "", ""},
+        {"void f() { a::Foo::Nested::NestedEnum e; }",
+         "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
+        {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
+         "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "", ""},
+        {"void f() { auto e = a::Foo::Nested::E1; }",
+         "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
+
+        // templates
+        {"template <typename T> struct Foo { T t; };\n"
+         "void f() { Foo<a::Foo> foo; }",
+         "template <typename T> struct Foo { T t; };\n"
+         "void f() { Foo<b::Bar> foo; }",
+         "", ""},
+        {"template <typename T> struct Foo { a::Foo a; };",
+         "template <typename T> struct Foo { b::Bar a; };", "", ""},
+        {"template <typename T> void f(T t) {}\n"
+         "void g() { f<a::Foo>(a::Foo()); }",
+         "template <typename T> void f(T t) {}\n"
+         "void g() { f<b::Bar>(b::Bar()); }",
+         "", ""},
+        {"template <typename T> int f() { return 1; }\n"
+         "template <> int f<a::Foo>() { return 2; }\n"
+         "int g() { return f<a::Foo>(); }",
+         "template <typename T> int f() { return 1; }\n"
+         "template <> int f<b::Bar>() { return 2; }\n"
+         "int g() { return f<b::Bar>(); }",
+         "", ""},
+        {"struct Foo { template <typename T> T foo(); };\n"
+         "void g() { Foo f;  auto a = f.template foo<a::Foo>(); }",
+         "struct Foo { template <typename T> T foo(); };\n"
+         "void g() { Foo f;  auto a = f.template foo<b::Bar>(); }",
+         "", ""},
+
+        // The following two templates are distilled from regressions found in
+        // unique_ptr<> and type_traits.h
+        {"template <typename T> struct outer {\n"
+         "     typedef T type;\n"
+         "     type Baz();\n"
+         "    };\n"
+         "    outer<a::Foo> g_A;",
+         "template <typename T> struct outer {\n"
+         "      typedef T type;\n"
+         "      type Baz();\n"
+         "    };\n"
+         "    outer<b::Bar> g_A;",
+         "", ""},
+        {"template <typename T> struct nested { typedef T type; };\n"
+         "template <typename T> struct outer { typename nested<T>::type Foo(); "
+         "};\n"
+         "outer<a::Foo> g_A;",
+         "template <typename T> struct nested { typedef T type; };\n"
+         "template <typename T> struct outer { typename nested<T>::type Foo(); "
+         "};\n"
+         "outer<b::Bar> g_A;",
+         "", ""},
+
+        // macros
+        {"#define FOO(T, t) T t\n"
+         "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
+         "#define FOO(T, t) T t\n"
+         "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
+         "", ""},
+        {"#define FOO(n) a::Foo n\n"
+         " void f() { FOO(a1); FOO(a2); }",
+         "#define FOO(n) b::Bar n\n"
+         " void f() { FOO(a1); FOO(a2); }",
+         "", ""},
+
+        // Pointer to member functions
+        {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
+        {"using a::Foo; auto gA = &Foo::func;",
+         "using b::Bar; auto gA = &b::Bar::func;", "", ""},
+        {"using a::Foo; namespace x { auto gA = &Foo::func; }",
+         "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
+        {"typedef a::Foo T; auto gA = &T::func;",
+         "typedef b::Bar T; auto gA = &T::func;", "", ""},
+        {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",
+         "", ""},
+
+        // Short match inside a namespace
+        {"namespace a { void f(Foo a1) {} }",
+         "namespace a { void f(b::Bar a1) {} }", "", ""},
+
+        // Correct match.
+        {"using a::Foo; struct F { ptr<Foo> a_; };",
+         "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
+
+        // avoid false positives
+        {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
+        {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",
+         "", ""},
+
+        // friends, everyone needs friends.
+        {"class Foo { int i; friend class a::Foo; };",
+         "class Foo { int i; friend class b::Bar; };", "", ""},
+    })), );
+
+TEST_P(RenameClassTest, RenameClasses) {
+  auto Param = GetParam();
+  std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
+  std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
+  std::string Actual = runClangRenameOnCode(Param.Before, OldName, NewName);
+  CompareSnippets(Param.After, Actual);
+}
+
+class NamespaceDetectionTest : public ClangRenameTest {
+protected:
+  NamespaceDetectionTest() {
+    AppendToHeader(R"(
+         class Old {};
+         namespace o1 {
+         class Old {};
+         namespace o2 {
+         class Old {};
+         namespace o3 {
+         class Old {};
+         }  // namespace o3
+         }  // namespace o2
+         }  // namespace o1
+     )");
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    RenameClassTest, NamespaceDetectionTest,
+    ::testing::ValuesIn(std::vector<Case>({
+        // Test old and new namespace overlap.
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+         "o1::o2::o3::Old", "o1::o2::o3::New"},
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",
+         "o1::o2::o3::Old", "o1::o2::n3::New"},
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",
+         "o1::o2::o3::Old", "o1::n2::n3::New"},
+        {"namespace o1 { namespace o2 { Old moo; } }",
+         "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
+         "::o1::o2::New"},
+        {"namespace o1 { namespace o2 { Old moo; } }",
+         "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",
+         "::o1::n2::New"},
+        {"namespace o1 { namespace o2 { Old moo; } }",
+         "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
+         "::o1::o2::Old", "::n1::n2::New"},
+        {"namespace o1 { namespace o2 { Old moo; } }",
+         "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",
+         "n1::n2::New"},
+
+        // Test old and new namespace with differing depths.
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+         "o1::o2::o3::Old", "::o1::New"},
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+         "o1::o2::o3::Old", "::o1::o2::New"},
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+         "o1::o2::o3::Old", "o1::New"},
+        {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+         "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+         "o1::o2::o3::Old", "o1::o2::New"},
+        {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
+        {"Old moo;", "o1::New moo;", "Old", "o1::New"},
+        {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",
+         "o1::New"},
+        {"namespace o1 { namespace o2 {  Old moo; } }",
+         "namespace o1 { namespace o2 {  ::New moo; } }", "::o1::o2::Old",
+         "::New"},
+        {"namespace o1 { namespace o2 {  Old moo; } }",
+         "namespace o1 { namespace o2 {  New moo; } }", "::o1::o2::Old", "New"},
+
+        // Test moving into the new namespace at different levels.
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
+         "::n1::n2::New"},
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
+         "n1::n2::New"},
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
+         "::n1::o2::New"},
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
+         "n1::o2::New"},
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
+         "::o1::o2::Old", "::o1::o2::New"},
+        {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+         "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",
+         "o1::o2::New"},
+
+        // Test friends declarations.
+        {"class Foo { friend class o1::Old; };",
+         "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
+        {"class Foo { int i; friend class o1::Old; };",
+         "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
+         "::o1::New"},
+        {"namespace o1 { class Foo { int i; friend class Old; }; }",
+         "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",
+         "o1::New"},
+        {"namespace o1 { class Foo { int i; friend class Old; }; }",
+         "namespace o1 { class Foo { int i; friend class New; }; }",
+         "::o1::Old", "::o1::New"},
+    })), );
+
+TEST_P(NamespaceDetectionTest, RenameClasses) {
+  auto Param = GetParam();
+  std::string Actual =
+      runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+  CompareSnippets(Param.After, Actual);
+}
+
+class TemplatedClassRenameTest : public ClangRenameTest {
+protected:
+  TemplatedClassRenameTest() {
+    AppendToHeader(R"(
+           template <typename T> struct Old {
+             T t_;
+             T f() { return T(); };
+             static T s(T t) { return t; }
+           };
+           namespace ns {
+           template <typename T> struct Old {
+             T t_;
+             T f() { return T(); };
+             static T s(T t) { return t; }
+           };
+           }  // namespace ns
+
+           namespace o1 {
+           namespace o2 {
+           namespace o3 {
+           template <typename T> struct Old {
+             T t_;
+             T f() { return T(); };
+             static T s(T t) { return t; }
+           };
+           }  // namespace o3
+           }  // namespace o2
+           }  // namespace o1
+       )");
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    RenameClassTests, TemplatedClassRenameTest,
+    ::testing::ValuesIn(std::vector<Case>({
+        {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",
+         "New"},
+        {"ns::Old<int> gI; ns::Old<bool> gB;",
+         "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
+        {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
+         "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},
+        {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
+         "ns::Old", "ns::New"},
+
+        {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
+         "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
+         "New"},
+        {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",
+         "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",
+         "ns::Old", "ns::New"},
+
+        {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",
+         "New"},
+        {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",
+         "ns::Old", "ns::New"},
+
+        {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
+         "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old", "New"},
+        {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
+         "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
+         "ns::Old", "ns::New"},
+        {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
+         "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",
+         "New"},
+        {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",
+         "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",
+         "ns::Old", "ns::New"},
+
+        {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
+        {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
+         "ns::New"},
+        {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
+         "o1::o2::o3::Old", "o1::o2::o3::New"},
+        {"namespace ns { Old<bool>& foo(); }",
+         "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
+        {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},
+        {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
+         "ns::Old", "ns::New"},
+
+        // FIXME: figure out why this only works when Moo gets
+        // specialized at some point.
+        {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
+         "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",
+         "New"},
+        {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",
+         "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",
+         "ns::Old", "ns::New"},
+    })), );
+
+TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
+  auto Param = GetParam();
+  std::string Actual =
+      runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+  CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
+  std::string Before = R"(
+      class Old {
+       public:
+        Old();
+        ~Old();
+
+        Old* next();
+
+       private:
+        Old* next_;
+      };
+
+      Old::Old() {}
+      Old::~Old() {}
+      Old* Old::next() { return next_; }
+    )";
+  std::string Expected = R"(
+      class New {
+       public:
+        New();
+        ~New();
+
+        New* next();
+
+       private:
+        New* next_;
+      };
+
+      New::New() {}
+      New::~New() {}
+      New* New::next() { return next_; }
+    )";
+  std::string After = runClangRenameOnCode(Before, "Old", "New");
+  CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
+  std::string Before = R"(
+      class Old {
+       public:
+        Old() {}
+        ~Old() {}
+
+        Old* next() { return next_; }
+
+       private:
+        Old* next_;
+      };
+    )";
+  std::string Expected = R"(
+      class New {
+       public:
+        New() {}
+        ~New() {}
+
+        New* next() { return next_; }
+
+       private:
+        New* next_;
+      };
+    )";
+  std::string After = runClangRenameOnCode(Before, "Old", "New");
+  CompareSnippets(Expected, After);
+}
+
+// FIXME: no prefix qualifiers being added to the class definition and
+// constructor.
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
+  std::string Before = R"(
+      namespace ns {
+      class Old {
+       public:
+        Old() {}
+        ~Old() {}
+
+        Old* next() { return next_; }
+
+       private:
+        Old* next_;
+      };
+      }  // namespace ns
+    )";
+  std::string Expected = R"(
+      namespace ns {
+      class ns::New {
+       public:
+        ns::New() {}
+        ~New() {}
+
+        New* next() { return next_; }
+
+       private:
+        New* next_;
+      };
+      }  // namespace ns
+    )";
+  std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+  CompareSnippets(Expected, After);
+}
+
+// FIXME: no prefix qualifiers being added to the class definition and
+// constructor.
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
+  std::string Before = R"(
+      namespace ns {
+      class Old {
+       public:
+        Old();
+        ~Old();
+
+        Old* next();
+
+       private:
+        Old* next_;
+      };
+
+      Old::Old() {}
+      Old::~Old() {}
+      Old* Old::next() { return next_; }
+      }  // namespace ns
+    )";
+  std::string Expected = R"(
+      namespace ns {
+      class ns::New {
+       public:
+        ns::New();
+        ~New();
+
+        New* next();
+
+       private:
+        New* next_;
+      };
+
+      New::ns::New() {}
+      New::~New() {}
+      New* New::next() { return next_; }
+      }  // namespace ns
+    )";
+  std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+  CompareSnippets(Expected, After);
+}
+
+// FIXME: no prefix qualifiers being added to the definition.
+TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
+  // `using Base::Base;` will generate an implicit constructor containing usage
+  // of `::ns::Old` which should not be matched.
+  std::string Before = R"(
+      namespace ns {
+      class Old {
+        int x;
+      };
+      class Base {
+       protected:
+        Old *moo_;
+       public:
+        Base(Old *moo) : moo_(moo) {}
+      };
+      class Derived : public Base {
+       public:
+         using Base::Base;
+      };
+      }  // namespace ns
+      int main() {
+        ::ns::Old foo;
+        ::ns::Derived d(&foo);
+        return 0;
+      })";
+  std::string Expected = R"(
+      namespace ns {
+      class ns::New {
+        int x;
+      };
+      class Base {
+       protected:
+        New *moo_;
+       public:
+        Base(New *moo) : moo_(moo) {}
+      };
+      class Derived : public Base {
+       public:
+         using Base::Base;
+      };
+      }  // namespace ns
+      int main() {
+        ::ns::New foo;
+        ::ns::Derived d(&foo);
+        return 0;
+      })";
+  std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+  CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
+  std::string Before = R"(
+      namespace ns {
+      class Old {
+      };
+      } // namespace ns
+      struct S {
+        int y;
+        ns::Old old;
+      };
+      void f() {
+        S s1, s2, s3;
+        // This causes an implicit assignment operator to be created.
+        s1 = s2 = s3;
+      }
+      )";
+  std::string Expected = R"(
+      namespace ns {
+      class ::new_ns::New {
+      };
+      } // namespace ns
+      struct S {
+        int y;
+        ::new_ns::New old;
+      };
+      void f() {
+        S s1, s2, s3;
+        // This causes an implicit assignment operator to be created.
+        s1 = s2 = s3;
+      }
+      )";
+  std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+  CompareSnippets(Expected, After);
+}
+
+// FIXME: no prefix qualifiers being adding to the definition.
+TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
+  std::string Before = R"(
+      template <class T>
+      class function;
+      template <class R, class... ArgTypes>
+      class function<R(ArgTypes...)> {
+      public:
+        template <typename Functor>
+        function(Functor f) {}
+
+        function() {}
+
+        R operator()(ArgTypes...) const {}
+      };
+
+      namespace ns {
+      class Old {};
+      void f() {
+        function<void(Old)> func;
+      }
+      }  // namespace ns)";
+  std::string Expected = R"(
+      template <class T>
+      class function;
+      template <class R, class... ArgTypes>
+      class function<R(ArgTypes...)> {
+      public:
+        template <typename Functor>
+        function(Functor f) {}
+
+        function() {}
+
+        R operator()(ArgTypes...) const {}
+      };
+
+      namespace ns {
+      class ::new_ns::New {};
+      void f() {
+        function<void(::new_ns::New)> func;
+      }
+      }  // namespace ns)";
+  std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+  CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang




More information about the cfe-commits mailing list