@@ -224,6 +224,7 @@ struct Obligation {
224
224
" Cannot form negative obligation!" );
225
225
}
226
226
227
+ Expectation::Scope getScope () const { return info.second ; }
227
228
Expectation::Kind getKind () const { return info.first ; }
228
229
StringRef getName () const { return name; }
229
230
bool getCascades () const {
@@ -240,6 +241,22 @@ struct Obligation {
240
241
}
241
242
}
242
243
244
+ StringRef renderAsFixit (ASTContext &Ctx) const {
245
+ llvm::StringRef selector =
246
+ #define MATRIX_ENTRY (SELECTOR, SCOPE, KIND ) \
247
+ if (getKind () == Expectation::Kind::KIND && \
248
+ getScope () == Expectation::Scope::SCOPE) { \
249
+ return SELECTOR; \
250
+ }
251
+
252
+ [this ]() -> StringRef {
253
+ EXPECTATION_MATRIX
254
+ return " " ;
255
+ }();
256
+ #undef MATRIX_ENTRY
257
+ return Ctx.AllocateCopy ((" // " + selector + " {{" + getName () + " }}" ).str ());
258
+ }
259
+
243
260
public:
244
261
bool isOwed () const { return state == State::Owed; }
245
262
FullfillmentToken fullfill () {
@@ -439,17 +456,19 @@ bool DependencyVerifier::constructObligations(const SourceFile *SF,
439
456
auto demContext = copyDemangledTypeName (Ctx, context);
440
457
auto key = Ctx.AllocateCopy ((demContext + " ." + name).str ());
441
458
Obligations.insert ({Obligation::Key::forMember (key),
442
- {context , Expectation::Kind::Member,
459
+ {key , Expectation::Kind::Member,
443
460
isCascadingUse ? Expectation::Scope::Cascading
444
461
: Expectation::Scope::Private}});
445
462
}
446
463
break ;
447
- case NodeKind::dynamicLookup:
464
+ case NodeKind::dynamicLookup: {
465
+ auto contextCpy = Ctx.AllocateCopy (context);
448
466
Obligations.insert ({Obligation::Key::forDynamicMember (name),
449
- {context , Expectation::Kind::DynamicMember,
467
+ {contextCpy , Expectation::Kind::DynamicMember,
450
468
isCascadingUse ? Expectation::Scope::Cascading
451
469
: Expectation::Scope::Private}});
452
470
break ;
471
+ }
453
472
case NodeKind::topLevel:
454
473
case NodeKind::sourceFileProvide:
455
474
Obligations.insert ({Obligation::Key::forProvides (name),
@@ -564,6 +583,7 @@ bool DependencyVerifier::diagnoseUnfulfilledObligations(
564
583
CharSourceRange EntireRange = SM.getRangeForBuffer (*SF->getBufferID ());
565
584
StringRef InputFile = SM.extractText (EntireRange);
566
585
auto &diags = SF->getASTContext ().Diags ;
586
+ auto &Ctx = SF->getASTContext ();
567
587
forEachOwedObligation (Obligations, [&](StringRef key, Obligation &p) {
568
588
// HACK: Diagnosing the end of the buffer will print a carat pointing
569
589
// at the file path, but not print any of the buffer's contents, which
@@ -576,10 +596,12 @@ bool DependencyVerifier::diagnoseUnfulfilledObligations(
576
596
case Expectation::Kind::DynamicMember:
577
597
case Expectation::Kind::PotentialMember:
578
598
diags.diagnose (Loc, diag::unexpected_dependency, p.describeCascade (),
579
- static_cast <uint8_t >(p.getKind ()), key);
599
+ static_cast <uint8_t >(p.getKind ()), key)
600
+ .fixItInsert (Loc, p.renderAsFixit (Ctx));
580
601
break ;
581
602
case Expectation::Kind::Provides:
582
- diags.diagnose (Loc, diag::unexpected_provided_entity, p.getName ());
603
+ diags.diagnose (Loc, diag::unexpected_provided_entity, p.getName ())
604
+ .fixItInsert (Loc, p.renderAsFixit (Ctx));
583
605
break ;
584
606
}
585
607
});
0 commit comments