<div dir="ltr">Thanks! I'll take a look.</div><div class="gmail_extra"><br><div class="gmail_quote">On 30 June 2017 at 21:14, Evgenii Stepanov <span dir="ltr"><<a href="mailto:eugeni.stepanov@gmail.com" target="_blank">eugeni.stepanov@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi,<div><br></div><div>there are new memory leaks related to this change:</div><div><a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/6072/steps/check-clang%20asan/logs/stdio" target="_blank">http://lab.llvm.org:8011/<wbr>builders/sanitizer-x86_64-<wbr>linux-fast/builds/6072/steps/<wbr>check-clang%20asan/logs/stdio</a><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jun 30, 2017 at 9:36 AM, Alex Lorenz via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: arphaman<br>
Date: Fri Jun 30 09:36:09 2017<br>
New Revision: 306840<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=306840&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=306840&view=rev</a><br>
Log:<br>
[refactor] Move clang-rename into the clang repository<br>
<br>
The core engine of clang-rename will be used for local and global renames in the<br>
new refactoring engine, as mentioned in<br>
<a href="http://lists.llvm.org/pipermail/cfe-dev/2017-June/054286.html" rel="noreferrer" target="_blank">http://lists.llvm.org/pipermai<wbr>l/cfe-dev/2017-June/054286.<wbr>html</a>.<br>
<br>
The clang-rename tool is still supported but might get deprecated in the future.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D34696" rel="noreferrer" target="_blank">https://reviews.llvm.org/D3469<wbr>6</a><br>
<br>
Added:<br>
cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/<br>
cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/RenamingA<wbr>ction.h<br>
cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFinder<wbr>.h<br>
cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFindin<wbr>gAction.h<br>
cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRLocFin<wbr>der.h<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/RenamingAction.cpp<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFinder.cpp<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFindingAction.<wbr>cpp<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRLocFinder.cpp<br>
cfe/trunk/test/clang-rename/<br>
cfe/trunk/test/clang-rename/Cl<wbr>assAsTemplateArgument.cpp<br>
cfe/trunk/test/clang-rename/Cl<wbr>assFindByName.cpp<br>
cfe/trunk/test/clang-rename/Cl<wbr>assReplacements.cpp<br>
cfe/trunk/test/clang-rename/Cl<wbr>assSimpleRenaming.cpp<br>
cfe/trunk/test/clang-rename/Cl<wbr>assTestMulti.cpp<br>
cfe/trunk/test/clang-rename/Cl<wbr>assTestMultiByName.cpp<br>
cfe/trunk/test/clang-rename/Co<wbr>mplexFunctionOverride.cpp<br>
cfe/trunk/test/clang-rename/Co<wbr>mplicatedClassType.cpp<br>
cfe/trunk/test/clang-rename/Ct<wbr>or.cpp<br>
cfe/trunk/test/clang-rename/Ct<wbr>orInitializer.cpp<br>
cfe/trunk/test/clang-rename/De<wbr>clRefExpr.cpp<br>
cfe/trunk/test/clang-rename/Fi<wbr>eld.cpp<br>
cfe/trunk/test/clang-rename/Fu<wbr>nctionMacro.cpp<br>
cfe/trunk/test/clang-rename/Fu<wbr>nctionOverride.cpp<br>
cfe/trunk/test/clang-rename/Fu<wbr>nctionWithClassFindByName.cpp<br>
cfe/trunk/test/clang-rename/In<wbr>cludeHeaderWithSymbol.cpp<br>
cfe/trunk/test/clang-rename/In<wbr>puts/<br>
cfe/trunk/test/clang-rename/In<wbr>puts/HeaderWithSymbol.h<br>
cfe/trunk/test/clang-rename/In<wbr>puts/OffsetToNewName.yaml<br>
cfe/trunk/test/clang-rename/In<wbr>puts/QualifiedNameToNewName.ya<wbr>ml<br>
cfe/trunk/test/clang-rename/In<wbr>validNewName.cpp<br>
cfe/trunk/test/clang-rename/In<wbr>validOffset.cpp<br>
cfe/trunk/test/clang-rename/In<wbr>validQualifiedName.cpp<br>
cfe/trunk/test/clang-rename/Me<wbr>mberExprMacro.cpp<br>
cfe/trunk/test/clang-rename/Na<wbr>mespace.cpp<br>
cfe/trunk/test/clang-rename/No<wbr>NewName.cpp<br>
cfe/trunk/test/clang-rename/Te<wbr>mplateClassInstantiation.cpp<br>
cfe/trunk/test/clang-rename/Te<wbr>mplateTypename.cpp<br>
cfe/trunk/test/clang-rename/Te<wbr>mplatedClassFunction.cpp<br>
cfe/trunk/test/clang-rename/Us<wbr>erDefinedConversion.cpp<br>
cfe/trunk/test/clang-rename/Va<wbr>riable.cpp<br>
cfe/trunk/test/clang-rename/Va<wbr>riableMacro.cpp<br>
cfe/trunk/test/clang-rename/YA<wbr>MLInput.cpp<br>
cfe/trunk/tools/clang-rename/<br>
cfe/trunk/tools/clang-rename/C<wbr>MakeLists.txt<br>
cfe/trunk/tools/clang-rename/C<wbr>langRename.cpp<br>
cfe/trunk/tools/clang-rename/c<wbr>lang-rename.el<br>
cfe/trunk/tools/clang-rename/c<wbr>lang-rename.py<br>
cfe/trunk/unittests/Rename/<br>
cfe/trunk/unittests/Rename/CMa<wbr>keLists.txt<br>
cfe/trunk/unittests/Rename/Cla<wbr>ngRenameTest.h<br>
cfe/trunk/unittests/Rename/Ren<wbr>ameClassTest.cpp<br>
Modified:<br>
cfe/trunk/include/clang/module<wbr>.modulemap<br>
cfe/trunk/lib/Tooling/Refactor<wbr>ing/CMakeLists.txt<br>
cfe/trunk/test/CMakeLists.txt<br>
cfe/trunk/tools/CMakeLists.txt<br>
cfe/trunk/unittests/CMakeLists<wbr>.txt<br>
<br>
Added: cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/RenamingA<wbr>ction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/include/clang/<wbr>Tooling/Refactoring/Rename/<wbr>RenamingAction.h?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/RenamingA<wbr>ction.h (added)<br>
+++ cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/RenamingA<wbr>ction.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,70 @@<br>
+//===--- RenamingAction.h - Clang refactoring library ---------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Provides an action to rename every symbol at a point.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_RENAMING_ACTION_H<br>
+#define LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_RENAMING_ACTION_H<br>
+<br>
+#include "clang/Tooling/Refactoring.h"<br>
+<br>
+namespace clang {<br>
+class ASTConsumer;<br>
+class CompilerInstance;<br>
+<br>
+namespace tooling {<br>
+<br>
+class RenamingAction {<br>
+public:<br>
+ RenamingAction(const std::vector<std::string> &NewNames,<br>
+ const std::vector<std::string> &PrevNames,<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList,<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces,<br>
+ bool PrintLocations = false)<br>
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),<br>
+ FileToReplaces(FileToReplaces)<wbr>, PrintLocations(PrintLocations) {}<br>
+<br>
+ std::unique_ptr<ASTConsumer> newASTConsumer();<br>
+<br>
+private:<br>
+ const std::vector<std::string> &NewNames, &PrevNames;<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList;<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces;<br>
+ bool PrintLocations;<br>
+};<br>
+<br>
+/// Rename all symbols identified by the given USRs.<br>
+class QualifiedRenamingAction {<br>
+public:<br>
+ QualifiedRenamingAction(<br>
+ const std::vector<std::string> &NewNames,<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList,<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces)<br>
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {}<br>
+<br>
+ std::unique_ptr<ASTConsumer> newASTConsumer();<br>
+<br>
+private:<br>
+ /// New symbol names.<br>
+ const std::vector<std::string> &NewNames;<br>
+<br>
+ /// A list of USRs. Each element represents USRs of a symbol being renamed.<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList;<br>
+<br>
+ /// A file path to replacements map.<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces;<br>
+};<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
+<br>
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_RENAMING_ACTION_H<br>
<br>
Added: cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFinder<wbr>.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFinder.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/include/clang/<wbr>Tooling/Refactoring/Rename/<wbr>USRFinder.h?rev=306840&view=<wbr>auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFinder<wbr>.h (added)<br>
+++ cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFinder<wbr>.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,84 @@<br>
+//===--- USRFinder.h - Clang refactoring library --------------------------===/<wbr>/<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Methods for determining the USR of a symbol at a location in source<br>
+/// code.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDER_H<br>
+#define LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDER_H<br>
+<br>
+#include "clang/AST/AST.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/ASTMatchers/ASTMatchFin<wbr>der.h"<br>
+#include <string><br>
+#include <vector><br>
+<br>
+using namespace llvm;<br>
+using namespace clang::ast_matchers;<br>
+<br>
+namespace clang {<br>
+<br>
+class ASTContext;<br>
+class Decl;<br>
+class SourceLocation;<br>
+class NamedDecl;<br>
+<br>
+namespace tooling {<br>
+<br>
+// Given an AST context and a point, returns a NamedDecl identifying the symbol<br>
+// at the point. Returns null if nothing is found at the point.<br>
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,<br>
+ const SourceLocation Point);<br>
+<br>
+// Given an AST context and a fully qualified name, returns a NamedDecl<br>
+// identifying the symbol with a matching name. Returns null if nothing is<br>
+// found for the name.<br>
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,<br>
+ const std::string &Name);<br>
+<br>
+// Converts a Decl into a USR.<br>
+std::string getUSRForDecl(const Decl *Decl);<br>
+<br>
+// FIXME: Implement RecursiveASTVisitor<T>::VisitN<wbr>estedNameSpecifier instead.<br>
+class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback {<br>
+public:<br>
+ explicit NestedNameSpecifierLocFinder(A<wbr>STContext &Context)<br>
+ : Context(Context) {}<br>
+<br>
+ std::vector<NestedNameSpecifie<wbr>rLoc> getNestedNameSpecifierLocation<wbr>s() {<br>
+ addMatchers();<br>
+ Finder.matchAST(Context);<br>
+ return Locations;<br>
+ }<br>
+<br>
+private:<br>
+ void addMatchers() {<br>
+ const auto NestedNameSpecifierLocMatcher =<br>
+ nestedNameSpecifierLoc().bind(<wbr>"nestedNameSpecifierLoc");<br>
+ Finder.addMatcher(NestedNameSp<wbr>ecifierLocMatcher, this);<br>
+ }<br>
+<br>
+ void run(const MatchFinder::MatchResult &Result) override {<br>
+ const auto *NNS = Result.Nodes.getNodeAs<NestedN<wbr>ameSpecifierLoc>(<br>
+ "nestedNameSpecifierLoc");<br>
+ Locations.push_back(*NNS);<br>
+ }<br>
+<br>
+ ASTContext &Context;<br>
+ std::vector<NestedNameSpecifie<wbr>rLoc> Locations;<br>
+ MatchFinder Finder;<br>
+};<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
+<br>
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDER_H<br>
<br>
Added: cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFindin<wbr>gAction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/include/clang/<wbr>Tooling/Refactoring/Rename/<wbr>USRFindingAction.h?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFindin<wbr>gAction.h (added)<br>
+++ cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRFindin<wbr>gAction.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,54 @@<br>
+//===--- USRFindingAction.h - Clang refactoring library -------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Provides an action to find all relevant USRs at a point.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDING_ACTION_H<br>
+#define LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDING_ACTION_H<br>
+<br>
+#include "clang/Basic/LLVM.h"<br>
+#include "llvm/ADT/ArrayRef.h"<br>
+<br>
+#include <string><br>
+#include <vector><br>
+<br>
+namespace clang {<br>
+class ASTConsumer;<br>
+class CompilerInstance;<br>
+class NamedDecl;<br>
+<br>
+namespace tooling {<br>
+<br>
+struct USRFindingAction {<br>
+ USRFindingAction(ArrayRef<unsi<wbr>gned> SymbolOffsets,<br>
+ ArrayRef<std::string> QualifiedNames, bool Force)<br>
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames)<wbr>,<br>
+ ErrorOccurred(false), Force(Force) {}<br>
+ std::unique_ptr<ASTConsumer> newASTConsumer();<br>
+<br>
+ ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }<br>
+ ArrayRef<std::vector<std::stri<wbr>ng>> getUSRList() { return USRList; }<br>
+ bool errorOccurred() { return ErrorOccurred; }<br>
+<br>
+private:<br>
+ std::vector<unsigned> SymbolOffsets;<br>
+ std::vector<std::string> QualifiedNames;<br>
+ std::vector<std::string> SpellingNames;<br>
+ std::vector<std::vector<std::s<wbr>tring>> USRList;<br>
+ bool ErrorOccurred;<br>
+ bool Force;<br>
+};<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
+<br>
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_FINDING_ACTION_H<br>
<br>
Added: cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRLocFin<wbr>der.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/include/clang/<wbr>Tooling/Refactoring/Rename/<wbr>USRLocFinder.h?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRLocFin<wbr>der.h (added)<br>
+++ cfe/trunk/include/clang/Toolin<wbr>g/Refactoring/Rename/USRLocFin<wbr>der.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,49 @@<br>
+//===--- USRLocFinder.h - Clang refactoring library -----------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Provides functionality for finding all instances of a USR in a given<br>
+/// AST.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_LOC_FINDER_H<br>
+#define LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_LOC_FINDER_H<br>
+<br>
+#include "clang/AST/AST.h"<br>
+#include "clang/Tooling/Core/Replacemen<wbr>t.h"<br>
+#include "clang/Tooling/Refactoring/Ato<wbr>micChange.h"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include <string><br>
+#include <vector><br>
+<br>
+namespace clang {<br>
+namespace tooling {<br>
+<br>
+/// Create atomic changes for renaming all symbol references which are<br>
+/// identified by the USRs set to a given new name.<br>
+///<br>
+/// \param USRs The set containing USRs of a particular old symbol.<br>
+/// \param NewName The new name to replace old symbol name.<br>
+/// \param TranslationUnitDecl The translation unit declaration.<br>
+///<br>
+/// \return Atomic changes for renaming.<br>
+std::vector<tooling::AtomicCh<wbr>ange><br>
+createRenameAtomicChanges(llv<wbr>m::ArrayRef<std::string> USRs,<br>
+ llvm::StringRef NewName, Decl *TranslationUnitDecl);<br>
+<br>
+// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!<br>
+std::vector<SourceLocation><br>
+getLocationsOfUSRs(const std::vector<std::string> &USRs,<br>
+ llvm::StringRef PrevName, Decl *Decl);<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
+<br>
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RE<wbr>NAME_USR_LOC_FINDER_H<br>
<br>
Modified: cfe/trunk/include/clang/module<wbr>.modulemap<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/module.modulemap?rev=306840&r1=306839&r2=306840&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/include/clang/<wbr>module.modulemap?rev=306840&<wbr>r1=306839&r2=306840&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/module<wbr>.modulemap (original)<br>
+++ cfe/trunk/include/clang/module<wbr>.modulemap Fri Jun 30 09:36:09 2017<br>
@@ -133,9 +133,10 @@ module Clang_StaticAnalyzer_Frontend {<br>
<br>
module Clang_Tooling {<br>
requires cplusplus umbrella "Tooling" module * { export * }<br>
- // FIXME: Exclude this header to avoid pulling all of the AST matchers<br>
+ // FIXME: Exclude these headers to avoid pulling all of the AST matchers<br>
// library into clang-format. Due to inline key functions in the headers,<br>
// importing the AST matchers library gives a link dependency on the AST<br>
// matchers (and thus the AST), which clang-format should not have.<br>
exclude header "Tooling/RefactoringCallbacks.<wbr>h"<br>
+ exclude header "Tooling/Refactoring/Rename/US<wbr>RFinder.h"<br>
}<br>
<br>
Modified: cfe/trunk/lib/Tooling/Refactor<wbr>ing/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/lib/Tooling/Re<wbr>factoring/CMakeLists.txt?rev=<wbr>306840&r1=306839&r2=306840&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Tooling/Refactor<wbr>ing/CMakeLists.txt (original)<br>
+++ cfe/trunk/lib/Tooling/Refactor<wbr>ing/CMakeLists.txt Fri Jun 30 09:36:09 2017<br>
@@ -5,8 +5,16 @@ set(LLVM_LINK_COMPONENTS<br>
<br>
add_clang_library(clangToolin<wbr>gRefactor<br>
AtomicChange.cpp<br>
+ Rename/RenamingAction.cpp<br>
+ Rename/USRFinder.cpp<br>
+ Rename/USRFindingAction.cpp<br>
+ Rename/USRLocFinder.cpp<br>
<br>
LINK_LIBS<br>
+ clangAST<br>
+ clangASTMatchers<br>
clangBasic<br>
+ clangIndex<br>
+ clangLex<br>
clangToolingCore<br>
)<br>
<br>
Added: cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/RenamingAction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/lib/Tooling/Re<wbr>factoring/Rename/RenamingActio<wbr>n.cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/RenamingAction.cpp (added)<br>
+++ cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/RenamingAction.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,134 @@<br>
+//===--- RenamingAction.cpp - Clang refactoring library -------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Provides an action to rename every symbol at a point.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/RenamingAction.h"<br>
+#include "clang/AST/ASTConsumer.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/Basic/FileManager.h"<br>
+#include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>
+#include "clang/Frontend/FrontendAction<wbr>.h"<br>
+#include "clang/Lex/Lexer.h"<br>
+#include "clang/Lex/Preprocessor.h"<br>
+#include "clang/Tooling/CommonOptionsPa<wbr>rser.h"<br>
+#include "clang/Tooling/Refactoring.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRLocFinder.h"<br>
+#include "clang/Tooling/Tooling.h"<br>
+#include <string><br>
+#include <vector><br>
+<br>
+using namespace llvm;<br>
+<br>
+namespace clang {<br>
+namespace tooling {<br>
+<br>
+class RenamingASTConsumer : public ASTConsumer {<br>
+public:<br>
+ RenamingASTConsumer(<br>
+ const std::vector<std::string> &NewNames,<br>
+ const std::vector<std::string> &PrevNames,<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList,<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces,<br>
+ bool PrintLocations)<br>
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),<br>
+ FileToReplaces(FileToReplaces)<wbr>, PrintLocations(PrintLocations) {}<br>
+<br>
+ void HandleTranslationUnit(ASTConte<wbr>xt &Context) override {<br>
+ for (unsigned I = 0; I < NewNames.size(); ++I)<br>
+ HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);<br>
+ }<br>
+<br>
+ void HandleOneRename(ASTContext &Context, const std::string &NewName,<br>
+ const std::string &PrevName,<br>
+ const std::vector<std::string> &USRs) {<br>
+ const SourceManager &SourceMgr = Context.getSourceManager();<br>
+ std::vector<SourceLocation> RenamingCandidates;<br>
+ std::vector<SourceLocation> NewCandidates;<br>
+<br>
+ NewCandidates = tooling::getLocationsOfUSRs(<br>
+ USRs, PrevName, Context.getTranslationUnitDecl<wbr>());<br>
+ RenamingCandidates.insert(Rena<wbr>mingCandidates.end(), NewCandidates.begin(),<br>
+ NewCandidates.end());<br>
+<br>
+ unsigned PrevNameLen = PrevName.length();<br>
+ for (const auto &Loc : RenamingCandidates) {<br>
+ if (PrintLocations) {<br>
+ FullSourceLoc FullLoc(Loc, SourceMgr);<br>
+ errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc)<br>
+ << ":" << FullLoc.getSpellingLineNumber(<wbr>) << ":"<br>
+ << FullLoc.getSpellingColumnNumbe<wbr>r() << "\n";<br>
+ }<br>
+ // FIXME: better error handling.<br>
+ tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName);<br>
+ llvm::Error Err = FileToReplaces[Replace.getFile<wbr>Path()].add(Replace);<br>
+ if (Err)<br>
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! "<br>
+ << llvm::toString(std::move(Err)) << "\n";<br>
+ }<br>
+ }<br>
+<br>
+private:<br>
+ const std::vector<std::string> &NewNames, &PrevNames;<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList;<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces;<br>
+ bool PrintLocations;<br>
+};<br>
+<br>
+// A renamer to rename symbols which are identified by a give USRList to<br>
+// new name.<br>
+//<br>
+// FIXME: Merge with the above RenamingASTConsumer.<br>
+class USRSymbolRenamer : public ASTConsumer {<br>
+public:<br>
+ USRSymbolRenamer(const std::vector<std::string> &NewNames,<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList,<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces)<br>
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {<br>
+ assert(USRList.size() == NewNames.size());<br>
+ }<br>
+<br>
+ void HandleTranslationUnit(ASTConte<wbr>xt &Context) override {<br>
+ for (unsigned I = 0; I < NewNames.size(); ++I) {<br>
+ // FIXME: Apply AtomicChanges directly once the refactoring APIs are<br>
+ // ready.<br>
+ auto AtomicChanges = tooling::createRenameAtomicCha<wbr>nges(<br>
+ USRList[I], NewNames[I], Context.getTranslationUnitDecl<wbr>());<br>
+ for (const auto AtomicChange : AtomicChanges) {<br>
+ for (const auto &Replace : AtomicChange.getReplacements()<wbr>) {<br>
+ llvm::Error Err = FileToReplaces[Replace.getFile<wbr>Path()].add(Replace);<br>
+ if (Err) {<br>
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath()<br>
+ << "! " << llvm::toString(std::move(Err)) << "\n";<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+private:<br>
+ const std::vector<std::string> &NewNames;<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList;<br>
+ std::map<std::string, tooling::Replacements> &FileToReplaces;<br>
+};<br>
+<br>
+std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer<wbr>() {<br>
+ return llvm::make_unique<RenamingASTC<wbr>onsumer>(NewNames, PrevNames, USRList,<br>
+ FileToReplaces, PrintLocations);<br>
+}<br>
+<br>
+std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newAS<wbr>TConsumer() {<br>
+ return llvm::make_unique<USRSymbolRen<wbr>amer>(NewNames, USRList, FileToReplaces);<br>
+}<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
<br>
Added: cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFinder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRFinder.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/lib/Tooling/Re<wbr>factoring/Rename/USRFinder.cpp<wbr>?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFinder.cpp (added)<br>
+++ cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFinder.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,213 @@<br>
+//===--- USRFinder.cpp - Clang refactoring library ------------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file Implements a recursive AST visitor that finds the USR of a symbol at a<br>
+/// point.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFinder.h"<br>
+#include "clang/AST/AST.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/RecursiveASTVisitor<wbr>.h"<br>
+#include "clang/Index/USRGeneration.h"<br>
+#include "clang/Lex/Lexer.h"<br>
+#include "llvm/ADT/SmallVector.h"<br>
+<br>
+using namespace llvm;<br>
+<br>
+namespace clang {<br>
+namespace tooling {<br>
+<br>
+// NamedDeclFindingASTVisitor recursively visits each AST node to find the<br>
+// symbol underneath the cursor.<br>
+// FIXME: move to separate .h/.cc file if this gets too large.<br>
+namespace {<br>
+class NamedDeclFindingASTVisitor<br>
+ : public clang::RecursiveASTVisitor<Nam<wbr>edDeclFindingASTVisitor> {<br>
+public:<br>
+ // \brief Finds the NamedDecl at a point in the source.<br>
+ // \param Point the location in the source to search for the NamedDecl.<br>
+ explicit NamedDeclFindingASTVisitor(con<wbr>st SourceLocation Point,<br>
+ const ASTContext &Context)<br>
+ : Result(nullptr), Point(Point), Context(Context) {}<br>
+<br>
+ // \brief Finds the NamedDecl for a name in the source.<br>
+ // \param Name the fully qualified name.<br>
+ explicit NamedDeclFindingASTVisitor(con<wbr>st std::string &Name,<br>
+ const ASTContext &Context)<br>
+ : Result(nullptr), Name(Name), Context(Context) {}<br>
+<br>
+ // Declaration visitors:<br>
+<br>
+ // \brief Checks if the point falls within the NameDecl. This covers every<br>
+ // declaration of a named entity that we may come across. Usually, just<br>
+ // checking if the point lies within the length of the name of the declaration<br>
+ // and the start location is sufficient.<br>
+ bool VisitNamedDecl(const NamedDecl *Decl) {<br>
+ return dyn_cast<CXXConversionDecl>(De<wbr>cl)<br>
+ ? true<br>
+ : setResult(Decl, Decl->getLocation(),<br>
+ Decl->getNameAsString().lengt<wbr>h());<br>
+ }<br>
+<br>
+ // Expression visitors:<br>
+<br>
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {<br>
+ const NamedDecl *Decl = Expr->getFoundDecl();<br>
+ return setResult(Decl, Expr->getLocation(),<br>
+ Decl->getNameAsString().lengt<wbr>h());<br>
+ }<br>
+<br>
+ bool VisitMemberExpr(const MemberExpr *Expr) {<br>
+ const NamedDecl *Decl = Expr->getFoundDecl().getDecl()<wbr>;<br>
+ return setResult(Decl, Expr->getMemberLoc(),<br>
+ Decl->getNameAsString().lengt<wbr>h());<br>
+ }<br>
+<br>
+ // Other visitors:<br>
+<br>
+ bool VisitTypeLoc(const TypeLoc Loc) {<br>
+ const SourceLocation TypeBeginLoc = Loc.getBeginLoc();<br>
+ const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(<br>
+ TypeBeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());<br>
+ if (const auto *TemplateTypeParm =<br>
+ dyn_cast<TemplateTypeParmType><wbr>(Loc.getType()))<br>
+ return setResult(TemplateTypeParm->ge<wbr>tDecl(), TypeBeginLoc, TypeEndLoc);<br>
+ if (const auto *TemplateSpecType =<br>
+ dyn_cast<TemplateSpecializatio<wbr>nType>(Loc.getType())) {<br>
+ return setResult(TemplateSpecType->ge<wbr>tTemplateName().getAsTemplateD<wbr>ecl(),<br>
+ TypeBeginLoc, TypeEndLoc);<br>
+ }<br>
+ return setResult(Loc.getType()->getAs<wbr>CXXRecordDecl(), TypeBeginLoc,<br>
+ TypeEndLoc);<br>
+ }<br>
+<br>
+ bool VisitCXXConstructorDecl(clang:<wbr>:CXXConstructorDecl *ConstructorDecl) {<br>
+ for (const auto *Initializer : ConstructorDecl->inits()) {<br>
+ // Ignore implicit initializers.<br>
+ if (!Initializer->isWritten())<br>
+ continue;<br>
+ if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {<br>
+ const SourceLocation InitBeginLoc = Initializer->getSourceLocation<wbr>(),<br>
+ InitEndLoc = Lexer::getLocForEndOfToken(<br>
+ InitBeginLoc, 0, Context.getSourceManager(),<br>
+ Context.getLangOpts());<br>
+ if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc))<br>
+ return false;<br>
+ }<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ // Other:<br>
+<br>
+ const NamedDecl *getNamedDecl() { return Result; }<br>
+<br>
+ // \brief Determines if a namespace qualifier contains the point.<br>
+ // \returns false on success and sets Result.<br>
+ void handleNestedNameSpecifierLoc(N<wbr>estedNameSpecifierLoc NameLoc) {<br>
+ while (NameLoc) {<br>
+ const NamespaceDecl *Decl =<br>
+ NameLoc.getNestedNameSpecifier<wbr>()->getAsNamespace();<br>
+ setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());<br>
+ NameLoc = NameLoc.getPrefix();<br>
+ }<br>
+ }<br>
+<br>
+private:<br>
+ // \brief Sets Result to Decl if the Point is within Start and End.<br>
+ // \returns false on success.<br>
+ bool setResult(const NamedDecl *Decl, SourceLocation Start,<br>
+ SourceLocation End) {<br>
+ if (!Decl)<br>
+ return true;<br>
+ if (Name.empty()) {<br>
+ // Offset is used to find the declaration.<br>
+ if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||<br>
+ !End.isFileID() || !isPointWithin(Start, End))<br>
+ return true;<br>
+ } else {<br>
+ // Fully qualified name is used to find the declaration.<br>
+ if (Name != Decl->getQualifiedNameAsString<wbr>() &&<br>
+ Name != "::" + Decl->getQualifiedNameAsString<wbr>())<br>
+ return true;<br>
+ }<br>
+ Result = Decl;<br>
+ return false;<br>
+ }<br>
+<br>
+ // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.<br>
+ // \returns false on success.<br>
+ bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {<br>
+ // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).<br>
+ return Offset == 0 ||<br>
+ setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));<br>
+ }<br>
+<br>
+ // \brief Determines if the Point is within Start and End.<br>
+ bool isPointWithin(const SourceLocation Start, const SourceLocation End) {<br>
+ // FIXME: Add tests for Point == End.<br>
+ return Point == Start || Point == End ||<br>
+ (Context.getSourceManager().i<wbr>sBeforeInTranslationUnit(Start<wbr>,<br>
+ Point) &&<br>
+ Context.getSourceManager().isB<wbr>eforeInTranslationUnit(Point, End));<br>
+ }<br>
+<br>
+ const NamedDecl *Result;<br>
+ const SourceLocation Point; // The location to find the NamedDecl.<br>
+ const std::string Name;<br>
+ const ASTContext &Context;<br>
+};<br>
+} // namespace<br>
+<br>
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,<br>
+ const SourceLocation Point) {<br>
+ const SourceManager &SM = Context.getSourceManager();<br>
+ NamedDeclFindingASTVisitor Visitor(Point, Context);<br>
+<br>
+ // Try to be clever about pruning down the number of top-level declarations we<br>
+ // see. If both start and end is either before or after the point we're<br>
+ // looking for the point cannot be inside of this decl. Don't even look at it.<br>
+ for (auto *CurrDecl : Context.getTranslationUnitDecl<wbr>()->decls()) {<br>
+ SourceLocation StartLoc = CurrDecl->getLocStart();<br>
+ SourceLocation EndLoc = CurrDecl->getLocEnd();<br>
+ if (StartLoc.isValid() && EndLoc.isValid() &&<br>
+ SM.isBeforeInTranslationUnit(S<wbr>tartLoc, Point) !=<br>
+ SM.isBeforeInTranslationUnit(E<wbr>ndLoc, Point))<br>
+ Visitor.TraverseDecl(CurrDecl)<wbr>;<br>
+ }<br>
+<br>
+ NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));<br>
+ for (const auto &Location : Finder.getNestedNameSpecifierL<wbr>ocations())<br>
+ Visitor.handleNestedNameSpecif<wbr>ierLoc(Location);<br>
+<br>
+ return Visitor.getNamedDecl();<br>
+}<br>
+<br>
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,<br>
+ const std::string &Name) {<br>
+ NamedDeclFindingASTVisitor Visitor(Name, Context);<br>
+ Visitor.TraverseDecl(Context.g<wbr>etTranslationUnitDecl());<br>
+<br>
+ return Visitor.getNamedDecl();<br>
+}<br>
+<br>
+std::string getUSRForDecl(const Decl *Decl) {<br>
+ llvm::SmallVector<char, 128> Buff;<br>
+<br>
+ // FIXME: Add test for the nullptr case.<br>
+ if (Decl == nullptr || index::generateUSRForDecl(Decl<wbr>, Buff))<br>
+ return "";<br>
+<br>
+ return std::string(Buff.data(), Buff.size());<br>
+}<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
<br>
Added: cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFindingAction.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/lib/Tooling/Re<wbr>factoring/Rename/USRFindingAct<wbr>ion.cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFindingAction.<wbr>cpp (added)<br>
+++ cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRFindingAction.<wbr>cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,236 @@<br>
+//===--- USRFindingAction.cpp - Clang refactoring library -----------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Provides an action to find USR for the symbol at <offset>, as well as<br>
+/// all additional USRs.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFindingAction.h"<br>
+#include "clang/AST/AST.h"<br>
+#include "clang/AST/ASTConsumer.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/Decl.h"<br>
+#include "clang/AST/RecursiveASTVisitor<wbr>.h"<br>
+#include "clang/Basic/FileManager.h"<br>
+#include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>
+#include "clang/Frontend/FrontendAction<wbr>.h"<br>
+#include "clang/Lex/Lexer.h"<br>
+#include "clang/Lex/Preprocessor.h"<br>
+#include "clang/Tooling/CommonOptionsPa<wbr>rser.h"<br>
+#include "clang/Tooling/Refactoring.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFinder.h"<br>
+#include "clang/Tooling/Tooling.h"<br>
+<br>
+#include <algorithm><br>
+#include <set><br>
+#include <string><br>
+#include <vector><br>
+<br>
+using namespace llvm;<br>
+<br>
+namespace clang {<br>
+namespace tooling {<br>
+<br>
+namespace {<br>
+// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to<br>
+// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given<br>
+// Decl refers to class and adds USRs of all overridden methods if Decl refers<br>
+// to virtual method.<br>
+class AdditionalUSRFinder : public RecursiveASTVisitor<Additional<wbr>USRFinder> {<br>
+public:<br>
+ AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)<br>
+ : FoundDecl(FoundDecl), Context(Context) {}<br>
+<br>
+ std::vector<std::string> Find() {<br>
+ // Fill OverriddenMethods and PartialSpecs storages.<br>
+ TraverseDecl(Context.getTransl<wbr>ationUnitDecl());<br>
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundD<wbr>ecl)) {<br>
+ addUSRsOfOverridenFunctions(Me<wbr>thodDecl);<br>
+ for (const auto &OverriddenMethod : OverriddenMethods) {<br>
+ if (checkIfOverriddenFunctionAsce<wbr>nds(OverriddenMethod))<br>
+ USRSet.insert(getUSRForDecl(Ov<wbr>erriddenMethod));<br>
+ }<br>
+ } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundD<wbr>ecl)) {<br>
+ handleCXXRecordDecl(RecordDecl<wbr>);<br>
+ } else if (const auto *TemplateDecl =<br>
+ dyn_cast<ClassTemplateDecl>(F<wbr>oundDecl)) {<br>
+ handleClassTemplateDecl(Templa<wbr>teDecl);<br>
+ } else {<br>
+ USRSet.insert(getUSRForDecl(Fo<wbr>undDecl));<br>
+ }<br>
+ return std::vector<std::string>(USRSe<wbr>t.begin(), USRSet.end());<br>
+ }<br>
+<br>
+ bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {<br>
+ if (MethodDecl->isVirtual())<br>
+ OverriddenMethods.push_back(Me<wbr>thodDecl);<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitClassTemplatePartialSpeci<wbr>alizationDecl(<br>
+ const ClassTemplatePartialSpecializa<wbr>tionDecl *PartialSpec) {<br>
+ PartialSpecs.push_back(Partial<wbr>Spec);<br>
+ return true;<br>
+ }<br>
+<br>
+private:<br>
+ void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {<br>
+ RecordDecl = RecordDecl->getDefinition();<br>
+ if (const auto *ClassTemplateSpecDecl =<br>
+ dyn_cast<ClassTemplateSpeciali<wbr>zationDecl>(RecordDecl))<br>
+ handleClassTemplateDecl(ClassT<wbr>emplateSpecDecl->getSpecialize<wbr>dTemplate());<br>
+ addUSRsOfCtorDtors(RecordDecl)<wbr>;<br>
+ }<br>
+<br>
+ void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {<br>
+ for (const auto *Specialization : TemplateDecl->specializations(<wbr>))<br>
+ addUSRsOfCtorDtors(Specializat<wbr>ion);<br>
+<br>
+ for (const auto *PartialSpec : PartialSpecs) {<br>
+ if (PartialSpec->getSpecializedTe<wbr>mplate() == TemplateDecl)<br>
+ addUSRsOfCtorDtors(PartialSpec<wbr>);<br>
+ }<br>
+ addUSRsOfCtorDtors(TemplateDec<wbr>l->getTemplatedDecl());<br>
+ }<br>
+<br>
+ void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {<br>
+ RecordDecl = RecordDecl->getDefinition();<br>
+<br>
+ // Skip if the CXXRecordDecl doesn't have definition.<br>
+ if (!RecordDecl)<br>
+ return;<br>
+<br>
+ for (const auto *CtorDecl : RecordDecl->ctors())<br>
+ USRSet.insert(getUSRForDecl(Ct<wbr>orDecl));<br>
+<br>
+ USRSet.insert(getUSRForDecl(Re<wbr>cordDecl->getDestructor()));<br>
+ USRSet.insert(getUSRForDecl(Re<wbr>cordDecl));<br>
+ }<br>
+<br>
+ void addUSRsOfOverridenFunctions(co<wbr>nst CXXMethodDecl *MethodDecl) {<br>
+ USRSet.insert(getUSRForDecl(Me<wbr>thodDecl));<br>
+ // Recursively visit each OverridenMethod.<br>
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods<wbr>())<br>
+ addUSRsOfOverridenFunctions(Ov<wbr>erriddenMethod);<br>
+ }<br>
+<br>
+ bool checkIfOverriddenFunctionAscen<wbr>ds(const CXXMethodDecl *MethodDecl) {<br>
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods<wbr>()) {<br>
+ if (USRSet.find(getUSRForDecl(Ove<wbr>rriddenMethod)) != USRSet.end())<br>
+ return true;<br>
+ return checkIfOverriddenFunctionAscen<wbr>ds(OverriddenMethod);<br>
+ }<br>
+ return false;<br>
+ }<br>
+<br>
+ const Decl *FoundDecl;<br>
+ ASTContext &Context;<br>
+ std::set<std::string> USRSet;<br>
+ std::vector<const CXXMethodDecl *> OverriddenMethods;<br>
+ std::vector<const ClassTemplatePartialSpecializa<wbr>tionDecl *> PartialSpecs;<br>
+};<br>
+} // namespace<br>
+<br>
+class NamedDeclFindingConsumer : public ASTConsumer {<br>
+public:<br>
+ NamedDeclFindingConsumer(Array<wbr>Ref<unsigned> SymbolOffsets,<br>
+ ArrayRef<std::string> QualifiedNames,<br>
+ std::vector<std::string> &SpellingNames,<br>
+ std::vector<std::vector<std::<wbr>string>> &USRList,<br>
+ bool Force, bool &ErrorOccurred)<br>
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames)<wbr>,<br>
+ SpellingNames(SpellingNames), USRList(USRList), Force(Force),<br>
+ ErrorOccurred(ErrorOccurred) {}<br>
+<br>
+private:<br>
+ bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,<br>
+ unsigned SymbolOffset, const std::string &QualifiedName) {<br>
+ DiagnosticsEngine &Engine = Context.getDiagnostics();<br>
+ const FileID MainFileID = SourceMgr.getMainFileID();<br>
+<br>
+ if (SymbolOffset >= SourceMgr.getFileIDSize(MainFi<wbr>leID)) {<br>
+ ErrorOccurred = true;<br>
+ unsigned InvalidOffset = Engine.getCustomDiagID(<br>
+ DiagnosticsEngine::Error,<br>
+ "SourceLocation in file %0 at offset %1 is invalid");<br>
+ Engine.Report(SourceLocation()<wbr>, InvalidOffset)<br>
+ << SourceMgr.getFileEntryForID(Ma<wbr>inFileID)->getName() << SymbolOffset;<br>
+ return false;<br>
+ }<br>
+<br>
+ const SourceLocation Point = SourceMgr.getLocForStartOfFile<wbr>(MainFileID)<br>
+ .getLocWithOffset(SymbolOffse<wbr>t);<br>
+ const NamedDecl *FoundDecl = QualifiedName.empty()<br>
+ ? getNamedDeclAt(Context, Point)<br>
+ : getNamedDeclFor(Context, QualifiedName);<br>
+<br>
+ if (FoundDecl == nullptr) {<br>
+ if (QualifiedName.empty()) {<br>
+ FullSourceLoc FullLoc(Point, SourceMgr);<br>
+ unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(<br>
+ DiagnosticsEngine::Error,<br>
+ "clang-rename could not find symbol (offset %0)");<br>
+ Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;<br>
+ ErrorOccurred = true;<br>
+ return false;<br>
+ }<br>
+<br>
+ if (Force)<br>
+ return true;<br>
+<br>
+ unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(<br>
+ DiagnosticsEngine::Error, "clang-rename could not find symbol %0");<br>
+ Engine.Report(CouldNotFindSymb<wbr>olNamed) << QualifiedName;<br>
+ ErrorOccurred = true;<br>
+ return false;<br>
+ }<br>
+<br>
+ // If FoundDecl is a constructor or destructor, we want to instead take<br>
+ // the Decl of the corresponding class.<br>
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(F<wbr>oundDecl))<br>
+ FoundDecl = CtorDecl->getParent();<br>
+ else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(Fo<wbr>undDecl))<br>
+ FoundDecl = DtorDecl->getParent();<br>
+<br>
+ SpellingNames.push_back(FoundD<wbr>ecl->getNameAsString());<br>
+ AdditionalUSRFinder Finder(FoundDecl, Context);<br>
+ USRList.push_back(Finder.Find(<wbr>));<br>
+ return true;<br>
+ }<br>
+<br>
+ void HandleTranslationUnit(ASTConte<wbr>xt &Context) override {<br>
+ const SourceManager &SourceMgr = Context.getSourceManager();<br>
+ for (unsigned Offset : SymbolOffsets) {<br>
+ if (!FindSymbol(Context, SourceMgr, Offset, ""))<br>
+ return;<br>
+ }<br>
+ for (const std::string &QualifiedName : QualifiedNames) {<br>
+ if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))<br>
+ return;<br>
+ }<br>
+ }<br>
+<br>
+ ArrayRef<unsigned> SymbolOffsets;<br>
+ ArrayRef<std::string> QualifiedNames;<br>
+ std::vector<std::string> &SpellingNames;<br>
+ std::vector<std::vector<std::s<wbr>tring>> &USRList;<br>
+ bool Force;<br>
+ bool &ErrorOccurred;<br>
+};<br>
+<br>
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsum<wbr>er() {<br>
+ return llvm::make_unique<NamedDeclFin<wbr>dingConsumer>(<br>
+ SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,<br>
+ ErrorOccurred);<br>
+}<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
<br>
Added: cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRLocFinder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/lib/Tooling/Re<wbr>factoring/Rename/USRLocFinder.<wbr>cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRLocFinder.cpp (added)<br>
+++ cfe/trunk/lib/Tooling/Refactor<wbr>ing/Rename/USRLocFinder.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,509 @@<br>
+//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Methods for finding all instances of a USR. Our strategy is very<br>
+/// simple; we just compare the USR at every relevant AST node with the one<br>
+/// provided.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRLocFinder.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/RecursiveASTVisitor<wbr>.h"<br>
+#include "clang/Basic/LLVM.h"<br>
+#include "clang/Basic/SourceLocation.h"<br>
+#include "clang/Basic/SourceManager.h"<br>
+#include "clang/Lex/Lexer.h"<br>
+#include "clang/Tooling/Core/Lookup.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFinder.h"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/Support/Casting.h"<br>
+#include <cstddef><br>
+#include <set><br>
+#include <string><br>
+#include <vector><br>
+<br>
+using namespace llvm;<br>
+<br>
+namespace clang {<br>
+namespace tooling {<br>
+<br>
+namespace {<br>
+<br>
+// \brief This visitor recursively searches for all instances of a USR in a<br>
+// translation unit and stores them for later usage.<br>
+class USRLocFindingASTVisitor<br>
+ : public clang::RecursiveASTVisitor<USR<wbr>LocFindingASTVisitor> {<br>
+public:<br>
+ explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,<br>
+ StringRef PrevName,<br>
+ const ASTContext &Context)<br>
+ : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {<br>
+ }<br>
+<br>
+ // Declaration visitors:<br>
+<br>
+ bool VisitCXXConstructorDecl(clang:<wbr>:CXXConstructorDecl *ConstructorDecl) {<br>
+ for (const auto *Initializer : ConstructorDecl->inits()) {<br>
+ // Ignore implicit initializers.<br>
+ if (!Initializer->isWritten())<br>
+ continue;<br>
+ if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {<br>
+ if (USRSet.find(getUSRForDecl(Fie<wbr>ldDecl)) != USRSet.end())<br>
+ LocationsFound.push_back(Initi<wbr>alizer->getSourceLocation());<br>
+ }<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitNamedDecl(const NamedDecl *Decl) {<br>
+ if (USRSet.find(getUSRForDecl(Dec<wbr>l)) != USRSet.end())<br>
+ checkAndAddLocation(Decl->getL<wbr>ocation());<br>
+ return true;<br>
+ }<br>
+<br>
+ // Expression visitors:<br>
+<br>
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {<br>
+ const NamedDecl *Decl = Expr->getFoundDecl();<br>
+<br>
+ if (USRSet.find(getUSRForDecl(Dec<wbr>l)) != USRSet.end()) {<br>
+ const SourceManager &Manager = Decl->getASTContext().getSourc<wbr>eManager();<br>
+ SourceLocation Location = Manager.getSpellingLoc(Expr->g<wbr>etLocation());<br>
+ checkAndAddLocation(Location);<br>
+ }<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitMemberExpr(const MemberExpr *Expr) {<br>
+ const NamedDecl *Decl = Expr->getFoundDecl().getDecl()<wbr>;<br>
+ if (USRSet.find(getUSRForDecl(Dec<wbr>l)) != USRSet.end()) {<br>
+ const SourceManager &Manager = Decl->getASTContext().getSourc<wbr>eManager();<br>
+ SourceLocation Location = Manager.getSpellingLoc(Expr->g<wbr>etMemberLoc());<br>
+ checkAndAddLocation(Location);<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ // Other visitors:<br>
+<br>
+ bool VisitTypeLoc(const TypeLoc Loc) {<br>
+ if (USRSet.find(getUSRForDecl(Loc<wbr>.getType()->getAsCXXRecordDecl<wbr>())) !=<br>
+ USRSet.end())<br>
+ checkAndAddLocation(Loc.getBeg<wbr>inLoc());<br>
+ if (const auto *TemplateTypeParm =<br>
+ dyn_cast<TemplateTypeParmType><wbr>(Loc.getType())) {<br>
+ if (USRSet.find(getUSRForDecl(Tem<wbr>plateTypeParm->getDecl())) !=<br>
+ USRSet.end())<br>
+ checkAndAddLocation(Loc.getBeg<wbr>inLoc());<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ // Non-visitors:<br>
+<br>
+ // \brief Returns a list of unique locations. Duplicate or overlapping<br>
+ // locations are erroneous and should be reported!<br>
+ const std::vector<clang::SourceLocat<wbr>ion> &getLocationsFound() const {<br>
+ return LocationsFound;<br>
+ }<br>
+<br>
+ // Namespace traversal:<br>
+ void handleNestedNameSpecifierLoc(N<wbr>estedNameSpecifierLoc NameLoc) {<br>
+ while (NameLoc) {<br>
+ const NamespaceDecl *Decl =<br>
+ NameLoc.getNestedNameSpecifier<wbr>()->getAsNamespace();<br>
+ if (Decl && USRSet.find(getUSRForDecl(Decl<wbr>)) != USRSet.end())<br>
+ checkAndAddLocation(NameLoc.ge<wbr>tLocalBeginLoc());<br>
+ NameLoc = NameLoc.getPrefix();<br>
+ }<br>
+ }<br>
+<br>
+private:<br>
+ void checkAndAddLocation(SourceLoca<wbr>tion Loc) {<br>
+ const SourceLocation BeginLoc = Loc;<br>
+ const SourceLocation EndLoc = Lexer::getLocForEndOfToken(<br>
+ BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());<br>
+ StringRef TokenName =<br>
+ Lexer::getSourceText(CharSourc<wbr>eRange::getTokenRange(<wbr>BeginLoc, EndLoc),<br>
+ Context.getSourceManager(), Context.getLangOpts());<br>
+ size_t Offset = TokenName.find(PrevName);<br>
+<br>
+ // The token of the source location we find actually has the old<br>
+ // name.<br>
+ if (Offset != StringRef::npos)<br>
+ LocationsFound.push_back(Begin<wbr>Loc.getLocWithOffset(Offset));<br>
+ }<br>
+<br>
+ const std::set<std::string> USRSet;<br>
+ const std::string PrevName;<br>
+ std::vector<clang::SourceLocat<wbr>ion> LocationsFound;<br>
+ const ASTContext &Context;<br>
+};<br>
+<br>
+SourceLocation StartLocationForType(TypeLoc TL) {<br>
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the<br>
+ // `struct` but including the namespace qualifier, `a::`.<br>
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedType<wbr>Loc>()) {<br>
+ NestedNameSpecifierLoc NestedNameSpecifier =<br>
+ ElaboratedTypeLoc.getQualifier<wbr>Loc();<br>
+ if (NestedNameSpecifier.getNested<wbr>NameSpecifier())<br>
+ return NestedNameSpecifier.getBeginLo<wbr>c();<br>
+ TL = TL.getNextTypeLoc();<br>
+ }<br>
+ return TL.getLocStart();<br>
+}<br>
+<br>
+SourceLocation EndLocationForType(TypeLoc TL) {<br>
+ // Dig past any namespace or keyword qualifications.<br>
+ while (TL.getTypeLocClass() == TypeLoc::Elaborated ||<br>
+ TL.getTypeLocClass() == TypeLoc::Qualified)<br>
+ TL = TL.getNextTypeLoc();<br>
+<br>
+ // The location for template specializations (e.g. Foo<int>) includes the<br>
+ // templated types in its location range. We want to restrict this to just<br>
+ // before the `<` character.<br>
+ if (TL.getTypeLocClass() == TypeLoc::TemplateSpecializatio<wbr>n) {<br>
+ return TL.castAs<TemplateSpecializati<wbr>onTypeLoc>()<br>
+ .getLAngleLoc()<br>
+ .getLocWithOffset(-1);<br>
+ }<br>
+ return TL.getEndLoc();<br>
+}<br>
+<br>
+NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {<br>
+ // Dig past any keyword qualifications.<br>
+ while (TL.getTypeLocClass() == TypeLoc::Qualified)<br>
+ TL = TL.getNextTypeLoc();<br>
+<br>
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the<br>
+ // `struct` but including the namespace qualifier, `a::`.<br>
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedType<wbr>Loc>())<br>
+ return ElaboratedTypeLoc.getQualifier<wbr>Loc().getNestedNameSpecifier()<wbr>;<br>
+ return nullptr;<br>
+}<br>
+<br>
+// Find all locations identified by the given USRs for rename.<br>
+//<br>
+// This class will traverse the AST and find every AST node whose USR is in the<br>
+// given USRs' set.<br>
+class RenameLocFinder : public RecursiveASTVisitor<RenameLocF<wbr>inder> {<br>
+public:<br>
+ RenameLocFinder(llvm::ArrayRef<wbr><std::string> USRs, ASTContext &Context)<br>
+ : USRSet(USRs.begin(), USRs.end()), Context(Context) {}<br>
+<br>
+ // A structure records all information of a symbol reference being renamed.<br>
+ // We try to add as few prefix qualifiers as possible.<br>
+ struct RenameInfo {<br>
+ // The begin location of a symbol being renamed.<br>
+ SourceLocation Begin;<br>
+ // The end location of a symbol being renamed.<br>
+ SourceLocation End;<br>
+ // The declaration of a symbol being renamed (can be nullptr).<br>
+ const NamedDecl *FromDecl;<br>
+ // The declaration in which the nested name is contained (can be nullptr).<br>
+ const Decl *Context;<br>
+ // The nested name being replaced (can be nullptr).<br>
+ const NestedNameSpecifier *Specifier;<br>
+ };<br>
+<br>
+ // FIXME: Currently, prefix qualifiers will be added to the renamed symbol<br>
+ // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming<br>
+ // "a::Foo" to "b::Bar").<br>
+ // For renaming declarations/definitions, prefix qualifiers should be filtered<br>
+ // out.<br>
+ bool VisitNamedDecl(const NamedDecl *Decl) {<br>
+ // UsingDecl has been handled in other place.<br>
+ if (llvm::isa<UsingDecl>(Decl))<br>
+ return true;<br>
+<br>
+ // DestructorDecl has been handled in Typeloc.<br>
+ if (llvm::isa<CXXDestructorDecl>(<wbr>Decl))<br>
+ return true;<br>
+<br>
+ if (Decl->isImplicit())<br>
+ return true;<br>
+<br>
+ if (isInUSRSet(Decl)) {<br>
+ RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr,<br>
+ nullptr, nullptr};<br>
+ RenameInfos.push_back(Info);<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {<br>
+ const NamedDecl *Decl = Expr->getFoundDecl();<br>
+ if (isInUSRSet(Decl)) {<br>
+ RenameInfo Info = {Expr->getSourceRange().getBeg<wbr>in(),<br>
+ Expr->getSourceRange().<wbr>getEnd(), Decl,<br>
+ getClosestAncestorDecl(*Expr)<wbr>, Expr->getQualifier()};<br>
+ RenameInfos.push_back(Info);<br>
+ }<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitUsingDecl(const UsingDecl *Using) {<br>
+ for (const auto *UsingShadow : Using->shadows()) {<br>
+ if (isInUSRSet(UsingShadow->getTa<wbr>rgetDecl())) {<br>
+ UsingDecls.push_back(Using);<br>
+ break;<br>
+ }<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitNestedNameSpecifierLocati<wbr>ons(NestedNameSpecifierLoc NestedLoc) {<br>
+ if (!NestedLoc.getNestedNameSpeci<wbr>fier()->getAsType())<br>
+ return true;<br>
+ if (IsTypeAliasWhichWillBeRenamed<wbr>Elsewhere(NestedLoc.<wbr>getTypeLoc()))<br>
+ return true;<br>
+<br>
+ if (const auto *TargetDecl =<br>
+ getSupportedDeclFromTypeLoc(Ne<wbr>stedLoc.getTypeLoc())) {<br>
+ if (isInUSRSet(TargetDecl)) {<br>
+ RenameInfo Info = {NestedLoc.getBeginLoc(),<br>
+ EndLocationForType(NestedLoc.<wbr>getTypeLoc()),<br>
+ TargetDecl, getClosestAncestorDecl(NestedL<wbr>oc),<br>
+ NestedLoc.getNestedNameSpecif<wbr>ier()->getPrefix()};<br>
+ RenameInfos.push_back(Info);<br>
+ }<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ bool VisitTypeLoc(TypeLoc Loc) {<br>
+ if (IsTypeAliasWhichWillBeRenamed<wbr>Elsewhere(Loc))<br>
+ return true;<br>
+<br>
+ auto Parents = Context.getParents(Loc);<br>
+ TypeLoc ParentTypeLoc;<br>
+ if (!Parents.empty()) {<br>
+ // Handle cases of nested name specificier locations.<br>
+ //<br>
+ // The VisitNestedNameSpecifierLoc interface is not impelmented in<br>
+ // RecursiveASTVisitor, we have to handle it explicitly.<br>
+ if (const auto *NSL = Parents[0].get<NestedNameSpeci<wbr>fierLoc>()) {<br>
+ VisitNestedNameSpecifierLocati<wbr>ons(*NSL);<br>
+ return true;<br>
+ }<br>
+<br>
+ if (const auto *TL = Parents[0].get<TypeLoc>())<br>
+ ParentTypeLoc = *TL;<br>
+ }<br>
+<br>
+ // Handle the outermost TypeLoc which is directly linked to the interesting<br>
+ // declaration and don't handle nested name specifier locations.<br>
+ if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Lo<wbr>c)) {<br>
+ if (isInUSRSet(TargetDecl)) {<br>
+ // Only handle the outermost typeLoc.<br>
+ //<br>
+ // For a type like "a::Foo", there will be two typeLocs for it.<br>
+ // One ElaboratedType, the other is RecordType:<br>
+ //<br>
+ // ElaboratedType 0x33b9390 'a::Foo' sugar<br>
+ // `-RecordType 0x338fef0 'class a::Foo'<br>
+ // `-CXXRecord 0x338fe58 'Foo'<br>
+ //<br>
+ // Skip if this is an inner typeLoc.<br>
+ if (!ParentTypeLoc.isNull() &&<br>
+ isInUSRSet(getSupportedDeclFro<wbr>mTypeLoc(ParentTypeLoc)))<br>
+ return true;<br>
+ RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc),<br>
+ TargetDecl, getClosestAncestorDecl(Loc),<br>
+ GetNestedNameForType(Loc)};<br>
+ RenameInfos.push_back(Info);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Handle specific template class specialiation cases.<br>
+ if (const auto *TemplateSpecType =<br>
+ dyn_cast<TemplateSpecializatio<wbr>nType>(Loc.getType())) {<br>
+ TypeLoc TargetLoc = Loc;<br>
+ if (!ParentTypeLoc.isNull()) {<br>
+ if (llvm::isa<ElaboratedType>(Par<wbr>entTypeLoc.getType()))<br>
+ TargetLoc = ParentTypeLoc;<br>
+ }<br>
+<br>
+ if (isInUSRSet(TemplateSpecType-><wbr>getTemplateName().getAsTemplat<wbr>eDecl())) {<br>
+ TypeLoc TargetLoc = Loc;<br>
+ // FIXME: Find a better way to handle this case.<br>
+ // For the qualified template class specification type like<br>
+ // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc<br>
+ // (ElaboratedType) of the TemplateSpecializationType in order to<br>
+ // catch the prefix qualifiers "ns::".<br>
+ if (!ParentTypeLoc.isNull() &&<br>
+ llvm::isa<ElaboratedType>(Pare<wbr>ntTypeLoc.getType()))<br>
+ TargetLoc = ParentTypeLoc;<br>
+ RenameInfo Info = {<br>
+ StartLocationForType(TargetLoc<wbr>), EndLocationForType(TargetLoc),<br>
+ TemplateSpecType->getTemplateN<wbr>ame().getAsTemplateDecl(),<br>
+ getClosestAncestorDecl(<br>
+ ast_type_traits::DynTypedNode:<wbr>:create(TargetLoc)),<br>
+ GetNestedNameForType(TargetLoc<wbr>)};<br>
+ RenameInfos.push_back(Info);<br>
+ }<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ // Returns a list of RenameInfo.<br>
+ const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }<br>
+<br>
+ // Returns a list of using declarations which are needed to update.<br>
+ const std::vector<const UsingDecl *> &getUsingDecls() const {<br>
+ return UsingDecls;<br>
+ }<br>
+<br>
+private:<br>
+ // FIXME: This method may not be suitable for renaming other types like alias<br>
+ // types. Need to figure out a way to handle it.<br>
+ bool IsTypeAliasWhichWillBeRenamedE<wbr>lsewhere(TypeLoc TL) const {<br>
+ while (!TL.isNull()) {<br>
+ // SubstTemplateTypeParm is the TypeLocation class for a substituted type<br>
+ // inside a template expansion so we ignore these. For example:<br>
+ //<br>
+ // template<typename T> struct S {<br>
+ // T t; // <-- this T becomes a TypeLoc(int) with class<br>
+ // // SubstTemplateTypeParm when S<int> is instantiated<br>
+ // }<br>
+ if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm<wbr>)<br>
+ return true;<br>
+<br>
+ // Typedef is the TypeLocation class for a type which is a typedef to the<br>
+ // type we want to replace. We ignore the use of the typedef as we will<br>
+ // replace the definition of it. For example:<br>
+ //<br>
+ // typedef int T;<br>
+ // T a; // <--- This T is a TypeLoc(int) with class Typedef.<br>
+ if (TL.getTypeLocClass() == TypeLoc::Typedef)<br>
+ return true;<br>
+ TL = TL.getNextTypeLoc();<br>
+ }<br>
+ return false;<br>
+ }<br>
+<br>
+ // Get the supported declaration from a given typeLoc. If the declaration type<br>
+ // is not supported, returns nullptr.<br>
+ //<br>
+ // FIXME: support more types, e.g. enum, type alias.<br>
+ const NamedDecl *getSupportedDeclFromTypeLoc(T<wbr>ypeLoc Loc) {<br>
+ if (const auto *RD = Loc.getType()->getAsCXXRecordD<wbr>ecl())<br>
+ return RD;<br>
+ return nullptr;<br>
+ }<br>
+<br>
+ // Get the closest ancester which is a declaration of a given AST node.<br>
+ template <typename ASTNodeType><br>
+ const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {<br>
+ auto Parents = Context.getParents(Node);<br>
+ // FIXME: figure out how to handle it when there are multiple parents.<br>
+ if (Parents.size() != 1)<br>
+ return nullptr;<br>
+ if (ast_type_traits::ASTNodeKind:<wbr>:getFromNodeKind<Decl>().isBas<wbr>eOf(<br>
+ Parents[0].getNodeKind()))<br>
+ return Parents[0].template get<Decl>();<br>
+ return getClosestAncestorDecl(Parents<wbr>[0]);<br>
+ }<br>
+<br>
+ // Get the parent typeLoc of a given typeLoc. If there is no such parent,<br>
+ // return nullptr.<br>
+ const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {<br>
+ auto Parents = Context.getParents(Loc);<br>
+ // FIXME: figure out how to handle it when there are multiple parents.<br>
+ if (Parents.size() != 1)<br>
+ return nullptr;<br>
+ return Parents[0].get<TypeLoc>();<br>
+ }<br>
+<br>
+ // Check whether the USR of a given Decl is in the USRSet.<br>
+ bool isInUSRSet(const Decl *Decl) const {<br>
+ auto USR = getUSRForDecl(Decl);<br>
+ if (USR.empty())<br>
+ return false;<br>
+ return llvm::is_contained(USRSet, USR);<br>
+ }<br>
+<br>
+ const std::set<std::string> USRSet;<br>
+ ASTContext &Context;<br>
+ std::vector<RenameInfo> RenameInfos;<br>
+ // Record all interested using declarations which contains the using-shadow<br>
+ // declarations of the symbol declarations being renamed.<br>
+ std::vector<const UsingDecl *> UsingDecls;<br>
+};<br>
+<br>
+} // namespace<br>
+<br>
+std::vector<SourceLocation><br>
+getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName,<br>
+ Decl *Decl) {<br>
+ USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());<br>
+ Visitor.TraverseDecl(Decl);<br>
+ NestedNameSpecifierLocFinder Finder(Decl->getASTContext());<br>
+<br>
+ for (const auto &Location : Finder.getNestedNameSpecifierL<wbr>ocations())<br>
+ Visitor.handleNestedNameSpecif<wbr>ierLoc(Location);<br>
+<br>
+ return Visitor.getLocationsFound();<br>
+}<br>
+<br>
+std::vector<tooling::AtomicCh<wbr>ange><br>
+createRenameAtomicChanges(llv<wbr>m::ArrayRef<std::string> USRs,<br>
+ llvm::StringRef NewName, Decl *TranslationUnitDecl) {<br>
+ RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTCon<wbr>text());<br>
+ Finder.TraverseDecl(Translatio<wbr>nUnitDecl);<br>
+<br>
+ const SourceManager &SM =<br>
+ TranslationUnitDecl->getASTCon<wbr>text().getSourceManager();<br>
+<br>
+ std::vector<tooling::AtomicCha<wbr>nge> AtomicChanges;<br>
+ auto Replace = [&](SourceLocation Start, SourceLocation End,<br>
+ llvm::StringRef Text) {<br>
+ tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);<br>
+ llvm::Error Err = ReplaceChange.replace(<br>
+ SM, CharSourceRange::getTokenRange<wbr>(Start, End), Text);<br>
+ if (Err) {<br>
+ llvm::errs() << "Faile to add replacement to AtomicChange: "<br>
+ << llvm::toString(std::move(Err)) << "\n";<br>
+ return;<br>
+ }<br>
+ AtomicChanges.push_back(std::m<wbr>ove(ReplaceChange));<br>
+ };<br>
+<br>
+ for (const auto &RenameInfo : Finder.getRenameInfos()) {<br>
+ std::string ReplacedName = NewName.str();<br>
+ if (RenameInfo.FromDecl && RenameInfo.Context) {<br>
+ if (!llvm::isa<clang::Translation<wbr>UnitDecl>(<br>
+ RenameInfo.Context->getDeclCon<wbr>text())) {<br>
+ ReplacedName = tooling::replaceNestedName(<br>
+ RenameInfo.Specifier, RenameInfo.Context->getDeclCon<wbr>text(),<br>
+ RenameInfo.FromDecl,<br>
+ NewName.startswith("::") ? NewName.str() : ("::" + NewName).str());<br>
+ }<br>
+ }<br>
+ // If the NewName contains leading "::", add it back.<br>
+ if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)<br>
+ ReplacedName = NewName.str();<br>
+ Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);<br>
+ }<br>
+<br>
+ // Hanlde using declarations explicitly as "using a::Foo" don't trigger<br>
+ // typeLoc for "a::Foo".<br>
+ for (const auto *Using : Finder.getUsingDecls())<br>
+ Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());<br>
+<br>
+ return AtomicChanges;<br>
+}<br>
+<br>
+} // end namespace tooling<br>
+} // end namespace clang<br>
<br>
Modified: cfe/trunk/test/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/CMakeList<wbr>s.txt?rev=306840&r1=306839&r2=<wbr>306840&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CMakeLists.txt (original)<br>
+++ cfe/trunk/test/CMakeLists.txt Fri Jun 30 09:36:09 2017<br>
@@ -47,6 +47,7 @@ list(APPEND CLANG_TEST_DEPS<br>
clang-tblgen<br>
clang-offload-bundler<br>
clang-import-test<br>
+ clang-rename<br>
)<br>
<br>
if(CLANG_ENABLE_STATIC_ANALYZ<wbr>ER)<br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assAsTemplateArgument.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassAsTemplateArgument.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassAsTemplateArgument.<wbr>cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assAsTemplateArgument.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assAsTemplateArgument.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,21 @@<br>
+class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {};<br>
+<br>
+template <typename T><br>
+void func() {}<br>
+<br>
+template <typename T><br>
+class Baz {};<br>
+<br>
+int main() {<br>
+ func<Foo>(); // CHECK: func<Bar>();<br>
+ Baz<Foo> /* Test 2 */ obj; // CHECK: Baz<Bar> /* Test 2 */ obj;<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assFindByName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassFindByName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassFindByName.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assFindByName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assFindByName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,10 @@<br>
+class Foo { // CHECK: class Bar {<br>
+};<br>
+<br>
+int main() {<br>
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assReplacements.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassReplacements.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassReplacements.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assReplacements.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assReplacements.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,11 @@<br>
+// RUN: rm -rf %t<br>
+// RUN: mkdir -p %t/fixes<br>
+// RUN: cat %s > %t.cpp<br>
+// RUN: clang-rename -offset=254 -new-name=Bar -export-fixes=%t/fixes/clang-r<wbr>ename.yaml %t.cpp --<br>
+// RUN: clang-apply-replacements %t<br>
+// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s<br>
+<br>
+class Foo {}; // CHECK: class Bar {};<br>
+<br>
+// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when changing<br>
+// this file.<br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assSimpleRenaming.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassSimpleRenaming.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassSimpleRenaming.cpp?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assSimpleRenaming.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assSimpleRenaming.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,14 @@<br>
+class Foo /* Test 1 */ { // CHECK: class Bar /* Test 1 */ {<br>
+public:<br>
+ void foo(int x);<br>
+};<br>
+<br>
+void Foo::foo(int x) /* Test 2 */ {} // CHECK: void Bar::foo(int x) /* Test 2 */ {}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assTestMulti.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassTestMulti.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassTestMulti.cpp?rev=306<wbr>840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assTestMulti.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assTestMulti.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,11 @@<br>
+class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ {<br>
+};<br>
+<br>
+class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ {<br>
+};<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Cl<wbr>assTestMultiByName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ClassTestMultiByName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ClassTestMultiByName.cpp?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Cl<wbr>assTestMultiByName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Cl<wbr>assTestMultiByName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,8 @@<br>
+class Foo1 { // CHECK: class Bar1<br>
+};<br>
+<br>
+class Foo2 { // CHECK: class Bar2<br>
+};<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -qualified-name=Foo1 -new-name=Bar1 -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s<br>
<br>
Added: cfe/trunk/test/clang-rename/Co<wbr>mplexFunctionOverride.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ComplexFunctionOverride.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ComplexFunctionOverride.<wbr>cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Co<wbr>mplexFunctionOverride.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Co<wbr>mplexFunctionOverride.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,47 @@<br>
+struct A {<br>
+ virtual void foo() {} /* Test 1 */ // CHECK: virtual void bar() {}<br>
+};<br>
+<br>
+struct B : A {<br>
+ void foo() override {} /* Test 2 */ // CHECK: void bar() override {}<br>
+};<br>
+<br>
+struct C : B {<br>
+ void foo() override {} /* Test 3 */ // CHECK: void bar() override {}<br>
+};<br>
+<br>
+struct D : B {<br>
+ void foo() override {} /* Test 4 */ // CHECK: void bar() override {}<br>
+};<br>
+<br>
+struct E : D {<br>
+ void foo() override {} /* Test 5 */ // CHECK: void bar() override {}<br>
+};<br>
+<br>
+int main() {<br>
+ A a;<br>
+ a.foo(); // CHECK: a.bar();<br>
+ B b;<br>
+ b.foo(); // CHECK: b.bar();<br>
+ C c;<br>
+ c.foo(); // CHECK: c.bar();<br>
+ D d;<br>
+ d.foo(); // CHECK: d.bar();<br>
+ E e;<br>
+ e.foo(); // CHECK: e.bar();<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 4.<br>
+// RUN: clang-rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 5.<br>
+// RUN: clang-rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Co<wbr>mplicatedClassType.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/ComplicatedClassType.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/ComplicatedClassType.cpp?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Co<wbr>mplicatedClassType.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Co<wbr>mplicatedClassType.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,63 @@<br>
+// Forward declaration.<br>
+class Foo; /* Test 1 */ // CHECK: class Bar; /* Test 1 */<br>
+<br>
+class Baz {<br>
+ virtual int getValue() const = 0;<br>
+};<br>
+<br>
+class Foo : public Baz { /* Test 2 */// CHECK: class Bar : public Baz {<br>
+public:<br>
+ Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {}<br>
+<br>
+ Foo &operator++(int) { // CHECK: Bar &operator++(int) {<br>
+ x++;<br>
+ return *this;<br>
+ }<br>
+<br>
+ bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) {<br>
+ return this->x < rhs.x;<br>
+ }<br>
+<br>
+ int getValue() const {<br>
+ return 0;<br>
+ }<br>
+<br>
+private:<br>
+ int x;<br>
+};<br>
+<br>
+int main() {<br>
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;<br>
+ Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10);<br>
+ for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) {<br>
+ }<br>
+ const Foo *C = new Foo(); // CHECK: const Bar *C = new Bar();<br>
+ const_cast<Foo *>(C)->getValue(); // CHECK: const_cast<Bar *>(C)->getValue();<br>
+ Foo foo; // CHECK: Bar foo;<br>
+ const Baz &BazReference = foo;<br>
+ const Baz *BazPointer = &foo;<br>
+ dynamic_cast<const Foo &>(BazReference).getValue(); /* Test 3 */ // CHECK: dynamic_cast<const Bar &>(BazReference).getValue();<br>
+ dynamic_cast<const Foo *>(BazPointer)->getValue(); /* Test 4 */ // CHECK: dynamic_cast<const Bar *>(BazPointer)->getValue();<br>
+ reinterpret_cast<const Foo *>(BazPointer)->getValue(); /* Test 5 */ // CHECK: reinterpret_cast<const Bar *>(BazPointer)->getValue();<br>
+ static_cast<const Foo &>(BazReference).getValue(); /* Test 6 */ // CHECK: static_cast<const Bar &>(BazReference).getValue();<br>
+ static_cast<const Foo *>(BazPointer)->getValue(); /* Test 7 */ // CHECK: static_cast<const Bar *>(BazPointer)->getValue();<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=30 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=1133 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 4.<br>
+// RUN: clang-rename -offset=1266 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 5.<br>
+// RUN: clang-rename -offset=1402 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 6.<br>
+// RUN: clang-rename -offset=1533 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+// Test 7.<br>
+// RUN: clang-rename -offset=1665 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Ct<wbr>or.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Ctor.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Ctor.cpp?rev=306840&view=<wbr>auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Ct<wbr>or.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Ct<wbr>or.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,14 @@<br>
+class Foo { // CHECK: class Bar {<br>
+public:<br>
+ Foo(); /* Test 1 */ // CHECK: Bar();<br>
+};<br>
+<br>
+Foo::Foo() /* Test 2 */ {} // CHECK: Bar::Bar() /* Test 2 */ {}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Ct<wbr>orInitializer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/CtorInitializer.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/CtorInitializer.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Ct<wbr>orInitializer.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Ct<wbr>orInitializer.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,17 @@<br>
+class Baz {};<br>
+<br>
+class Qux {<br>
+ Baz Foo; /* Test 1 */ // CHECK: Baz Bar;<br>
+public:<br>
+ Qux();<br>
+};<br>
+<br>
+Qux::Qux() : Foo() /* Test 2 */ {} // CHECK: Qux::Qux() : Bar() /* Test 2 */ {}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/De<wbr>clRefExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/DeclRefExpr.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/DeclRefExpr.cpp?rev=306840<wbr>&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/De<wbr>clRefExpr.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/De<wbr>clRefExpr.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,24 @@<br>
+class C {<br>
+public:<br>
+ static int Foo; /* Test 1 */ // CHECK: static int Bar;<br>
+};<br>
+<br>
+int foo(int x) { return 0; }<br>
+#define MACRO(a) foo(a)<br>
+<br>
+int main() {<br>
+ C::Foo = 1; /* Test 2 */ // CHECK: C::Bar = 1;<br>
+ MACRO(C::Foo); // CHECK: MACRO(C::Bar);<br>
+ int y = C::Foo; /* Test 3 */ // CHECK: int y = C::Bar;<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Fi<wbr>eld.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Field.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Field.cpp?rev=306840&view=<wbr>auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Fi<wbr>eld.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Fi<wbr>eld.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,15 @@<br>
+class Baz {<br>
+ int Foo; /* Test 1 */ // CHECK: int Bar;<br>
+public:<br>
+ Baz();<br>
+};<br>
+<br>
+Baz::Baz() : Foo(0) /* Test 2 */ {} // CHECK: Baz::Baz() : Bar(0)<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=18 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=89 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Fu<wbr>nctionMacro.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionMacro.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/FunctionMacro.cpp?rev=3068<wbr>40&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Fu<wbr>nctionMacro.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Fu<wbr>nctionMacro.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,20 @@<br>
+#define moo foo // CHECK: #define moo macro_function<br>
+<br>
+int foo() /* Test 1 */ { // CHECK: int macro_function() /* Test 1 */ {<br>
+ return 42;<br>
+}<br>
+<br>
+void boo(int value) {}<br>
+<br>
+void qoo() {<br>
+ foo(); // CHECK: macro_function();<br>
+ boo(foo()); // CHECK: boo(macro_function());<br>
+ moo();<br>
+ boo(moo());<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=68 -new-name=macro_function %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Fu<wbr>nctionOverride.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionOverride.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/FunctionOverride.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Fu<wbr>nctionOverride.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Fu<wbr>nctionOverride.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,13 @@<br>
+class A { virtual void foo(); /* Test 1 */ }; // CHECK: class A { virtual void bar();<br>
+class B : public A { void foo(); /* Test 2 */ }; // CHECK: class B : public A { void bar();<br>
+class C : public B { void foo(); /* Test 3 */ }; // CHECK: class C : public B { void bar();<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Fu<wbr>nctionWithClassFindByName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/FunctionWithClassFindByName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/FunctionWithClassFindByNam<wbr>e.cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Fu<wbr>nctionWithClassFindByName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Fu<wbr>nctionWithClassFindByName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,12 @@<br>
+void foo() {<br>
+}<br>
+<br>
+class Foo { // CHECK: class Bar<br>
+};<br>
+<br>
+int main() {<br>
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;<br>
+ return 0;<br>
+}<br>
+<br>
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>cludeHeaderWithSymbol.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/IncludeHeaderWithSymbol.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/IncludeHeaderWithSymbol.<wbr>cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>cludeHeaderWithSymbol.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>cludeHeaderWithSymbol.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,10 @@<br>
+#include "Inputs/HeaderWithSymbol.h"<br>
+<br>
+int main() {<br>
+ return 0; // CHECK: {{^ return 0;}}<br>
+}<br>
+<br>
+// Test 1.<br>
+// The file IncludeHeaderWithSymbol.cpp doesn't contain the symbol Foo<br>
+// and is expected to be written to stdout without modifications<br>
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | FileCheck %s<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>puts/HeaderWithSymbol.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/HeaderWithSymbol.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Inputs/HeaderWithSymbol.h?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>puts/HeaderWithSymbol.h (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>puts/HeaderWithSymbol.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1 @@<br>
+struct Foo {};<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>puts/OffsetToNewName.yaml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/OffsetToNewName.yaml?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Inputs/OffsetToNewName.yam<wbr>l?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>puts/OffsetToNewName.yaml (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>puts/OffsetToNewName.yaml Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,6 @@<br>
+---<br>
+- Offset: 6<br>
+ NewName: Bar1<br>
+- Offset: 44<br>
+ NewName: Bar2<br>
+...<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>puts/QualifiedNameToNewName.ya<wbr>ml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Inputs/QualifiedNameToNewName.yaml?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Inputs/QualifiedNameToNewN<wbr>ame.yaml?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>puts/QualifiedNameToNewName.ya<wbr>ml (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>puts/QualifiedNameToNewName.ya<wbr>ml Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,6 @@<br>
+---<br>
+- QualifiedName: Foo1<br>
+ NewName: Bar1<br>
+- QualifiedName: Foo2<br>
+ NewName: Bar2<br>
+...<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>validNewName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidNewName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/InvalidNewName.cpp?rev=306<wbr>840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>validNewName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>validNewName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,2 @@<br>
+// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s<br>
+// CHECK: ERROR: new name is not a valid identifier in C++17.<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>validOffset.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidOffset.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/InvalidOffset.cpp?rev=3068<wbr>40&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>validOffset.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>validOffset.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,9 @@<br>
+#include "Inputs/HeaderWithSymbol.h"<br>
+#define FOO int bar;<br>
+FOO<br>
+<br>
+int foo;<br>
+<br>
+// RUN: not clang-rename -new-name=qux -offset=259 %s -- 2>&1 | FileCheck %s<br>
+// CHECK-NOT: CHECK<br>
+// CHECK: error: SourceLocation in file {{.*}}InvalidOffset.cpp at offset 259 is invalid<br>
<br>
Added: cfe/trunk/test/clang-rename/In<wbr>validQualifiedName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/InvalidQualifiedName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/InvalidQualifiedName.cpp?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/In<wbr>validQualifiedName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/In<wbr>validQualifiedName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,4 @@<br>
+struct S {<br>
+};<br>
+<br>
+// RUN: clang-rename -force -qualified-name S2 -new-name=T %s --<br>
<br>
Added: cfe/trunk/test/clang-rename/Me<wbr>mberExprMacro.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/MemberExprMacro.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/MemberExprMacro.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Me<wbr>mberExprMacro.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Me<wbr>mberExprMacro.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,22 @@<br>
+class Baz {<br>
+public:<br>
+ int Foo; /* Test 1 */ // CHECK: int Bar;<br>
+};<br>
+<br>
+int qux(int x) { return 0; }<br>
+#define MACRO(a) qux(a)<br>
+<br>
+int main() {<br>
+ Baz baz;<br>
+ baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1;<br>
+ MACRO(baz.Foo); // CHECK: MACRO(baz.Bar);<br>
+ int y = baz.Foo; // CHECK: int y = baz.Bar;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Na<wbr>mespace.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Namespace.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Namespace.cpp?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Na<wbr>mespace.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Na<wbr>mespace.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,13 @@<br>
+namespace gcc /* Test 1 */ { // CHECK: namespace clang /* Test 1 */ {<br>
+ int x;<br>
+}<br>
+<br>
+void boo() {<br>
+ gcc::x = 42; // CHECK: clang::x = 42;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/No<wbr>NewName.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/NoNewName.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/NoNewName.cpp?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/No<wbr>NewName.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/No<wbr>NewName.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,4 @@<br>
+// Check for an error while -new-name argument has not been passed to<br>
+// clang-rename.<br>
+// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s<br>
+// CHECK: clang-rename: -new-name must be specified.<br>
<br>
Added: cfe/trunk/test/clang-rename/Te<wbr>mplateClassInstantiation.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplateClassInstantiation.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/TemplateClassInstantiation<wbr>.cpp?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Te<wbr>mplateClassInstantiation.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Te<wbr>mplateClassInstantiation.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,42 @@<br>
+template <typename T><br>
+class Foo { /* Test 1 */ // CHECK: class Bar { /* Test 1 */<br>
+public:<br>
+ T foo(T arg, T& ref, T* ptr) {<br>
+ T value;<br>
+ int number = 42;<br>
+ value = (T)number;<br>
+ value = static_cast<T>(number);<br>
+ return value;<br>
+ }<br>
+ static void foo(T value) {}<br>
+ T member;<br>
+};<br>
+<br>
+template <typename T><br>
+void func() {<br>
+ Foo<T> obj; /* Test 2 */ // CHECK: Bar<T> obj;<br>
+ obj.member = T();<br>
+ Foo<T>::foo(); // CHECK: Bar<T>::foo();<br>
+}<br>
+<br>
+int main() {<br>
+ Foo<int> i; /* Test 3 */ // CHECK: Bar<int> i;<br>
+ i.member = 0;<br>
+ Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);<br>
+<br>
+ Foo<bool> b; // CHECK: Bar<bool> b;<br>
+ b.member = false;<br>
+ Foo<bool>::foo(false); // CHECK: Bar<bool>::foo(false);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=29 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=324 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=463 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Te<wbr>mplateTypename.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplateTypename.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/TemplateTypename.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Te<wbr>mplateTypename.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Te<wbr>mplateTypename.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,24 @@<br>
+template <typename T /* Test 1 */> // CHECK: template <typename U /* Test 1 */><br>
+class Foo {<br>
+T foo(T arg, T& ref, T* /* Test 2 */ ptr) { // CHECK: U foo(U arg, U& ref, U* /* Test 2 */ ptr) {<br>
+ T value; // CHECK: U value;<br>
+ int number = 42;<br>
+ value = (T)number; // CHECK: value = (U)number;<br>
+ value = static_cast<T /* Test 3 */>(number); // CHECK: value = static_cast<U /* Test 3 */>(number);<br>
+ return value;<br>
+}<br>
+<br>
+static void foo(T value) {} // CHECK: static void foo(U value) {}<br>
+<br>
+T member; // CHECK: U member;<br>
+};<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=19 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=126 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=392 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'T.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Te<wbr>mplatedClassFunction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/TemplatedClassFunction.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/TemplatedClassFunction.cpp<wbr>?rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Te<wbr>mplatedClassFunction.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Te<wbr>mplatedClassFunction.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,22 @@<br>
+template <typename T><br>
+class A {<br>
+public:<br>
+ void foo() /* Test 1 */ {} // CHECK: void bar() /* Test 1 */ {}<br>
+};<br>
+<br>
+int main(int argc, char **argv) {<br>
+ A<int> a;<br>
+ a.foo(); /* Test 2 */ // CHECK: a.bar() /* Test 2 */<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-refactor rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-refactor rename -offset=162 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+//<br>
+// Currently unsupported test.<br>
+// XFAIL: *<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Us<wbr>erDefinedConversion.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/UserDefinedConversion.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/UserDefinedConversion.cpp?<wbr>rev=306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Us<wbr>erDefinedConversion.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Us<wbr>erDefinedConversion.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,26 @@<br>
+class Foo { /* Test 1 */ // CHECK: class Bar {<br>
+public:<br>
+ Foo() {} // CHECK: Bar() {}<br>
+};<br>
+<br>
+class Baz {<br>
+public:<br>
+ operator Foo() /* Test 2 */ const { // CHECK: operator Bar() /* Test 2 */ const {<br>
+ Foo foo; // CHECK: Bar foo;<br>
+ return foo;<br>
+ }<br>
+};<br>
+<br>
+int main() {<br>
+ Baz boo;<br>
+ Foo foo = static_cast<Foo>(boo); // CHECK: Bar foo = static_cast<Bar>(boo);<br>
+ return 0;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Va<wbr>riable.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/Variable.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/Variable.cpp?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Va<wbr>riable.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Va<wbr>riable.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,33 @@<br>
+#define NAMESPACE namespace A<br>
+NAMESPACE {<br>
+int Foo; /* Test 1 */ // CHECK: int Bar;<br>
+}<br>
+int Foo; // CHECK: int Foo;<br>
+int Qux = Foo; // CHECK: int Qux = Foo;<br>
+int Baz = A::Foo; /* Test 2 */ // CHECK: Baz = A::Bar;<br>
+void fun() {<br>
+ struct {<br>
+ int Foo; // CHECK: int Foo;<br>
+ } b = {100};<br>
+ int Foo = 100; // CHECK: int Foo = 100;<br>
+ Baz = Foo; // CHECK: Baz = Foo;<br>
+ {<br>
+ extern int Foo; // CHECK: extern int Foo;<br>
+ Baz = Foo; // CHECK: Baz = Foo;<br>
+ Foo = A::Foo /* Test 3 */ + Baz; // CHECK: Foo = A::Bar /* Test 3 */ + Baz;<br>
+ A::Foo /* Test 4 */ = b.Foo; // CHECK: A::Bar /* Test 4 */ = b.Foo;<br>
+ }<br>
+ Foo = b.Foo; // Foo = b.Foo;<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=46 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=234 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=641 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 4.<br>
+// RUN: clang-rename -offset=716 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/Va<wbr>riableMacro.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/VariableMacro.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/VariableMacro.cpp?rev=3068<wbr>40&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/Va<wbr>riableMacro.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/Va<wbr>riableMacro.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,21 @@<br>
+#define Baz Foo // CHECK: #define Baz Bar<br>
+<br>
+void foo(int value) {}<br>
+<br>
+void macro() {<br>
+ int Foo; /* Test 1 */ // CHECK: int Bar;<br>
+ Foo = 42; /* Test 2 */ // CHECK: Bar = 42;<br>
+ Baz -= 0;<br>
+ foo(Foo); /* Test 3 */ // CHECK: foo(Bar);<br>
+ foo(Baz);<br>
+}<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 3.<br>
+// RUN: clang-rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s<br>
+<br>
+// To find offsets after modifying the file, use:<br>
+// grep -Ubo 'Foo.*' <file><br>
<br>
Added: cfe/trunk/test/clang-rename/YA<wbr>MLInput.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/clang-rename/YAMLInput.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/test/clang-ren<wbr>ame/YAMLInput.cpp?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/clang-rename/YA<wbr>MLInput.cpp (added)<br>
+++ cfe/trunk/test/clang-rename/YA<wbr>MLInput.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,10 @@<br>
+class Foo1 { // CHECK: class Bar1<br>
+};<br>
+<br>
+class Foo2 { // CHECK: class Bar2<br>
+};<br>
+<br>
+// Test 1.<br>
+// RUN: clang-rename -input %S/Inputs/OffsetToNewName.yaml %s -- | sed 's,//.*,,' | FileCheck %s<br>
+// Test 2.<br>
+// RUN: clang-rename -input %S/Inputs/QualifiedNameToNewNa<wbr>me.yaml %s -- | sed 's,//.*,,' | FileCheck %s<br>
<br>
Modified: cfe/trunk/tools/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/tools/CMakeLis<wbr>ts.txt?rev=306840&r1=306839&<wbr>r2=306840&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/CMakeLists.txt (original)<br>
+++ cfe/trunk/tools/CMakeLists.txt Fri Jun 30 09:36:09 2017<br>
@@ -10,6 +10,8 @@ add_clang_subdirectory(clang-o<wbr>ffload-bun<br>
<br>
add_clang_subdirectory(c-inde<wbr>x-test)<br>
<br>
+add_clang_subdirectory(clang-<wbr>rename)<br>
+<br>
if(CLANG_ENABLE_ARCMT)<br>
add_clang_subdirectory(arcmt-<wbr>test)<br>
add_clang_subdirectory(c-arcm<wbr>t-test)<br>
<br>
Added: cfe/trunk/tools/clang-rename/C<wbr>MakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/CMakeLists.txt?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/tools/clang-re<wbr>name/CMakeLists.txt?rev=306840<wbr>&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/clang-rename/C<wbr>MakeLists.txt (added)<br>
+++ cfe/trunk/tools/clang-rename/C<wbr>MakeLists.txt Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,19 @@<br>
+add_clang_executable(clang-re<wbr>name ClangRename.cpp)<br>
+<br>
+target_link_libraries(clang-r<wbr>ename<br>
+ clangBasic<br>
+ clangFrontend<br>
+ clangRewrite<br>
+ clangTooling<br>
+ clangToolingCore<br>
+ clangToolingRefactor<br>
+ )<br>
+<br>
+install(TARGETS clang-rename RUNTIME DESTINATION bin)<br>
+<br>
+install(PROGRAMS clang-rename.py<br>
+ DESTINATION share/clang<br>
+ COMPONENT clang-rename)<br>
+install(PROGRAMS clang-rename.el<br>
+ DESTINATION share/clang<br>
+ COMPONENT clang-rename)<br>
<br>
Added: cfe/trunk/tools/clang-rename/C<wbr>langRename.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/ClangRename.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/tools/clang-re<wbr>name/ClangRename.cpp?rev=30684<wbr>0&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/clang-rename/C<wbr>langRename.cpp (added)<br>
+++ cfe/trunk/tools/clang-rename/C<wbr>langRename.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,240 @@<br>
+//===--- tools/extra/clang-rename/Clang<wbr>Rename.cpp - Clang rename tool -----===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+///<br>
+/// \file<br>
+/// \brief This file implements a clang-rename tool that automatically finds and<br>
+/// renames symbols in C++ code.<br>
+///<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "clang/Basic/Diagnostic.h"<br>
+#include "clang/Basic/DiagnosticOptions<wbr>.h"<br>
+#include "clang/Basic/FileManager.h"<br>
+#include "clang/Basic/IdentifierTable.h<wbr>"<br>
+#include "clang/Basic/LangOptions.h"<br>
+#include "clang/Basic/SourceManager.h"<br>
+#include "clang/Basic/TokenKinds.h"<br>
+#include "clang/Frontend/TextDiagnostic<wbr>Printer.h"<br>
+#include "clang/Rewrite/Core/Rewriter.h<wbr>"<br>
+#include "clang/Tooling/CommonOptionsPa<wbr>rser.h"<br>
+#include "clang/Tooling/Refactoring.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/RenamingAction.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFindingAction.h"<br>
+#include "clang/Tooling/ReplacementsYam<wbr>l.h"<br>
+#include "clang/Tooling/Tooling.h"<br>
+#include "llvm/ADT/IntrusiveRefCntPtr.h<wbr>"<br>
+#include "llvm/Support/CommandLine.h"<br>
+#include "llvm/Support/FileSystem.h"<br>
+#include "llvm/Support/YAMLTraits.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+#include <cstdlib><br>
+#include <string><br>
+#include <system_error><br>
+<br>
+using namespace llvm;<br>
+using namespace clang;<br>
+<br>
+/// \brief An oldname -> newname rename.<br>
+struct RenameAllInfo {<br>
+ unsigned Offset = 0;<br>
+ std::string QualifiedName;<br>
+ std::string NewName;<br>
+};<br>
+<br>
+LLVM_YAML_IS_SEQUENCE_VECTOR(<wbr>RenameAllInfo)<br>
+<br>
+namespace llvm {<br>
+namespace yaml {<br>
+<br>
+/// \brief Specialized MappingTraits to describe how a RenameAllInfo is<br>
+/// (de)serialized.<br>
+template <> struct MappingTraits<RenameAllInfo> {<br>
+ static void mapping(IO &IO, RenameAllInfo &Info) {<br>
+ IO.mapOptional("Offset", Info.Offset);<br>
+ IO.mapOptional("QualifiedName"<wbr>, Info.QualifiedName);<br>
+ IO.mapRequired("NewName", Info.NewName);<br>
+ }<br>
+};<br>
+<br>
+} // end namespace yaml<br>
+} // end namespace llvm<br>
+<br>
+static cl::OptionCategory ClangRenameOptions("clang-rena<wbr>me common options");<br>
+<br>
+static cl::list<unsigned> SymbolOffsets(<br>
+ "offset",<br>
+ cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),<br>
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));<br>
+static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),<br>
+ cl::cat(ClangRenameOptions));<br>
+static cl::list<std::string><br>
+ QualifiedNames("qualified-name<wbr>",<br>
+ cl::desc("The fully qualified name of the symbol."),<br>
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));<br>
+<br>
+static cl::list<std::string><br>
+ NewNames("new-name", cl::desc("The new name to change the symbol to."),<br>
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));<br>
+static cl::opt<bool> PrintName(<br>
+ "pn",<br>
+ cl::desc("Print the found symbol's name prior to renaming to stderr."),<br>
+ cl::cat(ClangRenameOptions));<br>
+static cl::opt<bool> PrintLocations(<br>
+ "pl", cl::desc("Print the locations affected by renaming to stderr."),<br>
+ cl::cat(ClangRenameOptions));<br>
+static cl::opt<std::string><br>
+ ExportFixes("export-fixes",<br>
+ cl::desc("YAML file to store suggested fixes in."),<br>
+ cl::value_desc("filename"), cl::cat(ClangRenameOptions));<br>
+static cl::opt<std::string><br>
+ Input("input", cl::desc("YAML file to load oldname-newname pairs from."),<br>
+ cl::Optional, cl::cat(ClangRenameOptions));<br>
+static cl::opt<bool> Force("force",<br>
+ cl::desc("Ignore nonexistent qualified names."),<br>
+ cl::cat(ClangRenameOptions));<br>
+<br>
+int main(int argc, const char **argv) {<br>
+ tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);<br>
+<br>
+ if (!Input.empty()) {<br>
+ // Populate QualifiedNames and NewNames from a YAML file.<br>
+ ErrorOr<std::unique_ptr<Memory<wbr>Buffer>> Buffer =<br>
+ llvm::MemoryBuffer::getFile(In<wbr>put);<br>
+ if (!Buffer) {<br>
+ errs() << "clang-rename: failed to read " << Input << ": "<br>
+ << Buffer.getError().message() << "\n";<br>
+ return 1;<br>
+ }<br>
+<br>
+ std::vector<RenameAllInfo> Infos;<br>
+ llvm::yaml::Input YAML(Buffer.get()->getBuffer()<wbr>);<br>
+ YAML >> Infos;<br>
+ for (const auto &Info : Infos) {<br>
+ if (!Info.QualifiedName.empty())<br>
+ QualifiedNames.push_back(Info.<wbr>QualifiedName);<br>
+ else<br>
+ SymbolOffsets.push_back(Info.O<wbr>ffset);<br>
+ NewNames.push_back(Info.NewNam<wbr>e);<br>
+ }<br>
+ }<br>
+<br>
+ // Check the arguments for correctness.<br>
+ if (NewNames.empty()) {<br>
+ errs() << "clang-rename: -new-name must be specified.\n\n";<br>
+ exit(1);<br>
+ }<br>
+<br>
+ if (SymbolOffsets.empty() == QualifiedNames.empty()) {<br>
+ errs() << "clang-rename: -offset and -qualified-name can't be present at "<br>
+ "the same time.\n";<br>
+ exit(1);<br>
+ }<br>
+<br>
+ // Check if NewNames is a valid identifier in C++17.<br>
+ LangOptions Options;<br>
+ Options.CPlusPlus = true;<br>
+ Options.CPlusPlus1z = true;<br>
+ IdentifierTable Table(Options);<br>
+ for (const auto &NewName : NewNames) {<br>
+ auto NewNameTokKind = Table.get(NewName).getTokenID(<wbr>);<br>
+ if (!tok::isAnyIdentifier(NewName<wbr>TokKind)) {<br>
+ errs() << "ERROR: new name is not a valid identifier in C++17.\n\n";<br>
+ exit(1);<br>
+ }<br>
+ }<br>
+<br>
+ if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) {<br>
+ errs() << "clang-rename: number of symbol offsets(" << SymbolOffsets.size()<br>
+ << ") + number of qualified names (" << QualifiedNames.size()<br>
+ << ") must be equal to number of new names(" << NewNames.size()<br>
+ << ").\n\n";<br>
+ cl::PrintHelpMessage();<br>
+ exit(1);<br>
+ }<br>
+<br>
+ auto Files = OP.getSourcePathList();<br>
+ tooling::RefactoringTool Tool(OP.getCompilations(), Files);<br>
+ tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames, Force);<br>
+ Tool.run(tooling::newFrontendA<wbr>ctionFactory(&FindingAction).<wbr>get());<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList =<br>
+ FindingAction.getUSRList();<br>
+ const std::vector<std::string> &PrevNames = FindingAction.getUSRSpellings(<wbr>);<br>
+ if (PrintName) {<br>
+ for (const auto &PrevName : PrevNames) {<br>
+ outs() << "clang-rename found name: " << PrevName << '\n';<br>
+ }<br>
+ }<br>
+<br>
+ if (FindingAction.errorOccurred()<wbr>) {<br>
+ // Diagnostics are already issued at this point.<br>
+ exit(1);<br>
+ }<br>
+<br>
+ if (Force && PrevNames.size() < NewNames.size()) {<br>
+ // No matching PrevName for all NewNames. Without Force this is an error<br>
+ // above already.<br>
+ exit(0);<br>
+ }<br>
+<br>
+ // Perform the renaming.<br>
+ tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,<br>
+ Tool.getReplacements(), PrintLocations);<br>
+ std::unique_ptr<tooling::Front<wbr>endActionFactory> Factory =<br>
+ tooling::newFrontendActionFact<wbr>ory(&RenameAction);<br>
+ int ExitCode;<br>
+<br>
+ if (Inplace) {<br>
+ ExitCode = Tool.runAndSave(Factory.get())<wbr>;<br>
+ } else {<br>
+ ExitCode = Tool.run(Factory.get());<br>
+<br>
+ if (!ExportFixes.empty()) {<br>
+ std::error_code EC;<br>
+ llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);<br>
+ if (EC) {<br>
+ llvm::errs() << "Error opening output file: " << EC.message() << '\n';<br>
+ exit(1);<br>
+ }<br>
+<br>
+ // Export replacements.<br>
+ tooling::TranslationUnitReplac<wbr>ements TUR;<br>
+ const auto &FileToReplacements = Tool.getReplacements();<br>
+ for (const auto &Entry : FileToReplacements)<br>
+ TUR.Replacements.insert(TUR.Re<wbr>placements.end(), Entry.second.begin(),<br>
+ Entry.second.end());<br>
+<br>
+ yaml::Output YAML(OS);<br>
+ YAML << TUR;<br>
+ OS.close();<br>
+ exit(0);<br>
+ }<br>
+<br>
+ // Write every file to stdout. Right now we just barf the files without any<br>
+ // indication of which files start where, other than that we print the files<br>
+ // in the same order we see them.<br>
+ LangOptions DefaultLangOptions;<br>
+ IntrusiveRefCntPtr<DiagnosticO<wbr>ptions> DiagOpts = new DiagnosticOptions();<br>
+ TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);<br>
+ DiagnosticsEngine Diagnostics(<br>
+ IntrusiveRefCntPtr<DiagnosticI<wbr>Ds>(new DiagnosticIDs()), &*DiagOpts,<br>
+ &DiagnosticPrinter, false);<br>
+ auto &FileMgr = Tool.getFiles();<br>
+ SourceManager Sources(Diagnostics, FileMgr);<br>
+ Rewriter Rewrite(Sources, DefaultLangOptions);<br>
+<br>
+ Tool.applyAllReplacements(Rewr<wbr>ite);<br>
+ for (const auto &File : Files) {<br>
+ const auto *Entry = FileMgr.getFile(File);<br>
+ const auto ID = Sources.getOrCreateFileID(Entr<wbr>y, SrcMgr::C_User);<br>
+ Rewrite.getEditBuffer(ID).writ<wbr>e(outs());<br>
+ }<br>
+ }<br>
+<br>
+ exit(ExitCode);<br>
+}<br>
<br>
Added: cfe/trunk/tools/clang-rename/c<wbr>lang-rename.el<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/clang-rename.el?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/tools/clang-re<wbr>name/clang-rename.el?rev=30684<wbr>0&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/clang-rename/c<wbr>lang-rename.el (added)<br>
+++ cfe/trunk/tools/clang-rename/c<wbr>lang-rename.el Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,79 @@<br>
+;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>. -*- lexical-binding: t; -*-<br>
+<br>
+;; Keywords: tools, c<br>
+<br>
+;;; Commentary:<br>
+<br>
+;; To install clang-rename.el make sure the directory of this file is in your<br>
+;; `load-path' and add<br>
+;;<br>
+;; (require 'clang-rename)<br>
+;;<br>
+;; to your .emacs configuration.<br>
+<br>
+;;; Code:<br>
+<br>
+(defgroup clang-rename nil<br>
+ "Integration with clang-rename"<br>
+ :group 'c)<br>
+<br>
+(defcustom clang-rename-binary "clang-rename"<br>
+ "Path to clang-rename executable."<br>
+ :type '(file :must-match t)<br>
+ :group 'clang-rename)<br>
+<br>
+;;;###autoload<br>
+(defun clang-rename (new-name)<br>
+ "Rename all instances of the symbol at point to NEW-NAME using clang-rename."<br>
+ (interactive "sEnter a new name: ")<br>
+ (save-some-buffers :all)<br>
+ ;; clang-rename should not be combined with other operations when undoing.<br>
+ (undo-boundary)<br>
+ (let ((output-buffer (get-buffer-create "*clang-rename*")))<br>
+ (with-current-buffer output-buffer (erase-buffer))<br>
+ (let ((exit-code (call-process<br>
+ clang-rename-binary nil output-buffer nil<br>
+ (format "-offset=%d"<br>
+ ;; clang-rename wants file (byte) offsets, not<br>
+ ;; buffer (character) positions.<br>
+ (clang-rename--bufferpos-to-fi<wbr>lepos<br>
+ ;; Emacs treats one character after a symbol as<br>
+ ;; part of the symbol, but clang-rename doesn’t.<br>
+ ;; Use the beginning of the current symbol, if<br>
+ ;; available, to resolve the inconsistency.<br>
+ (or (car (bounds-of-thing-at-point 'symbol))<br>
+ (point))<br>
+ 'exact))<br>
+ (format "-new-name=%s" new-name)<br>
+ "-i" (buffer-file-name))))<br>
+ (if (and (integerp exit-code) (zerop exit-code))<br>
+ ;; Success; revert current buffer so it gets the modifications.<br>
+ (progn<br>
+ (kill-buffer output-buffer)<br>
+ (revert-buffer :ignore-auto :noconfirm :preserve-modes))<br>
+ ;; Failure; append exit code to output buffer and display it.<br>
+ (let ((message (clang-rename--format-message<br>
+ "clang-rename failed with %s %s"<br>
+ (if (integerp exit-code) "exit status" "signal")<br>
+ exit-code)))<br>
+ (with-current-buffer output-buffer<br>
+ (insert ?\n message ?\n))<br>
+ (message "%s" message)<br>
+ (display-buffer output-buffer))))))<br>
+<br>
+(defalias 'clang-rename--bufferpos-to-fi<wbr>lepos<br>
+ (if (fboundp 'bufferpos-to-filepos)<br>
+ 'bufferpos-to-filepos<br>
+ ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it using<br>
+ ;; ‘position-bytes’.<br>
+ (lambda (position &optional _quality _coding-system)<br>
+ (1- (position-bytes position)))))<br>
+<br>
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older<br>
+;; versions.<br>
+(defalias 'clang-rename--format-message<br>
+ (if (fboundp 'format-message) 'format-message 'format))<br>
+<br>
+(provide 'clang-rename)<br>
+<br>
+;;; clang-rename.el ends here<br>
<br>
Added: cfe/trunk/tools/clang-rename/c<wbr>lang-rename.py<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-rename/clang-rename.py?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/tools/clang-re<wbr>name/clang-rename.py?rev=30684<wbr>0&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/clang-rename/c<wbr>lang-rename.py (added)<br>
+++ cfe/trunk/tools/clang-rename/c<wbr>lang-rename.py Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,61 @@<br>
+'''<br>
+Minimal clang-rename integration with Vim.<br>
+<br>
+Before installing make sure one of the following is satisfied:<br>
+<br>
+* clang-rename is in your PATH<br>
+* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable<br>
+* `binary` in clang-rename.py points to valid to clang-rename executable<br>
+<br>
+To install, simply put this into your ~/.vimrc<br>
+<br>
+ noremap <leader>cr :pyf <path-to>/clang-rename.py<cr><br>
+<br>
+IMPORTANT NOTE: Before running the tool, make sure you saved the file.<br>
+<br>
+All you have to do now is to place a cursor on a variable/function/class which<br>
+you would like to rename and press '<leader>cr'. You will be prompted for a new<br>
+name if the cursor points to a valid symbol.<br>
+'''<br>
+<br>
+import vim<br>
+import subprocess<br>
+import sys<br>
+<br>
+def main():<br>
+ binary = 'clang-rename'<br>
+ if vim.eval('exists("g:clang_rena<wbr>me_path")') == "1":<br>
+ binary = vim.eval('g:clang_rename_path'<wbr>)<br>
+<br>
+ # Get arguments for clang-rename binary.<br>
+ offset = int(vim.eval('line2byte(line("<wbr>."))+col(".")')) - 2<br>
+ if offset < 0:<br>
+ print >> sys.stderr, '''Couldn\'t determine cursor position.<br>
+ Is your file empty?'''<br>
+ return<br>
+ filename = <a href="http://vim.current.buffer.name" rel="noreferrer" target="_blank">vim.current.buffer.name</a><br>
+<br>
+ new_name_request_message = 'type new name:'<br>
+ new_name = vim.eval("input('{}\n')".forma<wbr>t(new_name_request_message))<br>
+<br>
+ # Call clang-rename.<br>
+ command = [binary,<br>
+ filename,<br>
+ '-i',<br>
+ '-offset', str(offset),<br>
+ '-new-name', str(new_name)]<br>
+ # FIXME: make it possible to run the tool on unsaved file.<br>
+ p = subprocess.Popen(command,<br>
+ stdout=subprocess.PIPE,<br>
+ stderr=subprocess.PIPE)<br>
+ stdout, stderr = p.communicate()<br>
+<br>
+ if stderr:<br>
+ print stderr<br>
+<br>
+ # Reload all buffers in Vim.<br>
+ vim.command("checktime")<br>
+<br>
+<br>
+if __name__ == '__main__':<br>
+ main()<br>
<br>
Modified: cfe/trunk/unittests/CMakeLists<wbr>.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/CMakeLists.txt?rev=306840&r1=306839&r2=306840&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/unittests/CMak<wbr>eLists.txt?rev=306840&r1=30683<wbr>9&r2=306840&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/unittests/CMakeLists<wbr>.txt (original)<br>
+++ cfe/trunk/unittests/CMakeLists<wbr>.txt Fri Jun 30 09:36:09 2017<br>
@@ -29,3 +29,4 @@ add_subdirectory(CodeGen)<br>
if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)<br>
add_subdirectory(libclang)<br>
endif()<br>
+add_subdirectory(Rename)<br>
<br>
Added: cfe/trunk/unittests/Rename/CMa<wbr>keLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/CMakeLists.txt?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/unittests/Rena<wbr>me/CMakeLists.txt?rev=306840&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/unittests/Rename/CMa<wbr>keLists.txt (added)<br>
+++ cfe/trunk/unittests/Rename/CMa<wbr>keLists.txt Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,22 @@<br>
+set(LLVM_LINK_COMPONENTS<br>
+ support<br>
+ )<br>
+<br>
+# We'd like clang/unittests/Tooling/Rewrit<wbr>erTestContext.h in the test.<br>
+include_directories(${CLANG_S<wbr>OURCE_DIR})<br>
+<br>
+add_extra_unittest(ClangRenam<wbr>eTests<br>
+ RenameClassTest.cpp<br>
+ )<br>
+<br>
+target_link_libraries(ClangRe<wbr>nameTests<br>
+ clangAST<br>
+ clangASTMatchers<br>
+ clangBasic<br>
+ clangFormat<br>
+ clangFrontend<br>
+ clangRewrite<br>
+ clangTooling<br>
+ clangToolingCore<br>
+ clangToolingRefactor<br>
+ )<br>
<br>
Added: cfe/trunk/unittests/Rename/Cla<wbr>ngRenameTest.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/ClangRenameTest.h?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/unittests/Rena<wbr>me/ClangRenameTest.h?rev=30684<wbr>0&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/unittests/Rename/Cla<wbr>ngRenameTest.h (added)<br>
+++ cfe/trunk/unittests/Rename/Cla<wbr>ngRenameTest.h Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,112 @@<br>
+//===-- ClangRenameTests.cpp - clang-rename unit tests --------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "unittests/Tooling/RewriterTes<wbr>tContext.h"<br>
+#include "clang/ASTMatchers/ASTMatchFin<wbr>der.h"<br>
+#include "clang/Basic/FileManager.h"<br>
+#include "clang/Basic/FileSystemOptions<wbr>.h"<br>
+#include "clang/Basic/VirtualFileSystem<wbr>.h"<br>
+#include "clang/Format/Format.h"<br>
+#include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>
+#include "clang/Frontend/PCHContainerOp<wbr>erations.h"<br>
+#include "clang/Tooling/Refactoring.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/RenamingAction.h"<br>
+#include "clang/Tooling/Refactoring/Ren<wbr>ame/USRFindingAction.h"<br>
+#include "clang/Tooling/Tooling.h"<br>
+#include "llvm/ADT/IntrusiveRefCntPtr.h<wbr>"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/Support/Format.h"<br>
+#include "llvm/Support/MemoryBuffer.h"<br>
+#include "gtest/gtest.h"<br>
+#include <memory><br>
+#include <string><br>
+#include <vector><br>
+<br>
+namespace clang {<br>
+namespace clang_rename {<br>
+namespace test {<br>
+<br>
+struct Case {<br>
+ std::string Before;<br>
+ std::string After;<br>
+ std::string OldName;<br>
+ std::string NewName;<br>
+};<br>
+<br>
+class ClangRenameTest : public testing::Test,<br>
+ public testing::WithParamInterface<Ca<wbr>se> {<br>
+protected:<br>
+ void AppendToHeader(StringRef Code) { HeaderContent += Code.str(); }<br>
+<br>
+ std::string runClangRenameOnCode(llvm::Str<wbr>ingRef Code,<br>
+ llvm::StringRef OldName,<br>
+ llvm::StringRef NewName) {<br>
+ std::string NewCode;<br>
+ llvm::raw_string_ostream(NewCo<wbr>de) << llvm::format(<br>
+ "#include \"%s\"\n%s", HeaderName.c_str(), Code.str().c_str());<br>
+ tooling::FileContentMappings FileContents = {{HeaderName, HeaderContent},<br>
+ {CCName, NewCode}};<br>
+ clang::RewriterTestContext Context;<br>
+ Context.createInMemoryFile(Hea<wbr>derName, HeaderContent);<br>
+ clang::FileID InputFileID = Context.createInMemoryFile(CCN<wbr>ame, NewCode);<br>
+<br>
+ tooling::USRFindingAction FindingAction({}, {OldName}, false);<br>
+ std::unique_ptr<tooling::Front<wbr>endActionFactory> USRFindingActionFactory =<br>
+ tooling::newFrontendActionFact<wbr>ory(&FindingAction);<br>
+<br>
+ if (!tooling::runToolOnCodeWithAr<wbr>gs(<br>
+ USRFindingActionFactory->creat<wbr>e(), NewCode, {"-std=c++11"}, CCName,<br>
+ "clang-rename", std::make_shared<PCHContainerO<wbr>perations>(),<br>
+ FileContents))<br>
+ return "";<br>
+<br>
+ const std::vector<std::vector<std::s<wbr>tring>> &USRList =<br>
+ FindingAction.getUSRList();<br>
+ std::vector<std::string> NewNames = {NewName};<br>
+ std::map<std::string, tooling::Replacements> FileToReplacements;<br>
+ tooling::QualifiedRenamingActi<wbr>on RenameAction(NewNames, USRList,<br>
+ FileToReplacements);<br>
+ auto RenameActionFactory = tooling::newFrontendActionFact<wbr>ory(&RenameAction);<br>
+ if (!tooling::runToolOnCodeWithAr<wbr>gs(<br>
+ RenameActionFactory->create(), NewCode, {"-std=c++11"}, CCName,<br>
+ "clang-rename", std::make_shared<PCHContainerO<wbr>perations>(),<br>
+ FileContents))<br>
+ return "";<br>
+<br>
+ formatAndApplyAllReplacements(<wbr>FileToReplacements, Context.Rewrite, "llvm");<br>
+ return Context.getRewrittenText(Input<wbr>FileID);<br>
+ }<br>
+<br>
+ void CompareSnippets(StringRef Expected, StringRef Actual) {<br>
+ std::string ExpectedCode;<br>
+ llvm::raw_string_ostream(Expec<wbr>tedCode) << llvm::format(<br>
+ "#include \"%s\"\n%s", HeaderName.c_str(), Expected.str().c_str());<br>
+ EXPECT_EQ(format(ExpectedCode)<wbr>, format(Actual));<br>
+ }<br>
+<br>
+ std::string format(llvm::StringRef Code) {<br>
+ tooling::Replacements Replaces = format::reformat(<br>
+ format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});<br>
+ auto ChangedCode = tooling::applyAllReplacements(<wbr>Code, Replaces);<br>
+ EXPECT_TRUE(static_cast<bool>(<wbr>ChangedCode));<br>
+ if (!ChangedCode) {<br>
+ llvm::errs() << llvm::toString(ChangedCode.tak<wbr>eError());<br>
+ return "";<br>
+ }<br>
+ return *ChangedCode;<br>
+ }<br>
+<br>
+ std::string HeaderContent;<br>
+ std::string HeaderName = "header.h";<br>
+ std::string CCName = "input.cc";<br>
+};<br>
+<br>
+} // namespace test<br>
+} // namespace clang_rename<br>
+} // namesdpace clang<br>
<br>
Added: cfe/trunk/unittests/Rename/Ren<wbr>ameClassTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Rename/RenameClassTest.cpp?rev=306840&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/cfe/trunk/unittests/Rena<wbr>me/RenameClassTest.cpp?rev=<wbr>306840&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/unittests/Rename/Ren<wbr>ameClassTest.cpp (added)<br>
+++ cfe/trunk/unittests/Rename/Ren<wbr>ameClassTest.cpp Fri Jun 30 09:36:09 2017<br>
@@ -0,0 +1,684 @@<br>
+//===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "ClangRenameTest.h"<br>
+<br>
+namespace clang {<br>
+namespace clang_rename {<br>
+namespace test {<br>
+namespace {<br>
+<br>
+class RenameClassTest : public ClangRenameTest {<br>
+public:<br>
+ RenameClassTest() {<br>
+ AppendToHeader(R"(<br>
+ namespace a {<br>
+ class Foo {<br>
+ public:<br>
+ struct Nested {<br>
+ enum NestedEnum {E1, E2};<br>
+ };<br>
+ void func() {}<br>
+ static int Constant;<br>
+ };<br>
+ class Goo {<br>
+ public:<br>
+ struct Nested {<br>
+ enum NestedEnum {E1, E2};<br>
+ };<br>
+ };<br>
+ int Foo::Constant = 1;<br>
+ } // namespace a<br>
+ namespace b {<br>
+ class Foo {};<br>
+ } // namespace b<br>
+<br>
+ #define MACRO(x) x<br>
+<br>
+ template<typename T> class ptr {};<br>
+ )");<br>
+ }<br>
+};<br>
+<br>
+INSTANTIATE_TEST_CASE_P(<br>
+ RenameClassTests, RenameClassTest,<br>
+ testing::ValuesIn(std::vector<<wbr>Case>({<br>
+ // basic classes<br>
+ {"a::Foo f;", "b::Bar f;", "", ""},<br>
+ {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},<br>
+ {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},<br>
+ {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",<br>
+ "", ""},<br>
+ {"namespace a {a::Foo f() { return Foo(); }}",<br>
+ "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},<br>
+ {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}", "", ""},<br>
+ {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}", "", ""},<br>
+ {"namespace a { void f(Foo a1) {} }",<br>
+ "namespace a { void f(b::Bar a1) {} }", "", ""},<br>
+ {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}", "", ""},<br>
+ {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}", "", ""},<br>
+ {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},<br>
+ {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "", ""},<br>
+ {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",<br>
+ "a::Foo::Nested2"},<br>
+<br>
+ // use namespace and typedefs<br>
+ {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},<br>
+ {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}",<br>
+ "", ""},<br>
+ {"using a::Foo; namespace x { Foo gA; }",<br>
+ "using b::Bar; namespace x { Bar gA; }", "", ""},<br>
+ {"struct S { using T = a::Foo; T a_; };",<br>
+ "struct S { using T = b::Bar; T a_; };", "", ""},<br>
+ {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},<br>
+ {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},<br>
+ {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;", "",<br>
+ ""},<br>
+<br>
+ // struct members and other oddities<br>
+ {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",<br>
+ ""},<br>
+ {"struct F { void f(a::Foo a1) {} };",<br>
+ "struct F { void f(b::Bar a1) {} };", "", ""},<br>
+ {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},<br>
+ {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };", "",<br>
+ ""},<br>
+<br>
+ {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }",<br>
+ "", ""},<br>
+ {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }",<br>
+ "", ""},<br>
+ {"void f() { a::Foo::Nested::NestedEnum e; }",<br>
+ "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},<br>
+ {"void f() { auto e = a::Foo::Nested::NestedEnum::E1<wbr>; }",<br>
+ "void f() { auto e = b::Bar::Nested::NestedEnum::E1<wbr>; }", "", ""},<br>
+ {"void f() { auto e = a::Foo::Nested::E1; }",<br>
+ "void f() { auto e = b::Bar::Nested::E1; }", "", ""},<br>
+<br>
+ // templates<br>
+ {"template <typename T> struct Foo { T t; };\n"<br>
+ "void f() { Foo<a::Foo> foo; }",<br>
+ "template <typename T> struct Foo { T t; };\n"<br>
+ "void f() { Foo<b::Bar> foo; }",<br>
+ "", ""},<br>
+ {"template <typename T> struct Foo { a::Foo a; };",<br>
+ "template <typename T> struct Foo { b::Bar a; };", "", ""},<br>
+ {"template <typename T> void f(T t) {}\n"<br>
+ "void g() { f<a::Foo>(a::Foo()); }",<br>
+ "template <typename T> void f(T t) {}\n"<br>
+ "void g() { f<b::Bar>(b::Bar()); }",<br>
+ "", ""},<br>
+ {"template <typename T> int f() { return 1; }\n"<br>
+ "template <> int f<a::Foo>() { return 2; }\n"<br>
+ "int g() { return f<a::Foo>(); }",<br>
+ "template <typename T> int f() { return 1; }\n"<br>
+ "template <> int f<b::Bar>() { return 2; }\n"<br>
+ "int g() { return f<b::Bar>(); }",<br>
+ "", ""},<br>
+ {"struct Foo { template <typename T> T foo(); };\n"<br>
+ "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",<br>
+ "struct Foo { template <typename T> T foo(); };\n"<br>
+ "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",<br>
+ "", ""},<br>
+<br>
+ // The following two templates are distilled from regressions found in<br>
+ // unique_ptr<> and type_traits.h<br>
+ {"template <typename T> struct outer {\n"<br>
+ " typedef T type;\n"<br>
+ " type Baz();\n"<br>
+ " };\n"<br>
+ " outer<a::Foo> g_A;",<br>
+ "template <typename T> struct outer {\n"<br>
+ " typedef T type;\n"<br>
+ " type Baz();\n"<br>
+ " };\n"<br>
+ " outer<b::Bar> g_A;",<br>
+ "", ""},<br>
+ {"template <typename T> struct nested { typedef T type; };\n"<br>
+ "template <typename T> struct outer { typename nested<T>::type Foo(); "<br>
+ "};\n"<br>
+ "outer<a::Foo> g_A;",<br>
+ "template <typename T> struct nested { typedef T type; };\n"<br>
+ "template <typename T> struct outer { typename nested<T>::type Foo(); "<br>
+ "};\n"<br>
+ "outer<b::Bar> g_A;",<br>
+ "", ""},<br>
+<br>
+ // macros<br>
+ {"#define FOO(T, t) T t\n"<br>
+ "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",<br>
+ "#define FOO(T, t) T t\n"<br>
+ "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",<br>
+ "", ""},<br>
+ {"#define FOO(n) a::Foo n\n"<br>
+ " void f() { FOO(a1); FOO(a2); }",<br>
+ "#define FOO(n) b::Bar n\n"<br>
+ " void f() { FOO(a1); FOO(a2); }",<br>
+ "", ""},<br>
+<br>
+ // Pointer to member functions<br>
+ {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},<br>
+ {"using a::Foo; auto gA = &Foo::func;",<br>
+ "using b::Bar; auto gA = &b::Bar::func;", "", ""},<br>
+ {"using a::Foo; namespace x { auto gA = &Foo::func; }",<br>
+ "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},<br>
+ {"typedef a::Foo T; auto gA = &T::func;",<br>
+ "typedef b::Bar T; auto gA = &T::func;", "", ""},<br>
+ {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",<br>
+ "", ""},<br>
+<br>
+ // Short match inside a namespace<br>
+ {"namespace a { void f(Foo a1) {} }",<br>
+ "namespace a { void f(b::Bar a1) {} }", "", ""},<br>
+<br>
+ // Correct match.<br>
+ {"using a::Foo; struct F { ptr<Foo> a_; };",<br>
+ "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},<br>
+<br>
+ // avoid false positives<br>
+ {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},<br>
+ {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",<br>
+ "", ""},<br>
+<br>
+ // friends, everyone needs friends.<br>
+ {"class Foo { int i; friend class a::Foo; };",<br>
+ "class Foo { int i; friend class b::Bar; };", "", ""},<br>
+ })), );<br>
+<br>
+TEST_P(RenameClassTest, RenameClasses) {<br>
+ auto Param = GetParam();<br>
+ std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;<br>
+ std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;<br>
+ std::string Actual = runClangRenameOnCode(Param.Bef<wbr>ore, OldName, NewName);<br>
+ CompareSnippets(Param.After, Actual);<br>
+}<br>
+<br>
+class NamespaceDetectionTest : public ClangRenameTest {<br>
+protected:<br>
+ NamespaceDetectionTest() {<br>
+ AppendToHeader(R"(<br>
+ class Old {};<br>
+ namespace o1 {<br>
+ class Old {};<br>
+ namespace o2 {<br>
+ class Old {};<br>
+ namespace o3 {<br>
+ class Old {};<br>
+ } // namespace o3<br>
+ } // namespace o2<br>
+ } // namespace o1<br>
+ )");<br>
+ }<br>
+};<br>
+<br>
+INSTANTIATE_TEST_CASE_P(<br>
+ RenameClassTest, NamespaceDetectionTest,<br>
+ ::testing::ValuesIn(std::vecto<wbr>r<Case>({<br>
+ // Test old and new namespace overlap.<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",<br>
+ "o1::o2::o3::Old", "o1::o2::o3::New"},<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",<br>
+ "o1::o2::o3::Old", "o1::o2::n3::New"},<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",<br>
+ "o1::o2::o3::Old", "o1::n2::n3::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",<br>
+ "::o1::o2::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",<br>
+ "::o1::n2::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",<br>
+ "::o1::o2::Old", "::n1::n2::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",<br>
+ "n1::n2::New"},<br>
+<br>
+ // Test old and new namespace with differing depths.<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",<br>
+ "o1::o2::o3::Old", "::o1::New"},<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",<br>
+ "o1::o2::o3::Old", "::o1::o2::New"},<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",<br>
+ "o1::o2::o3::Old", "o1::New"},<br>
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",<br>
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",<br>
+ "o1::o2::o3::Old", "o1::o2::New"},<br>
+ {"Old moo;", "o1::New moo;", "::Old", "o1::New"},<br>
+ {"Old moo;", "o1::New moo;", "Old", "o1::New"},<br>
+ {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",<br>
+ "o1::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",<br>
+ "::New"},<br>
+ {"namespace o1 { namespace o2 { Old moo; } }",<br>
+ "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old", "New"},<br>
+<br>
+ // Test moving into the new namespace at different levels.<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",<br>
+ "::n1::n2::New"},<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",<br>
+ "n1::n2::New"},<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",<br>
+ "::n1::o2::New"},<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",<br>
+ "n1::o2::New"},<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",<br>
+ "::o1::o2::Old", "::o1::o2::New"},<br>
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",<br>
+ "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",<br>
+ "o1::o2::New"},<br>
+<br>
+ // Test friends declarations.<br>
+ {"class Foo { friend class o1::Old; };",<br>
+ "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},<br>
+ {"class Foo { int i; friend class o1::Old; };",<br>
+ "class Foo { int i; friend class ::o1::New; };", "::o1::Old",<br>
+ "::o1::New"},<br>
+ {"namespace o1 { class Foo { int i; friend class Old; }; }",<br>
+ "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",<br>
+ "o1::New"},<br>
+ {"namespace o1 { class Foo { int i; friend class Old; }; }",<br>
+ "namespace o1 { class Foo { int i; friend class New; }; }",<br>
+ "::o1::Old", "::o1::New"},<br>
+ })), );<br>
+<br>
+TEST_P(NamespaceDetectionTest<wbr>, RenameClasses) {<br>
+ auto Param = GetParam();<br>
+ std::string Actual =<br>
+ runClangRenameOnCode(Param.Bef<wbr>ore, Param.OldName, Param.NewName);<br>
+ CompareSnippets(Param.After, Actual);<br>
+}<br>
+<br>
+class TemplatedClassRenameTest : public ClangRenameTest {<br>
+protected:<br>
+ TemplatedClassRenameTest() {<br>
+ AppendToHeader(R"(<br>
+ template <typename T> struct Old {<br>
+ T t_;<br>
+ T f() { return T(); };<br>
+ static T s(T t) { return t; }<br>
+ };<br>
+ namespace ns {<br>
+ template <typename T> struct Old {<br>
+ T t_;<br>
+ T f() { return T(); };<br>
+ static T s(T t) { return t; }<br>
+ };<br>
+ } // namespace ns<br>
+<br>
+ namespace o1 {<br>
+ namespace o2 {<br>
+ namespace o3 {<br>
+ template <typename T> struct Old {<br>
+ T t_;<br>
+ T f() { return T(); };<br>
+ static T s(T t) { return t; }<br>
+ };<br>
+ } // namespace o3<br>
+ } // namespace o2<br>
+ } // namespace o1<br>
+ )");<br>
+ }<br>
+};<br>
+<br>
+INSTANTIATE_TEST_CASE_P(<br>
+ RenameClassTests, TemplatedClassRenameTest,<br>
+ ::testing::ValuesIn(std::vecto<wbr>r<Case>({<br>
+ {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",<br>
+ "New"},<br>
+ {"ns::Old<int> gI; ns::Old<bool> gB;",<br>
+ "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},<br>
+ {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",<br>
+ "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},<br>
+ {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",<br>
+ "ns::Old", "ns::New"},<br>
+<br>
+ {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",<br>
+ "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",<br>
+ "New"},<br>
+ {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",<br>
+ "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",<br>
+ "ns::Old", "ns::New"},<br>
+<br>
+ {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",<br>
+ "New"},<br>
+ {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",<br>
+ "ns::Old", "ns::New"},<br>
+<br>
+ {"auto a = reinterpret_cast<Old<int>*>(ne<wbr>w Old<int>);",<br>
+ "auto a = reinterpret_cast<New<int>*>(ne<wbr>w New<int>);", "Old", "New"},<br>
+ {"auto a = reinterpret_cast<ns::Old<int>*<wbr>>(new ns::Old<int>);",<br>
+ "auto a = reinterpret_cast<ns::New<int>*<wbr>>(new ns::New<int>);",<br>
+ "ns::Old", "ns::New"},<br>
+ {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",<br>
+ "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",<br>
+ "New"},<br>
+ {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",<br>
+ "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",<br>
+ "ns::Old", "ns::New"},<br>
+<br>
+ {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},<br>
+ {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",<br>
+ "ns::New"},<br>
+ {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",<br>
+ "o1::o2::o3::Old", "o1::o2::o3::New"},<br>
+ {"namespace ns { Old<bool>& foo(); }",<br>
+ "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},<br>
+ {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},<br>
+ {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",<br>
+ "ns::Old", "ns::New"},<br>
+<br>
+ // FIXME: figure out why this only works when Moo gets<br>
+ // specialized at some point.<br>
+ {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",<br>
+ "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",<br>
+ "New"},<br>
+ {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",<br>
+ "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",<br>
+ "ns::Old", "ns::New"},<br>
+ })), );<br>
+<br>
+TEST_P(TemplatedClassRenameTe<wbr>st, RenameTemplateClasses) {<br>
+ auto Param = GetParam();<br>
+ std::string Actual =<br>
+ runClangRenameOnCode(Param.Bef<wbr>ore, Param.OldName, Param.NewName);<br>
+ CompareSnippets(Param.After, Actual);<br>
+}<br>
+<br>
+TEST_F(ClangRenameTest, RenameClassWithOutOfLineMember<wbr>s) {<br>
+ std::string Before = R"(<br>
+ class Old {<br>
+ public:<br>
+ Old();<br>
+ ~Old();<br>
+<br>
+ Old* next();<br>
+<br>
+ private:<br>
+ Old* next_;<br>
+ };<br>
+<br>
+ Old::Old() {}<br>
+ Old::~Old() {}<br>
+ Old* Old::next() { return next_; }<br>
+ )";<br>
+ std::string Expected = R"(<br>
+ class New {<br>
+ public:<br>
+ New();<br>
+ ~New();<br>
+<br>
+ New* next();<br>
+<br>
+ private:<br>
+ New* next_;<br>
+ };<br>
+<br>
+ New::New() {}<br>
+ New::~New() {}<br>
+ New* New::next() { return next_; }<br>
+ )";<br>
+ std::string After = runClangRenameOnCode(Before, "Old", "New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {<br>
+ std::string Before = R"(<br>
+ class Old {<br>
+ public:<br>
+ Old() {}<br>
+ ~Old() {}<br>
+<br>
+ Old* next() { return next_; }<br>
+<br>
+ private:<br>
+ Old* next_;<br>
+ };<br>
+ )";<br>
+ std::string Expected = R"(<br>
+ class New {<br>
+ public:<br>
+ New() {}<br>
+ ~New() {}<br>
+<br>
+ New* next() { return next_; }<br>
+<br>
+ private:<br>
+ New* next_;<br>
+ };<br>
+ )";<br>
+ std::string After = runClangRenameOnCode(Before, "Old", "New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+// FIXME: no prefix qualifiers being added to the class definition and<br>
+// constructor.<br>
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithIn<wbr>lineMembers) {<br>
+ std::string Before = R"(<br>
+ namespace ns {<br>
+ class Old {<br>
+ public:<br>
+ Old() {}<br>
+ ~Old() {}<br>
+<br>
+ Old* next() { return next_; }<br>
+<br>
+ private:<br>
+ Old* next_;<br>
+ };<br>
+ } // namespace ns<br>
+ )";<br>
+ std::string Expected = R"(<br>
+ namespace ns {<br>
+ class ns::New {<br>
+ public:<br>
+ ns::New() {}<br>
+ ~New() {}<br>
+<br>
+ New* next() { return next_; }<br>
+<br>
+ private:<br>
+ New* next_;<br>
+ };<br>
+ } // namespace ns<br>
+ )";<br>
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+// FIXME: no prefix qualifiers being added to the class definition and<br>
+// constructor.<br>
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOu<wbr>tOfInlineMembers) {<br>
+ std::string Before = R"(<br>
+ namespace ns {<br>
+ class Old {<br>
+ public:<br>
+ Old();<br>
+ ~Old();<br>
+<br>
+ Old* next();<br>
+<br>
+ private:<br>
+ Old* next_;<br>
+ };<br>
+<br>
+ Old::Old() {}<br>
+ Old::~Old() {}<br>
+ Old* Old::next() { return next_; }<br>
+ } // namespace ns<br>
+ )";<br>
+ std::string Expected = R"(<br>
+ namespace ns {<br>
+ class ns::New {<br>
+ public:<br>
+ ns::New();<br>
+ ~New();<br>
+<br>
+ New* next();<br>
+<br>
+ private:<br>
+ New* next_;<br>
+ };<br>
+<br>
+ New::ns::New() {}<br>
+ New::~New() {}<br>
+ New* New::next() { return next_; }<br>
+ } // namespace ns<br>
+ )";<br>
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+// FIXME: no prefix qualifiers being added to the definition.<br>
+TEST_F(ClangRenameTest, RenameClassInInheritedConstruc<wbr>tor) {<br>
+ // `using Base::Base;` will generate an implicit constructor containing usage<br>
+ // of `::ns::Old` which should not be matched.<br>
+ std::string Before = R"(<br>
+ namespace ns {<br>
+ class Old {<br>
+ int x;<br>
+ };<br>
+ class Base {<br>
+ protected:<br>
+ Old *moo_;<br>
+ public:<br>
+ Base(Old *moo) : moo_(moo) {}<br>
+ };<br>
+ class Derived : public Base {<br>
+ public:<br>
+ using Base::Base;<br>
+ };<br>
+ } // namespace ns<br>
+ int main() {<br>
+ ::ns::Old foo;<br>
+ ::ns::Derived d(&foo);<br>
+ return 0;<br>
+ })";<br>
+ std::string Expected = R"(<br>
+ namespace ns {<br>
+ class ns::New {<br>
+ int x;<br>
+ };<br>
+ class Base {<br>
+ protected:<br>
+ New *moo_;<br>
+ public:<br>
+ Base(New *moo) : moo_(moo) {}<br>
+ };<br>
+ class Derived : public Base {<br>
+ public:<br>
+ using Base::Base;<br>
+ };<br>
+ } // namespace ns<br>
+ int main() {<br>
+ ::ns::New foo;<br>
+ ::ns::Derived d(&foo);<br>
+ return 0;<br>
+ })";<br>
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+TEST_F(ClangRenameTest, DontRenameReferencesInImplicit<wbr>Function) {<br>
+ std::string Before = R"(<br>
+ namespace ns {<br>
+ class Old {<br>
+ };<br>
+ } // namespace ns<br>
+ struct S {<br>
+ int y;<br>
+ ns::Old old;<br>
+ };<br>
+ void f() {<br>
+ S s1, s2, s3;<br>
+ // This causes an implicit assignment operator to be created.<br>
+ s1 = s2 = s3;<br>
+ }<br>
+ )";<br>
+ std::string Expected = R"(<br>
+ namespace ns {<br>
+ class ::new_ns::New {<br>
+ };<br>
+ } // namespace ns<br>
+ struct S {<br>
+ int y;<br>
+ ::new_ns::New old;<br>
+ };<br>
+ void f() {<br>
+ S s1, s2, s3;<br>
+ // This causes an implicit assignment operator to be created.<br>
+ s1 = s2 = s3;<br>
+ }<br>
+ )";<br>
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+// FIXME: no prefix qualifiers being adding to the definition.<br>
+TEST_F(ClangRenameTest, ReferencesInLambdaFunctionPara<wbr>meters) {<br>
+ std::string Before = R"(<br>
+ template <class T><br>
+ class function;<br>
+ template <class R, class... ArgTypes><br>
+ class function<R(ArgTypes...)> {<br>
+ public:<br>
+ template <typename Functor><br>
+ function(Functor f) {}<br>
+<br>
+ function() {}<br>
+<br>
+ R operator()(ArgTypes...) const {}<br>
+ };<br>
+<br>
+ namespace ns {<br>
+ class Old {};<br>
+ void f() {<br>
+ function<void(Old)> func;<br>
+ }<br>
+ } // namespace ns)";<br>
+ std::string Expected = R"(<br>
+ template <class T><br>
+ class function;<br>
+ template <class R, class... ArgTypes><br>
+ class function<R(ArgTypes...)> {<br>
+ public:<br>
+ template <typename Functor><br>
+ function(Functor f) {}<br>
+<br>
+ function() {}<br>
+<br>
+ R operator()(ArgTypes...) const {}<br>
+ };<br>
+<br>
+ namespace ns {<br>
+ class ::new_ns::New {};<br>
+ void f() {<br>
+ function<void(::new_ns::New)> func;<br>
+ }<br>
+ } // namespace ns)";<br>
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");<br>
+ CompareSnippets(Expected, After);<br>
+}<br>
+<br>
+} // anonymous namespace<br>
+} // namespace test<br>
+} // namespace clang_rename<br>
+} // namesdpace clang<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>
</blockquote></div><br></div>