Skip to content

Commit cc7fc99

Browse files
authored
[clang] Add source range to 'use of undeclared identifier' diagnostics (#117671)
1 parent d27175d commit cc7fc99

File tree

2 files changed

+51
-69
lines changed

2 files changed

+51
-69
lines changed

clang/lib/Frontend/DiagnosticRenderer.cpp

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -454,62 +454,41 @@ void DiagnosticRenderer::emitSingleMacroExpansion(
454454
SpellingRanges, {});
455455
}
456456

457-
/// Check that the macro argument location of Loc starts with ArgumentLoc.
458-
/// The starting location of the macro expansions is used to differeniate
459-
/// different macro expansions.
460-
static bool checkLocForMacroArgExpansion(SourceLocation Loc,
461-
const SourceManager &SM,
462-
SourceLocation ArgumentLoc) {
463-
SourceLocation MacroLoc;
464-
if (SM.isMacroArgExpansion(Loc, &MacroLoc)) {
465-
if (ArgumentLoc == MacroLoc) return true;
466-
}
467-
468-
return false;
469-
}
470-
471-
/// Check if all the locations in the range have the same macro argument
472-
/// expansion, and that the expansion starts with ArgumentLoc.
473-
static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
474-
const SourceManager &SM,
475-
SourceLocation ArgumentLoc) {
476-
SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd();
477-
while (BegLoc != EndLoc) {
478-
if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc))
479-
return false;
480-
BegLoc.getLocWithOffset(1);
481-
}
482-
483-
return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc);
484-
}
485-
486457
/// A helper function to check if the current ranges are all inside the same
487458
/// macro argument expansion as Loc.
488-
static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc,
489-
ArrayRef<CharSourceRange> Ranges) {
459+
static bool
460+
rangesInsideSameMacroArgExpansion(FullSourceLoc Loc,
461+
ArrayRef<CharSourceRange> Ranges) {
490462
assert(Loc.isMacroID() && "Must be a macro expansion!");
491463

492-
SmallVector<CharSourceRange, 4> SpellingRanges;
464+
SmallVector<CharSourceRange> SpellingRanges;
493465
mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
494466

495-
// Count all valid ranges.
496467
unsigned ValidCount =
497468
llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); });
498-
499469
if (ValidCount > SpellingRanges.size())
500470
return false;
501471

502-
// To store the source location of the argument location.
503-
FullSourceLoc ArgumentLoc;
472+
const SourceManager &SM = Loc.getManager();
473+
for (const auto &R : Ranges) {
474+
// All positions in the range need to point to Loc.
475+
SourceLocation Begin = R.getBegin();
476+
if (Begin == R.getEnd()) {
477+
if (!SM.isMacroArgExpansion(Begin))
478+
return false;
479+
continue;
480+
}
504481

505-
// Set the ArgumentLoc to the beginning location of the expansion of Loc
506-
// so to check if the ranges expands to the same beginning location.
507-
if (!Loc.isMacroArgExpansion(&ArgumentLoc))
508-
return false;
482+
while (Begin != R.getEnd()) {
483+
SourceLocation MacroLoc;
484+
if (!SM.isMacroArgExpansion(Begin, &MacroLoc))
485+
return false;
486+
if (MacroLoc != Loc)
487+
return false;
509488

510-
for (const auto &Range : SpellingRanges)
511-
if (!checkRangeForMacroArgExpansion(Range, Loc.getManager(), ArgumentLoc))
512-
return false;
489+
Begin = Begin.getLocWithOffset(1);
490+
}
491+
}
513492

514493
return true;
515494
}
@@ -539,13 +518,13 @@ void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
539518
while (L.isMacroID()) {
540519
// If this is the expansion of a macro argument, point the caret at the
541520
// use of the argument in the definition of the macro, not the expansion.
542-
if (SM.isMacroArgExpansion(L))
521+
if (SM.isMacroArgExpansion(L)) {
543522
LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());
544-
else
545-
LocationStack.push_back(L);
546523

547-
if (checkRangesForMacroArgExpansion(FullSourceLoc(L, SM), Ranges))
548-
IgnoredEnd = LocationStack.size();
524+
if (rangesInsideSameMacroArgExpansion(FullSourceLoc(L, SM), Ranges))
525+
IgnoredEnd = LocationStack.size();
526+
} else
527+
LocationStack.push_back(L);
549528

550529
L = SM.getImmediateMacroCallerLoc(L);
551530

clang/lib/Sema/SemaExpr.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,20 +2376,22 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
23762376
}
23772377
}
23782378

2379-
static void emitEmptyLookupTypoDiagnostic(
2380-
const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS,
2381-
DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args,
2382-
unsigned DiagnosticID, unsigned DiagnosticSuggestID) {
2379+
static void emitEmptyLookupTypoDiagnostic(const TypoCorrection &TC,
2380+
Sema &SemaRef, const CXXScopeSpec &SS,
2381+
DeclarationName Typo,
2382+
SourceRange TypoRange,
2383+
unsigned DiagnosticID,
2384+
unsigned DiagnosticSuggestID) {
23832385
DeclContext *Ctx =
23842386
SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false);
23852387
if (!TC) {
23862388
// Emit a special diagnostic for failed member lookups.
23872389
// FIXME: computing the declaration context might fail here (?)
23882390
if (Ctx)
2389-
SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
2390-
<< SS.getRange();
2391+
SemaRef.Diag(TypoRange.getBegin(), diag::err_no_member)
2392+
<< Typo << Ctx << TypoRange;
23912393
else
2392-
SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
2394+
SemaRef.Diag(TypoRange.getBegin(), DiagnosticID) << Typo << TypoRange;
23932395
return;
23942396
}
23952397

@@ -2400,12 +2402,13 @@ static void emitEmptyLookupTypoDiagnostic(
24002402
? diag::note_implicit_param_decl
24012403
: diag::note_previous_decl;
24022404
if (!Ctx)
2403-
SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo,
2404-
SemaRef.PDiag(NoteID));
2405+
SemaRef.diagnoseTypo(
2406+
TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo << TypoRange,
2407+
SemaRef.PDiag(NoteID));
24052408
else
2406-
SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
2407-
<< Typo << Ctx << DroppedSpecifier
2408-
<< SS.getRange(),
2409+
SemaRef.diagnoseTypo(TC,
2410+
SemaRef.PDiag(diag::err_no_member_suggest)
2411+
<< Typo << Ctx << DroppedSpecifier << TypoRange,
24092412
SemaRef.PDiag(NoteID));
24102413
}
24112414

@@ -2474,6 +2477,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
24742477
ArrayRef<Expr *> Args, DeclContext *LookupCtx,
24752478
TypoExpr **Out) {
24762479
DeclarationName Name = R.getLookupName();
2480+
SourceRange NameRange = R.getLookupNameInfo().getSourceRange();
24772481

24782482
unsigned diagnostic = diag::err_undeclared_var_use;
24792483
unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest;
@@ -2531,13 +2535,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
25312535
// We didn't find anything, so try to correct for a typo.
25322536
TypoCorrection Corrected;
25332537
if (S && Out) {
2534-
SourceLocation TypoLoc = R.getNameLoc();
25352538
assert(!ExplicitTemplateArgs &&
25362539
"Diagnosing an empty lookup with explicit template args!");
25372540
*Out = CorrectTypoDelayed(
25382541
R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC,
25392542
[=](const TypoCorrection &TC) {
2540-
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
2543+
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, NameRange,
25412544
diagnostic, diagnostic_suggest);
25422545
},
25432546
nullptr, CTK_ErrorRecovery, LookupCtx);
@@ -2616,12 +2619,13 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
26162619
? diag::note_implicit_param_decl
26172620
: diag::note_previous_decl;
26182621
if (SS.isEmpty())
2619-
diagnoseTypo(Corrected, PDiag(diagnostic_suggest) << Name,
2622+
diagnoseTypo(Corrected, PDiag(diagnostic_suggest) << Name << NameRange,
26202623
PDiag(NoteID), AcceptableWithRecovery);
26212624
else
2622-
diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
2623-
<< Name << computeDeclContext(SS, false)
2624-
<< DroppedSpecifier << SS.getRange(),
2625+
diagnoseTypo(Corrected,
2626+
PDiag(diag::err_no_member_suggest)
2627+
<< Name << computeDeclContext(SS, false)
2628+
<< DroppedSpecifier << NameRange,
26252629
PDiag(NoteID), AcceptableWithRecovery);
26262630

26272631
// Tell the callee whether to try to recover.
@@ -2634,13 +2638,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
26342638
// FIXME: computing the declaration context might fail here (?)
26352639
if (!SS.isEmpty()) {
26362640
Diag(R.getNameLoc(), diag::err_no_member)
2637-
<< Name << computeDeclContext(SS, false)
2638-
<< SS.getRange();
2641+
<< Name << computeDeclContext(SS, false) << NameRange;
26392642
return true;
26402643
}
26412644

26422645
// Give up, we can't recover.
2643-
Diag(R.getNameLoc(), diagnostic) << Name;
2646+
Diag(R.getNameLoc(), diagnostic) << Name << NameRange;
26442647
return true;
26452648
}
26462649

0 commit comments

Comments
 (0)