Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
35295 views
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/Basic/SourceManager.h"
19
#include "clang/Index/USRGeneration.h"
20
#include "clang/Lex/Lexer.h"
21
#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
22
#include "llvm/ADT/SmallVector.h"
23
24
using namespace llvm;
25
26
namespace clang {
27
namespace tooling {
28
29
namespace {
30
31
/// Recursively visits each AST node to find the symbol underneath the cursor.
32
class NamedDeclOccurrenceFindingVisitor
33
: public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
34
public:
35
// Finds the NamedDecl at a point in the source.
36
// \param Point the location in the source to search for the NamedDecl.
37
explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
38
const ASTContext &Context)
39
: RecursiveSymbolVisitor(Context.getSourceManager(),
40
Context.getLangOpts()),
41
Point(Point), Context(Context) {}
42
43
bool visitSymbolOccurrence(const NamedDecl *ND,
44
ArrayRef<SourceRange> NameRanges) {
45
if (!ND)
46
return true;
47
for (const auto &Range : NameRanges) {
48
SourceLocation Start = Range.getBegin();
49
SourceLocation End = Range.getEnd();
50
if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
51
!End.isFileID() || !isPointWithin(Start, End))
52
return true;
53
}
54
Result = ND;
55
return false;
56
}
57
58
const NamedDecl *getNamedDecl() const { return Result; }
59
60
private:
61
// Determines if the Point is within Start and End.
62
bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
63
// FIXME: Add tests for Point == End.
64
return Point == Start || Point == End ||
65
(Context.getSourceManager().isBeforeInTranslationUnit(Start,
66
Point) &&
67
Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
68
}
69
70
const NamedDecl *Result = nullptr;
71
const SourceLocation Point; // The location to find the NamedDecl.
72
const ASTContext &Context;
73
};
74
75
} // end anonymous namespace
76
77
const NamedDecl *getNamedDeclAt(const ASTContext &Context,
78
const SourceLocation Point) {
79
const SourceManager &SM = Context.getSourceManager();
80
NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
81
82
// Try to be clever about pruning down the number of top-level declarations we
83
// see. If both start and end is either before or after the point we're
84
// looking for the point cannot be inside of this decl. Don't even look at it.
85
for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
86
SourceLocation StartLoc = CurrDecl->getBeginLoc();
87
SourceLocation EndLoc = CurrDecl->getEndLoc();
88
if (StartLoc.isValid() && EndLoc.isValid() &&
89
SM.isBeforeInTranslationUnit(StartLoc, Point) !=
90
SM.isBeforeInTranslationUnit(EndLoc, Point))
91
Visitor.TraverseDecl(CurrDecl);
92
}
93
94
return Visitor.getNamedDecl();
95
}
96
97
namespace {
98
99
/// Recursively visits each NamedDecl node to find the declaration with a
100
/// specific name.
101
class NamedDeclFindingVisitor
102
: public RecursiveASTVisitor<NamedDeclFindingVisitor> {
103
public:
104
explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
105
106
// We don't have to traverse the uses to find some declaration with a
107
// specific name, so just visit the named declarations.
108
bool VisitNamedDecl(const NamedDecl *ND) {
109
if (!ND)
110
return true;
111
// Fully qualified name is used to find the declaration.
112
if (Name != ND->getQualifiedNameAsString() &&
113
Name != "::" + ND->getQualifiedNameAsString())
114
return true;
115
Result = ND;
116
return false;
117
}
118
119
const NamedDecl *getNamedDecl() const { return Result; }
120
121
private:
122
const NamedDecl *Result = nullptr;
123
StringRef Name;
124
};
125
126
} // end anonymous namespace
127
128
const NamedDecl *getNamedDeclFor(const ASTContext &Context,
129
const std::string &Name) {
130
NamedDeclFindingVisitor Visitor(Name);
131
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
132
return Visitor.getNamedDecl();
133
}
134
135
std::string getUSRForDecl(const Decl *Decl) {
136
llvm::SmallString<128> Buff;
137
138
// FIXME: Add test for the nullptr case.
139
if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
140
return "";
141
142
return std::string(Buff);
143
}
144
145
} // end namespace tooling
146
} // end namespace clang
147
148