clang 10.0.0git

USRFinder.cpp
Go to the documentation of this file.
1 //===--- USRFinder.cpp - Clang refactoring library ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file Implements a recursive AST visitor that finds the USR of a symbol at a
10 /// point.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Tooling/Refactoring/Rename/USRFinder.h"
15 #include "clang/AST/AST.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/RecursiveASTVisitor.h"
18 #include "clang/Index/USRGeneration.h"
19 #include "clang/Lex/Lexer.h"
20 #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
21 #include "llvm/ADT/SmallVector.h"
22
23 using namespace llvm;
24
25 namespace clang {
26 namespace tooling {
27
28 namespace {
29
30 /// Recursively visits each AST node to find the symbol underneath the cursor.
31 class NamedDeclOccurrenceFindingVisitor
32 : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
33 public:
34 // Finds the NamedDecl at a point in the source.
35 // \param Point the location in the source to search for the NamedDecl.
36 explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
37 const ASTContext &Context)
38 : RecursiveSymbolVisitor(Context.getSourceManager(),
39 Context.getLangOpts()),
40 Point(Point), Context(Context) {}
41
42 bool visitSymbolOccurrence(const NamedDecl *ND,
43 ArrayRef<SourceRange> NameRanges) {
44 if (!ND)
45 return true;
46 for (const auto &Range : NameRanges) {
47 SourceLocation Start = Range.getBegin();
48 SourceLocation End = Range.getEnd();
49 if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
50 !End.isFileID() || !isPointWithin(Start, End))
51 return true;
52 }
53 Result = ND;
54 return false;
55 }
56
57 const NamedDecl *getNamedDecl() const { return Result; }
58
59 private:
60 // Determines if the Point is within Start and End.
61 bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
62 // FIXME: Add tests for Point == End.
63 return Point == Start || Point == End ||
64 (Context.getSourceManager().isBeforeInTranslationUnit(Start,
65 Point) &&
66 Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
67 }
68
69 const NamedDecl *Result = nullptr;
70 const SourceLocation Point; // The location to find the NamedDecl.
71 const ASTContext &Context;
72 };
73
74 } // end anonymous namespace
75
76 const NamedDecl *getNamedDeclAt(const ASTContext &Context,
77 const SourceLocation Point) {
78 const SourceManager &SM = Context.getSourceManager();
79 NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
80
81 // Try to be clever about pruning down the number of top-level declarations we
82 // see. If both start and end is either before or after the point we're
83 // looking for the point cannot be inside of this decl. Don't even look at it.
84 for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
85 SourceLocation StartLoc = CurrDecl->getBeginLoc();
86 SourceLocation EndLoc = CurrDecl->getEndLoc();
87 if (StartLoc.isValid() && EndLoc.isValid() &&
88 SM.isBeforeInTranslationUnit(StartLoc, Point) !=
89 SM.isBeforeInTranslationUnit(EndLoc, Point))
90 Visitor.TraverseDecl(CurrDecl);
91 }
92
93 return Visitor.getNamedDecl();
94 }
95
96 namespace {
97
98 /// Recursively visits each NamedDecl node to find the declaration with a
99 /// specific name.
100 class NamedDeclFindingVisitor
101 : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
102 public:
103 explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
104
105 // We don't have to traverse the uses to find some declaration with a
106 // specific name, so just visit the named declarations.
107 bool VisitNamedDecl(const NamedDecl *ND) {
108 if (!ND)
109 return true;
110 // Fully qualified name is used to find the declaration.
111 if (Name != ND->getQualifiedNameAsString() &&
112 Name != "::" + ND->getQualifiedNameAsString())
113 return true;
114 Result = ND;
115 return false;
116 }
117
118 const NamedDecl *getNamedDecl() const { return Result; }
119
120 private:
121 const NamedDecl *Result = nullptr;
122 StringRef Name;
123 };
124
125 } // end anonymous namespace
126
127 const NamedDecl *getNamedDeclFor(const ASTContext &Context,
128 const std::string &Name) {
129 NamedDeclFindingVisitor Visitor(Name);
130 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
131 return Visitor.getNamedDecl();
132 }
133
134 std::string getUSRForDecl(const Decl *Decl) {
135 llvm::SmallVector<char, 128> Buff;
136
137 // FIXME: Add test for the nullptr case.
138 if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
139 return "";
140
141 return std::string(Buff.data(), Buff.size());
142 }
143
144 } // end namespace tooling
145 } // end namespace clang
ASTContext.h
Defines the clang::ASTContext interface.
AST.h
llvm
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
Definition: Dominators.h:30
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
clang::SourceManager::isBeforeInTranslationUnit
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Definition: SourceManager.cpp:1936
clang::DeclContext::decls
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2033
RecursiveSymbolVisitor.h
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol...
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:168
USRFinder.h
Methods for determining the USR of a symbol at a location in source code.
clang::RecursiveASTVisitor
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Definition: RecursiveASTVisitor.h:151
llvm::ArrayRef
Definition: LLVM.h:31
clang::tooling::getNamedDeclFor
const NamedDecl * getNamedDeclFor(const ASTContext &Context, const std::string &Name)
Definition: USRFinder.cpp:127
End
SourceLocation End
Definition: USRLocFinder.cpp:166
Lexer.h
RecursiveASTVisitor.h
SM
const SourceManager & SM
Definition: Format.cpp:1685
clang::tooling::getNamedDeclAt
const NamedDecl * getNamedDeclAt(const ASTContext &Context, const SourceLocation Point)
Definition: USRFinder.cpp:76
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
USRGeneration.h
clang::tooling::getUSRForDecl
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:134
llvm::SmallVector
Definition: LLVM.h:35
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::SourceLocation::isValid
bool isValid() const
Return true if this is a valid SourceLocation object.
Definition: SourceLocation.h:106
clang::ASTContext::getSourceManager
SourceManager & getSourceManager()
Definition: ASTContext.h:679
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1009
clang::NamedDecl::getQualifiedNameAsString
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1555
clang::index::generateUSRForDecl
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
Definition: USRGeneration.cpp:1073
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:223
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition: SourceManager.h:596