@@ -3681,6 +3681,118 @@ static ArrayRef<ASTContext::MissingWitness> pruneMissingWitnesses(
36813681 return missingWitnesses;
36823682}
36833683
3684+ static void diagnoseProtocolStubFixit (
3685+ NormalProtocolConformance *Conf,
3686+ llvm::SmallVector<ASTContext::MissingWitness, 4 > MissingWitnesses) {
3687+ DeclContext *DC = Conf->getDeclContext ();
3688+
3689+ auto &Ctx = DC->getASTContext ();
3690+
3691+ SourceLoc ComplainLoc = Conf->getLoc ();
3692+
3693+ // The location where to insert stubs.
3694+ SourceLoc FixitLocation;
3695+
3696+ // The location where the type starts.
3697+ SourceLoc TypeLoc;
3698+ if (auto Extension = dyn_cast<ExtensionDecl>(DC)) {
3699+ FixitLocation = Extension->getBraces ().Start ;
3700+ TypeLoc = Extension->getStartLoc ();
3701+ } else if (auto Nominal = dyn_cast<NominalTypeDecl>(DC)) {
3702+ FixitLocation = Nominal->getBraces ().Start ;
3703+ TypeLoc = Nominal->getStartLoc ();
3704+ } else {
3705+ llvm_unreachable (" Unknown adopter kind" );
3706+ }
3707+ std::string FixIt;
3708+ llvm::SetVector<ValueDecl*> NoStubRequirements;
3709+
3710+ // Print stubs for all known missing witnesses.
3711+ printProtocolStubFixitString (TypeLoc, Conf, MissingWitnesses, FixIt,
3712+ NoStubRequirements);
3713+ auto &Diags = Ctx.Diags ;
3714+
3715+ // If we are in editor mode, squash all notes into a single fixit.
3716+ if (Ctx.LangOpts .DiagnosticsEditorMode ) {
3717+ if (!FixIt.empty ()) {
3718+ Diags.diagnose (ComplainLoc, diag::missing_witnesses_general).
3719+ fixItInsertAfter (FixitLocation, FixIt);
3720+ }
3721+ return ;
3722+ }
3723+ auto &SM = Ctx.SourceMgr ;
3724+ auto FixitBufferId = SM.findBufferContainingLoc (FixitLocation);
3725+ for (const auto &Missing : MissingWitnesses) {
3726+ auto VD = Missing.requirement ;
3727+
3728+ // Don't ever emit a diagnostic for a requirement in the NSObject
3729+ // protocol. They're not implementable.
3730+ if (isNSObjectProtocol (VD->getDeclContext ()->getSelfProtocolDecl ()))
3731+ continue ;
3732+
3733+ // Whether this VD has a stub printed.
3734+ bool AddFixit = !NoStubRequirements.count (VD);
3735+ bool SameFile = VD->getLoc ().isValid () ?
3736+ SM.findBufferContainingLoc (VD->getLoc ()) == FixitBufferId : false ;
3737+
3738+ // Issue diagnostics for witness types.
3739+ if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(VD)) {
3740+ llvm::Optional<InFlightDiagnostic> diag;
3741+ if (isa<BuiltinTupleDecl>(DC->getSelfNominalTypeDecl ())) {
3742+ auto expectedTy = getTupleConformanceTypeWitness (DC, MissingTypeWitness);
3743+ diag.emplace (Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type_tuple,
3744+ MissingTypeWitness, expectedTy));
3745+ } else {
3746+ diag.emplace (Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type,
3747+ MissingTypeWitness));
3748+ }
3749+ if (SameFile) {
3750+ // If the protocol member decl is in the same file of the stub,
3751+ // we can directly associate the fixit with the note issued to the
3752+ // requirement.
3753+ diag->fixItInsertAfter (FixitLocation, FixIt);
3754+ } else {
3755+ diag.value ().flush ();
3756+
3757+ // Otherwise, we have to issue another note to carry the fixit,
3758+ // because editor may assume the fixit is in the same file with the note.
3759+ if (Ctx.LangOpts .DiagnosticsEditorMode ) {
3760+ Diags.diagnose (ComplainLoc, diag::missing_witnesses_general)
3761+ .fixItInsertAfter (FixitLocation, FixIt);
3762+ }
3763+ }
3764+ continue ;
3765+ }
3766+
3767+ // Issue diagnostics for witness values.
3768+ Type RequirementType =
3769+ getRequirementTypeForDisplay (DC->getParentModule (), Conf, VD);
3770+ if (AddFixit) {
3771+ if (SameFile) {
3772+ // If the protocol member decl is in the same file of the stub,
3773+ // we can directly associate the fixit with the note issued to the
3774+ // requirement.
3775+ Diags
3776+ .diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3777+ VD, RequirementType, true )
3778+ .fixItInsertAfter (FixitLocation, FixIt);
3779+ } else {
3780+ // Otherwise, we have to issue another note to carry the fixit,
3781+ // because editor may assume the fixit is in the same file with the note.
3782+ Diags.diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3783+ VD, RequirementType, false );
3784+ if (Ctx.LangOpts .DiagnosticsEditorMode ) {
3785+ Diags.diagnose (ComplainLoc, diag::missing_witnesses_general)
3786+ .fixItInsertAfter (FixitLocation, FixIt);
3787+ }
3788+ }
3789+ } else {
3790+ Diags.diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3791+ VD, RequirementType, true );
3792+ }
3793+ }
3794+ }
3795+
36843796bool ConformanceChecker::
36853797diagnoseMissingWitnesses (MissingWitnessDiagnosisKind Kind, bool Delayed) {
36863798 auto LocalMissing = getLocalMissingWitness ();
@@ -3693,6 +3805,16 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind, bool Delayed) {
36933805 if (LocalMissing.empty ())
36943806 return false ;
36953807
3808+ if (Delayed) {
3809+ // If the diagnostics are suppressed, we register these missing witnesses
3810+ // for later revisiting.
3811+ for (auto Missing : LocalMissing) {
3812+ getASTContext ().addDelayedMissingWitness (Conformance, Missing);
3813+ }
3814+
3815+ return true ;
3816+ }
3817+
36963818 // Diagnose the missing witnesses.
36973819 for (auto &Missing : LocalMissing) {
36983820 auto requirement = Missing.requirement ;
@@ -3712,132 +3834,14 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind, bool Delayed) {
37123834 });
37133835 }
37143836
3715- const auto InsertFixit = [](
3716- NormalProtocolConformance *Conf, SourceLoc ComplainLoc, bool EditorMode,
3717- llvm::SmallVector<ASTContext::MissingWitness, 4 > MissingWitnesses) {
3718- DeclContext *DC = Conf->getDeclContext ();
3719- // The location where to insert stubs.
3720- SourceLoc FixitLocation;
3721-
3722- // The location where the type starts.
3723- SourceLoc TypeLoc;
3724- if (auto Extension = dyn_cast<ExtensionDecl>(DC)) {
3725- FixitLocation = Extension->getBraces ().Start ;
3726- TypeLoc = Extension->getStartLoc ();
3727- } else if (auto Nominal = dyn_cast<NominalTypeDecl>(DC)) {
3728- FixitLocation = Nominal->getBraces ().Start ;
3729- TypeLoc = Nominal->getStartLoc ();
3730- } else {
3731- llvm_unreachable (" Unknown adopter kind" );
3732- }
3733- std::string FixIt;
3734- llvm::SetVector<ValueDecl*> NoStubRequirements;
3735-
3736- // Print stubs for all known missing witnesses.
3737- printProtocolStubFixitString (TypeLoc, Conf, MissingWitnesses, FixIt,
3738- NoStubRequirements);
3739- auto &Diags = DC->getASTContext ().Diags ;
3740-
3741- // If we are in editor mode, squash all notes into a single fixit.
3742- if (EditorMode) {
3743- if (!FixIt.empty ()) {
3744- Diags.diagnose (ComplainLoc, diag::missing_witnesses_general).
3745- fixItInsertAfter (FixitLocation, FixIt);
3746- }
3747- return ;
3748- }
3749- auto &SM = DC->getASTContext ().SourceMgr ;
3750- auto FixitBufferId = SM.findBufferContainingLoc (FixitLocation);
3751- for (const auto &Missing : MissingWitnesses) {
3752- auto VD = Missing.requirement ;
3753-
3754- // Don't ever emit a diagnostic for a requirement in the NSObject
3755- // protocol. They're not implementable.
3756- if (isNSObjectProtocol (VD->getDeclContext ()->getSelfProtocolDecl ()))
3757- continue ;
3758-
3759- // Whether this VD has a stub printed.
3760- bool AddFixit = !NoStubRequirements.count (VD);
3761- bool SameFile = VD->getLoc ().isValid () ?
3762- SM.findBufferContainingLoc (VD->getLoc ()) == FixitBufferId : false ;
3763-
3764- // Issue diagnostics for witness types.
3765- if (auto MissingTypeWitness = dyn_cast<AssociatedTypeDecl>(VD)) {
3766- llvm::Optional<InFlightDiagnostic> diag;
3767- if (isa<BuiltinTupleDecl>(DC->getSelfNominalTypeDecl ())) {
3768- auto expectedTy = getTupleConformanceTypeWitness (DC, MissingTypeWitness);
3769- diag.emplace (Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type_tuple,
3770- MissingTypeWitness, expectedTy));
3771- } else {
3772- diag.emplace (Diags.diagnose (MissingTypeWitness, diag::no_witnesses_type,
3773- MissingTypeWitness));
3774- }
3775- if (SameFile) {
3776- // If the protocol member decl is in the same file of the stub,
3777- // we can directly associate the fixit with the note issued to the
3778- // requirement.
3779- diag->fixItInsertAfter (FixitLocation, FixIt);
3780- } else {
3781- diag.value ().flush ();
3782-
3783- // Otherwise, we have to issue another note to carry the fixit,
3784- // because editor may assume the fixit is in the same file with the note.
3785- if (EditorMode) {
3786- Diags.diagnose (ComplainLoc, diag::missing_witnesses_general)
3787- .fixItInsertAfter (FixitLocation, FixIt);
3788- }
3789- }
3790- continue ;
3791- }
3792-
3793- // Issue diagnostics for witness values.
3794- Type RequirementType =
3795- getRequirementTypeForDisplay (DC->getParentModule (), Conf, VD);
3796- if (AddFixit) {
3797- if (SameFile) {
3798- // If the protocol member decl is in the same file of the stub,
3799- // we can directly associate the fixit with the note issued to the
3800- // requirement.
3801- Diags
3802- .diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3803- VD, RequirementType, true )
3804- .fixItInsertAfter (FixitLocation, FixIt);
3805- } else {
3806- // Otherwise, we have to issue another note to carry the fixit,
3807- // because editor may assume the fixit is in the same file with the note.
3808- Diags.diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3809- VD, RequirementType, false );
3810- if (EditorMode) {
3811- Diags.diagnose (ComplainLoc, diag::missing_witnesses_general)
3812- .fixItInsertAfter (FixitLocation, FixIt);
3813- }
3814- }
3815- } else {
3816- Diags.diagnose (VD, diag::no_witnesses, getProtocolRequirementKind (VD),
3817- VD, RequirementType, true );
3818- }
3819- }
3820- };
3821-
3822- const bool IsEditorMode = Context.LangOpts .DiagnosticsEditorMode ;
38233837 switch (Kind) {
38243838 case MissingWitnessDiagnosisKind::ErrorFixIt: {
38253839 const auto MissingWitnesses = filterProtocolRequirements (
38263840 GlobalMissingWitnesses.getArrayRef (), Adoptee);
3827- if (Delayed) {
3828- // If the diagnostics are suppressed, we register these missing witnesses
3829- // for later revisiting.
3830- Conformance->setInvalid ();
3831- for (auto Missing : MissingWitnesses) {
3832- getASTContext ().addDelayedMissingWitness (Conformance, Missing);
3833- }
3834- } else {
3835- auto Loc = this ->Loc ;
3836- getASTContext ().addDelayedConformanceDiag (Conformance, true ,
3837- [InsertFixit, Loc, IsEditorMode, MissingWitnesses](NormalProtocolConformance *Conf) {
3838- InsertFixit (Conf, Loc, IsEditorMode, MissingWitnesses);
3839- });
3840- }
3841+ getASTContext ().addDelayedConformanceDiag (Conformance, true ,
3842+ [MissingWitnesses](NormalProtocolConformance *Conf) {
3843+ diagnoseProtocolStubFixit (Conf, MissingWitnesses);
3844+ });
38413845 clearGlobalMissingWitnesses ();
38423846 return true ;
38433847 }
@@ -3847,7 +3851,7 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind, bool Delayed) {
38473851 return true ;
38483852 }
38493853 case MissingWitnessDiagnosisKind::FixItOnly:
3850- InsertFixit (Conformance, Loc, IsEditorMode ,
3854+ diagnoseProtocolStubFixit (Conformance,
38513855 filterProtocolRequirements (GlobalMissingWitnesses.getArrayRef (),
38523856 Adoptee));
38533857 clearGlobalMissingWitnesses ();
0 commit comments