@@ -52,8 +52,7 @@ using ast_type_traits::DynTypedNode;
52
52
// On traversing an AST node, its token range is erased from the unclaimed set.
53
53
// The tokens actually removed are associated with that node, and hit-tested
54
54
// against the selection to determine whether the node is selected.
55
- template <typename T>
56
- class IntervalSet {
55
+ template <typename T> class IntervalSet {
57
56
public:
58
57
IntervalSet (llvm::ArrayRef<T> Range) { UnclaimedRanges.insert (Range); }
59
58
@@ -78,7 +77,7 @@ class IntervalSet {
78
77
--Overlap.first ;
79
78
// ...unless B isn't selected at all.
80
79
if (Overlap.first ->end () <= Claim.begin ())
81
- ++Overlap.first ;
80
+ ++Overlap.first ;
82
81
}
83
82
if (Overlap.first == Overlap.second )
84
83
return Out;
@@ -118,8 +117,7 @@ class IntervalSet {
118
117
};
119
118
120
119
// Disjoint sorted unclaimed ranges of expanded tokens.
121
- std::set<llvm::ArrayRef<T>, RangeLess>
122
- UnclaimedRanges;
120
+ std::set<llvm::ArrayRef<T>, RangeLess> UnclaimedRanges;
123
121
};
124
122
125
123
// Sentinel value for the selectedness of a node where we've seen no tokens yet.
@@ -148,11 +146,37 @@ bool shouldIgnore(const syntax::Token &Tok) {
148
146
return Tok.kind () == tok::comment || Tok.kind () == tok::semi;
149
147
}
150
148
149
+ // Determine whether 'Target' is the first expansion of the macro
150
+ // argument whose top-level spelling location is 'SpellingLoc'.
151
+ bool isFirstExpansion (FileID Target, SourceLocation SpellingLoc,
152
+ const SourceManager &SM) {
153
+ SourceLocation Prev = SpellingLoc;
154
+ while (true ) {
155
+ // If the arg is expanded multiple times, getMacroArgExpandedLocation()
156
+ // returns the first expansion.
157
+ SourceLocation Next = SM.getMacroArgExpandedLocation (Prev);
158
+ // So if we reach the target, target is the first-expansion of the
159
+ // first-expansion ...
160
+ if (SM.getFileID (Next) == Target)
161
+ return true ;
162
+
163
+ // Otherwise, if the FileID stops changing, we've reached the innermost
164
+ // macro expansion, and Target was on a different branch.
165
+ if (SM.getFileID (Next) == SM.getFileID (Prev))
166
+ return false ;
167
+
168
+ Prev = Next;
169
+ }
170
+ return false ;
171
+ }
172
+
151
173
// SelectionTester can determine whether a range of tokens from the PP-expanded
152
174
// stream (corresponding to an AST node) is considered selected.
153
175
//
154
176
// When the tokens result from macro expansions, the appropriate tokens in the
155
177
// main file are examined (macro invocation or args). Similarly for #includes.
178
+ // However, only the first expansion of a given spelled token is considered
179
+ // selected.
156
180
//
157
181
// It tests each token in the range (not just the endpoints) as contiguous
158
182
// expanded tokens may not have contiguous spellings (with macros).
@@ -260,9 +284,14 @@ class SelectionTester {
260
284
// Handle tokens that were passed as a macro argument.
261
285
SourceLocation ArgStart = SM.getTopMacroCallerLoc (StartLoc);
262
286
if (SM.getFileID (ArgStart) == SelFile) {
263
- SourceLocation ArgEnd = SM.getTopMacroCallerLoc (Batch.back ().location ());
264
- return testTokenRange (SM.getFileOffset (ArgStart),
265
- SM.getFileOffset (ArgEnd));
287
+ if (isFirstExpansion (FID, ArgStart, SM)) {
288
+ SourceLocation ArgEnd =
289
+ SM.getTopMacroCallerLoc (Batch.back ().location ());
290
+ return testTokenRange (SM.getFileOffset (ArgStart),
291
+ SM.getFileOffset (ArgEnd));
292
+ } else {
293
+ /* fall through and treat as part of the macro body */
294
+ }
266
295
}
267
296
268
297
// Handle tokens produced by non-argument macro expansion.
@@ -346,7 +375,7 @@ std::string printNodeToString(const DynTypedNode &N, const PrintingPolicy &PP) {
346
375
}
347
376
#endif
348
377
349
- bool isImplicit (const Stmt* S) {
378
+ bool isImplicit (const Stmt * S) {
350
379
// Some Stmts are implicit and shouldn't be traversed, but there's no
351
380
// "implicit" attribute on Stmt/Expr.
352
381
// Unwrap implicit casts first if present (other nodes too?).
@@ -611,7 +640,7 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
611
640
// int (*[[s]])();
612
641
else if (auto *VD = llvm::dyn_cast<VarDecl>(D))
613
642
return VD->getLocation ();
614
- } else if (const auto * CCI = N.get <CXXCtorInitializer>()) {
643
+ } else if (const auto * CCI = N.get <CXXCtorInitializer>()) {
615
644
// : [[b_]](42)
616
645
return CCI->getMemberLocation ();
617
646
}
@@ -747,10 +776,10 @@ const Node *SelectionTree::commonAncestor() const {
747
776
return Ancestor != Root ? Ancestor : nullptr ;
748
777
}
749
778
750
- const DeclContext& SelectionTree::Node::getDeclContext () const {
751
- for (const Node* CurrentNode = this ; CurrentNode != nullptr ;
779
+ const DeclContext & SelectionTree::Node::getDeclContext () const {
780
+ for (const Node * CurrentNode = this ; CurrentNode != nullptr ;
752
781
CurrentNode = CurrentNode->Parent ) {
753
- if (const Decl* Current = CurrentNode->ASTNode .get <Decl>()) {
782
+ if (const Decl * Current = CurrentNode->ASTNode .get <Decl>()) {
754
783
if (CurrentNode != this )
755
784
if (auto *DC = dyn_cast<DeclContext>(Current))
756
785
return *DC;
0 commit comments