21
21
#include " TypoCorrection.h"
22
22
#include " swift/AST/ConformanceLookup.h"
23
23
#include " swift/AST/ExistentialLayout.h"
24
+ #include " swift/AST/ImportCache.h"
24
25
#include " swift/AST/Initializer.h"
25
26
#include " swift/AST/NameLookup.h"
26
27
#include " swift/AST/NameLookupRequests.h"
@@ -798,7 +799,50 @@ TypoCorrectionResults::claimUniqueCorrection() {
798
799
return SyntacticTypoCorrection (WrittenName, Loc, uniqueCorrectedName);
799
800
}
800
801
802
+ // / Returns a sorted vector of modules that are not imported in the given
803
+ // / `SourceFile` and must be in order to make declarations from \p owningModule
804
+ // / visible.
805
+ static SmallVector<ModuleDecl *, 2 >
806
+ missingImportsForDefiningModule (ModuleDecl *owningModule, SourceFile &sf) {
807
+ SmallVector<ModuleDecl *, 2 > result;
808
+ auto &ctx = sf.getASTContext ();
809
+
810
+ if (auto *declaringModule =
811
+ owningModule->getDeclaringModuleIfCrossImportOverlay ()) {
812
+ // If the module that owns the declaration is a cross import overlay the
813
+ // fix-its should suggest importing the declaring and bystanding modules,
814
+ // not the overlay module.
815
+ result.push_back (declaringModule);
816
+
817
+ SmallVector<Identifier, 2 > bystanders;
818
+ if (owningModule->getRequiredBystandersIfCrossImportOverlay (declaringModule,
819
+ bystanders)) {
820
+ for (auto bystander : bystanders) {
821
+ if (auto bystanderModule = ctx.getModuleByIdentifier (bystander))
822
+ result.push_back (bystanderModule);
823
+ }
824
+ }
825
+
826
+ // Remove the modules that are already imported by the source file.
827
+ auto &importCache = ctx.getImportCache ();
828
+ const DeclContext *dc = &sf;
829
+ llvm::erase_if (result, [&](ModuleDecl *candidate) {
830
+ return importCache.isImportedBy (candidate, dc);
831
+ });
832
+ } else {
833
+ // Just the module that owns the declaration is required.
834
+ result.push_back (owningModule);
835
+ }
836
+
837
+ std::sort (result.begin (), result.end (), [](ModuleDecl *LHS, ModuleDecl *RHS) {
838
+ return LHS->getNameStr () < LHS->getNameStr ();
839
+ });
840
+
841
+ return result;
842
+ }
843
+
801
844
struct MissingImportFixItInfo {
845
+ const ModuleDecl *moduleToImport = nullptr ;
802
846
OptionSet<ImportFlags> flags;
803
847
std::optional<AccessLevel> accessLevel;
804
848
};
@@ -807,15 +851,13 @@ class MissingImportFixItCache {
807
851
SourceFile &sf;
808
852
llvm::DenseMap<const ModuleDecl *, MissingImportFixItInfo> infos;
809
853
810
- public:
811
- MissingImportFixItCache (SourceFile &sf) : sf(sf){};
812
-
813
- MissingImportFixItInfo getInfo (const ModuleDecl *mod) {
854
+ MissingImportFixItInfo getFixItInfo (ModuleDecl *mod) {
814
855
auto existing = infos.find (mod);
815
856
if (existing != infos.end ())
816
857
return existing->getSecond ();
817
858
818
859
MissingImportFixItInfo info;
860
+ info.moduleToImport = mod;
819
861
820
862
// Find imports of the defining module in other source files and aggregate
821
863
// the attributes and access level usage on those imports collectively. This
@@ -845,33 +887,49 @@ class MissingImportFixItCache {
845
887
infos[mod] = info;
846
888
return info;
847
889
}
848
- };
849
890
850
- static void diagnoseMissingImportForMember (const ValueDecl *decl,
851
- SourceFile *sf, SourceLoc loc) {
852
- auto &ctx = sf->getASTContext ();
853
- auto definingModule = decl->getModuleContextForNameLookup ();
854
- ctx.Diags .diagnose (loc, diag::candidate_from_missing_import, decl,
855
- definingModule);
856
- }
891
+ public:
892
+ MissingImportFixItCache (SourceFile &sf) : sf(sf) {};
857
893
858
- static void
859
- diagnoseAndFixMissingImportForMember (const ValueDecl *decl, SourceFile *sf,
860
- SourceLoc loc,
861
- MissingImportFixItCache &fixItCache) {
894
+ std::pair<SmallVector<ModuleDecl *, 2 >,
895
+ SmallVector<MissingImportFixItInfo, 2 >>
896
+ getModulesAndFixIts (ModuleDecl *mod) {
897
+ auto modulesToImport = missingImportsForDefiningModule (mod, sf);
898
+ SmallVector<MissingImportFixItInfo, 2 > fixItInfos;
862
899
863
- diagnoseMissingImportForMember (decl, sf, loc);
900
+ for (auto *mod : modulesToImport) {
901
+ fixItInfos.emplace_back (getFixItInfo (mod));
902
+ }
864
903
904
+ return {modulesToImport, fixItInfos};
905
+ }
906
+ };
907
+
908
+ static void
909
+ diagnoseMissingImportsForMember (const ValueDecl *decl,
910
+ SmallVectorImpl<ModuleDecl *> &modulesToImport,
911
+ SourceFile *sf, SourceLoc loc) {
865
912
auto &ctx = sf->getASTContext ();
866
- auto definingModule = decl->getModuleContextForNameLookup ();
867
- SourceLoc bestLoc = ctx.Diags .getBestAddImportFixItLoc (decl, sf);
868
- if (!bestLoc.isValid ())
869
- return ;
913
+ auto count = modulesToImport.size ();
914
+ ASSERT (count > 0 );
915
+
916
+ if (count > 1 ) {
917
+ ctx.Diags .diagnose (loc, diag::candidate_from_missing_imports_2_or_more,
918
+ decl, bool (count > 2 ), modulesToImport[0 ],
919
+ modulesToImport[1 ]);
920
+ } else {
921
+ ctx.Diags .diagnose (loc, diag::candidate_from_missing_import, decl,
922
+ modulesToImport.front ());
923
+ }
924
+ }
870
925
926
+ static void emitMissingImportFixIt (SourceLoc loc,
927
+ const MissingImportFixItInfo &fixItInfo,
928
+ const ValueDecl *decl) {
929
+ ASTContext &ctx = decl->getASTContext ();
871
930
llvm::SmallString<64 > importText;
872
931
873
932
// Add flags that must be used consistently on every import in every file.
874
- auto fixItInfo = fixItCache.getInfo (definingModule);
875
933
if (fixItInfo.flags .contains (ImportFlags::ImplementationOnly))
876
934
importText += " @_implementationOnly " ;
877
935
if (fixItInfo.flags .contains (ImportFlags::WeakLinked))
@@ -905,10 +963,36 @@ diagnoseAndFixMissingImportForMember(const ValueDecl *decl, SourceFile *sf,
905
963
}
906
964
907
965
importText += " import " ;
908
- importText += definingModule ->getName ().str ();
966
+ importText += fixItInfo. moduleToImport ->getName ().str ();
909
967
importText += " \n " ;
910
- ctx.Diags .diagnose (bestLoc, diag::candidate_add_import, definingModule)
911
- .fixItInsert (bestLoc, importText);
968
+ ctx.Diags
969
+ .diagnose (loc, diag::candidate_add_import, fixItInfo.moduleToImport )
970
+ .fixItInsert (loc, importText);
971
+ }
972
+
973
+ static void
974
+ diagnoseAndFixMissingImportForMember (const ValueDecl *decl, SourceFile *sf,
975
+ SourceLoc loc,
976
+ MissingImportFixItCache &fixItCache) {
977
+
978
+ auto modulesAndFixits =
979
+ fixItCache.getModulesAndFixIts (decl->getModuleContextForNameLookup ());
980
+ auto modulesToImport = modulesAndFixits.first ;
981
+ auto fixItInfos = modulesAndFixits.second ;
982
+
983
+ if (modulesToImport.empty ())
984
+ return ;
985
+
986
+ diagnoseMissingImportsForMember (decl, modulesToImport, sf, loc);
987
+
988
+ auto &ctx = sf->getASTContext ();
989
+ SourceLoc bestLoc = ctx.Diags .getBestAddImportFixItLoc (decl, sf);
990
+ if (!bestLoc.isValid ())
991
+ return ;
992
+
993
+ for (auto &fixItInfo : fixItInfos) {
994
+ emitMissingImportFixIt (bestLoc, fixItInfo, decl);
995
+ }
912
996
}
913
997
914
998
bool swift::maybeDiagnoseMissingImportForMember (const ValueDecl *decl,
@@ -917,12 +1001,13 @@ bool swift::maybeDiagnoseMissingImportForMember(const ValueDecl *decl,
917
1001
if (dc->isDeclImported (decl))
918
1002
return false ;
919
1003
1004
+ auto definingModule = decl->getModuleContextForNameLookup ();
920
1005
if (dc->getASTContext ().LangOpts .EnableCXXInterop ) {
921
1006
// With Cxx interop enabled, there are some declarations that always belong
922
1007
// to the Clang header import module which should always be implicitly
923
1008
// visible. However, that module is not implicitly imported in source files
924
1009
// so we need to special case it here and avoid diagnosing.
925
- if (decl-> getModuleContextForNameLookup () ->isClangHeaderImportModule ())
1010
+ if (definingModule ->isClangHeaderImportModule ())
926
1011
return false ;
927
1012
}
928
1013
@@ -935,7 +1020,11 @@ bool swift::maybeDiagnoseMissingImportForMember(const ValueDecl *decl,
935
1020
// In lazy typechecking mode just emit the diagnostic immediately without a
936
1021
// fix-it since there won't be an opportunity to emit delayed diagnostics.
937
1022
if (ctx.TypeCheckerOpts .EnableLazyTypecheck ) {
938
- diagnoseMissingImportForMember (decl, sf, loc);
1023
+ auto modulesToImport = missingImportsForDefiningModule (definingModule, *sf);
1024
+ if (modulesToImport.empty ())
1025
+ return false ;
1026
+
1027
+ diagnoseMissingImportsForMember (decl, modulesToImport, sf, loc);
939
1028
return true ;
940
1029
}
941
1030
0 commit comments