13 #include "llvm/Support/SaveAndRestore.h" 15 using namespace clang;
16 using namespace tooling;
23 if (!isa<ObjCImplDecl>(D))
29 R.getEnd(), tok::raw_identifier,
SM, LangOpts,
38 class ASTSelectionFinder
44 SelectionBegin(Selection.getBegin()),
45 SelectionEnd(Selection.getBegin() == Selection.getEnd()
47 : Selection.getEnd()),
48 TargetFile(TargetFile), Context(Context) {
50 SelectionStack.push_back(
56 assert(SelectionStack.size() == 1 &&
"stack was not popped");
58 SelectionStack.pop_back();
59 if (Result.Children.empty())
61 return std::move(Result);
73 if (!LookThroughOpaqueValueExprs)
79 bool TraverseDecl(
Decl *D) {
80 if (isa<TranslationUnitDecl>(D))
90 FileLoc = DeclRange.
getEnd();
97 selectionKindFor(getLexicalDeclRange(D, SM, Context.
getLangOpts()));
98 SelectionStack.push_back(
101 popAndAddToSelectionIfSelected(SelectionKind);
113 bool TraverseStmt(
Stmt *S) {
116 if (
auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
117 return TraverseOpaqueValueExpr(Opaque);
119 if (
auto *TE = dyn_cast<CXXThisExpr>(S)) {
120 if (TE->isImplicit())
126 SelectionStack.push_back(
129 popAndAddToSelectionIfSelected(SelectionKind);
136 SelectionStack.pop_back();
138 SelectionStack.back().Children.push_back(std::move(Node));
148 if (!SelectionEnd.isValid()) {
156 if (HasStart && HasEnd)
163 if (HasStart && SelectionBegin != End)
165 if (HasEnd && SelectionEnd != Range.
getBegin())
174 std::vector<SelectedASTNode> SelectionStack;
178 bool LookThroughOpaqueValueExprs =
false;
186 assert(SelectionRange.
isValid() &&
188 SelectionRange.
getEnd()) &&
189 "Expected a file range");
194 "selection range must span one file");
196 ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
198 return Visitor.getSelectedASTNode();
206 return "contains-selection";
208 return "contains-selection-start";
210 return "contains-selection-end";
214 llvm_unreachable(
"invalid selection kind");
218 unsigned Indent = 0) {
219 OS.indent(Indent * 2);
222 if (
const auto *ND = dyn_cast<NamedDecl>(D))
223 OS <<
" \"" << ND->getNameAsString() <<
'"';
228 for (
const auto &Child : Node.
Children)
229 dump(Child, OS, Indent + 1);
242 for (
const auto &Child : Node.
Children) {
243 if (Child.SelectionKind == Kind)
252 struct SelectedNodeWithParents {
253 SelectedNodeWithParents(SelectedNodeWithParents &&) =
default;
254 SelectedNodeWithParents &operator=(SelectedNodeWithParents &&) =
default;
268 getSelectionCanonizalizationAction(
const Stmt *S,
const Stmt *
Parent) {
273 if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
282 else if (
const auto *CE = dyn_cast<CallExpr>(Parent)) {
283 if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) &&
284 CE->getCallee()->IgnoreImpCasts() == S)
288 return KeepSelection;
293 void SelectedNodeWithParents::canonicalize() {
295 assert(S &&
"non statement selection!");
296 const Stmt *
Parent = Parents[Parents.size() - 1].get().Node.get<
Stmt>();
301 unsigned ParentIndex = 1;
302 for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(
Parent);
304 const Stmt *NewParent =
305 Parents[Parents.size() - ParentIndex - 1].get().Node.get<
Stmt>();
311 switch (getSelectionCanonizalizationAction(S, Parent)) {
313 Node = Parents[Parents.size() - ParentIndex];
314 for (; ParentIndex != 0; --ParentIndex)
352 for (
const auto &Child : ASTSelection.
Children) {
354 MatchingNodes.push_back(SelectedNodeWithParents{
355 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
362 MatchingNodes.push_back(SelectedNodeWithParents{
363 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
368 ParentStack.push_back(std::cref(ASTSelection));
369 for (
const auto &Child : ASTSelection.
Children)
371 ParentStack.pop_back();
393 if (ContainSelection.size() != 1)
395 SelectedNodeWithParents &Selected = ContainSelection[0];
396 if (!Selected.Node.get().Node.get<
Stmt>())
398 const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<
Stmt>();
399 if (!isa<CompoundStmt>(CodeRangeStmt)) {
400 Selected.canonicalize();
412 Selected.Parents.push_back(Selected.Node);
419 return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D);
423 bool IsPrevCompound =
false;
427 for (
const auto &
Parent : llvm::reverse(Parents)) {
429 if (
const auto *D = Node.
get<
Decl>()) {
431 return IsPrevCompound;
436 if (isa<TypeDecl>(D))
445 for (
const auto &
Parent : llvm::reverse(Parents)) {
447 if (
const auto *D = Node.
get<
Decl>()) {
Expr * getSyntacticForm()
Return the syntactic form of this expression, i.e.
const char * getDeclKindName() const
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 void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS, unsigned Indent=0)
Stmt - This represents one statement.
static CharSourceRange getTokenRange(SourceRange R)
const T * get() const
Retrieve the stored node as type T.
Decl - This represents one declaration (or definition), e.g.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
const char * getStmtClassName() const
SourceLocation getBegin() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
CompoundStmt - This represents a group of statements like { stmt stmt }.
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.
Represents a character-granular source range.
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...
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getEnd() const
static CharSourceRange getCharRange(SourceRange R)
static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node, SourceSelectionKind Kind)
Returns true if the given node has any direct children with the following selection kind...
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class...
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Encodes a location in the source.
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
A RecursiveASTVisitor subclass that guarantees that AST traversal is performed in a lexical order (i...
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
ast_type_traits::DynTypedNode DynTypedNode
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Dataflow Directional Tag Classes.
static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End)
bool isValid() const
Return true if this is a valid SourceLocation object.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
static bool isFunctionLikeDeclaration(const Decl *D)
A dynamically typed AST node container.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceLocation getEnd() const
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isPointWithin(SourceLocation Location, SourceLocation Start, SourceLocation End) const
Return true if the Point is within Start and End.
SelectionCanonicalizationAction
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
static const char * selectionKindToString(SourceSelectionKind Kind)