12#include "llvm/Support/SaveAndRestore.h"
28 R.getEnd(), tok::raw_identifier, SM, LangOpts,
37class ASTSelectionFinder
40 ASTSelectionFinder(SourceRange Selection, FileID TargetFile,
41 const ASTContext &Context)
42 : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
43 SelectionBegin(Selection.getBegin()),
44 SelectionEnd(Selection.getBegin() == Selection.getEnd()
46 : Selection.getEnd()),
47 TargetFile(TargetFile), Context(Context) {
49 SelectionStack.push_back(
50 SelectedASTNode(DynTypedNode::create(*Context.getTranslationUnitDecl()),
51 SourceSelectionKind::None));
54 std::optional<SelectedASTNode> getSelectedASTNode() {
55 assert(SelectionStack.size() == 1 &&
"stack was not popped");
56 SelectedASTNode
Result = std::move(SelectionStack.back());
57 SelectionStack.pop_back();
58 if (
Result.Children.empty())
63 bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
67 llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs,
true);
71 bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
72 if (!LookThroughOpaqueValueExprs)
74 llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs,
false);
78 bool TraverseDecl(Decl *D) {
80 return LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
86 const SourceManager &SM = Context.getSourceManager();
87 SourceLocation FileLoc;
89 FileLoc = DeclRange.
getEnd();
96 selectionKindFor(getLexicalDeclRange(D, SM, Context.getLangOpts()));
97 SelectionStack.push_back(
98 SelectedASTNode(DynTypedNode::create(*D), SelectionKind));
99 LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
100 popAndAddToSelectionIfSelected(SelectionKind);
112 bool TraverseStmt(Stmt *S) {
115 if (
auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
116 return TraverseOpaqueValueExpr(Opaque);
118 if (
auto *TE = dyn_cast<CXXThisExpr>(S)) {
119 if (TE->isImplicit())
125 SelectionStack.push_back(
126 SelectedASTNode(DynTypedNode::create(*S), SelectionKind));
127 LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
128 popAndAddToSelectionIfSelected(SelectionKind);
134 SelectedASTNode Node = std::move(SelectionStack.back());
135 SelectionStack.pop_back();
136 if (SelectionKind != SourceSelectionKind::None || !Node.
Children.empty())
137 SelectionStack.back().Children.push_back(std::move(Node));
141 SourceLocation End =
Range.getEnd();
142 const SourceManager &SM = Context.getSourceManager();
143 if (
Range.isTokenRange())
145 if (!SourceLocation::isPairOfFileLocations(
Range.getBegin(), End))
146 return SourceSelectionKind::None;
147 if (!SelectionEnd.isValid()) {
150 return SourceSelectionKind::ContainsSelection;
151 return SourceSelectionKind::None;
155 if (HasStart && HasEnd)
156 return SourceSelectionKind::ContainsSelection;
159 return SourceSelectionKind::InsideSelection;
162 if (HasStart && SelectionBegin != End)
163 return SourceSelectionKind::ContainsSelectionStart;
164 if (HasEnd && SelectionEnd !=
Range.getBegin())
165 return SourceSelectionKind::ContainsSelectionEnd;
167 return SourceSelectionKind::None;
170 const SourceLocation SelectionBegin, SelectionEnd;
172 const ASTContext &Context;
173 std::vector<SelectedASTNode> SelectionStack;
177 bool LookThroughOpaqueValueExprs =
false;
182std::optional<SelectedASTNode>
185 assert(SelectionRange.
isValid() &&
187 SelectionRange.
getEnd()) &&
188 "Expected a file range");
190 Context.getSourceManager().getFileID(SelectionRange.
getBegin());
191 assert(Context.getSourceManager().getFileID(SelectionRange.
getEnd()) ==
193 "selection range must span one file");
195 ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
196 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
197 return Visitor.getSelectedASTNode();
202 case SourceSelectionKind::None:
204 case SourceSelectionKind::ContainsSelection:
205 return "contains-selection";
206 case SourceSelectionKind::ContainsSelectionStart:
207 return "contains-selection-start";
208 case SourceSelectionKind::ContainsSelectionEnd:
209 return "contains-selection-end";
210 case SourceSelectionKind::InsideSelection:
213 llvm_unreachable(
"invalid selection kind");
221 if (
const auto *ND = dyn_cast<NamedDecl>(D))
222 OS <<
" \"" << ND->getDeclName() <<
'"';
227 for (
const auto &Child : Node.
Children)
241 for (
const auto &Child : Node.
Children) {
242 if (Child.SelectionKind == Kind)
251struct SelectedNodeWithParents {
253 llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
260enum SelectionCanonicalizationAction { KeepSelection, SelectParent };
264SelectionCanonicalizationAction
265getSelectionCanonizalizationAction(
const Stmt *S,
const Stmt *Parent) {
279 else if (
const auto *CE = dyn_cast<CallExpr>(Parent)) {
281 CE->getCallee()->IgnoreImpCasts() == S)
285 return KeepSelection;
290void SelectedNodeWithParents::canonicalize() {
291 const Stmt *S = Node.get().
Node.
get<Stmt>();
292 assert(S &&
"non statement selection!");
293 const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>();
298 unsigned ParentIndex = 1;
301 const Stmt *NewParent =
302 Parents[Parents.size() - ParentIndex - 1].get().Node.get<Stmt>();
308 switch (getSelectionCanonizalizationAction(S, Parent)) {
310 Node = Parents[Parents.size() - ParentIndex];
311 for (; ParentIndex != 0; --ParentIndex)
349 for (
const auto &Child : ASTSelection.
Children) {
351 MatchingNodes.push_back(SelectedNodeWithParents{
352 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
359 MatchingNodes.push_back(SelectedNodeWithParents{
360 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
365 ParentStack.push_back(std::cref(ASTSelection));
366 for (
const auto &Child : ASTSelection.
Children)
368 ParentStack.pop_back();
379std::optional<CodeRangeASTSelection>
390 if (ContainSelection.size() != 1)
392 SelectedNodeWithParents &Selected = ContainSelection[0];
393 if (!Selected.Node.get().Node.get<
Stmt>())
395 const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<
Stmt>();
397 Selected.canonicalize();
409 Selected.Parents.push_back(Selected.Node);
420 bool IsPrevCompound =
false;
424 for (
const auto &Parent : llvm::reverse(Parents)) {
426 if (
const auto *D = Node.
get<
Decl>()) {
428 return IsPrevCompound;
442 for (
const auto &Parent : llvm::reverse(Parents)) {
444 if (
const auto *D = Node.
get<
Decl>()) {
static bool isFunctionLikeDeclaration(const Decl *D)
static const char * selectionKindToString(SourceSelectionKind Kind)
static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS, unsigned Indent=0)
static void findDeepestWithKind(const SelectedASTNode &ASTSelection, llvm::SmallVectorImpl< SelectedNodeWithParents > &MatchingNodes, SourceSelectionKind Kind, llvm::SmallVectorImpl< SelectedASTNode::ReferenceType > &ParentStack)
Finds the set of bottom-most selected AST nodes that are in the selection tree with the specified sel...
static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node, SourceSelectionKind Kind)
Returns true if the given node has any direct children with the following selection kind.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
static CharSourceRange getTokenRange(SourceRange R)
CompoundStmt - This represents a group of statements like { stmt stmt }.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
const char * getDeclKindName() const
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static SourceLocation findLocationAfterToken(SourceLocation loc, tok::TokenKind TKind, const SourceManager &SM, const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine)
Checks that the given token is the first token that occurs after the given location (this excludes co...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
A RecursiveASTVisitor subclass that guarantees that AST traversal is performed in a lexical order (i....
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Expr * getSyntacticForm()
Return the syntactic form of this expression, i.e.
Encodes a location in the source.
static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End)
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
bool isPointWithin(SourceLocation Location, SourceLocation Start, SourceLocation End) const
Return true if the Point is within Start and End.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
@ Result
The result type of a method or function.