@@ -296,31 +296,72 @@ static SourceRange unionTokenRange(SourceRange R1, SourceRange R2,
296
296
E1 < E2 ? R2.getEnd () : R1.getEnd ());
297
297
}
298
298
299
- // Returns the tokenFileRange for a given Location as a Token Range
299
+ // Check if two locations have the same file id.
300
+ static bool inSameFile (SourceLocation Loc1, SourceLocation Loc2,
301
+ const SourceManager &SM) {
302
+ return SM.getFileID (Loc1) == SM.getFileID (Loc2);
303
+ }
304
+
305
+ // Find an expansion range (not necessarily immediate) the ends of which are in
306
+ // the same file id.
307
+ static SourceRange
308
+ getExpansionTokenRangeInSameFile (SourceLocation Loc, const SourceManager &SM,
309
+ const LangOptions &LangOpts) {
310
+ SourceRange ExpansionRange =
311
+ toTokenRange (SM.getImmediateExpansionRange (Loc), SM, LangOpts);
312
+ // Fast path for most common cases.
313
+ if (inSameFile (ExpansionRange.getBegin (), ExpansionRange.getEnd (), SM))
314
+ return ExpansionRange;
315
+ // Record the stack of expansion locations for the beginning, keyed by FileID.
316
+ llvm::DenseMap<FileID, SourceLocation> BeginExpansions;
317
+ for (SourceLocation Begin = ExpansionRange.getBegin (); Begin.isValid ();
318
+ Begin = Begin.isFileID ()
319
+ ? SourceLocation ()
320
+ : SM.getImmediateExpansionRange (Begin).getBegin ()) {
321
+ BeginExpansions[SM.getFileID (Begin)] = Begin;
322
+ }
323
+ // Move up the stack of expansion locations for the end until we find the
324
+ // location in BeginExpansions with that has the same file id.
325
+ for (SourceLocation End = ExpansionRange.getEnd (); End.isValid ();
326
+ End = End.isFileID () ? SourceLocation ()
327
+ : toTokenRange (SM.getImmediateExpansionRange (End),
328
+ SM, LangOpts)
329
+ .getEnd ()) {
330
+ auto It = BeginExpansions.find (SM.getFileID (End));
331
+ if (It != BeginExpansions.end ())
332
+ return {It->second , End};
333
+ }
334
+ llvm_unreachable (
335
+ " We should able to find a common ancestor in the expansion tree." );
336
+ }
337
+ // Returns the file range for a given Location as a Token Range
300
338
// This is quite similar to getFileLoc in SourceManager as both use
301
339
// getImmediateExpansionRange and getImmediateSpellingLoc (for macro IDs).
302
340
// However:
303
341
// - We want to maintain the full range information as we move from one file to
304
342
// the next. getFileLoc only uses the BeginLoc of getImmediateExpansionRange.
305
- // - We want to split '>>' tokens as the lexer parses the '>>' in template
306
- // instantiations as a '>>' instead of a '>'.
343
+ // - We want to split '>>' tokens as the lexer parses the '>>' in nested
344
+ // template instantiations as a '>>' instead of two '>'s .
307
345
// There is also getExpansionRange but it simply calls
308
346
// getImmediateExpansionRange on the begin and ends separately which is wrong.
309
347
static SourceRange getTokenFileRange (SourceLocation Loc,
310
348
const SourceManager &SM,
311
349
const LangOptions &LangOpts) {
312
350
SourceRange FileRange = Loc;
313
351
while (!FileRange.getBegin ().isFileID ()) {
314
- assert (!FileRange.getEnd ().isFileID () &&
315
- " Both Begin and End should be MacroIDs." );
316
352
if (SM.isMacroArgExpansion (FileRange.getBegin ())) {
317
- FileRange.setBegin (SM.getImmediateSpellingLoc (FileRange.getBegin ()));
318
- FileRange.setEnd (SM.getImmediateSpellingLoc (FileRange.getEnd ()));
353
+ FileRange = unionTokenRange (
354
+ SM.getImmediateSpellingLoc (FileRange.getBegin ()),
355
+ SM.getImmediateSpellingLoc (FileRange.getEnd ()), SM, LangOpts);
356
+ assert (inSameFile (FileRange.getBegin (), FileRange.getEnd (), SM));
319
357
} else {
320
- SourceRange ExpansionRangeForBegin = toTokenRange (
321
- SM.getImmediateExpansionRange (FileRange.getBegin ()), SM, LangOpts);
322
- SourceRange ExpansionRangeForEnd = toTokenRange (
323
- SM.getImmediateExpansionRange (FileRange.getEnd ()), SM, LangOpts);
358
+ SourceRange ExpansionRangeForBegin =
359
+ getExpansionTokenRangeInSameFile (FileRange.getBegin (), SM, LangOpts);
360
+ SourceRange ExpansionRangeForEnd =
361
+ getExpansionTokenRangeInSameFile (FileRange.getEnd (), SM, LangOpts);
362
+ assert (inSameFile (ExpansionRangeForBegin.getBegin (),
363
+ ExpansionRangeForEnd.getBegin (), SM) &&
364
+ " Both Expansion ranges should be in same file." );
324
365
FileRange = unionTokenRange (ExpansionRangeForBegin, ExpansionRangeForEnd,
325
366
SM, LangOpts);
326
367
}
0 commit comments