r306840 - [refactor] Move clang-rename into the clang repository
Alex L via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 30 13:54:45 PDT 2017
Thanks! I'll take a look.
On 30 June 2017 at 21:14, Evgenii Stepanov <eugeni.stepanov at gmail.com>
wrote:
> Hi,
>
> there are new memory leaks related to this change:
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-
> linux-fast/builds/6072/steps/check-clang%20asan/logs/stdio
>
> On Fri, Jun 30, 2017 at 9:36 AM, Alex Lorenz via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Author: arphaman
>> Date: Fri Jun 30 09:36:09 2017
>> New Revision: 306840
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=306840&view=rev
>> Log:
>> [refactor] Move clang-rename into the clang repository
>>
>> The core engine of clang-rename will be used for local and global renames
>> in the
>> new refactoring engine, as mentioned in
>> http://lists.llvm.org/pipermail/cfe-dev/2017-June/054286.html.
>>
>> The clang-rename tool is still supported but might get deprecated in the
>> future.
>>
>> Differential Revision: https://reviews.llvm.org/D34696
>>
>> Added:
>> cfe/trunk/include/clang/Tooling/Refactoring/Rename/
>> cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
>> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
>> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
>> cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
>> cfe/trunk/lib/Tooling/Refactoring/Rename/
>> cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
>> cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
>> cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
>> cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
>> cfe/trunk/test/clang-rename/
>> cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
>> cfe/trunk/test/clang-rename/ClassFindByName.cpp
>> cfe/trunk/test/clang-rename/ClassReplacements.cpp
>> cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
>> cfe/trunk/test/clang-rename/ClassTestMulti.cpp
>> cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
>> cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
>> cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
>> cfe/trunk/test/clang-rename/Ctor.cpp
>> cfe/trunk/test/clang-rename/CtorInitializer.cpp
>> cfe/trunk/test/clang-rename/DeclRefExpr.cpp
>> cfe/trunk/test/clang-rename/Field.cpp
>> cfe/trunk/test/clang-rename/FunctionMacro.cpp
>> cfe/trunk/test/clang-rename/FunctionOverride.cpp
>> cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
>> cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
>> cfe/trunk/test/clang-rename/Inputs/
>> cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
>> cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
>> cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
>> cfe/trunk/test/clang-rename/InvalidNewName.cpp
>> cfe/trunk/test/clang-rename/InvalidOffset.cpp
>> cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
>> cfe/trunk/test/clang-rename/MemberExprMacro.cpp
>> cfe/trunk/test/clang-rename/Namespace.cpp
>> cfe/trunk/test/clang-rename/NoNewName.cpp
>> cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
>> cfe/trunk/test/clang-rename/TemplateTypename.cpp
>> cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
>> cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
>> cfe/trunk/test/clang-rename/Variable.cpp
>> cfe/trunk/test/clang-rename/VariableMacro.cpp
>> cfe/trunk/test/clang-rename/YAMLInput.cpp
>> cfe/trunk/tools/clang-rename/
>> cfe/trunk/tools/clang-rename/CMakeLists.txt
>> cfe/trunk/tools/clang-rename/ClangRename.cpp
>> cfe/trunk/tools/clang-rename/clang-rename.el
>> cfe/trunk/tools/clang-rename/clang-rename.py
>> cfe/trunk/unittests/Rename/
>> cfe/trunk/unittests/Rename/CMakeLists.txt
>> cfe/trunk/unittests/Rename/ClangRenameTest.h
>> cfe/trunk/unittests/Rename/RenameClassTest.cpp
>> Modified:
>> cfe/trunk/include/clang/module.modulemap
>> cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
>> cfe/trunk/test/CMakeLists.txt
>> cfe/trunk/tools/CMakeLists.txt
>> cfe/trunk/unittests/CMakeLists.txt
>>
>> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingA
>> ction.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Tooling/Refactoring/Rename/RenamingAction.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
>> (added)
>> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
>> Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,70 @@
>> +//===--- RenamingAction.h - Clang refactoring library
>> ---------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Provides an action to rename every symbol at a point.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
>> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
>> +
>> +#include "clang/Tooling/Refactoring.h"
>> +
>> +namespace clang {
>> +class ASTConsumer;
>> +class CompilerInstance;
>> +
>> +namespace tooling {
>> +
>> +class RenamingAction {
>> +public:
>> + RenamingAction(const std::vector<std::string> &NewNames,
>> + const std::vector<std::string> &PrevNames,
>> + const std::vector<std::vector<std::string>> &USRList,
>> + std::map<std::string, tooling::Replacements>
>> &FileToReplaces,
>> + bool PrintLocations = false)
>> + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
>> + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations)
>> {}
>> +
>> + std::unique_ptr<ASTConsumer> newASTConsumer();
>> +
>> +private:
>> + const std::vector<std::string> &NewNames, &PrevNames;
>> + const std::vector<std::vector<std::string>> &USRList;
>> + std::map<std::string, tooling::Replacements> &FileToReplaces;
>> + bool PrintLocations;
>> +};
>> +
>> +/// Rename all symbols identified by the given USRs.
>> +class QualifiedRenamingAction {
>> +public:
>> + QualifiedRenamingAction(
>> + const std::vector<std::string> &NewNames,
>> + const std::vector<std::vector<std::string>> &USRList,
>> + std::map<std::string, tooling::Replacements> &FileToReplaces)
>> + : NewNames(NewNames), USRList(USRList),
>> FileToReplaces(FileToReplaces) {}
>> +
>> + std::unique_ptr<ASTConsumer> newASTConsumer();
>> +
>> +private:
>> + /// New symbol names.
>> + const std::vector<std::string> &NewNames;
>> +
>> + /// A list of USRs. Each element represents USRs of a symbol being
>> renamed.
>> + const std::vector<std::vector<std::string>> &USRList;
>> +
>> + /// A file path to replacements map.
>> + std::map<std::string, tooling::Replacements> &FileToReplaces;
>> +};
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>> +
>> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
>>
>> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Tooling/Refactoring/Rename/USRFinder.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h
>> (added)
>> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h Fri
>> Jun 30 09:36:09 2017
>> @@ -0,0 +1,84 @@
>> +//===--- USRFinder.h - Clang refactoring library
>> --------------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Methods for determining the USR of a symbol at a location in
>> source
>> +/// code.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
>> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
>> +
>> +#include "clang/AST/AST.h"
>> +#include "clang/AST/ASTContext.h"
>> +#include "clang/ASTMatchers/ASTMatchFinder.h"
>> +#include <string>
>> +#include <vector>
>> +
>> +using namespace llvm;
>> +using namespace clang::ast_matchers;
>> +
>> +namespace clang {
>> +
>> +class ASTContext;
>> +class Decl;
>> +class SourceLocation;
>> +class NamedDecl;
>> +
>> +namespace tooling {
>> +
>> +// Given an AST context and a point, returns a NamedDecl identifying the
>> symbol
>> +// at the point. Returns null if nothing is found at the point.
>> +const NamedDecl *getNamedDeclAt(const ASTContext &Context,
>> + const SourceLocation Point);
>> +
>> +// Given an AST context and a fully qualified name, returns a NamedDecl
>> +// identifying the symbol with a matching name. Returns null if nothing
>> is
>> +// found for the name.
>> +const NamedDecl *getNamedDeclFor(const ASTContext &Context,
>> + const std::string &Name);
>> +
>> +// Converts a Decl into a USR.
>> +std::string getUSRForDecl(const Decl *Decl);
>> +
>> +// FIXME: Implement RecursiveASTVisitor<T>::VisitNestedNameSpecifier
>> instead.
>> +class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback {
>> +public:
>> + explicit NestedNameSpecifierLocFinder(ASTContext &Context)
>> + : Context(Context) {}
>> +
>> + std::vector<NestedNameSpecifierLoc> getNestedNameSpecifierLocations()
>> {
>> + addMatchers();
>> + Finder.matchAST(Context);
>> + return Locations;
>> + }
>> +
>> +private:
>> + void addMatchers() {
>> + const auto NestedNameSpecifierLocMatcher =
>> + nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc");
>> + Finder.addMatcher(NestedNameSpecifierLocMatcher, this);
>> + }
>> +
>> + void run(const MatchFinder::MatchResult &Result) override {
>> + const auto *NNS = Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
>> + "nestedNameSpecifierLoc");
>> + Locations.push_back(*NNS);
>> + }
>> +
>> + ASTContext &Context;
>> + std::vector<NestedNameSpecifierLoc> Locations;
>> + MatchFinder Finder;
>> +};
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>> +
>> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
>>
>> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindin
>> gAction.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Tooling/Refactoring/Rename/USRFindingAction.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
>> (added)
>> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
>> Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,54 @@
>> +//===--- USRFindingAction.h - Clang refactoring library
>> -------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Provides an action to find all relevant USRs at a point.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
>> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
>> +
>> +#include "clang/Basic/LLVM.h"
>> +#include "llvm/ADT/ArrayRef.h"
>> +
>> +#include <string>
>> +#include <vector>
>> +
>> +namespace clang {
>> +class ASTConsumer;
>> +class CompilerInstance;
>> +class NamedDecl;
>> +
>> +namespace tooling {
>> +
>> +struct USRFindingAction {
>> + USRFindingAction(ArrayRef<unsigned> SymbolOffsets,
>> + ArrayRef<std::string> QualifiedNames, bool Force)
>> + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
>> + ErrorOccurred(false), Force(Force) {}
>> + std::unique_ptr<ASTConsumer> newASTConsumer();
>> +
>> + ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }
>> + ArrayRef<std::vector<std::string>> getUSRList() { return USRList; }
>> + bool errorOccurred() { return ErrorOccurred; }
>> +
>> +private:
>> + std::vector<unsigned> SymbolOffsets;
>> + std::vector<std::string> QualifiedNames;
>> + std::vector<std::string> SpellingNames;
>> + std::vector<std::vector<std::string>> USRList;
>> + bool ErrorOccurred;
>> + bool Force;
>> +};
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>> +
>> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
>>
>> Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Tooling/Refactoring/Rename/USRLocFinder.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
>> (added)
>> +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
>> Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,49 @@
>> +//===--- USRLocFinder.h - Clang refactoring library
>> -----------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Provides functionality for finding all instances of a USR in
>> a given
>> +/// AST.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
>> +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
>> +
>> +#include "clang/AST/AST.h"
>> +#include "clang/Tooling/Core/Replacement.h"
>> +#include "clang/Tooling/Refactoring/AtomicChange.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include <string>
>> +#include <vector>
>> +
>> +namespace clang {
>> +namespace tooling {
>> +
>> +/// Create atomic changes for renaming all symbol references which are
>> +/// identified by the USRs set to a given new name.
>> +///
>> +/// \param USRs The set containing USRs of a particular old symbol.
>> +/// \param NewName The new name to replace old symbol name.
>> +/// \param TranslationUnitDecl The translation unit declaration.
>> +///
>> +/// \return Atomic changes for renaming.
>> +std::vector<tooling::AtomicChange>
>> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
>> + llvm::StringRef NewName, Decl
>> *TranslationUnitDecl);
>> +
>> +// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!
>> +std::vector<SourceLocation>
>> +getLocationsOfUSRs(const std::vector<std::string> &USRs,
>> + llvm::StringRef PrevName, Decl *Decl);
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>> +
>> +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
>>
>> Modified: cfe/trunk/include/clang/module.modulemap
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> module.modulemap?rev=306840&r1=306839&r2=306840&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/module.modulemap (original)
>> +++ cfe/trunk/include/clang/module.modulemap Fri Jun 30 09:36:09 2017
>> @@ -133,9 +133,10 @@ module Clang_StaticAnalyzer_Frontend {
>>
>> module Clang_Tooling {
>> requires cplusplus umbrella "Tooling" module * { export * }
>> - // FIXME: Exclude this header to avoid pulling all of the AST matchers
>> + // FIXME: Exclude these headers to avoid pulling all of the AST
>> matchers
>> // library into clang-format. Due to inline key functions in the
>> headers,
>> // importing the AST matchers library gives a link dependency on the
>> AST
>> // matchers (and thus the AST), which clang-format should not have.
>> exclude header "Tooling/RefactoringCallbacks.h"
>> + exclude header "Tooling/Refactoring/Rename/USRFinder.h"
>> }
>>
>> Modified: cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Re
>> factoring/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt (original)
>> +++ cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt Fri Jun 30 09:36:09
>> 2017
>> @@ -5,8 +5,16 @@ set(LLVM_LINK_COMPONENTS
>>
>> add_clang_library(clangToolingRefactor
>> AtomicChange.cpp
>> + Rename/RenamingAction.cpp
>> + Rename/USRFinder.cpp
>> + Rename/USRFindingAction.cpp
>> + Rename/USRLocFinder.cpp
>>
>> LINK_LIBS
>> + clangAST
>> + clangASTMatchers
>> clangBasic
>> + clangIndex
>> + clangLex
>> clangToolingCore
>> )
>>
>> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Re
>> factoring/Rename/RenamingAction.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp (added)
>> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp Fri Jun
>> 30 09:36:09 2017
>> @@ -0,0 +1,134 @@
>> +//===--- RenamingAction.cpp - Clang refactoring library
>> -------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Provides an action to rename every symbol at a point.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
>> +#include "clang/AST/ASTConsumer.h"
>> +#include "clang/AST/ASTContext.h"
>> +#include "clang/Basic/FileManager.h"
>> +#include "clang/Frontend/CompilerInstance.h"
>> +#include "clang/Frontend/FrontendAction.h"
>> +#include "clang/Lex/Lexer.h"
>> +#include "clang/Lex/Preprocessor.h"
>> +#include "clang/Tooling/CommonOptionsParser.h"
>> +#include "clang/Tooling/Refactoring.h"
>> +#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
>> +#include "clang/Tooling/Tooling.h"
>> +#include <string>
>> +#include <vector>
>> +
>> +using namespace llvm;
>> +
>> +namespace clang {
>> +namespace tooling {
>> +
>> +class RenamingASTConsumer : public ASTConsumer {
>> +public:
>> + RenamingASTConsumer(
>> + const std::vector<std::string> &NewNames,
>> + const std::vector<std::string> &PrevNames,
>> + const std::vector<std::vector<std::string>> &USRList,
>> + std::map<std::string, tooling::Replacements> &FileToReplaces,
>> + bool PrintLocations)
>> + : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
>> + FileToReplaces(FileToReplaces), PrintLocations(PrintLocations)
>> {}
>> +
>> + void HandleTranslationUnit(ASTContext &Context) override {
>> + for (unsigned I = 0; I < NewNames.size(); ++I)
>> + HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);
>> + }
>> +
>> + void HandleOneRename(ASTContext &Context, const std::string &NewName,
>> + const std::string &PrevName,
>> + const std::vector<std::string> &USRs) {
>> + const SourceManager &SourceMgr = Context.getSourceManager();
>> + std::vector<SourceLocation> RenamingCandidates;
>> + std::vector<SourceLocation> NewCandidates;
>> +
>> + NewCandidates = tooling::getLocationsOfUSRs(
>> + USRs, PrevName, Context.getTranslationUnitDecl());
>> + RenamingCandidates.insert(RenamingCandidates.end(),
>> NewCandidates.begin(),
>> + NewCandidates.end());
>> +
>> + unsigned PrevNameLen = PrevName.length();
>> + for (const auto &Loc : RenamingCandidates) {
>> + if (PrintLocations) {
>> + FullSourceLoc FullLoc(Loc, SourceMgr);
>> + errs() << "clang-rename: renamed at: " <<
>> SourceMgr.getFilename(Loc)
>> + << ":" << FullLoc.getSpellingLineNumber() << ":"
>> + << FullLoc.getSpellingColumnNumber() << "\n";
>> + }
>> + // FIXME: better error handling.
>> + tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName);
>> + llvm::Error Err = FileToReplaces[Replace.getFile
>> Path()].add(Replace);
>> + if (Err)
>> + llvm::errs() << "Renaming failed in " << Replace.getFilePath()
>> << "! "
>> + << llvm::toString(std::move(Err)) << "\n";
>> + }
>> + }
>> +
>> +private:
>> + const std::vector<std::string> &NewNames, &PrevNames;
>> + const std::vector<std::vector<std::string>> &USRList;
>> + std::map<std::string, tooling::Replacements> &FileToReplaces;
>> + bool PrintLocations;
>> +};
>> +
>> +// A renamer to rename symbols which are identified by a give USRList to
>> +// new name.
>> +//
>> +// FIXME: Merge with the above RenamingASTConsumer.
>> +class USRSymbolRenamer : public ASTConsumer {
>> +public:
>> + USRSymbolRenamer(const std::vector<std::string> &NewNames,
>> + const std::vector<std::vector<std::string>> &USRList,
>> + std::map<std::string, tooling::Replacements>
>> &FileToReplaces)
>> + : NewNames(NewNames), USRList(USRList),
>> FileToReplaces(FileToReplaces) {
>> + assert(USRList.size() == NewNames.size());
>> + }
>> +
>> + void HandleTranslationUnit(ASTContext &Context) override {
>> + for (unsigned I = 0; I < NewNames.size(); ++I) {
>> + // FIXME: Apply AtomicChanges directly once the refactoring APIs
>> are
>> + // ready.
>> + auto AtomicChanges = tooling::createRenameAtomicChanges(
>> + USRList[I], NewNames[I], Context.getTranslationUnitDecl());
>> + for (const auto AtomicChange : AtomicChanges) {
>> + for (const auto &Replace : AtomicChange.getReplacements()) {
>> + llvm::Error Err = FileToReplaces[Replace.getFile
>> Path()].add(Replace);
>> + if (Err) {
>> + llvm::errs() << "Renaming failed in " <<
>> Replace.getFilePath()
>> + << "! " << llvm::toString(std::move(Err)) <<
>> "\n";
>> + }
>> + }
>> + }
>> + }
>> + }
>> +
>> +private:
>> + const std::vector<std::string> &NewNames;
>> + const std::vector<std::vector<std::string>> &USRList;
>> + std::map<std::string, tooling::Replacements> &FileToReplaces;
>> +};
>> +
>> +std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
>> + return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames,
>> USRList,
>> + FileToReplaces,
>> PrintLocations);
>> +}
>> +
>> +std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
>> + return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList,
>> FileToReplaces);
>> +}
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>>
>> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Re
>> factoring/Rename/USRFinder.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp (added)
>> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,213 @@
>> +//===--- USRFinder.cpp - Clang refactoring library
>> ------------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file Implements a recursive AST visitor that finds the USR of a
>> symbol at a
>> +/// point.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
>> +#include "clang/AST/AST.h"
>> +#include "clang/AST/ASTContext.h"
>> +#include "clang/AST/RecursiveASTVisitor.h"
>> +#include "clang/Index/USRGeneration.h"
>> +#include "clang/Lex/Lexer.h"
>> +#include "llvm/ADT/SmallVector.h"
>> +
>> +using namespace llvm;
>> +
>> +namespace clang {
>> +namespace tooling {
>> +
>> +// NamedDeclFindingASTVisitor recursively visits each AST node to find
>> the
>> +// symbol underneath the cursor.
>> +// FIXME: move to separate .h/.cc file if this gets too large.
>> +namespace {
>> +class NamedDeclFindingASTVisitor
>> + : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
>> +public:
>> + // \brief Finds the NamedDecl at a point in the source.
>> + // \param Point the location in the source to search for the NamedDecl.
>> + explicit NamedDeclFindingASTVisitor(const SourceLocation Point,
>> + const ASTContext &Context)
>> + : Result(nullptr), Point(Point), Context(Context) {}
>> +
>> + // \brief Finds the NamedDecl for a name in the source.
>> + // \param Name the fully qualified name.
>> + explicit NamedDeclFindingASTVisitor(const std::string &Name,
>> + const ASTContext &Context)
>> + : Result(nullptr), Name(Name), Context(Context) {}
>> +
>> + // Declaration visitors:
>> +
>> + // \brief Checks if the point falls within the NameDecl. This covers
>> every
>> + // declaration of a named entity that we may come across. Usually, just
>> + // checking if the point lies within the length of the name of the
>> declaration
>> + // and the start location is sufficient.
>> + bool VisitNamedDecl(const NamedDecl *Decl) {
>> + return dyn_cast<CXXConversionDecl>(Decl)
>> + ? true
>> + : setResult(Decl, Decl->getLocation(),
>> + Decl->getNameAsString().length());
>> + }
>> +
>> + // Expression visitors:
>> +
>> + bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
>> + const NamedDecl *Decl = Expr->getFoundDecl();
>> + return setResult(Decl, Expr->getLocation(),
>> + Decl->getNameAsString().length());
>> + }
>> +
>> + bool VisitMemberExpr(const MemberExpr *Expr) {
>> + const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
>> + return setResult(Decl, Expr->getMemberLoc(),
>> + Decl->getNameAsString().length());
>> + }
>> +
>> + // Other visitors:
>> +
>> + bool VisitTypeLoc(const TypeLoc Loc) {
>> + const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
>> + const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(
>> + TypeBeginLoc, 0, Context.getSourceManager(),
>> Context.getLangOpts());
>> + if (const auto *TemplateTypeParm =
>> + dyn_cast<TemplateTypeParmType>(Loc.getType()))
>> + return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc,
>> TypeEndLoc);
>> + if (const auto *TemplateSpecType =
>> + dyn_cast<TemplateSpecializationType>(Loc.getType())) {
>> + return setResult(TemplateSpecType->ge
>> tTemplateName().getAsTemplateDecl(),
>> + TypeBeginLoc, TypeEndLoc);
>> + }
>> + return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
>> + TypeEndLoc);
>> + }
>> +
>> + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl
>> *ConstructorDecl) {
>> + for (const auto *Initializer : ConstructorDecl->inits()) {
>> + // Ignore implicit initializers.
>> + if (!Initializer->isWritten())
>> + continue;
>> + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
>> + const SourceLocation InitBeginLoc =
>> Initializer->getSourceLocation(),
>> + InitEndLoc = Lexer::getLocForEndOfToken(
>> + InitBeginLoc, 0,
>> Context.getSourceManager(),
>> + Context.getLangOpts());
>> + if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc))
>> + return false;
>> + }
>> + }
>> + return true;
>> + }
>> +
>> + // Other:
>> +
>> + const NamedDecl *getNamedDecl() { return Result; }
>> +
>> + // \brief Determines if a namespace qualifier contains the point.
>> + // \returns false on success and sets Result.
>> + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
>> + while (NameLoc) {
>> + const NamespaceDecl *Decl =
>> + NameLoc.getNestedNameSpecifier()->getAsNamespace();
>> + setResult(Decl, NameLoc.getLocalBeginLoc(),
>> NameLoc.getLocalEndLoc());
>> + NameLoc = NameLoc.getPrefix();
>> + }
>> + }
>> +
>> +private:
>> + // \brief Sets Result to Decl if the Point is within Start and End.
>> + // \returns false on success.
>> + bool setResult(const NamedDecl *Decl, SourceLocation Start,
>> + SourceLocation End) {
>> + if (!Decl)
>> + return true;
>> + if (Name.empty()) {
>> + // Offset is used to find the declaration.
>> + if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
>> + !End.isFileID() || !isPointWithin(Start, End))
>> + return true;
>> + } else {
>> + // Fully qualified name is used to find the declaration.
>> + if (Name != Decl->getQualifiedNameAsString() &&
>> + Name != "::" + Decl->getQualifiedNameAsString())
>> + return true;
>> + }
>> + Result = Decl;
>> + return false;
>> + }
>> +
>> + // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
>> + // \returns false on success.
>> + bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned
>> Offset) {
>> + // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2
>> etc).
>> + return Offset == 0 ||
>> + setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
>> + }
>> +
>> + // \brief Determines if the Point is within Start and End.
>> + bool isPointWithin(const SourceLocation Start, const SourceLocation
>> End) {
>> + // FIXME: Add tests for Point == End.
>> + return Point == Start || Point == End ||
>> + (Context.getSourceManager().isBeforeInTranslationUnit(Start,
>> + Point)
>> &&
>> + Context.getSourceManager().isBeforeInTranslationUnit(Point,
>> End));
>> + }
>> +
>> + const NamedDecl *Result;
>> + const SourceLocation Point; // The location to find the NamedDecl.
>> + const std::string Name;
>> + const ASTContext &Context;
>> +};
>> +} // namespace
>> +
>> +const NamedDecl *getNamedDeclAt(const ASTContext &Context,
>> + const SourceLocation Point) {
>> + const SourceManager &SM = Context.getSourceManager();
>> + NamedDeclFindingASTVisitor Visitor(Point, Context);
>> +
>> + // Try to be clever about pruning down the number of top-level
>> declarations we
>> + // see. If both start and end is either before or after the point we're
>> + // looking for the point cannot be inside of this decl. Don't even
>> look at it.
>> + for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
>> + SourceLocation StartLoc = CurrDecl->getLocStart();
>> + SourceLocation EndLoc = CurrDecl->getLocEnd();
>> + if (StartLoc.isValid() && EndLoc.isValid() &&
>> + SM.isBeforeInTranslationUnit(StartLoc, Point) !=
>> + SM.isBeforeInTranslationUnit(EndLoc, Point))
>> + Visitor.TraverseDecl(CurrDecl);
>> + }
>> +
>> + NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
>> + for (const auto &Location : Finder.getNestedNameSpecifierLocations())
>> + Visitor.handleNestedNameSpecifierLoc(Location);
>> +
>> + return Visitor.getNamedDecl();
>> +}
>> +
>> +const NamedDecl *getNamedDeclFor(const ASTContext &Context,
>> + const std::string &Name) {
>> + NamedDeclFindingASTVisitor Visitor(Name, Context);
>> + Visitor.TraverseDecl(Context.getTranslationUnitDecl());
>> +
>> + return Visitor.getNamedDecl();
>> +}
>> +
>> +std::string getUSRForDecl(const Decl *Decl) {
>> + llvm::SmallVector<char, 128> Buff;
>> +
>> + // FIXME: Add test for the nullptr case.
>> + if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
>> + return "";
>> +
>> + return std::string(Buff.data(), Buff.size());
>> +}
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>>
>> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Re
>> factoring/Rename/USRFindingAction.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp (added)
>> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp Fri
>> Jun 30 09:36:09 2017
>> @@ -0,0 +1,236 @@
>> +//===--- USRFindingAction.cpp - Clang refactoring library
>> -----------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Provides an action to find USR for the symbol at <offset>, as
>> well as
>> +/// all additional USRs.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
>> +#include "clang/AST/AST.h"
>> +#include "clang/AST/ASTConsumer.h"
>> +#include "clang/AST/ASTContext.h"
>> +#include "clang/AST/Decl.h"
>> +#include "clang/AST/RecursiveASTVisitor.h"
>> +#include "clang/Basic/FileManager.h"
>> +#include "clang/Frontend/CompilerInstance.h"
>> +#include "clang/Frontend/FrontendAction.h"
>> +#include "clang/Lex/Lexer.h"
>> +#include "clang/Lex/Preprocessor.h"
>> +#include "clang/Tooling/CommonOptionsParser.h"
>> +#include "clang/Tooling/Refactoring.h"
>> +#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
>> +#include "clang/Tooling/Tooling.h"
>> +
>> +#include <algorithm>
>> +#include <set>
>> +#include <string>
>> +#include <vector>
>> +
>> +using namespace llvm;
>> +
>> +namespace clang {
>> +namespace tooling {
>> +
>> +namespace {
>> +// \brief NamedDeclFindingConsumer should delegate finding USRs of given
>> Decl to
>> +// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor
>> if given
>> +// Decl refers to class and adds USRs of all overridden methods if Decl
>> refers
>> +// to virtual method.
>> +class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder>
>> {
>> +public:
>> + AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
>> + : FoundDecl(FoundDecl), Context(Context) {}
>> +
>> + std::vector<std::string> Find() {
>> + // Fill OverriddenMethods and PartialSpecs storages.
>> + TraverseDecl(Context.getTranslationUnitDecl());
>> + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
>> + addUSRsOfOverridenFunctions(MethodDecl);
>> + for (const auto &OverriddenMethod : OverriddenMethods) {
>> + if (checkIfOverriddenFunctionAscends(OverriddenMethod))
>> + USRSet.insert(getUSRForDecl(OverriddenMethod));
>> + }
>> + } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl))
>> {
>> + handleCXXRecordDecl(RecordDecl);
>> + } else if (const auto *TemplateDecl =
>> + dyn_cast<ClassTemplateDecl>(FoundDecl)) {
>> + handleClassTemplateDecl(TemplateDecl);
>> + } else {
>> + USRSet.insert(getUSRForDecl(FoundDecl));
>> + }
>> + return std::vector<std::string>(USRSet.begin(), USRSet.end());
>> + }
>> +
>> + bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
>> + if (MethodDecl->isVirtual())
>> + OverriddenMethods.push_back(MethodDecl);
>> + return true;
>> + }
>> +
>> + bool VisitClassTemplatePartialSpecializationDecl(
>> + const ClassTemplatePartialSpecializationDecl *PartialSpec) {
>> + PartialSpecs.push_back(PartialSpec);
>> + return true;
>> + }
>> +
>> +private:
>> + void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
>> + RecordDecl = RecordDecl->getDefinition();
>> + if (const auto *ClassTemplateSpecDecl =
>> + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
>> + handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecialize
>> dTemplate());
>> + addUSRsOfCtorDtors(RecordDecl);
>> + }
>> +
>> + void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
>> + for (const auto *Specialization : TemplateDecl->specializations())
>> + addUSRsOfCtorDtors(Specialization);
>> +
>> + for (const auto *PartialSpec : PartialSpecs) {
>> + if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
>> + addUSRsOfCtorDtors(PartialSpec);
>> + }
>> + addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
>> + }
>> +
>> + void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
>> + RecordDecl = RecordDecl->getDefinition();
>> +
>> + // Skip if the CXXRecordDecl doesn't have definition.
>> + if (!RecordDecl)
>> + return;
>> +
>> + for (const auto *CtorDecl : RecordDecl->ctors())
>> + USRSet.insert(getUSRForDecl(CtorDecl));
>> +
>> + USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
>> + USRSet.insert(getUSRForDecl(RecordDecl));
>> + }
>> +
>> + void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
>> + USRSet.insert(getUSRForDecl(MethodDecl));
>> + // Recursively visit each OverridenMethod.
>> + for (const auto &OverriddenMethod : MethodDecl->overridden_methods
>> ())
>> + addUSRsOfOverridenFunctions(OverriddenMethod);
>> + }
>> +
>> + bool checkIfOverriddenFunctionAscends(const CXXMethodDecl
>> *MethodDecl) {
>> + for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
>> {
>> + if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
>> + return true;
>> + return checkIfOverriddenFunctionAscends(OverriddenMethod);
>> + }
>> + return false;
>> + }
>> +
>> + const Decl *FoundDecl;
>> + ASTContext &Context;
>> + std::set<std::string> USRSet;
>> + std::vector<const CXXMethodDecl *> OverriddenMethods;
>> + std::vector<const ClassTemplatePartialSpecializationDecl *>
>> PartialSpecs;
>> +};
>> +} // namespace
>> +
>> +class NamedDeclFindingConsumer : public ASTConsumer {
>> +public:
>> + NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
>> + ArrayRef<std::string> QualifiedNames,
>> + std::vector<std::string> &SpellingNames,
>> + std::vector<std::vector<std::string>>
>> &USRList,
>> + bool Force, bool &ErrorOccurred)
>> + : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
>> + SpellingNames(SpellingNames), USRList(USRList), Force(Force),
>> + ErrorOccurred(ErrorOccurred) {}
>> +
>> +private:
>> + bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
>> + unsigned SymbolOffset, const std::string
>> &QualifiedName) {
>> + DiagnosticsEngine &Engine = Context.getDiagnostics();
>> + const FileID MainFileID = SourceMgr.getMainFileID();
>> +
>> + if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
>> + ErrorOccurred = true;
>> + unsigned InvalidOffset = Engine.getCustomDiagID(
>> + DiagnosticsEngine::Error,
>> + "SourceLocation in file %0 at offset %1 is invalid");
>> + Engine.Report(SourceLocation(), InvalidOffset)
>> + << SourceMgr.getFileEntryForID(MainFileID)->getName() <<
>> SymbolOffset;
>> + return false;
>> + }
>> +
>> + const SourceLocation Point = SourceMgr.getLocForStartOfFile
>> (MainFileID)
>> + .getLocWithOffset(SymbolOffset);
>> + const NamedDecl *FoundDecl = QualifiedName.empty()
>> + ? getNamedDeclAt(Context, Point)
>> + : getNamedDeclFor(Context,
>> QualifiedName);
>> +
>> + if (FoundDecl == nullptr) {
>> + if (QualifiedName.empty()) {
>> + FullSourceLoc FullLoc(Point, SourceMgr);
>> + unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
>> + DiagnosticsEngine::Error,
>> + "clang-rename could not find symbol (offset %0)");
>> + Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
>> + ErrorOccurred = true;
>> + return false;
>> + }
>> +
>> + if (Force)
>> + return true;
>> +
>> + unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
>> + DiagnosticsEngine::Error, "clang-rename could not find symbol
>> %0");
>> + Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
>> + ErrorOccurred = true;
>> + return false;
>> + }
>> +
>> + // If FoundDecl is a constructor or destructor, we want to instead
>> take
>> + // the Decl of the corresponding class.
>> + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
>> + FoundDecl = CtorDecl->getParent();
>> + else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(Fo
>> undDecl))
>> + FoundDecl = DtorDecl->getParent();
>> +
>> + SpellingNames.push_back(FoundDecl->getNameAsString());
>> + AdditionalUSRFinder Finder(FoundDecl, Context);
>> + USRList.push_back(Finder.Find());
>> + return true;
>> + }
>> +
>> + void HandleTranslationUnit(ASTContext &Context) override {
>> + const SourceManager &SourceMgr = Context.getSourceManager();
>> + for (unsigned Offset : SymbolOffsets) {
>> + if (!FindSymbol(Context, SourceMgr, Offset, ""))
>> + return;
>> + }
>> + for (const std::string &QualifiedName : QualifiedNames) {
>> + if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
>> + return;
>> + }
>> + }
>> +
>> + ArrayRef<unsigned> SymbolOffsets;
>> + ArrayRef<std::string> QualifiedNames;
>> + std::vector<std::string> &SpellingNames;
>> + std::vector<std::vector<std::string>> &USRList;
>> + bool Force;
>> + bool &ErrorOccurred;
>> +};
>> +
>> +std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
>> + return llvm::make_unique<NamedDeclFindingConsumer>(
>> + SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
>> + ErrorOccurred);
>> +}
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>>
>> Added: cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Re
>> factoring/Rename/USRLocFinder.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (added)
>> +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,509 @@
>> +//===--- USRLocFinder.cpp - Clang refactoring library
>> ---------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief Methods for finding all instances of a USR. Our strategy is
>> very
>> +/// simple; we just compare the USR at every relevant AST node with the
>> one
>> +/// provided.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
>> +#include "clang/AST/ASTContext.h"
>> +#include "clang/AST/RecursiveASTVisitor.h"
>> +#include "clang/Basic/LLVM.h"
>> +#include "clang/Basic/SourceLocation.h"
>> +#include "clang/Basic/SourceManager.h"
>> +#include "clang/Lex/Lexer.h"
>> +#include "clang/Tooling/Core/Lookup.h"
>> +#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include "llvm/Support/Casting.h"
>> +#include <cstddef>
>> +#include <set>
>> +#include <string>
>> +#include <vector>
>> +
>> +using namespace llvm;
>> +
>> +namespace clang {
>> +namespace tooling {
>> +
>> +namespace {
>> +
>> +// \brief This visitor recursively searches for all instances of a USR
>> in a
>> +// translation unit and stores them for later usage.
>> +class USRLocFindingASTVisitor
>> + : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
>> +public:
>> + explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
>> + StringRef PrevName,
>> + const ASTContext &Context)
>> + : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName),
>> Context(Context) {
>> + }
>> +
>> + // Declaration visitors:
>> +
>> + bool VisitCXXConstructorDecl(clang::CXXConstructorDecl
>> *ConstructorDecl) {
>> + for (const auto *Initializer : ConstructorDecl->inits()) {
>> + // Ignore implicit initializers.
>> + if (!Initializer->isWritten())
>> + continue;
>> + if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
>> + if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end())
>> + LocationsFound.push_back(Initializer->getSourceLocation());
>> + }
>> + }
>> + return true;
>> + }
>> +
>> + bool VisitNamedDecl(const NamedDecl *Decl) {
>> + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
>> + checkAndAddLocation(Decl->getLocation());
>> + return true;
>> + }
>> +
>> + // Expression visitors:
>> +
>> + bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
>> + const NamedDecl *Decl = Expr->getFoundDecl();
>> +
>> + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
>> + const SourceManager &Manager = Decl->getASTContext().getSourc
>> eManager();
>> + SourceLocation Location = Manager.getSpellingLoc(Expr->g
>> etLocation());
>> + checkAndAddLocation(Location);
>> + }
>> +
>> + return true;
>> + }
>> +
>> + bool VisitMemberExpr(const MemberExpr *Expr) {
>> + const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
>> + if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
>> + const SourceManager &Manager = Decl->getASTContext().getSourc
>> eManager();
>> + SourceLocation Location = Manager.getSpellingLoc(Expr->g
>> etMemberLoc());
>> + checkAndAddLocation(Location);
>> + }
>> + return true;
>> + }
>> +
>> + // Other visitors:
>> +
>> + bool VisitTypeLoc(const TypeLoc Loc) {
>> + if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl()))
>> !=
>> + USRSet.end())
>> + checkAndAddLocation(Loc.getBeginLoc());
>> + if (const auto *TemplateTypeParm =
>> + dyn_cast<TemplateTypeParmType>(Loc.getType())) {
>> + if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) !=
>> + USRSet.end())
>> + checkAndAddLocation(Loc.getBeginLoc());
>> + }
>> + return true;
>> + }
>> +
>> + // Non-visitors:
>> +
>> + // \brief Returns a list of unique locations. Duplicate or overlapping
>> + // locations are erroneous and should be reported!
>> + const std::vector<clang::SourceLocation> &getLocationsFound() const {
>> + return LocationsFound;
>> + }
>> +
>> + // Namespace traversal:
>> + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
>> + while (NameLoc) {
>> + const NamespaceDecl *Decl =
>> + NameLoc.getNestedNameSpecifier()->getAsNamespace();
>> + if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
>> + checkAndAddLocation(NameLoc.getLocalBeginLoc());
>> + NameLoc = NameLoc.getPrefix();
>> + }
>> + }
>> +
>> +private:
>> + void checkAndAddLocation(SourceLocation Loc) {
>> + const SourceLocation BeginLoc = Loc;
>> + const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
>> + BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
>> + StringRef TokenName =
>> + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc,
>> EndLoc),
>> + Context.getSourceManager(),
>> Context.getLangOpts());
>> + size_t Offset = TokenName.find(PrevName);
>> +
>> + // The token of the source location we find actually has the old
>> + // name.
>> + if (Offset != StringRef::npos)
>> + LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
>> + }
>> +
>> + const std::set<std::string> USRSet;
>> + const std::string PrevName;
>> + std::vector<clang::SourceLocation> LocationsFound;
>> + const ASTContext &Context;
>> +};
>> +
>> +SourceLocation StartLocationForType(TypeLoc TL) {
>> + // For elaborated types (e.g. `struct a::A`) we want the portion after
>> the
>> + // `struct` but including the namespace qualifier, `a::`.
>> + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
>> + NestedNameSpecifierLoc NestedNameSpecifier =
>> + ElaboratedTypeLoc.getQualifierLoc();
>> + if (NestedNameSpecifier.getNestedNameSpecifier())
>> + return NestedNameSpecifier.getBeginLoc();
>> + TL = TL.getNextTypeLoc();
>> + }
>> + return TL.getLocStart();
>> +}
>> +
>> +SourceLocation EndLocationForType(TypeLoc TL) {
>> + // Dig past any namespace or keyword qualifications.
>> + while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
>> + TL.getTypeLocClass() == TypeLoc::Qualified)
>> + TL = TL.getNextTypeLoc();
>> +
>> + // The location for template specializations (e.g. Foo<int>) includes
>> the
>> + // templated types in its location range. We want to restrict this to
>> just
>> + // before the `<` character.
>> + if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
>> + return TL.castAs<TemplateSpecializationTypeLoc>()
>> + .getLAngleLoc()
>> + .getLocWithOffset(-1);
>> + }
>> + return TL.getEndLoc();
>> +}
>> +
>> +NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
>> + // Dig past any keyword qualifications.
>> + while (TL.getTypeLocClass() == TypeLoc::Qualified)
>> + TL = TL.getNextTypeLoc();
>> +
>> + // For elaborated types (e.g. `struct a::A`) we want the portion after
>> the
>> + // `struct` but including the namespace qualifier, `a::`.
>> + if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
>> + return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
>> + return nullptr;
>> +}
>> +
>> +// Find all locations identified by the given USRs for rename.
>> +//
>> +// This class will traverse the AST and find every AST node whose USR is
>> in the
>> +// given USRs' set.
>> +class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
>> +public:
>> + RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
>> + : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
>> +
>> + // A structure records all information of a symbol reference being
>> renamed.
>> + // We try to add as few prefix qualifiers as possible.
>> + struct RenameInfo {
>> + // The begin location of a symbol being renamed.
>> + SourceLocation Begin;
>> + // The end location of a symbol being renamed.
>> + SourceLocation End;
>> + // The declaration of a symbol being renamed (can be nullptr).
>> + const NamedDecl *FromDecl;
>> + // The declaration in which the nested name is contained (can be
>> nullptr).
>> + const Decl *Context;
>> + // The nested name being replaced (can be nullptr).
>> + const NestedNameSpecifier *Specifier;
>> + };
>> +
>> + // FIXME: Currently, prefix qualifiers will be added to the renamed
>> symbol
>> + // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming
>> + // "a::Foo" to "b::Bar").
>> + // For renaming declarations/definitions, prefix qualifiers should be
>> filtered
>> + // out.
>> + bool VisitNamedDecl(const NamedDecl *Decl) {
>> + // UsingDecl has been handled in other place.
>> + if (llvm::isa<UsingDecl>(Decl))
>> + return true;
>> +
>> + // DestructorDecl has been handled in Typeloc.
>> + if (llvm::isa<CXXDestructorDecl>(Decl))
>> + return true;
>> +
>> + if (Decl->isImplicit())
>> + return true;
>> +
>> + if (isInUSRSet(Decl)) {
>> + RenameInfo Info = {Decl->getLocation(), Decl->getLocation(),
>> nullptr,
>> + nullptr, nullptr};
>> + RenameInfos.push_back(Info);
>> + }
>> + return true;
>> + }
>> +
>> + bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
>> + const NamedDecl *Decl = Expr->getFoundDecl();
>> + if (isInUSRSet(Decl)) {
>> + RenameInfo Info = {Expr->getSourceRange().getBegin(),
>> + Expr->getSourceRange().getEnd(), Decl,
>> + getClosestAncestorDecl(*Expr),
>> Expr->getQualifier()};
>> + RenameInfos.push_back(Info);
>> + }
>> +
>> + return true;
>> + }
>> +
>> + bool VisitUsingDecl(const UsingDecl *Using) {
>> + for (const auto *UsingShadow : Using->shadows()) {
>> + if (isInUSRSet(UsingShadow->getTargetDecl())) {
>> + UsingDecls.push_back(Using);
>> + break;
>> + }
>> + }
>> + return true;
>> + }
>> +
>> + bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc
>> NestedLoc) {
>> + if (!NestedLoc.getNestedNameSpecifier()->getAsType())
>> + return true;
>> + if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
>> + return true;
>> +
>> + if (const auto *TargetDecl =
>> + getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
>> + if (isInUSRSet(TargetDecl)) {
>> + RenameInfo Info = {NestedLoc.getBeginLoc(),
>> + EndLocationForType(NestedLoc.getTypeLoc()),
>> + TargetDecl, getClosestAncestorDecl(NestedL
>> oc),
>> + NestedLoc.getNestedNameSpecif
>> ier()->getPrefix()};
>> + RenameInfos.push_back(Info);
>> + }
>> + }
>> + return true;
>> + }
>> +
>> + bool VisitTypeLoc(TypeLoc Loc) {
>> + if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
>> + return true;
>> +
>> + auto Parents = Context.getParents(Loc);
>> + TypeLoc ParentTypeLoc;
>> + if (!Parents.empty()) {
>> + // Handle cases of nested name specificier locations.
>> + //
>> + // The VisitNestedNameSpecifierLoc interface is not impelmented in
>> + // RecursiveASTVisitor, we have to handle it explicitly.
>> + if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
>> + VisitNestedNameSpecifierLocations(*NSL);
>> + return true;
>> + }
>> +
>> + if (const auto *TL = Parents[0].get<TypeLoc>())
>> + ParentTypeLoc = *TL;
>> + }
>> +
>> + // Handle the outermost TypeLoc which is directly linked to the
>> interesting
>> + // declaration and don't handle nested name specifier locations.
>> + if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
>> + if (isInUSRSet(TargetDecl)) {
>> + // Only handle the outermost typeLoc.
>> + //
>> + // For a type like "a::Foo", there will be two typeLocs for it.
>> + // One ElaboratedType, the other is RecordType:
>> + //
>> + // ElaboratedType 0x33b9390 'a::Foo' sugar
>> + // `-RecordType 0x338fef0 'class a::Foo'
>> + // `-CXXRecord 0x338fe58 'Foo'
>> + //
>> + // Skip if this is an inner typeLoc.
>> + if (!ParentTypeLoc.isNull() &&
>> + isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
>> + return true;
>> + RenameInfo Info = {StartLocationForType(Loc),
>> EndLocationForType(Loc),
>> + TargetDecl, getClosestAncestorDecl(Loc),
>> + GetNestedNameForType(Loc)};
>> + RenameInfos.push_back(Info);
>> + return true;
>> + }
>> + }
>> +
>> + // Handle specific template class specialiation cases.
>> + if (const auto *TemplateSpecType =
>> + dyn_cast<TemplateSpecializationType>(Loc.getType())) {
>> + TypeLoc TargetLoc = Loc;
>> + if (!ParentTypeLoc.isNull()) {
>> + if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
>> + TargetLoc = ParentTypeLoc;
>> + }
>> +
>> + if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl()))
>> {
>> + TypeLoc TargetLoc = Loc;
>> + // FIXME: Find a better way to handle this case.
>> + // For the qualified template class specification type like
>> + // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent
>> typeLoc
>> + // (ElaboratedType) of the TemplateSpecializationType in order to
>> + // catch the prefix qualifiers "ns::".
>> + if (!ParentTypeLoc.isNull() &&
>> + llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
>> + TargetLoc = ParentTypeLoc;
>> + RenameInfo Info = {
>> + StartLocationForType(TargetLoc),
>> EndLocationForType(TargetLoc),
>> + TemplateSpecType->getTemplateName().getAsTemplateDecl(),
>> + getClosestAncestorDecl(
>> + ast_type_traits::DynTypedNode::create(TargetLoc)),
>> + GetNestedNameForType(TargetLoc)};
>> + RenameInfos.push_back(Info);
>> + }
>> + }
>> + return true;
>> + }
>> +
>> + // Returns a list of RenameInfo.
>> + const std::vector<RenameInfo> &getRenameInfos() const { return
>> RenameInfos; }
>> +
>> + // Returns a list of using declarations which are needed to update.
>> + const std::vector<const UsingDecl *> &getUsingDecls() const {
>> + return UsingDecls;
>> + }
>> +
>> +private:
>> + // FIXME: This method may not be suitable for renaming other types
>> like alias
>> + // types. Need to figure out a way to handle it.
>> + bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const {
>> + while (!TL.isNull()) {
>> + // SubstTemplateTypeParm is the TypeLocation class for a
>> substituted type
>> + // inside a template expansion so we ignore these. For example:
>> + //
>> + // template<typename T> struct S {
>> + // T t; // <-- this T becomes a TypeLoc(int) with class
>> + // // SubstTemplateTypeParm when S<int> is instantiated
>> + // }
>> + if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
>> + return true;
>> +
>> + // Typedef is the TypeLocation class for a type which is a typedef
>> to the
>> + // type we want to replace. We ignore the use of the typedef as
>> we will
>> + // replace the definition of it. For example:
>> + //
>> + // typedef int T;
>> + // T a; // <--- This T is a TypeLoc(int) with class Typedef.
>> + if (TL.getTypeLocClass() == TypeLoc::Typedef)
>> + return true;
>> + TL = TL.getNextTypeLoc();
>> + }
>> + return false;
>> + }
>> +
>> + // Get the supported declaration from a given typeLoc. If the
>> declaration type
>> + // is not supported, returns nullptr.
>> + //
>> + // FIXME: support more types, e.g. enum, type alias.
>> + const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
>> + if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
>> + return RD;
>> + return nullptr;
>> + }
>> +
>> + // Get the closest ancester which is a declaration of a given AST node.
>> + template <typename ASTNodeType>
>> + const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
>> + auto Parents = Context.getParents(Node);
>> + // FIXME: figure out how to handle it when there are multiple
>> parents.
>> + if (Parents.size() != 1)
>> + return nullptr;
>> + if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
>> + Parents[0].getNodeKind()))
>> + return Parents[0].template get<Decl>();
>> + return getClosestAncestorDecl(Parents[0]);
>> + }
>> +
>> + // Get the parent typeLoc of a given typeLoc. If there is no such
>> parent,
>> + // return nullptr.
>> + const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
>> + auto Parents = Context.getParents(Loc);
>> + // FIXME: figure out how to handle it when there are multiple
>> parents.
>> + if (Parents.size() != 1)
>> + return nullptr;
>> + return Parents[0].get<TypeLoc>();
>> + }
>> +
>> + // Check whether the USR of a given Decl is in the USRSet.
>> + bool isInUSRSet(const Decl *Decl) const {
>> + auto USR = getUSRForDecl(Decl);
>> + if (USR.empty())
>> + return false;
>> + return llvm::is_contained(USRSet, USR);
>> + }
>> +
>> + const std::set<std::string> USRSet;
>> + ASTContext &Context;
>> + std::vector<RenameInfo> RenameInfos;
>> + // Record all interested using declarations which contains the
>> using-shadow
>> + // declarations of the symbol declarations being renamed.
>> + std::vector<const UsingDecl *> UsingDecls;
>> +};
>> +
>> +} // namespace
>> +
>> +std::vector<SourceLocation>
>> +getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef
>> PrevName,
>> + Decl *Decl) {
>> + USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
>> + Visitor.TraverseDecl(Decl);
>> + NestedNameSpecifierLocFinder Finder(Decl->getASTContext());
>> +
>> + for (const auto &Location : Finder.getNestedNameSpecifierLocations())
>> + Visitor.handleNestedNameSpecifierLoc(Location);
>> +
>> + return Visitor.getLocationsFound();
>> +}
>> +
>> +std::vector<tooling::AtomicChange>
>> +createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
>> + llvm::StringRef NewName, Decl
>> *TranslationUnitDecl) {
>> + RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
>> + Finder.TraverseDecl(TranslationUnitDecl);
>> +
>> + const SourceManager &SM =
>> + TranslationUnitDecl->getASTContext().getSourceManager();
>> +
>> + std::vector<tooling::AtomicChange> AtomicChanges;
>> + auto Replace = [&](SourceLocation Start, SourceLocation End,
>> + llvm::StringRef Text) {
>> + tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM,
>> Start);
>> + llvm::Error Err = ReplaceChange.replace(
>> + SM, CharSourceRange::getTokenRange(Start, End), Text);
>> + if (Err) {
>> + llvm::errs() << "Faile to add replacement to AtomicChange: "
>> + << llvm::toString(std::move(Err)) << "\n";
>> + return;
>> + }
>> + AtomicChanges.push_back(std::move(ReplaceChange));
>> + };
>> +
>> + for (const auto &RenameInfo : Finder.getRenameInfos()) {
>> + std::string ReplacedName = NewName.str();
>> + if (RenameInfo.FromDecl && RenameInfo.Context) {
>> + if (!llvm::isa<clang::TranslationUnitDecl>(
>> + RenameInfo.Context->getDeclContext())) {
>> + ReplacedName = tooling::replaceNestedName(
>> + RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
>> + RenameInfo.FromDecl,
>> + NewName.startswith("::") ? NewName.str() : ("::" +
>> NewName).str());
>> + }
>> + }
>> + // If the NewName contains leading "::", add it back.
>> + if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
>> + ReplacedName = NewName.str();
>> + Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
>> + }
>> +
>> + // Hanlde using declarations explicitly as "using a::Foo" don't trigger
>> + // typeLoc for "a::Foo".
>> + for (const auto *Using : Finder.getUsingDecls())
>> + Replace(Using->getLocStart(), Using->getLocEnd(), "using " +
>> NewName.str());
>> +
>> + return AtomicChanges;
>> +}
>> +
>> +} // end namespace tooling
>> +} // end namespace clang
>>
>> Modified: cfe/trunk/test/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CMakeList
>> s.txt?rev=306840&r1=306839&r2=306840&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/CMakeLists.txt (original)
>> +++ cfe/trunk/test/CMakeLists.txt Fri Jun 30 09:36:09 2017
>> @@ -47,6 +47,7 @@ list(APPEND CLANG_TEST_DEPS
>> clang-tblgen
>> clang-offload-bundler
>> clang-import-test
>> + clang-rename
>> )
>>
>> if(CLANG_ENABLE_STATIC_ANALYZER)
>>
>> Added: cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassAsTemplateArgument.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,21 @@
>> +class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {};
>> +
>> +template <typename T>
>> +void func() {}
>> +
>> +template <typename T>
>> +class Baz {};
>> +
>> +int main() {
>> + func<Foo>(); // CHECK: func<Bar>();
>> + Baz<Foo> /* Test 2 */ obj; // CHECK: Baz<Bar> /* Test 2 */ obj;
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/ClassFindByName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassFindByName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassFindByName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassFindByName.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,10 @@
>> +class Foo { // CHECK: class Bar {
>> +};
>> +
>> +int main() {
>> + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed
>> 's,//.*,,' | FileCheck %s
>>
>> Added: cfe/trunk/test/clang-rename/ClassReplacements.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassReplacements.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassReplacements.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassReplacements.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,11 @@
>> +// RUN: rm -rf %t
>> +// RUN: mkdir -p %t/fixes
>> +// RUN: cat %s > %t.cpp
>> +// RUN: clang-rename -offset=254 -new-name=Bar
>> -export-fixes=%t/fixes/clang-rename.yaml %t.cpp --
>> +// RUN: clang-apply-replacements %t
>> +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
>> +
>> +class Foo {}; // CHECK: class Bar {};
>> +
>> +// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when
>> changing
>> +// this file.
>>
>> Added: cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassSimpleRenaming.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,14 @@
>> +class Foo /* Test 1 */ { // CHECK: class Bar /* Test 1 */ {
>> +public:
>> + void foo(int x);
>> +};
>> +
>> +void Foo::foo(int x) /* Test 2 */ {} // CHECK: void Bar::foo(int x) /*
>> Test 2 */ {}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/ClassTestMulti.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassTestMulti.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassTestMulti.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassTestMulti.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,11 @@
>> +class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ {
>> +};
>> +
>> +class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ {
>> +};
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2
>> %s -- | sed 's,//.*,,' | FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ClassTestMultiByName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,8 @@
>> +class Foo1 { // CHECK: class Bar1
>> +};
>> +
>> +class Foo2 { // CHECK: class Bar2
>> +};
>> +
>> +// Test 1.
>> +// RUN: clang-rename -qualified-name=Foo1 -new-name=Bar1
>> -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s
>>
>> Added: cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ComplexFunctionOverride.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,47 @@
>> +struct A {
>> + virtual void foo() {} /* Test 1 */ // CHECK: virtual void bar() {}
>> +};
>> +
>> +struct B : A {
>> + void foo() override {} /* Test 2 */ // CHECK: void bar() override {}
>> +};
>> +
>> +struct C : B {
>> + void foo() override {} /* Test 3 */ // CHECK: void bar() override {}
>> +};
>> +
>> +struct D : B {
>> + void foo() override {} /* Test 4 */ // CHECK: void bar() override {}
>> +};
>> +
>> +struct E : D {
>> + void foo() override {} /* Test 5 */ // CHECK: void bar() override {}
>> +};
>> +
>> +int main() {
>> + A a;
>> + a.foo(); // CHECK: a.bar();
>> + B b;
>> + b.foo(); // CHECK: b.bar();
>> + C c;
>> + c.foo(); // CHECK: c.bar();
>> + D d;
>> + d.foo(); // CHECK: d.bar();
>> + E e;
>> + e.foo(); // CHECK: e.bar();
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 4.
>> +// RUN: clang-rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 5.
>> +// RUN: clang-rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/ComplicatedClassType.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/ComplicatedClassType.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/ComplicatedClassType.cpp (added)
>> +++ cfe/trunk/test/clang-rename/ComplicatedClassType.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,63 @@
>> +// Forward declaration.
>> +class Foo; /* Test 1 */ // CHECK: class Bar; /* Test 1 */
>> +
>> +class Baz {
>> + virtual int getValue() const = 0;
>> +};
>> +
>> +class Foo : public Baz { /* Test 2 */// CHECK: class Bar : public Baz {
>> +public:
>> + Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) :
>> x(value) {}
>> +
>> + Foo &operator++(int) { // CHECK: Bar &operator++(int) {
>> + x++;
>> + return *this;
>> + }
>> +
>> + bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const
>> &rhs) {
>> + return this->x < rhs.x;
>> + }
>> +
>> + int getValue() const {
>> + return 0;
>> + }
>> +
>> +private:
>> + int x;
>> +};
>> +
>> +int main() {
>> + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
>> + Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10);
>> + for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it <
>> Variable; it++) {
>> + }
>> + const Foo *C = new Foo(); // CHECK: const Bar *C = new Bar();
>> + const_cast<Foo *>(C)->getValue(); // CHECK: const_cast<Bar
>> *>(C)->getValue();
>> + Foo foo; // CHECK: Bar foo;
>> + const Baz &BazReference = foo;
>> + const Baz *BazPointer = &foo;
>> + dynamic_cast<const Foo &>(BazReference).getValue(); /* Test 3 */
>> // CHECK: dynamic_cast<const Bar &>(BazReference).getValue();
>> + dynamic_cast<const Foo *>(BazPointer)->getValue(); /* Test 4 */
>> // CHECK: dynamic_cast<const Bar *>(BazPointer)->getValue();
>> + reinterpret_cast<const Foo *>(BazPointer)->getValue(); /* Test 5 */
>> // CHECK: reinterpret_cast<const Bar *>(BazPointer)->getValue();
>> + static_cast<const Foo &>(BazReference).getValue(); /* Test 6 */
>> // CHECK: static_cast<const Bar &>(BazReference).getValue();
>> + static_cast<const Foo *>(BazPointer)->getValue(); /* Test 7 */
>> // CHECK: static_cast<const Bar *>(BazPointer)->getValue();
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=30 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=155 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=1133 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 4.
>> +// RUN: clang-rename -offset=1266 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 5.
>> +// RUN: clang-rename -offset=1402 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 6.
>> +// RUN: clang-rename -offset=1533 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 7.
>> +// RUN: clang-rename -offset=1665 -new-name=Bar %s -- -frtti | sed
>> 's,//.*,,' | FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/Ctor.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Ctor.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Ctor.cpp (added)
>> +++ cfe/trunk/test/clang-rename/Ctor.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,14 @@
>> +class Foo { // CHECK: class Bar {
>> +public:
>> + Foo(); /* Test 1 */ // CHECK: Bar();
>> +};
>> +
>> +Foo::Foo() /* Test 2 */ {} // CHECK: Bar::Bar() /* Test 2 */ {}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/CtorInitializer.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/CtorInitializer.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/CtorInitializer.cpp (added)
>> +++ cfe/trunk/test/clang-rename/CtorInitializer.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,17 @@
>> +class Baz {};
>> +
>> +class Qux {
>> + Baz Foo; /* Test 1 */ // CHECK: Baz Bar;
>> +public:
>> + Qux();
>> +};
>> +
>> +Qux::Qux() : Foo() /* Test 2 */ {} // CHECK: Qux::Qux() : Bar() /*
>> Test 2 */ {}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/DeclRefExpr.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/DeclRefExpr.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/DeclRefExpr.cpp (added)
>> +++ cfe/trunk/test/clang-rename/DeclRefExpr.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,24 @@
>> +class C {
>> +public:
>> + static int Foo; /* Test 1 */ // CHECK: static int Bar;
>> +};
>> +
>> +int foo(int x) { return 0; }
>> +#define MACRO(a) foo(a)
>> +
>> +int main() {
>> + C::Foo = 1; /* Test 2 */ // CHECK: C::Bar = 1;
>> + MACRO(C::Foo); // CHECK: MACRO(C::Bar);
>> + int y = C::Foo; /* Test 3 */ // CHECK: int y = C::Bar;
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/Field.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Field.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Field.cpp (added)
>> +++ cfe/trunk/test/clang-rename/Field.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,15 @@
>> +class Baz {
>> + int Foo; /* Test 1 */ // CHECK: int Bar;
>> +public:
>> + Baz();
>> +};
>> +
>> +Baz::Baz() : Foo(0) /* Test 2 */ {} // CHECK: Baz::Baz() : Bar(0)
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=89 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/FunctionMacro.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/FunctionMacro.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/FunctionMacro.cpp (added)
>> +++ cfe/trunk/test/clang-rename/FunctionMacro.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,20 @@
>> +#define moo foo // CHECK: #define moo macro_function
>> +
>> +int foo() /* Test 1 */ { // CHECK: int macro_function() /* Test 1 */ {
>> + return 42;
>> +}
>> +
>> +void boo(int value) {}
>> +
>> +void qoo() {
>> + foo(); // CHECK: macro_function();
>> + boo(foo()); // CHECK: boo(macro_function());
>> + moo();
>> + boo(moo());
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=68 -new-name=macro_function %s -- | sed
>> 's,//.*,,' | FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/FunctionOverride.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/FunctionOverride.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/FunctionOverride.cpp (added)
>> +++ cfe/trunk/test/clang-rename/FunctionOverride.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,13 @@
>> +class A { virtual void foo(); /* Test 1 */ }; // CHECK: class A {
>> virtual void bar();
>> +class B : public A { void foo(); /* Test 2 */ }; // CHECK: class B :
>> public A { void bar();
>> +class C : public B { void foo(); /* Test 3 */ }; // CHECK: class C :
>> public B { void bar();
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/FunctionWithClassFindByName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp Fri Jun
>> 30 09:36:09 2017
>> @@ -0,0 +1,12 @@
>> +void foo() {
>> +}
>> +
>> +class Foo { // CHECK: class Bar
>> +};
>> +
>> +int main() {
>> + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
>> + return 0;
>> +}
>> +
>> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed
>> 's,//.*,,' | FileCheck %s
>>
>> Added: cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/IncludeHeaderWithSymbol.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp (added)
>> +++ cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,10 @@
>> +#include "Inputs/HeaderWithSymbol.h"
>> +
>> +int main() {
>> + return 0; // CHECK: {{^ return 0;}}
>> +}
>> +
>> +// Test 1.
>> +// The file IncludeHeaderWithSymbol.cpp doesn't contain the symbol Foo
>> +// and is expected to be written to stdout without modifications
>> +// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | FileCheck
>> %s
>>
>> Added: cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Inputs/HeaderWithSymbol.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h (added)
>> +++ cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1 @@
>> +struct Foo {};
>>
>> Added: cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Inputs/OffsetToNewName.yaml?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml (added)
>> +++ cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,6 @@
>> +---
>> +- Offset: 6
>> + NewName: Bar1
>> +- Offset: 44
>> + NewName: Bar2
>> +...
>>
>> Added: cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Inputs/QualifiedNameToNewName.yaml?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
>> (added)
>> +++ cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml Fri
>> Jun 30 09:36:09 2017
>> @@ -0,0 +1,6 @@
>> +---
>> +- QualifiedName: Foo1
>> + NewName: Bar1
>> +- QualifiedName: Foo2
>> + NewName: Bar2
>> +...
>>
>> Added: cfe/trunk/test/clang-rename/InvalidNewName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/InvalidNewName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/InvalidNewName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/InvalidNewName.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,2 @@
>> +// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck
>> %s
>> +// CHECK: ERROR: new name is not a valid identifier in C++17.
>>
>> Added: cfe/trunk/test/clang-rename/InvalidOffset.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/InvalidOffset.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/InvalidOffset.cpp (added)
>> +++ cfe/trunk/test/clang-rename/InvalidOffset.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,9 @@
>> +#include "Inputs/HeaderWithSymbol.h"
>> +#define FOO int bar;
>> +FOO
>> +
>> +int foo;
>> +
>> +// RUN: not clang-rename -new-name=qux -offset=259 %s -- 2>&1 |
>> FileCheck %s
>> +// CHECK-NOT: CHECK
>> +// CHECK: error: SourceLocation in file {{.*}}InvalidOffset.cpp at
>> offset 259 is invalid
>>
>> Added: cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/InvalidQualifiedName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,4 @@
>> +struct S {
>> +};
>> +
>> +// RUN: clang-rename -force -qualified-name S2 -new-name=T %s --
>>
>> Added: cfe/trunk/test/clang-rename/MemberExprMacro.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/MemberExprMacro.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/MemberExprMacro.cpp (added)
>> +++ cfe/trunk/test/clang-rename/MemberExprMacro.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,22 @@
>> +class Baz {
>> +public:
>> + int Foo; /* Test 1 */ // CHECK: int Bar;
>> +};
>> +
>> +int qux(int x) { return 0; }
>> +#define MACRO(a) qux(a)
>> +
>> +int main() {
>> + Baz baz;
>> + baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1;
>> + MACRO(baz.Foo); // CHECK: MACRO(baz.Bar);
>> + int y = baz.Foo; // CHECK: int y = baz.Bar;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/Namespace.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Namespace.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Namespace.cpp (added)
>> +++ cfe/trunk/test/clang-rename/Namespace.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,13 @@
>> +namespace gcc /* Test 1 */ { // CHECK: namespace clang /* Test 1 */ {
>> + int x;
>> +}
>> +
>> +void boo() {
>> + gcc::x = 42; // CHECK: clang::x = 42;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/NoNewName.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/NoNewName.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/NoNewName.cpp (added)
>> +++ cfe/trunk/test/clang-rename/NoNewName.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,4 @@
>> +// Check for an error while -new-name argument has not been passed to
>> +// clang-rename.
>> +// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s
>> +// CHECK: clang-rename: -new-name must be specified.
>>
>> Added: cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/TemplateClassInstantiation.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp (added)
>> +++ cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp Fri Jun
>> 30 09:36:09 2017
>> @@ -0,0 +1,42 @@
>> +template <typename T>
>> +class Foo { /* Test 1 */ // CHECK: class Bar { /* Test 1 */
>> +public:
>> + T foo(T arg, T& ref, T* ptr) {
>> + T value;
>> + int number = 42;
>> + value = (T)number;
>> + value = static_cast<T>(number);
>> + return value;
>> + }
>> + static void foo(T value) {}
>> + T member;
>> +};
>> +
>> +template <typename T>
>> +void func() {
>> + Foo<T> obj; /* Test 2 */ // CHECK: Bar<T> obj;
>> + obj.member = T();
>> + Foo<T>::foo(); // CHECK: Bar<T>::foo();
>> +}
>> +
>> +int main() {
>> + Foo<int> i; /* Test 3 */ // CHECK: Bar<int> i;
>> + i.member = 0;
>> + Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);
>> +
>> + Foo<bool> b; // CHECK: Bar<bool> b;
>> + b.member = false;
>> + Foo<bool>::foo(false); // CHECK: Bar<bool>::foo(false);
>> +
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=29 -new-name=Bar %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=324 -new-name=Bar %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=463 -new-name=Bar %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/TemplateTypename.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/TemplateTypename.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/TemplateTypename.cpp (added)
>> +++ cfe/trunk/test/clang-rename/TemplateTypename.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,24 @@
>> +template <typename T /* Test 1 */> // CHECK: template
>> <typename U /* Test 1 */>
>> +class Foo {
>> +T foo(T arg, T& ref, T* /* Test 2 */ ptr) { // CHECK: U foo(U arg,
>> U& ref, U* /* Test 2 */ ptr) {
>> + T value; // CHECK: U value;
>> + int number = 42;
>> + value = (T)number; // CHECK: value =
>> (U)number;
>> + value = static_cast<T /* Test 3 */>(number); // CHECK: value =
>> static_cast<U /* Test 3 */>(number);
>> + return value;
>> +}
>> +
>> +static void foo(T value) {} // CHECK: static void
>> foo(U value) {}
>> +
>> +T member; // CHECK: U member;
>> +};
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=19 -new-name=U %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=126 -new-name=U %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=392 -new-name=U %s --
>> -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'T.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/TemplatedClassFunction.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp (added)
>> +++ cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,22 @@
>> +template <typename T>
>> +class A {
>> +public:
>> + void foo() /* Test 1 */ {} // CHECK: void bar() /* Test 1 */ {}
>> +};
>> +
>> +int main(int argc, char **argv) {
>> + A<int> a;
>> + a.foo(); /* Test 2 */ // CHECK: a.bar() /* Test 2 */
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-refactor rename -offset=48 -new-name=bar %s -- | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 2.
>> +// RUN: clang-refactor rename -offset=162 -new-name=bar %s -- | sed
>> 's,//.*,,' | FileCheck %s
>> +//
>> +// Currently unsupported test.
>> +// XFAIL: *
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/UserDefinedConversion.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/UserDefinedConversion.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/UserDefinedConversion.cpp (added)
>> +++ cfe/trunk/test/clang-rename/UserDefinedConversion.cpp Fri Jun 30
>> 09:36:09 2017
>> @@ -0,0 +1,26 @@
>> +class Foo { /* Test 1 */ // CHECK: class Bar {
>> +public:
>> + Foo() {} // CHECK: Bar() {}
>> +};
>> +
>> +class Baz {
>> +public:
>> + operator Foo() /* Test 2 */ const { // CHECK: operator Bar() /*
>> Test 2 */ const {
>> + Foo foo; // CHECK: Bar foo;
>> + return foo;
>> + }
>> +};
>> +
>> +int main() {
>> + Baz boo;
>> + Foo foo = static_cast<Foo>(boo); // CHECK: Bar foo =
>> static_cast<Bar>(boo);
>> + return 0;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/Variable.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/Variable.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/Variable.cpp (added)
>> +++ cfe/trunk/test/clang-rename/Variable.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,33 @@
>> +#define NAMESPACE namespace A
>> +NAMESPACE {
>> +int Foo; /* Test 1 */ // CHECK: int Bar;
>> +}
>> +int Foo; // CHECK: int Foo;
>> +int Qux = Foo; // CHECK: int Qux = Foo;
>> +int Baz = A::Foo; /* Test 2 */ // CHECK: Baz = A::Bar;
>> +void fun() {
>> + struct {
>> + int Foo; // CHECK: int Foo;
>> + } b = {100};
>> + int Foo = 100; // CHECK: int Foo = 100;
>> + Baz = Foo; // CHECK: Baz = Foo;
>> + {
>> + extern int Foo; // CHECK: extern int Foo;
>> + Baz = Foo; // CHECK: Baz = Foo;
>> + Foo = A::Foo /* Test 3 */ + Baz; // CHECK: Foo = A::Bar /* Test 3
>> */ + Baz;
>> + A::Foo /* Test 4 */ = b.Foo; // CHECK: A::Bar /* Test 4 */ =
>> b.Foo;
>> + }
>> + Foo = b.Foo; // Foo = b.Foo;
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=46 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=234 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=641 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 4.
>> +// RUN: clang-rename -offset=716 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/VariableMacro.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/VariableMacro.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/VariableMacro.cpp (added)
>> +++ cfe/trunk/test/clang-rename/VariableMacro.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,21 @@
>> +#define Baz Foo // CHECK: #define Baz Bar
>> +
>> +void foo(int value) {}
>> +
>> +void macro() {
>> + int Foo; /* Test 1 */ // CHECK: int Bar;
>> + Foo = 42; /* Test 2 */ // CHECK: Bar = 42;
>> + Baz -= 0;
>> + foo(Foo); /* Test 3 */ // CHECK: foo(Bar);
>> + foo(Baz);
>> +}
>> +
>> +// Test 1.
>> +// RUN: clang-rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +// Test 3.
>> +// RUN: clang-rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' |
>> FileCheck %s
>> +
>> +// To find offsets after modifying the file, use:
>> +// grep -Ubo 'Foo.*' <file>
>>
>> Added: cfe/trunk/test/clang-rename/YAMLInput.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-ren
>> ame/YAMLInput.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/test/clang-rename/YAMLInput.cpp (added)
>> +++ cfe/trunk/test/clang-rename/YAMLInput.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,10 @@
>> +class Foo1 { // CHECK: class Bar1
>> +};
>> +
>> +class Foo2 { // CHECK: class Bar2
>> +};
>> +
>> +// Test 1.
>> +// RUN: clang-rename -input %S/Inputs/OffsetToNewName.yaml %s -- | sed
>> 's,//.*,,' | FileCheck %s
>> +// Test 2.
>> +// RUN: clang-rename -input %S/Inputs/QualifiedNameToNewName.yaml %s --
>> | sed 's,//.*,,' | FileCheck %s
>>
>> Modified: cfe/trunk/tools/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CMakeLis
>> ts.txt?rev=306840&r1=306839&r2=306840&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/tools/CMakeLists.txt (original)
>> +++ cfe/trunk/tools/CMakeLists.txt Fri Jun 30 09:36:09 2017
>> @@ -10,6 +10,8 @@ add_clang_subdirectory(clang-offload-bun
>>
>> add_clang_subdirectory(c-index-test)
>>
>> +add_clang_subdirectory(clang-rename)
>> +
>> if(CLANG_ENABLE_ARCMT)
>> add_clang_subdirectory(arcmt-test)
>> add_clang_subdirectory(c-arcmt-test)
>>
>> Added: cfe/trunk/tools/clang-rename/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-re
>> name/CMakeLists.txt?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/tools/clang-rename/CMakeLists.txt (added)
>> +++ cfe/trunk/tools/clang-rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,19 @@
>> +add_clang_executable(clang-rename ClangRename.cpp)
>> +
>> +target_link_libraries(clang-rename
>> + clangBasic
>> + clangFrontend
>> + clangRewrite
>> + clangTooling
>> + clangToolingCore
>> + clangToolingRefactor
>> + )
>> +
>> +install(TARGETS clang-rename RUNTIME DESTINATION bin)
>> +
>> +install(PROGRAMS clang-rename.py
>> + DESTINATION share/clang
>> + COMPONENT clang-rename)
>> +install(PROGRAMS clang-rename.el
>> + DESTINATION share/clang
>> + COMPONENT clang-rename)
>>
>> Added: cfe/trunk/tools/clang-rename/ClangRename.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-re
>> name/ClangRename.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/tools/clang-rename/ClangRename.cpp (added)
>> +++ cfe/trunk/tools/clang-rename/ClangRename.cpp Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,240 @@
>> +//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool
>> -----===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +///
>> +/// \file
>> +/// \brief This file implements a clang-rename tool that automatically
>> finds and
>> +/// renames symbols in C++ code.
>> +///
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "clang/Basic/Diagnostic.h"
>> +#include "clang/Basic/DiagnosticOptions.h"
>> +#include "clang/Basic/FileManager.h"
>> +#include "clang/Basic/IdentifierTable.h"
>> +#include "clang/Basic/LangOptions.h"
>> +#include "clang/Basic/SourceManager.h"
>> +#include "clang/Basic/TokenKinds.h"
>> +#include "clang/Frontend/TextDiagnosticPrinter.h"
>> +#include "clang/Rewrite/Core/Rewriter.h"
>> +#include "clang/Tooling/CommonOptionsParser.h"
>> +#include "clang/Tooling/Refactoring.h"
>> +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
>> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
>> +#include "clang/Tooling/ReplacementsYaml.h"
>> +#include "clang/Tooling/Tooling.h"
>> +#include "llvm/ADT/IntrusiveRefCntPtr.h"
>> +#include "llvm/Support/CommandLine.h"
>> +#include "llvm/Support/FileSystem.h"
>> +#include "llvm/Support/YAMLTraits.h"
>> +#include "llvm/Support/raw_ostream.h"
>> +#include <cstdlib>
>> +#include <string>
>> +#include <system_error>
>> +
>> +using namespace llvm;
>> +using namespace clang;
>> +
>> +/// \brief An oldname -> newname rename.
>> +struct RenameAllInfo {
>> + unsigned Offset = 0;
>> + std::string QualifiedName;
>> + std::string NewName;
>> +};
>> +
>> +LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo)
>> +
>> +namespace llvm {
>> +namespace yaml {
>> +
>> +/// \brief Specialized MappingTraits to describe how a RenameAllInfo is
>> +/// (de)serialized.
>> +template <> struct MappingTraits<RenameAllInfo> {
>> + static void mapping(IO &IO, RenameAllInfo &Info) {
>> + IO.mapOptional("Offset", Info.Offset);
>> + IO.mapOptional("QualifiedName", Info.QualifiedName);
>> + IO.mapRequired("NewName", Info.NewName);
>> + }
>> +};
>> +
>> +} // end namespace yaml
>> +} // end namespace llvm
>> +
>> +static cl::OptionCategory ClangRenameOptions("clang-rename common
>> options");
>> +
>> +static cl::list<unsigned> SymbolOffsets(
>> + "offset",
>> + cl::desc("Locates the symbol by offset as opposed to
>> <line>:<column>."),
>> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
>> +static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
>> + cl::cat(ClangRenameOptions));
>> +static cl::list<std::string>
>> + QualifiedNames("qualified-name",
>> + cl::desc("The fully qualified name of the symbol."),
>> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
>> +
>> +static cl::list<std::string>
>> + NewNames("new-name", cl::desc("The new name to change the symbol
>> to."),
>> + cl::ZeroOrMore, cl::cat(ClangRenameOptions));
>> +static cl::opt<bool> PrintName(
>> + "pn",
>> + cl::desc("Print the found symbol's name prior to renaming to
>> stderr."),
>> + cl::cat(ClangRenameOptions));
>> +static cl::opt<bool> PrintLocations(
>> + "pl", cl::desc("Print the locations affected by renaming to
>> stderr."),
>> + cl::cat(ClangRenameOptions));
>> +static cl::opt<std::string>
>> + ExportFixes("export-fixes",
>> + cl::desc("YAML file to store suggested fixes in."),
>> + cl::value_desc("filename"), cl::cat(ClangRenameOptions));
>> +static cl::opt<std::string>
>> + Input("input", cl::desc("YAML file to load oldname-newname pairs
>> from."),
>> + cl::Optional, cl::cat(ClangRenameOptions));
>> +static cl::opt<bool> Force("force",
>> + cl::desc("Ignore nonexistent qualified
>> names."),
>> + cl::cat(ClangRenameOptions));
>> +
>> +int main(int argc, const char **argv) {
>> + tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);
>> +
>> + if (!Input.empty()) {
>> + // Populate QualifiedNames and NewNames from a YAML file.
>> + ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
>> + llvm::MemoryBuffer::getFile(Input);
>> + if (!Buffer) {
>> + errs() << "clang-rename: failed to read " << Input << ": "
>> + << Buffer.getError().message() << "\n";
>> + return 1;
>> + }
>> +
>> + std::vector<RenameAllInfo> Infos;
>> + llvm::yaml::Input YAML(Buffer.get()->getBuffer());
>> + YAML >> Infos;
>> + for (const auto &Info : Infos) {
>> + if (!Info.QualifiedName.empty())
>> + QualifiedNames.push_back(Info.QualifiedName);
>> + else
>> + SymbolOffsets.push_back(Info.Offset);
>> + NewNames.push_back(Info.NewName);
>> + }
>> + }
>> +
>> + // Check the arguments for correctness.
>> + if (NewNames.empty()) {
>> + errs() << "clang-rename: -new-name must be specified.\n\n";
>> + exit(1);
>> + }
>> +
>> + if (SymbolOffsets.empty() == QualifiedNames.empty()) {
>> + errs() << "clang-rename: -offset and -qualified-name can't be
>> present at "
>> + "the same time.\n";
>> + exit(1);
>> + }
>> +
>> + // Check if NewNames is a valid identifier in C++17.
>> + LangOptions Options;
>> + Options.CPlusPlus = true;
>> + Options.CPlusPlus1z = true;
>> + IdentifierTable Table(Options);
>> + for (const auto &NewName : NewNames) {
>> + auto NewNameTokKind = Table.get(NewName).getTokenID();
>> + if (!tok::isAnyIdentifier(NewNameTokKind)) {
>> + errs() << "ERROR: new name is not a valid identifier in
>> C++17.\n\n";
>> + exit(1);
>> + }
>> + }
>> +
>> + if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) {
>> + errs() << "clang-rename: number of symbol offsets(" <<
>> SymbolOffsets.size()
>> + << ") + number of qualified names (" << QualifiedNames.size()
>> + << ") must be equal to number of new names(" <<
>> NewNames.size()
>> + << ").\n\n";
>> + cl::PrintHelpMessage();
>> + exit(1);
>> + }
>> +
>> + auto Files = OP.getSourcePathList();
>> + tooling::RefactoringTool Tool(OP.getCompilations(), Files);
>> + tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames,
>> Force);
>> + Tool.run(tooling::newFrontendActionFactory(&FindingAction).get());
>> + const std::vector<std::vector<std::string>> &USRList =
>> + FindingAction.getUSRList();
>> + const std::vector<std::string> &PrevNames =
>> FindingAction.getUSRSpellings();
>> + if (PrintName) {
>> + for (const auto &PrevName : PrevNames) {
>> + outs() << "clang-rename found name: " << PrevName << '\n';
>> + }
>> + }
>> +
>> + if (FindingAction.errorOccurred()) {
>> + // Diagnostics are already issued at this point.
>> + exit(1);
>> + }
>> +
>> + if (Force && PrevNames.size() < NewNames.size()) {
>> + // No matching PrevName for all NewNames. Without Force this is an
>> error
>> + // above already.
>> + exit(0);
>> + }
>> +
>> + // Perform the renaming.
>> + tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,
>> + Tool.getReplacements(),
>> PrintLocations);
>> + std::unique_ptr<tooling::FrontendActionFactory> Factory =
>> + tooling::newFrontendActionFactory(&RenameAction);
>> + int ExitCode;
>> +
>> + if (Inplace) {
>> + ExitCode = Tool.runAndSave(Factory.get());
>> + } else {
>> + ExitCode = Tool.run(Factory.get());
>> +
>> + if (!ExportFixes.empty()) {
>> + std::error_code EC;
>> + llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
>> + if (EC) {
>> + llvm::errs() << "Error opening output file: " << EC.message() <<
>> '\n';
>> + exit(1);
>> + }
>> +
>> + // Export replacements.
>> + tooling::TranslationUnitReplacements TUR;
>> + const auto &FileToReplacements = Tool.getReplacements();
>> + for (const auto &Entry : FileToReplacements)
>> + TUR.Replacements.insert(TUR.Replacements.end(),
>> Entry.second.begin(),
>> + Entry.second.end());
>> +
>> + yaml::Output YAML(OS);
>> + YAML << TUR;
>> + OS.close();
>> + exit(0);
>> + }
>> +
>> + // Write every file to stdout. Right now we just barf the files
>> without any
>> + // indication of which files start where, other than that we print
>> the files
>> + // in the same order we see them.
>> + LangOptions DefaultLangOptions;
>> + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new
>> DiagnosticOptions();
>> + TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
>> + DiagnosticsEngine Diagnostics(
>> + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
>> &*DiagOpts,
>> + &DiagnosticPrinter, false);
>> + auto &FileMgr = Tool.getFiles();
>> + SourceManager Sources(Diagnostics, FileMgr);
>> + Rewriter Rewrite(Sources, DefaultLangOptions);
>> +
>> + Tool.applyAllReplacements(Rewrite);
>> + for (const auto &File : Files) {
>> + const auto *Entry = FileMgr.getFile(File);
>> + const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
>> + Rewrite.getEditBuffer(ID).write(outs());
>> + }
>> + }
>> +
>> + exit(ExitCode);
>> +}
>>
>> Added: cfe/trunk/tools/clang-rename/clang-rename.el
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-re
>> name/clang-rename.el?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/tools/clang-rename/clang-rename.el (added)
>> +++ cfe/trunk/tools/clang-rename/clang-rename.el Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,79 @@
>> +;;; clang-rename.el --- Renames every occurrence of a symbol found at
>> <offset>. -*- lexical-binding: t; -*-
>> +
>> +;; Keywords: tools, c
>> +
>> +;;; Commentary:
>> +
>> +;; To install clang-rename.el make sure the directory of this file is in
>> your
>> +;; `load-path' and add
>> +;;
>> +;; (require 'clang-rename)
>> +;;
>> +;; to your .emacs configuration.
>> +
>> +;;; Code:
>> +
>> +(defgroup clang-rename nil
>> + "Integration with clang-rename"
>> + :group 'c)
>> +
>> +(defcustom clang-rename-binary "clang-rename"
>> + "Path to clang-rename executable."
>> + :type '(file :must-match t)
>> + :group 'clang-rename)
>> +
>> +;;;###autoload
>> +(defun clang-rename (new-name)
>> + "Rename all instances of the symbol at point to NEW-NAME using
>> clang-rename."
>> + (interactive "sEnter a new name: ")
>> + (save-some-buffers :all)
>> + ;; clang-rename should not be combined with other operations when
>> undoing.
>> + (undo-boundary)
>> + (let ((output-buffer (get-buffer-create "*clang-rename*")))
>> + (with-current-buffer output-buffer (erase-buffer))
>> + (let ((exit-code (call-process
>> + clang-rename-binary nil output-buffer nil
>> + (format "-offset=%d"
>> + ;; clang-rename wants file (byte) offsets,
>> not
>> + ;; buffer (character) positions.
>> + (clang-rename--bufferpos-to-filepos
>> + ;; Emacs treats one character after a
>> symbol as
>> + ;; part of the symbol, but clang-rename
>> doesn’t.
>> + ;; Use the beginning of the current
>> symbol, if
>> + ;; available, to resolve the
>> inconsistency.
>> + (or (car (bounds-of-thing-at-point
>> 'symbol))
>> + (point))
>> + 'exact))
>> + (format "-new-name=%s" new-name)
>> + "-i" (buffer-file-name))))
>> + (if (and (integerp exit-code) (zerop exit-code))
>> + ;; Success; revert current buffer so it gets the modifications.
>> + (progn
>> + (kill-buffer output-buffer)
>> + (revert-buffer :ignore-auto :noconfirm :preserve-modes))
>> + ;; Failure; append exit code to output buffer and display it.
>> + (let ((message (clang-rename--format-message
>> + "clang-rename failed with %s %s"
>> + (if (integerp exit-code) "exit status" "signal")
>> + exit-code)))
>> + (with-current-buffer output-buffer
>> + (insert ?\n message ?\n))
>> + (message "%s" message)
>> + (display-buffer output-buffer))))))
>> +
>> +(defalias 'clang-rename--bufferpos-to-filepos
>> + (if (fboundp 'bufferpos-to-filepos)
>> + 'bufferpos-to-filepos
>> + ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it
>> using
>> + ;; ‘position-bytes’.
>> + (lambda (position &optional _quality _coding-system)
>> + (1- (position-bytes position)))))
>> +
>> +;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for
>> older
>> +;; versions.
>> +(defalias 'clang-rename--format-message
>> + (if (fboundp 'format-message) 'format-message 'format))
>> +
>> +(provide 'clang-rename)
>> +
>> +;;; clang-rename.el ends here
>>
>> Added: cfe/trunk/tools/clang-rename/clang-rename.py
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-re
>> name/clang-rename.py?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/tools/clang-rename/clang-rename.py (added)
>> +++ cfe/trunk/tools/clang-rename/clang-rename.py Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,61 @@
>> +'''
>> +Minimal clang-rename integration with Vim.
>> +
>> +Before installing make sure one of the following is satisfied:
>> +
>> +* clang-rename is in your PATH
>> +* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename
>> executable
>> +* `binary` in clang-rename.py points to valid to clang-rename executable
>> +
>> +To install, simply put this into your ~/.vimrc
>> +
>> + noremap <leader>cr :pyf <path-to>/clang-rename.py<cr>
>> +
>> +IMPORTANT NOTE: Before running the tool, make sure you saved the file.
>> +
>> +All you have to do now is to place a cursor on a variable/function/class
>> which
>> +you would like to rename and press '<leader>cr'. You will be prompted
>> for a new
>> +name if the cursor points to a valid symbol.
>> +'''
>> +
>> +import vim
>> +import subprocess
>> +import sys
>> +
>> +def main():
>> + binary = 'clang-rename'
>> + if vim.eval('exists("g:clang_rename_path")') == "1":
>> + binary = vim.eval('g:clang_rename_path')
>> +
>> + # Get arguments for clang-rename binary.
>> + offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2
>> + if offset < 0:
>> + print >> sys.stderr, '''Couldn\'t determine cursor position.
>> + Is your file empty?'''
>> + return
>> + filename = vim.current.buffer.name
>> +
>> + new_name_request_message = 'type new name:'
>> + new_name = vim.eval("input('{}\n')".forma
>> t(new_name_request_message))
>> +
>> + # Call clang-rename.
>> + command = [binary,
>> + filename,
>> + '-i',
>> + '-offset', str(offset),
>> + '-new-name', str(new_name)]
>> + # FIXME: make it possible to run the tool on unsaved file.
>> + p = subprocess.Popen(command,
>> + stdout=subprocess.PIPE,
>> + stderr=subprocess.PIPE)
>> + stdout, stderr = p.communicate()
>> +
>> + if stderr:
>> + print stderr
>> +
>> + # Reload all buffers in Vim.
>> + vim.command("checktime")
>> +
>> +
>> +if __name__ == '__main__':
>> + main()
>>
>> Modified: cfe/trunk/unittests/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/CMak
>> eLists.txt?rev=306840&r1=306839&r2=306840&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/unittests/CMakeLists.txt (original)
>> +++ cfe/trunk/unittests/CMakeLists.txt Fri Jun 30 09:36:09 2017
>> @@ -29,3 +29,4 @@ add_subdirectory(CodeGen)
>> if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)
>> add_subdirectory(libclang)
>> endif()
>> +add_subdirectory(Rename)
>>
>> Added: cfe/trunk/unittests/Rename/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rena
>> me/CMakeLists.txt?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/unittests/Rename/CMakeLists.txt (added)
>> +++ cfe/trunk/unittests/Rename/CMakeLists.txt Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,22 @@
>> +set(LLVM_LINK_COMPONENTS
>> + support
>> + )
>> +
>> +# We'd like clang/unittests/Tooling/RewriterTestContext.h in the test.
>> +include_directories(${CLANG_SOURCE_DIR})
>> +
>> +add_extra_unittest(ClangRenameTests
>> + RenameClassTest.cpp
>> + )
>> +
>> +target_link_libraries(ClangRenameTests
>> + clangAST
>> + clangASTMatchers
>> + clangBasic
>> + clangFormat
>> + clangFrontend
>> + clangRewrite
>> + clangTooling
>> + clangToolingCore
>> + clangToolingRefactor
>> + )
>>
>> Added: cfe/trunk/unittests/Rename/ClangRenameTest.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rena
>> me/ClangRenameTest.h?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/unittests/Rename/ClangRenameTest.h (added)
>> +++ cfe/trunk/unittests/Rename/ClangRenameTest.h Fri Jun 30 09:36:09 2017
>> @@ -0,0 +1,112 @@
>> +//===-- ClangRenameTests.cpp - clang-rename unit tests
>> --------------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "unittests/Tooling/RewriterTestContext.h"
>> +#include "clang/ASTMatchers/ASTMatchFinder.h"
>> +#include "clang/Basic/FileManager.h"
>> +#include "clang/Basic/FileSystemOptions.h"
>> +#include "clang/Basic/VirtualFileSystem.h"
>> +#include "clang/Format/Format.h"
>> +#include "clang/Frontend/CompilerInstance.h"
>> +#include "clang/Frontend/PCHContainerOperations.h"
>> +#include "clang/Tooling/Refactoring.h"
>> +#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
>> +#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
>> +#include "clang/Tooling/Tooling.h"
>> +#include "llvm/ADT/IntrusiveRefCntPtr.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include "llvm/Support/Format.h"
>> +#include "llvm/Support/MemoryBuffer.h"
>> +#include "gtest/gtest.h"
>> +#include <memory>
>> +#include <string>
>> +#include <vector>
>> +
>> +namespace clang {
>> +namespace clang_rename {
>> +namespace test {
>> +
>> +struct Case {
>> + std::string Before;
>> + std::string After;
>> + std::string OldName;
>> + std::string NewName;
>> +};
>> +
>> +class ClangRenameTest : public testing::Test,
>> + public testing::WithParamInterface<Case> {
>> +protected:
>> + void AppendToHeader(StringRef Code) { HeaderContent += Code.str(); }
>> +
>> + std::string runClangRenameOnCode(llvm::StringRef Code,
>> + llvm::StringRef OldName,
>> + llvm::StringRef NewName) {
>> + std::string NewCode;
>> + llvm::raw_string_ostream(NewCode) << llvm::format(
>> + "#include \"%s\"\n%s", HeaderName.c_str(), Code.str().c_str());
>> + tooling::FileContentMappings FileContents = {{HeaderName,
>> HeaderContent},
>> + {CCName, NewCode}};
>> + clang::RewriterTestContext Context;
>> + Context.createInMemoryFile(HeaderName, HeaderContent);
>> + clang::FileID InputFileID = Context.createInMemoryFile(CCName,
>> NewCode);
>> +
>> + tooling::USRFindingAction FindingAction({}, {OldName}, false);
>> + std::unique_ptr<tooling::FrontendActionFactory>
>> USRFindingActionFactory =
>> + tooling::newFrontendActionFactory(&FindingAction);
>> +
>> + if (!tooling::runToolOnCodeWithArgs(
>> + USRFindingActionFactory->create(), NewCode, {"-std=c++11"},
>> CCName,
>> + "clang-rename", std::make_shared<PCHContainerOperations>(),
>> + FileContents))
>> + return "";
>> +
>> + const std::vector<std::vector<std::string>> &USRList =
>> + FindingAction.getUSRList();
>> + std::vector<std::string> NewNames = {NewName};
>> + std::map<std::string, tooling::Replacements> FileToReplacements;
>> + tooling::QualifiedRenamingAction RenameAction(NewNames, USRList,
>> + FileToReplacements);
>> + auto RenameActionFactory = tooling::newFrontendActionFact
>> ory(&RenameAction);
>> + if (!tooling::runToolOnCodeWithArgs(
>> + RenameActionFactory->create(), NewCode, {"-std=c++11"},
>> CCName,
>> + "clang-rename", std::make_shared<PCHContainerOperations>(),
>> + FileContents))
>> + return "";
>> +
>> + formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite,
>> "llvm");
>> + return Context.getRewrittenText(InputFileID);
>> + }
>> +
>> + void CompareSnippets(StringRef Expected, StringRef Actual) {
>> + std::string ExpectedCode;
>> + llvm::raw_string_ostream(ExpectedCode) << llvm::format(
>> + "#include \"%s\"\n%s", HeaderName.c_str(),
>> Expected.str().c_str());
>> + EXPECT_EQ(format(ExpectedCode), format(Actual));
>> + }
>> +
>> + std::string format(llvm::StringRef Code) {
>> + tooling::Replacements Replaces = format::reformat(
>> + format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
>> + auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
>> + EXPECT_TRUE(static_cast<bool>(ChangedCode));
>> + if (!ChangedCode) {
>> + llvm::errs() << llvm::toString(ChangedCode.takeError());
>> + return "";
>> + }
>> + return *ChangedCode;
>> + }
>> +
>> + std::string HeaderContent;
>> + std::string HeaderName = "header.h";
>> + std::string CCName = "input.cc";
>> +};
>> +
>> +} // namespace test
>> +} // namespace clang_rename
>> +} // namesdpace clang
>>
>> Added: cfe/trunk/unittests/Rename/RenameClassTest.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rena
>> me/RenameClassTest.cpp?rev=306840&view=auto
>> ============================================================
>> ==================
>> --- cfe/trunk/unittests/Rename/RenameClassTest.cpp (added)
>> +++ cfe/trunk/unittests/Rename/RenameClassTest.cpp Fri Jun 30 09:36:09
>> 2017
>> @@ -0,0 +1,684 @@
>> +//===-- RenameClassTest.cpp - unit tests for renaming classes
>> -------------===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#include "ClangRenameTest.h"
>> +
>> +namespace clang {
>> +namespace clang_rename {
>> +namespace test {
>> +namespace {
>> +
>> +class RenameClassTest : public ClangRenameTest {
>> +public:
>> + RenameClassTest() {
>> + AppendToHeader(R"(
>> + namespace a {
>> + class Foo {
>> + public:
>> + struct Nested {
>> + enum NestedEnum {E1, E2};
>> + };
>> + void func() {}
>> + static int Constant;
>> + };
>> + class Goo {
>> + public:
>> + struct Nested {
>> + enum NestedEnum {E1, E2};
>> + };
>> + };
>> + int Foo::Constant = 1;
>> + } // namespace a
>> + namespace b {
>> + class Foo {};
>> + } // namespace b
>> +
>> + #define MACRO(x) x
>> +
>> + template<typename T> class ptr {};
>> + )");
>> + }
>> +};
>> +
>> +INSTANTIATE_TEST_CASE_P(
>> + RenameClassTests, RenameClassTest,
>> + testing::ValuesIn(std::vector<Case>({
>> + // basic classes
>> + {"a::Foo f;", "b::Bar f;", "", ""},
>> + {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
>> + {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
>> + {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return
>> b::Bar(); }",
>> + "", ""},
>> + {"namespace a {a::Foo f() { return Foo(); }}",
>> + "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
>> + {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}",
>> "", ""},
>> + {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}",
>> "", ""},
>> + {"namespace a { void f(Foo a1) {} }",
>> + "namespace a { void f(b::Bar a1) {} }", "", ""},
>> + {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}",
>> "", ""},
>> + {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}",
>> "", ""},
>> + {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
>> + {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "",
>> ""},
>> + {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
>> + "a::Foo::Nested2"},
>> +
>> + // use namespace and typedefs
>> + {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
>> + {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar
>> gA) {}",
>> + "", ""},
>> + {"using a::Foo; namespace x { Foo gA; }",
>> + "using b::Bar; namespace x { Bar gA; }", "", ""},
>> + {"struct S { using T = a::Foo; T a_; };",
>> + "struct S { using T = b::Bar; T a_; };", "", ""},
>> + {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
>> + {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
>> + {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T
>> gA;", "",
>> + ""},
>> +
>> + // struct members and other oddities
>> + {"struct S : public a::Foo {};", "struct S : public b::Bar {};",
>> "",
>> + ""},
>> + {"struct F { void f(a::Foo a1) {} };",
>> + "struct F { void f(b::Bar a1) {} };", "", ""},
>> + {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
>> + {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_;
>> };", "",
>> + ""},
>> +
>> + {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested
>> ne; }",
>> + "", ""},
>> + {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested
>> ne; }",
>> + "", ""},
>> + {"void f() { a::Foo::Nested::NestedEnum e; }",
>> + "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
>> + {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
>> + "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "",
>> ""},
>> + {"void f() { auto e = a::Foo::Nested::E1; }",
>> + "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
>> +
>> + // templates
>> + {"template <typename T> struct Foo { T t; };\n"
>> + "void f() { Foo<a::Foo> foo; }",
>> + "template <typename T> struct Foo { T t; };\n"
>> + "void f() { Foo<b::Bar> foo; }",
>> + "", ""},
>> + {"template <typename T> struct Foo { a::Foo a; };",
>> + "template <typename T> struct Foo { b::Bar a; };", "", ""},
>> + {"template <typename T> void f(T t) {}\n"
>> + "void g() { f<a::Foo>(a::Foo()); }",
>> + "template <typename T> void f(T t) {}\n"
>> + "void g() { f<b::Bar>(b::Bar()); }",
>> + "", ""},
>> + {"template <typename T> int f() { return 1; }\n"
>> + "template <> int f<a::Foo>() { return 2; }\n"
>> + "int g() { return f<a::Foo>(); }",
>> + "template <typename T> int f() { return 1; }\n"
>> + "template <> int f<b::Bar>() { return 2; }\n"
>> + "int g() { return f<b::Bar>(); }",
>> + "", ""},
>> + {"struct Foo { template <typename T> T foo(); };\n"
>> + "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
>> + "struct Foo { template <typename T> T foo(); };\n"
>> + "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",
>> + "", ""},
>> +
>> + // The following two templates are distilled from regressions
>> found in
>> + // unique_ptr<> and type_traits.h
>> + {"template <typename T> struct outer {\n"
>> + " typedef T type;\n"
>> + " type Baz();\n"
>> + " };\n"
>> + " outer<a::Foo> g_A;",
>> + "template <typename T> struct outer {\n"
>> + " typedef T type;\n"
>> + " type Baz();\n"
>> + " };\n"
>> + " outer<b::Bar> g_A;",
>> + "", ""},
>> + {"template <typename T> struct nested { typedef T type; };\n"
>> + "template <typename T> struct outer { typename nested<T>::type
>> Foo(); "
>> + "};\n"
>> + "outer<a::Foo> g_A;",
>> + "template <typename T> struct nested { typedef T type; };\n"
>> + "template <typename T> struct outer { typename nested<T>::type
>> Foo(); "
>> + "};\n"
>> + "outer<b::Bar> g_A;",
>> + "", ""},
>> +
>> + // macros
>> + {"#define FOO(T, t) T t\n"
>> + "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
>> + "#define FOO(T, t) T t\n"
>> + "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
>> + "", ""},
>> + {"#define FOO(n) a::Foo n\n"
>> + " void f() { FOO(a1); FOO(a2); }",
>> + "#define FOO(n) b::Bar n\n"
>> + " void f() { FOO(a1); FOO(a2); }",
>> + "", ""},
>> +
>> + // Pointer to member functions
>> + {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
>> + {"using a::Foo; auto gA = &Foo::func;",
>> + "using b::Bar; auto gA = &b::Bar::func;", "", ""},
>> + {"using a::Foo; namespace x { auto gA = &Foo::func; }",
>> + "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
>> + {"typedef a::Foo T; auto gA = &T::func;",
>> + "typedef b::Bar T; auto gA = &T::func;", "", ""},
>> + {"auto gA = &MACRO(a::Foo)::func;", "auto gA =
>> &MACRO(b::Bar)::func;",
>> + "", ""},
>> +
>> + // Short match inside a namespace
>> + {"namespace a { void f(Foo a1) {} }",
>> + "namespace a { void f(b::Bar a1) {} }", "", ""},
>> +
>> + // Correct match.
>> + {"using a::Foo; struct F { ptr<Foo> a_; };",
>> + "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
>> +
>> + // avoid false positives
>> + {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
>> + {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo
>> a) {} }",
>> + "", ""},
>> +
>> + // friends, everyone needs friends.
>> + {"class Foo { int i; friend class a::Foo; };",
>> + "class Foo { int i; friend class b::Bar; };", "", ""},
>> + })), );
>> +
>> +TEST_P(RenameClassTest, RenameClasses) {
>> + auto Param = GetParam();
>> + std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
>> + std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
>> + std::string Actual = runClangRenameOnCode(Param.Before, OldName,
>> NewName);
>> + CompareSnippets(Param.After, Actual);
>> +}
>> +
>> +class NamespaceDetectionTest : public ClangRenameTest {
>> +protected:
>> + NamespaceDetectionTest() {
>> + AppendToHeader(R"(
>> + class Old {};
>> + namespace o1 {
>> + class Old {};
>> + namespace o2 {
>> + class Old {};
>> + namespace o3 {
>> + class Old {};
>> + } // namespace o3
>> + } // namespace o2
>> + } // namespace o1
>> + )");
>> + }
>> +};
>> +
>> +INSTANTIATE_TEST_CASE_P(
>> + RenameClassTest, NamespaceDetectionTest,
>> + ::testing::ValuesIn(std::vector<Case>({
>> + // Test old and new namespace overlap.
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
>> + "o1::o2::o3::Old", "o1::o2::o3::New"},
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } }
>> }",
>> + "o1::o2::o3::Old", "o1::o2::n3::New"},
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo;
>> } } }",
>> + "o1::o2::o3::Old", "o1::n2::n3::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
>> + "::o1::o2::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { n2::New moo; } }",
>> "::o1::o2::Old",
>> + "::o1::n2::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
>> + "::o1::o2::Old", "::n1::n2::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { n1::n2::New moo; } }",
>> "::o1::o2::Old",
>> + "n1::n2::New"},
>> +
>> + // Test old and new namespace with differing depths.
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
>> + "o1::o2::o3::Old", "::o1::New"},
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
>> + "o1::o2::o3::Old", "::o1::o2::New"},
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
>> + "o1::o2::o3::Old", "o1::New"},
>> + {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
>> + "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
>> + "o1::o2::o3::Old", "o1::o2::New"},
>> + {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
>> + {"Old moo;", "o1::New moo;", "Old", "o1::New"},
>> + {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }",
>> "Old",
>> + "o1::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { ::New moo; } }",
>> "::o1::o2::Old",
>> + "::New"},
>> + {"namespace o1 { namespace o2 { Old moo; } }",
>> + "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
>> "New"},
>> +
>> + // Test moving into the new namespace at different levels.
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
>> + "::n1::n2::New"},
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
>> + "n1::n2::New"},
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { o2::New moo; } }",
>> "::o1::o2::Old",
>> + "::n1::o2::New"},
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { o2::New moo; } }",
>> "::o1::o2::Old",
>> + "n1::o2::New"},
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
>> + "::o1::o2::Old", "::o1::o2::New"},
>> + {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
>> + "namespace n1 { namespace n2 { o1::o2::New moo; } }",
>> "::o1::o2::Old",
>> + "o1::o2::New"},
>> +
>> + // Test friends declarations.
>> + {"class Foo { friend class o1::Old; };",
>> + "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
>> + {"class Foo { int i; friend class o1::Old; };",
>> + "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
>> + "::o1::New"},
>> + {"namespace o1 { class Foo { int i; friend class Old; }; }",
>> + "namespace o1 { class Foo { int i; friend class New; }; }",
>> "o1::Old",
>> + "o1::New"},
>> + {"namespace o1 { class Foo { int i; friend class Old; }; }",
>> + "namespace o1 { class Foo { int i; friend class New; }; }",
>> + "::o1::Old", "::o1::New"},
>> + })), );
>> +
>> +TEST_P(NamespaceDetectionTest, RenameClasses) {
>> + auto Param = GetParam();
>> + std::string Actual =
>> + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
>> + CompareSnippets(Param.After, Actual);
>> +}
>> +
>> +class TemplatedClassRenameTest : public ClangRenameTest {
>> +protected:
>> + TemplatedClassRenameTest() {
>> + AppendToHeader(R"(
>> + template <typename T> struct Old {
>> + T t_;
>> + T f() { return T(); };
>> + static T s(T t) { return t; }
>> + };
>> + namespace ns {
>> + template <typename T> struct Old {
>> + T t_;
>> + T f() { return T(); };
>> + static T s(T t) { return t; }
>> + };
>> + } // namespace ns
>> +
>> + namespace o1 {
>> + namespace o2 {
>> + namespace o3 {
>> + template <typename T> struct Old {
>> + T t_;
>> + T f() { return T(); };
>> + static T s(T t) { return t; }
>> + };
>> + } // namespace o3
>> + } // namespace o2
>> + } // namespace o1
>> + )");
>> + }
>> +};
>> +
>> +INSTANTIATE_TEST_CASE_P(
>> + RenameClassTests, TemplatedClassRenameTest,
>> + ::testing::ValuesIn(std::vector<Case>({
>> + {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;",
>> "Old",
>> + "New"},
>> + {"ns::Old<int> gI; ns::Old<bool> gB;",
>> + "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
>> + {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
>> + "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old",
>> "New"},
>> + {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
>> + "ns::Old", "ns::New"},
>> +
>> + {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
>> + "int gI = New<int>::s(0); bool gB = New<bool>::s(false);",
>> "Old",
>> + "New"},
>> + {"int gI = ns::Old<int>::s(0); bool gB =
>> ns::Old<bool>::s(false);",
>> + "int gI = ns::New<int>::s(0); bool gB =
>> ns::New<bool>::s(false);",
>> + "ns::Old", "ns::New"},
>> +
>> + {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };",
>> "Old",
>> + "New"},
>> + {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*>
>> o_; };",
>> + "ns::Old", "ns::New"},
>> +
>> + {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
>> + "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old",
>> "New"},
>> + {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
>> + "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
>> + "ns::Old", "ns::New"},
>> + {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
>> + "auto a = reinterpret_cast<const New<int>*>(new New<int>);",
>> "Old",
>> + "New"},
>> + {"auto a = reinterpret_cast<const ns::Old<int>*>(new
>> ns::Old<int>);",
>> + "auto a = reinterpret_cast<const ns::New<int>*>(new
>> ns::New<int>);",
>> + "ns::Old", "ns::New"},
>> +
>> + {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
>> + {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
>> + "ns::New"},
>> + {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>&
>> foo();",
>> + "o1::o2::o3::Old", "o1::o2::o3::New"},
>> + {"namespace ns { Old<bool>& foo(); }",
>> + "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
>> + {"const Old<bool>& foo();", "const New<bool>& foo();", "Old",
>> "New"},
>> + {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
>> + "ns::Old", "ns::New"},
>> +
>> + // FIXME: figure out why this only works when Moo gets
>> + // specialized at some point.
>> + {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
>> + "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;",
>> "Old",
>> + "New"},
>> + {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int>
>> m;",
>> + "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int>
>> m;",
>> + "ns::Old", "ns::New"},
>> + })), );
>> +
>> +TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
>> + auto Param = GetParam();
>> + std::string Actual =
>> + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
>> + CompareSnippets(Param.After, Actual);
>> +}
>> +
>> +TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
>> + std::string Before = R"(
>> + class Old {
>> + public:
>> + Old();
>> + ~Old();
>> +
>> + Old* next();
>> +
>> + private:
>> + Old* next_;
>> + };
>> +
>> + Old::Old() {}
>> + Old::~Old() {}
>> + Old* Old::next() { return next_; }
>> + )";
>> + std::string Expected = R"(
>> + class New {
>> + public:
>> + New();
>> + ~New();
>> +
>> + New* next();
>> +
>> + private:
>> + New* next_;
>> + };
>> +
>> + New::New() {}
>> + New::~New() {}
>> + New* New::next() { return next_; }
>> + )";
>> + std::string After = runClangRenameOnCode(Before, "Old", "New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
>> + std::string Before = R"(
>> + class Old {
>> + public:
>> + Old() {}
>> + ~Old() {}
>> +
>> + Old* next() { return next_; }
>> +
>> + private:
>> + Old* next_;
>> + };
>> + )";
>> + std::string Expected = R"(
>> + class New {
>> + public:
>> + New() {}
>> + ~New() {}
>> +
>> + New* next() { return next_; }
>> +
>> + private:
>> + New* next_;
>> + };
>> + )";
>> + std::string After = runClangRenameOnCode(Before, "Old", "New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +// FIXME: no prefix qualifiers being added to the class definition and
>> +// constructor.
>> +TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
>> + std::string Before = R"(
>> + namespace ns {
>> + class Old {
>> + public:
>> + Old() {}
>> + ~Old() {}
>> +
>> + Old* next() { return next_; }
>> +
>> + private:
>> + Old* next_;
>> + };
>> + } // namespace ns
>> + )";
>> + std::string Expected = R"(
>> + namespace ns {
>> + class ns::New {
>> + public:
>> + ns::New() {}
>> + ~New() {}
>> +
>> + New* next() { return next_; }
>> +
>> + private:
>> + New* next_;
>> + };
>> + } // namespace ns
>> + )";
>> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +// FIXME: no prefix qualifiers being added to the class definition and
>> +// constructor.
>> +TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers)
>> {
>> + std::string Before = R"(
>> + namespace ns {
>> + class Old {
>> + public:
>> + Old();
>> + ~Old();
>> +
>> + Old* next();
>> +
>> + private:
>> + Old* next_;
>> + };
>> +
>> + Old::Old() {}
>> + Old::~Old() {}
>> + Old* Old::next() { return next_; }
>> + } // namespace ns
>> + )";
>> + std::string Expected = R"(
>> + namespace ns {
>> + class ns::New {
>> + public:
>> + ns::New();
>> + ~New();
>> +
>> + New* next();
>> +
>> + private:
>> + New* next_;
>> + };
>> +
>> + New::ns::New() {}
>> + New::~New() {}
>> + New* New::next() { return next_; }
>> + } // namespace ns
>> + )";
>> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +// FIXME: no prefix qualifiers being added to the definition.
>> +TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
>> + // `using Base::Base;` will generate an implicit constructor
>> containing usage
>> + // of `::ns::Old` which should not be matched.
>> + std::string Before = R"(
>> + namespace ns {
>> + class Old {
>> + int x;
>> + };
>> + class Base {
>> + protected:
>> + Old *moo_;
>> + public:
>> + Base(Old *moo) : moo_(moo) {}
>> + };
>> + class Derived : public Base {
>> + public:
>> + using Base::Base;
>> + };
>> + } // namespace ns
>> + int main() {
>> + ::ns::Old foo;
>> + ::ns::Derived d(&foo);
>> + return 0;
>> + })";
>> + std::string Expected = R"(
>> + namespace ns {
>> + class ns::New {
>> + int x;
>> + };
>> + class Base {
>> + protected:
>> + New *moo_;
>> + public:
>> + Base(New *moo) : moo_(moo) {}
>> + };
>> + class Derived : public Base {
>> + public:
>> + using Base::Base;
>> + };
>> + } // namespace ns
>> + int main() {
>> + ::ns::New foo;
>> + ::ns::Derived d(&foo);
>> + return 0;
>> + })";
>> + std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
>> + std::string Before = R"(
>> + namespace ns {
>> + class Old {
>> + };
>> + } // namespace ns
>> + struct S {
>> + int y;
>> + ns::Old old;
>> + };
>> + void f() {
>> + S s1, s2, s3;
>> + // This causes an implicit assignment operator to be created.
>> + s1 = s2 = s3;
>> + }
>> + )";
>> + std::string Expected = R"(
>> + namespace ns {
>> + class ::new_ns::New {
>> + };
>> + } // namespace ns
>> + struct S {
>> + int y;
>> + ::new_ns::New old;
>> + };
>> + void f() {
>> + S s1, s2, s3;
>> + // This causes an implicit assignment operator to be created.
>> + s1 = s2 = s3;
>> + }
>> + )";
>> + std::string After = runClangRenameOnCode(Before, "ns::Old",
>> "::new_ns::New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +// FIXME: no prefix qualifiers being adding to the definition.
>> +TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
>> + std::string Before = R"(
>> + template <class T>
>> + class function;
>> + template <class R, class... ArgTypes>
>> + class function<R(ArgTypes...)> {
>> + public:
>> + template <typename Functor>
>> + function(Functor f) {}
>> +
>> + function() {}
>> +
>> + R operator()(ArgTypes...) const {}
>> + };
>> +
>> + namespace ns {
>> + class Old {};
>> + void f() {
>> + function<void(Old)> func;
>> + }
>> + } // namespace ns)";
>> + std::string Expected = R"(
>> + template <class T>
>> + class function;
>> + template <class R, class... ArgTypes>
>> + class function<R(ArgTypes...)> {
>> + public:
>> + template <typename Functor>
>> + function(Functor f) {}
>> +
>> + function() {}
>> +
>> + R operator()(ArgTypes...) const {}
>> + };
>> +
>> + namespace ns {
>> + class ::new_ns::New {};
>> + void f() {
>> + function<void(::new_ns::New)> func;
>> + }
>> + } // namespace ns)";
>> + std::string After = runClangRenameOnCode(Before, "ns::Old",
>> "::new_ns::New");
>> + CompareSnippets(Expected, After);
>> +}
>> +
>> +} // anonymous namespace
>> +} // namespace test
>> +} // namespace clang_rename
>> +} // namesdpace clang
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170630/65ce1f8d/attachment-0001.html>
More information about the cfe-commits
mailing list