clang-tools  3.9.0
USRFindingAction.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Provides an action to rename every symbol at a point.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "USRFindingAction.h"
16 #include "USRFinder.h"
17 #include "clang/AST/AST.h"
18 #include "clang/AST/ASTConsumer.h"
19 #include "clang/AST/ASTContext.h"
20 #include "clang/Basic/FileManager.h"
21 #include "clang/Frontend/CompilerInstance.h"
22 #include "clang/Frontend/FrontendAction.h"
23 #include "clang/Lex/Lexer.h"
24 #include "clang/Lex/Preprocessor.h"
25 #include "clang/Tooling/CommonOptionsParser.h"
26 #include "clang/Tooling/Refactoring.h"
27 #include "clang/Tooling/Tooling.h"
28 #include <string>
29 #include <vector>
30 
31 using namespace llvm;
32 
33 namespace clang {
34 namespace rename {
35 
36 // Get the USRs for the constructors of the class.
37 static std::vector<std::string> getAllConstructorUSRs(
38  const CXXRecordDecl *Decl) {
39  std::vector<std::string> USRs;
40 
41  // We need to get the definition of the record (as opposed to any forward
42  // declarations) in order to find the constructor and destructor.
43  const auto *RecordDecl = Decl->getDefinition();
44 
45  // Iterate over all the constructors and add their USRs.
46  for (const auto *CtorDecl : RecordDecl->ctors())
47  USRs.push_back(getUSRForDecl(CtorDecl));
48 
49  // Ignore destructors. GetLocationsOfUSR will find the declaration of and
50  // explicit calls to a destructor through TagTypeLoc (and it is better for the
51  // purpose of renaming).
52  //
53  // For example, in the following code segment,
54  // 1 class C {
55  // 2 ~C();
56  // 3 };
57  // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc starting
58  // from 'C'.
59 
60  return USRs;
61 }
62 
64  void HandleTranslationUnit(ASTContext &Context) override {
65  const auto &SourceMgr = Context.getSourceManager();
66  // The file we look for the USR in will always be the main source file.
67  const auto Point = SourceMgr.getLocForStartOfFile(
68  SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset);
69  if (!Point.isValid())
70  return;
71  const NamedDecl *FoundDecl = nullptr;
72  if (OldName.empty()) {
73  FoundDecl = getNamedDeclAt(Context, Point);
74  } else {
75  FoundDecl = getNamedDeclFor(Context, OldName);
76  }
77  if (FoundDecl == nullptr) {
78  FullSourceLoc FullLoc(Point, SourceMgr);
79  errs() << "clang-rename: could not find symbol at "
80  << SourceMgr.getFilename(Point) << ":"
81  << FullLoc.getSpellingLineNumber() << ":"
82  << FullLoc.getSpellingColumnNumber() << " (offset " << SymbolOffset
83  << ").\n";
84  return;
85  }
86 
87  // If the decl is a constructor or destructor, we want to instead take the
88  // decl of the parent record.
89  if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
90  FoundDecl = CtorDecl->getParent();
91  else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
92  FoundDecl = DtorDecl->getParent();
93 
94  // If the decl is in any way relatedpp to a class, we want to make sure we
95  // search for the constructor and destructor as well as everything else.
96  if (const auto *Record = dyn_cast<CXXRecordDecl>(FoundDecl))
97  *USRs = getAllConstructorUSRs(Record);
98 
99  USRs->push_back(getUSRForDecl(FoundDecl));
100  *SpellingName = FoundDecl->getNameAsString();
101  }
102 
103  unsigned SymbolOffset;
104  std::string OldName;
105  std::string *SpellingName;
106  std::vector<std::string> *USRs;
107 };
108 
109 std::unique_ptr<ASTConsumer>
110 USRFindingAction::newASTConsumer() {
111  std::unique_ptr<NamedDeclFindingConsumer> Consumer(
113  SpellingName = "";
114  Consumer->SymbolOffset = SymbolOffset;
115  Consumer->OldName = OldName;
116  Consumer->USRs = &USRs;
117  Consumer->SpellingName = &SpellingName;
118  return std::move(Consumer);
119 }
120 
121 } // namespace rename
122 } // namespace clang
const SourceLocation Point
Definition: USRFinder.cpp:139
const NamedDecl * getNamedDeclAt(const ASTContext &Context, const SourceLocation Point)
Definition: USRFinder.cpp:144
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:184
SourceManager SourceMgr
Definition: ClangTidy.cpp:193
Provides an action to find all relevant USRs at a point.
Methods for determining the USR of a symbol at a location in source code.
void HandleTranslationUnit(ASTContext &Context) override
const NamedDecl * getNamedDeclFor(const ASTContext &Context, const std::string &Name)
Definition: USRFinder.cpp:168
static cl::opt< unsigned > SymbolOffset("offset", cl::desc("Locates the symbol by offset as opposed to <line>:<column>."), cl::cat(ClangRenameCategory))
static cl::opt< std::string > OldName("old-name", cl::desc("The fully qualified name of the symbol, if -offset is not used."), cl::cat(ClangRenameCategory))
static std::vector< std::string > getAllConstructorUSRs(const CXXRecordDecl *Decl)
ClangTidyContext & Context
Definition: ClangTidy.cpp:93