15
15
// declaration of members (such as constructors).
16
16
//
17
17
// ===----------------------------------------------------------------------===//
18
+
19
+ #include " TypeCheckAvailability.h"
18
20
#include " TypeChecker.h"
19
21
#include " TypoCorrection.h"
20
22
#include " swift/AST/ExistentialLayout.h"
@@ -755,43 +757,87 @@ TypoCorrectionResults::claimUniqueCorrection() {
755
757
return SyntacticTypoCorrection (WrittenName, Loc, uniqueCorrectedName);
756
758
}
757
759
758
- bool swift::diagnoseMissingImportForMember (const ValueDecl *decl,
759
- const DeclContext *dc,
760
- SourceLoc loc) {
761
- if (decl->findImport (dc))
762
- return false ;
760
+ struct MissingImportFixItInfo {
761
+ OptionSet<ImportFlags> flags;
762
+ std::optional<AccessLevel> accessLevel;
763
+ };
764
+
765
+ class MissingImportFixItCache {
766
+ SourceFile &sf;
767
+ llvm::DenseMap<const ModuleDecl *, MissingImportFixItInfo> infos;
768
+
769
+ public:
770
+ MissingImportFixItCache (SourceFile &sf) : sf(sf){};
771
+
772
+ MissingImportFixItInfo getInfo (const ModuleDecl *mod) {
773
+ auto existing = infos.find (mod);
774
+ if (existing != infos.end ())
775
+ return existing->getSecond ();
776
+
777
+ MissingImportFixItInfo info;
778
+
779
+ // Find imports of the defining module in other source files and aggregate
780
+ // the attributes and access level usage on those imports collectively. This
781
+ // information can be used to emit a fix-it that is consistent with
782
+ // how the module is imported in the rest of the module.
783
+ auto parentModule = sf.getParentModule ();
784
+ bool foundImport = false ;
785
+ bool anyImportHasAccessLevel = false ;
786
+ for (auto file : parentModule->getFiles ()) {
787
+ if (auto otherSF = dyn_cast<SourceFile>(file)) {
788
+ unsigned flagsInSourceFile = 0x0 ;
789
+ otherSF->forEachImportOfModule (
790
+ mod, [&](AttributedImport<ImportedModule> &import ) {
791
+ foundImport = true ;
792
+ anyImportHasAccessLevel |= import .accessLevelRange .isValid ();
793
+ flagsInSourceFile |= import .options .toRaw ();
794
+ });
795
+ info.flags |= ImportFlags (flagsInSourceFile);
796
+ }
797
+ }
763
798
764
- auto &ctx = dc->getASTContext ();
799
+ // Add an appropriate access level as long as it would not conflict with
800
+ // existing imports that lack access levels.
801
+ if (!foundImport || anyImportHasAccessLevel)
802
+ info.accessLevel = sf.getMaxAccessLevelUsingImport (mod);
803
+
804
+ infos[mod] = info;
805
+ return info;
806
+ }
807
+ };
808
+
809
+ static void diagnoseMissingImportForMember (const ValueDecl *decl,
810
+ SourceFile *sf, SourceLoc loc) {
811
+ auto &ctx = sf->getASTContext ();
765
812
auto definingModule = decl->getModuleContext ();
766
813
ctx.Diags .diagnose (loc, diag::candidate_from_missing_import,
767
814
decl->getDescriptiveKind (), decl->getName (),
768
815
definingModule);
816
+ }
817
+
818
+ static void
819
+ diagnoseAndFixMissingImportForMember (const ValueDecl *decl, SourceFile *sf,
820
+ SourceLoc loc,
821
+ MissingImportFixItCache &fixItCache) {
822
+
823
+ diagnoseMissingImportForMember (decl, sf, loc);
769
824
770
- SourceLoc bestLoc =
771
- ctx.Diags .getBestAddImportFixItLoc (decl, dc->getParentSourceFile ());
825
+ auto &ctx = sf->getASTContext ();
826
+ auto definingModule = decl->getModuleContext ();
827
+ SourceLoc bestLoc = ctx.Diags .getBestAddImportFixItLoc (decl, sf);
772
828
if (!bestLoc.isValid ())
773
- return false ;
829
+ return ;
774
830
775
831
llvm::SmallString<64 > importText;
776
832
777
- // Check other source files for import flags that should be applied to the
778
- // fix-it for consistency with the rest of the imports in the module.
779
- auto parentModule = dc->getParentModule ();
780
- OptionSet<ImportFlags> flags;
781
- for (auto file : parentModule->getFiles ()) {
782
- if (auto sf = dyn_cast<SourceFile>(file))
783
- flags |= sf->getImportFlags (definingModule);
784
- }
785
-
786
- if (flags.contains (ImportFlags::ImplementationOnly))
833
+ auto fixItInfo = fixItCache.getInfo (definingModule);
834
+ if (fixItInfo.flags .contains (ImportFlags::ImplementationOnly))
787
835
importText += " @_implementationOnly " ;
788
- if (flags.contains (ImportFlags::WeakLinked))
836
+ if (fixItInfo. flags .contains (ImportFlags::WeakLinked))
789
837
importText += " @_weakLinked " ;
790
- if (flags.contains (ImportFlags::SPIOnly))
838
+ if (fixItInfo. flags .contains (ImportFlags::SPIOnly))
791
839
importText += " @_spiOnly " ;
792
840
793
- // FIXME: Access level should be considered, too.
794
-
795
841
// @_spi imports.
796
842
if (decl->isSPI ()) {
797
843
auto spiGroups = decl->getSPIGroups ();
@@ -802,11 +848,49 @@ bool swift::diagnoseMissingImportForMember(const ValueDecl *decl,
802
848
}
803
849
}
804
850
851
+ if (auto accessLevel = fixItInfo.accessLevel ) {
852
+ importText += getAccessLevelSpelling (*accessLevel);
853
+ importText += " " ;
854
+ }
855
+
805
856
importText += " import " ;
806
857
importText += definingModule->getName ().str ();
807
858
importText += " \n " ;
808
859
ctx.Diags .diagnose (bestLoc, diag::candidate_add_import, definingModule)
809
860
.fixItInsert (bestLoc, importText);
861
+ }
810
862
811
- return true ;
863
+ bool swift::maybeDiagnoseMissingImportForMember (const ValueDecl *decl,
864
+ const DeclContext *dc,
865
+ SourceLoc loc) {
866
+ if (decl->findImport (dc))
867
+ return false ;
868
+
869
+ auto sf = dc->getParentSourceFile ();
870
+ if (!sf)
871
+ return false ;
872
+
873
+ auto &ctx = dc->getASTContext ();
874
+
875
+ // In lazy typechecking mode just emit the diagnostic immediately without a
876
+ // fix-it since there won't be an opportunity to emit delayed diagnostics.
877
+ if (ctx.TypeCheckerOpts .EnableLazyTypecheck ) {
878
+ diagnoseMissingImportForMember (decl, sf, loc);
879
+ return true ;
880
+ }
881
+
882
+ sf->addDelayedMissingImportForMemberDiagnostic (decl, loc);
883
+ return false ;
884
+ }
885
+
886
+ void swift::diagnoseMissingImports (SourceFile &sf) {
887
+ auto delayedDiags = sf.takeDelayedMissingImportForMemberDiagnostics ();
888
+ auto fixItCache = MissingImportFixItCache (sf);
889
+
890
+ for (auto declAndLocs : delayedDiags) {
891
+ for (auto loc : declAndLocs.second ) {
892
+ diagnoseAndFixMissingImportForMember (declAndLocs.first , &sf, loc,
893
+ fixItCache);
894
+ }
895
+ }
812
896
}
0 commit comments