]> granicus.if.org Git - clang/commitdiff
Initial implementation of -modules-earch-all option, for searching for symbols in...
authorJohn Thompson <John.Thompson.JTSoftware@gmail.com>
Wed, 23 Apr 2014 12:57:01 +0000 (12:57 +0000)
committerJohn Thompson <John.Thompson.JTSoftware@gmail.com>
Wed, 23 Apr 2014 12:57:01 +0000 (12:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206977 91177308-0d34-0410-b5e6-96231b3b80d8

34 files changed:
docs/Modules.rst
include/clang/Basic/LangOptions.def
include/clang/Driver/Options.td
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Lex/HeaderSearch.h
include/clang/Lex/ModuleLoader.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTReader.h
lib/Frontend/CompilerInstance.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaOpenMP.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateVariadic.cpp
test/Modules/Inputs/undefined-type-fixit/module.map [new file with mode: 0644]
test/Modules/Inputs/undefined-type-fixit/public1.h [new file with mode: 0644]
test/Modules/Inputs/undefined-type-fixit/public2.h [new file with mode: 0644]
test/Modules/Inputs/undefined-type-fixit/public2sub.h [new file with mode: 0644]
test/Modules/undefined-type-fixit1.cpp [new file with mode: 0644]
unittests/Basic/SourceManagerTest.cpp
unittests/Lex/CMakeLists.txt
unittests/Lex/LexerTest.cpp
unittests/Lex/Makefile
unittests/Lex/PPCallbacksTest.cpp
unittests/Lex/PPConditionalDirectiveRecordTest.cpp

index 59daebcc9361fb678d1058f15c3284549a3711c1..ce1e717bc2a0583e36c9678b459dc668651e87c6 100644 (file)
@@ -198,6 +198,9 @@ Command-line parameters
 ``-fmodule-map-file=<file>``
   Load the given module map file if a header from its directory or one of its subdirectories is loaded.
 
+``-fmodules-search-all``
+  If a symbol is not found, search modules referenced in the current module maps but not imported for symbols, so the error message can reference the module by name.  Note that if the global module index has not been built before, this might take some time as it needs to build all the modules.  Note that this option doesn't apply in module builds, to avoid the recursion.
+
 Module Semantics
 ================
 
index 3295ca4a2786ada79c67c91ff056bbb6e13cb0ef..699bf1fa4d3a71ccaaeb0d484718ad7fe4641fef 100644 (file)
@@ -96,6 +96,7 @@ LANGOPT(MathErrno         , 1, 1, "errno support for math functions")
 BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
 LANGOPT(Modules           , 1, 0, "modules extension to C")
 LANGOPT(ModulesDeclUse    , 1, 0, "require declaration of module uses")
+LANGOPT(ModulesSearchAll  , 1, 1, "search even non-imported modules to find unresolved references")
 LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules")
 LANGOPT(Optimize          , 1, 0, "__OPTIMIZE__ predefined macro")
 LANGOPT(OptimizeSize      , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
index b734280a8911a72ec7e1c29e524e879fec1899d2..d6b22795e0eaca7e0df2a6e0b92719acfaadded9 100644 (file)
@@ -583,6 +583,9 @@ def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i
 def fmodules_prune_after : Joined<["-"], "fmodules-prune-after=">, Group<i_Group>,
   Flags<[CC1Option]>, MetaVarName<"<seconds>">,
   HelpText<"Specify the interval (in seconds) after which a module file will be considered unused">;
+def fmodules_search_all : Flag <["-"], "fmodules-search-all">, Group<f_Group>,
+  Flags<[DriverOption, CC1Option]>,
+  HelpText<"Search even non-imported modules to resolve references">;
 def fbuild_session_timestamp : Joined<["-"], "fbuild-session-timestamp=">,
   Group<i_Group>, Flags<[CC1Option]>, MetaVarName<"<time since Epoch in seconds>">,
   HelpText<"Time when the current build session started">;
@@ -613,6 +616,8 @@ def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
 def fmodules_strict_decluse : Flag <["-"], "fmodules-strict-decluse">, Group<f_Group>,
   Flags<[DriverOption,CC1Option]>,
   HelpText<"Like -fmodules-decluse but requires all headers to be in modules">;
+def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>,
+  Flags<[DriverOption, CC1Option]>;
 def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
 
 def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
index ceabaa75e9b2e354b52775ed73a298c3f337284b..666e5dd7c72dad1cee6ae6572484de7e2adb527a 100644 (file)
@@ -874,6 +874,8 @@ public:
   void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
                          SourceLocation ImportLoc, bool Complain) override {}
 
+  GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
+    { return 0; }
 };
 
 } // namespace clang
index ee97d9bec3ffa8c05cf95355b2091b6262853cad..1a89a8a156fa29ec167ce95fe2d0dded15489fd9 100644 (file)
@@ -124,6 +124,9 @@ class CompilerInstance : public ModuleLoader {
   /// have finished with this translation unit.
   bool BuildGlobalModuleIndex;
 
+  /// \brief We have a full global module index, with all modules.
+  bool HaveFullGlobalModuleIndex;
+
   /// \brief One or more modules failed to build.
   bool ModuleBuildFailed;
 
@@ -148,7 +151,7 @@ class CompilerInstance : public ModuleLoader {
   CompilerInstance(const CompilerInstance &) LLVM_DELETED_FUNCTION;
   void operator=(const CompilerInstance &) LLVM_DELETED_FUNCTION;
 public:
-  CompilerInstance();
+  explicit CompilerInstance(bool BuildingModule = false);
   ~CompilerInstance();
 
   /// @name High-Level Operations
@@ -683,6 +686,9 @@ public:
 
   /// }
 
+  // Create module manager.
+  void createModuleManager();
+
   ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
                               Module::NameVisibilityKind Visibility,
                               bool IsInclusionDirective) override;
@@ -694,6 +700,7 @@ public:
     return ModuleLoader::HadFatalFailure;
   }
 
+  GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc);
 };
 
 } // end namespace clang
index 507ede583f4642b60110699a97f01aa6cb3914c8..a62a710d788b056e48c27e11f43bcde6e2a091fe 100644 (file)
@@ -511,7 +511,6 @@ public:
   /// \returns The module with the given name.
   Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
 
-
   /// \brief Try to find a module map file in the given directory, returning
   /// \c nullptr if none is found.
   const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir,
index 254ab36fe9607f0a7892c19ac675f2a516b9519d..0a690812a92059ccd790d121408113e5d1479977 100644 (file)
@@ -21,6 +21,7 @@
 
 namespace clang {
 
+class GlobalModuleIndex;
 class IdentifierInfo;
 class Module;
 
@@ -53,11 +54,24 @@ public:
 /// for resolving a module name (e.g., "std") to an actual module file, and
 /// then loading that module.
 class ModuleLoader {
+  // Building a module if true.
+  bool BuildingModule;
 public:
-  ModuleLoader() : HadFatalFailure(false) {}
+  explicit ModuleLoader(bool BuildingModule = false) :
+    BuildingModule(BuildingModule),
+    HadFatalFailure(false) {}
 
   virtual ~ModuleLoader();
   
+  /// \brief Returns true if this instance is building a module.
+  bool buildingModule() const {
+    return BuildingModule;
+  }
+  /// \brief Flag indicating whether this instance is building a module.
+  void setBuildingModule(bool BuildingModuleFlag) {
+    BuildingModule = BuildingModuleFlag;
+  }
   /// \brief Attempt to load the given module.
   ///
   /// This routine attempts to load the module described by the given 
@@ -88,6 +102,19 @@ public:
                                  SourceLocation ImportLoc,
                                  bool Complain) = 0;
 
+  /// \brief Load, create, or return global module.
+  /// This function returns an existing global module index, if one
+  /// had already been loaded or created, or loads one if it
+  /// exists, or creates one if it doesn't exist.
+  /// Also, importantly, if the index doesn't cover all the modules
+  /// in the module map, it will be update to do so here, because
+  /// of its use in searching for needed module imports and
+  /// associated fixit messages.
+  /// \param TriggerLoc The location for what triggered the load.
+  /// \returns Returns null if load failed.
+  virtual GlobalModuleIndex *loadGlobalModuleIndex(
+                                            SourceLocation TriggerLoc) = 0;
+
   bool HadFatalFailure;
 };
   
index fc6c42265a448016721893ad9b9adf8f1d0f39cc..4d4fd360a360a68638535d290bc810f2ad936e08 100644 (file)
@@ -2601,10 +2601,16 @@ public:
                           VisibleDeclConsumer &Consumer,
                           bool IncludeGlobalScope = true);
 
+  enum CorrectTypoKind {
+    CTK_NonError,     // CorrectTypo used in a non error recovery situation.
+    CTK_ErrorRecovery // CorrectTypo used in normal error recovery.
+  };
+
   TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
                              Sema::LookupNameKind LookupKind,
                              Scope *S, CXXScopeSpec *SS,
                              CorrectionCandidateCallback &CCC,
+                             CorrectTypoKind Mode,
                              DeclContext *MemberContext = 0,
                              bool EnteringContext = false,
                              const ObjCObjectPointerType *OPT = 0,
index 881d24b22e000f5568ab27f423784a1ae82ad1ee..ccf3822d6975cd083177e877519b8296034067ca 100644 (file)
@@ -1384,8 +1384,15 @@ public:
   /// \brief Determine whether this AST reader has a global index.
   bool hasGlobalIndex() const { return (bool)GlobalIndex; }
 
+  /// \brief Return global module index.
+  GlobalModuleIndex *getGlobalIndex() { return GlobalIndex.get(); }
+
+  /// \brief Reset reader for a reload try.
+  void resetForReload() { TriedLoadingGlobalIndex = false; }
+
   /// \brief Attempts to load the global index.
   ///
+  /// \param TriggerLoc The location for what triggered the load.
   /// \returns true if loading the global index has failed for any reason.
   bool loadGlobalIndex();
 
index 267d318fa9874c337adb8a9f2b4efcdc23541b0a..f06633ca51106c8194581b3eecc5ae6c8e8b850d 100644 (file)
@@ -31,6 +31,7 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/CrashRecoveryContext.h"
 
 using namespace clang;
 
-CompilerInstance::CompilerInstance()
-  : Invocation(new CompilerInvocation()), ModuleManager(0),
-    BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
+CompilerInstance::CompilerInstance(bool BuildingModule)
+  : ModuleLoader(BuildingModule),
+    Invocation(new CompilerInvocation()), ModuleManager(0),
+    BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
+    ModuleBuildFailed(false) {
 }
 
 CompilerInstance::~CompilerInstance() {
@@ -830,7 +833,7 @@ static void compileModuleImpl(CompilerInstance &ImportingInstance,
   
   // Construct a compiler instance that will be used to actually create the
   // module.
-  CompilerInstance Instance;
+  CompilerInstance Instance(/*BuildingModule=*/true);
   Instance.setInvocation(&*Invocation);
 
   Instance.createDiagnostics(new ForwardingDiagnosticConsumer(
@@ -1097,6 +1100,43 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
   }
 }
 
+void CompilerInstance::createModuleManager() {
+  if (!ModuleManager) {
+    if (!hasASTContext())
+      createASTContext();
+
+    // If we're not recursively building a module, check whether we
+    // need to prune the module cache.
+    if (getSourceManager().getModuleBuildStack().empty() &&
+        getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
+        getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
+      pruneModuleCache(getHeaderSearchOpts());
+    }
+
+    HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
+    std::string Sysroot = HSOpts.Sysroot;
+    const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+    ModuleManager = new ASTReader(getPreprocessor(), *Context,
+                                  Sysroot.empty() ? "" : Sysroot.c_str(),
+                                  PPOpts.DisablePCHValidation,
+                                  /*AllowASTWithCompilerErrors=*/false,
+                                  /*AllowConfigurationMismatch=*/false,
+                                  HSOpts.ModulesValidateSystemHeaders,
+                                  getFrontendOpts().UseGlobalModuleIndex);
+    if (hasASTConsumer()) {
+      ModuleManager->setDeserializationListener(
+        getASTConsumer().GetASTDeserializationListener());
+      getASTContext().setASTMutationListener(
+        getASTConsumer().GetASTMutationListener());
+    }
+    getASTContext().setExternalSource(ModuleManager);
+    if (hasSema())
+      ModuleManager->InitializeSema(getSema());
+    if (hasASTConsumer())
+      ModuleManager->StartTranslationUnit(&getASTConsumer());
+  }
+}
+
 ModuleLoadResult
 CompilerInstance::loadModule(SourceLocation ImportLoc,
                              ModuleIdPath Path,
@@ -1143,40 +1183,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
     std::string ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
 
     // If we don't already have an ASTReader, create one now.
-    if (!ModuleManager) {
-      if (!hasASTContext())
-        createASTContext();
-
-      // If we're not recursively building a module, check whether we
-      // need to prune the module cache.
-      if (getSourceManager().getModuleBuildStack().empty() &&
-          getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
-          getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
-        pruneModuleCache(getHeaderSearchOpts());
-      }
-
-      HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
-      std::string Sysroot = HSOpts.Sysroot;
-      const PreprocessorOptions &PPOpts = getPreprocessorOpts();
-      ModuleManager = new ASTReader(getPreprocessor(), *Context,
-                                    Sysroot.empty() ? "" : Sysroot.c_str(),
-                                    PPOpts.DisablePCHValidation,
-                                    /*AllowASTWithCompilerErrors=*/false,
-                                    /*AllowConfigurationMismatch=*/false,
-                                    HSOpts.ModulesValidateSystemHeaders,
-                                    getFrontendOpts().UseGlobalModuleIndex);
-      if (hasASTConsumer()) {
-        ModuleManager->setDeserializationListener(
-          getASTConsumer().GetASTDeserializationListener());
-        getASTContext().setASTMutationListener(
-          getASTConsumer().GetASTMutationListener());
-      }
-      getASTContext().setExternalSource(ModuleManager);
-      if (hasSema())
-        ModuleManager->InitializeSema(getSema());
-      if (hasASTConsumer())
-        ModuleManager->StartTranslationUnit(&getASTConsumer());
-    }
+    if (!ModuleManager)
+      createModuleManager();
 
     if (TheDependencyFileGenerator)
       TheDependencyFileGenerator->AttachToASTReader(*ModuleManager);
@@ -1403,3 +1411,58 @@ void CompilerInstance::makeModuleVisible(Module *Mod,
   ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
 }
 
+GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
+    SourceLocation TriggerLoc) {
+  if (!ModuleManager)
+    createModuleManager();
+  // Can't do anything if we don't have the module manager.
+  if (!ModuleManager)
+    return 0;
+  // Get an existing global index.  This loads it if not already
+  // loaded.
+  ModuleManager->loadGlobalIndex();
+  GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex();
+  // If the global index doesn't exist, create it.
+  if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() &&
+      hasPreprocessor()) {
+    llvm::sys::fs::create_directories(
+      getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+    GlobalModuleIndex::writeIndex(
+      getFileManager(),
+      getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+    ModuleManager->resetForReload();
+    ModuleManager->loadGlobalIndex();
+    GlobalIndex = ModuleManager->getGlobalIndex();
+  }
+  // For finding modules needing to be imported for fixit messages,
+  // we need to make the global index cover all modules, so we do that here.
+  if (!HaveFullGlobalModuleIndex && GlobalIndex && !buildingModule()) {
+    ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap();
+    bool RecreateIndex = false;
+    for (ModuleMap::module_iterator I = MMap.module_begin(),
+        E = MMap.module_end(); I != E; ++I) {
+      Module *TheModule = I->second;
+      const FileEntry *Entry = TheModule->getASTFile();
+      if (!Entry) {
+        SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+        Path.push_back(std::make_pair(
+                                 getPreprocessor().getIdentifierInfo(TheModule->Name), TriggerLoc));
+        std::reverse(Path.begin(), Path.end());
+                   // Load a module as hidden.  This also adds it to the global index.
+        ModuleLoadResult Result = loadModule(TheModule->DefinitionLoc, Path,
+                                             Module::Hidden, false);
+        RecreateIndex = true;
+      }
+    }
+    if (RecreateIndex) {
+      GlobalModuleIndex::writeIndex(
+        getFileManager(),
+        getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+      ModuleManager->resetForReload();
+      ModuleManager->loadGlobalIndex();
+      GlobalIndex = ModuleManager->getGlobalIndex();
+    }
+    HaveFullGlobalModuleIndex = true;
+  }
+  return GlobalIndex;
+}
index e51d2cf85290306f3d3779b81ded74d4acf89861..d10edd81eab6b77c43d11f0031011cedf1004171 100644 (file)
@@ -1357,6 +1357,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
   Opts.ModulesDeclUse =
       Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
+  Opts.ModulesSearchAll = Opts.Modules &&
+    !Args.hasArg(OPT_fno_modules_search_all) &&
+    Args.hasArg(OPT_fmodules_search_all);
   Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
   Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
   Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false);
index 7d038f72e9adb2afd403701a8cddc2a3b978effe..707d1b2e810756171461b93239b3ccb4877fa79a 100644 (file)
@@ -547,7 +547,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
     Found.clear();
     if (TypoCorrection Corrected =
             CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
-                        &SS, Validator, LookupCtx, EnteringContext)) {
+                        &SS, Validator, CTK_ErrorRecovery, LookupCtx,
+                        EnteringContext)) {
       if (LookupCtx) {
         bool DroppedSpecifier =
             Corrected.WillReplaceSpecifier() &&
index 50462b792733e32dfd2f747ebbefb8406ee2bef6..7603e2c2541e598643d38cc202d5ca966d56ee89 100644 (file)
@@ -218,7 +218,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
     if (CorrectedII) {
       TypeNameValidatorCCC Validator(true, isClassName);
       TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
-                                              Kind, S, SS, Validator);
+                                              Kind, S, SS, Validator,
+                                              CTK_ErrorRecovery);
       IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
       TemplateTy Template;
       bool MemberOfUnknownSpecialization;
@@ -408,7 +409,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
   TypeNameValidatorCCC Validator(false, false, AllowClassTemplates);
   if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
                                              LookupOrdinaryName, S, SS,
-                                             Validator)) {
+                                             Validator, CTK_ErrorRecovery)) {
     if (Corrected.isKeyword()) {
       // We corrected to a keyword.
       diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
@@ -650,7 +651,8 @@ Corrected:
       SecondTry = true;
       if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
                                                  Result.getLookupKind(), S, 
-                                                 &SS, *CCC)) {
+                                                 &SS, *CCC,
+                                                 CTK_ErrorRecovery)) {
         unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
         unsigned QualifiedDiag = diag::err_no_member_suggest;
 
@@ -1422,7 +1424,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
     DeclFilterCCC<ObjCInterfaceDecl> Validator;
     if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
                                        LookupOrdinaryName, TUScope, NULL,
-                                       Validator)) {
+                                       Validator, CTK_ErrorRecovery)) {
       diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
       IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
       Id = IDecl->getIdentifier();
@@ -6160,7 +6162,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
   } else if ((Correction = SemaRef.CorrectTypo(
                  Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
                  &ExtraArgs.D.getCXXScopeSpec(), Validator,
-                 IsLocalFriend ? 0 : NewDC))) {
+                 Sema::CTK_ErrorRecovery, IsLocalFriend ? 0 : NewDC))) {
     // Set up everything for the call to ActOnFunctionDeclarator
     ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
                               ExtraArgs.D.getIdentifierLoc());
@@ -10100,7 +10102,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
     TypoCorrection Corrected;
     DeclFilterCCC<FunctionDecl> Validator;
     if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
-                                      LookupOrdinaryName, S, 0, Validator)))
+                                      LookupOrdinaryName, S, 0, Validator,
+                                      CTK_NonError)))
       diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
                    /*ErrorRecovery*/false);
   }
index 197518f99efcd2d898e75cccd8648963cce76963..e3bedf78e6ee21fe961348d0a4c46c983f1c53ef 100644 (file)
@@ -2605,7 +2605,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
       MemInitializerValidatorCCC Validator(ClassDecl);
       if (R.empty() && BaseType.isNull() &&
           (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
-                              Validator, ClassDecl))) {
+                              Validator, CTK_ErrorRecovery, ClassDecl))) {
         if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
           // We have found a non-static data member with a similar
           // name to what was typed; complain and initialize that
@@ -6900,7 +6900,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
   R.clear();
   if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
                                                R.getLookupKind(), Sc, &SS,
-                                               Validator)) {
+                                               Validator,
+                                               Sema::CTK_ErrorRecovery)) {
     if (DeclContext *DC = S.computeDeclContext(SS, false)) {
       std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
       bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
@@ -7471,7 +7472,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
     UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
                           CurContext->isRecord());
     if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
-                                               R.getLookupKind(), S, &SS, CCC)){
+                                               R.getLookupKind(), S, &SS, CCC,
+                                               CTK_ErrorRecovery)){
       // We reject any correction for which ND would be NULL.
       NamedDecl *ND = Corrected.getCorrectionDecl();
       R.setLookupName(Corrected.getCorrection());
index d59dd8b9950addbabe24a0139590b84d0469c0f4..7fbca6aadb3863a0c568ad29d1b700b13d252df2 100644 (file)
@@ -524,7 +524,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
       ObjCInterfaceValidatorCCC Validator(IDecl);
       if (TypoCorrection Corrected = CorrectTypo(
           DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
-          NULL, Validator)) {
+          NULL, Validator, CTK_ErrorRecovery)) {
         diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
                                     << SuperName << ClassName);
         PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
@@ -794,7 +794,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
       DeclFilterCCC<ObjCProtocolDecl> Validator;
       TypoCorrection Corrected = CorrectTypo(
           DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
-          LookupObjCProtocolName, TUScope, NULL, Validator);
+          LookupObjCProtocolName, TUScope, NULL, Validator, CTK_ErrorRecovery);
       if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
         diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
                                     << ProtocolId[i].first);
@@ -1034,7 +1034,8 @@ Decl *Sema::ActOnStartClassImplementation(
     ObjCInterfaceValidatorCCC Validator;
     TypoCorrection Corrected =
             CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
-                        LookupOrdinaryName, TUScope, NULL, Validator);
+                        LookupOrdinaryName, TUScope, NULL, Validator,
+                        CTK_NonError);
     if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
       // Suggest the (potentially) correct interface name. Don't provide a
       // code-modification hint or use the typo name for recovery, because
index a38c7c1ef85cac5a629a3ac29615a142613ea648..1c6cfb8484e6947bfa3136fd2cf8611823ced556 100644 (file)
@@ -1843,7 +1843,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
   // We didn't find anything, so try to correct for a typo.
   TypoCorrection Corrected;
   if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
-                                    S, &SS, CCC))) {
+                                    S, &SS, CCC, CTK_ErrorRecovery))) {
     std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
     bool DroppedSpecifier =
         Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -4004,7 +4004,8 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
 
   if (TypoCorrection Corrected = S.CorrectTypo(
           DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
-          S.getScopeForContext(S.CurContext), NULL, CCC)) {
+          S.getScopeForContext(S.CurContext), NULL, CCC,
+          Sema::CTK_ErrorRecovery)) {
     if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
       if (Corrected.isOverloaded()) {
         OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
index 675c69fa88f5678fc220e5e095684d07e42c4c7a..95e3668f332ce3af12f4cc1d9ced09e2624b737f 100644 (file)
@@ -627,7 +627,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   RecordMemberExprValidatorCCC Validator(RTy);
   TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
                                                  R.getLookupKind(), NULL,
-                                                 &SS, Validator, DC);
+                                                 &SS, Validator,
+                                                 Sema::CTK_ErrorRecovery, DC);
   R.clear();
   if (Corrected.isResolved() && !Corrected.isKeyword()) {
     R.setLookupName(Corrected.getCorrection());
@@ -1270,7 +1271,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
       Validator.IsObjCIvarLookup = IsArrow;
       if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
                                                  LookupMemberName, NULL, NULL,
-                                                 Validator, IDecl)) {
+                                                 Validator, CTK_ErrorRecovery,
+                                                 IDecl)) {
         IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
         diagnoseTypo(Corrected,
                      PDiag(diag::err_typecheck_member_reference_ivar_suggest)
index d316c13f941598c9aae77526ab17a823fb814a60..7b0db1cfc1259c3864e5e6335265a77dc22eccab 100644 (file)
@@ -1669,7 +1669,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
   DeclFilterCCC<ObjCPropertyDecl> Validator;
   if (TypoCorrection Corrected = CorrectTypo(
           DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
-          NULL, Validator, IFace, false, OPT)) {
+          NULL, Validator, CTK_ErrorRecovery, IFace, false, OPT)) {
     diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
                               << MemberName << QualType(OPT, 0));
     DeclarationName TypoResult = Corrected.getCorrection();
@@ -1901,7 +1901,8 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
   ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
   if (TypoCorrection Corrected =
           CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
-                      NULL, Validator, NULL, false, NULL, false)) {
+                      NULL, Validator, CTK_ErrorRecovery, NULL, false, NULL,
+                      false)) {
     if (Corrected.isKeyword()) {
       // If we've found the keyword "super" (the only keyword that would be
       // returned by CorrectTypo), this is a send to super.
index 9c90ac0d9afd73906a632624f61f24cd4ccf328d..2cf559858111839a8366347a75eb60c0b8fbefa2 100644 (file)
@@ -1816,7 +1816,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
         if (TypoCorrection Corrected = SemaRef.CorrectTypo(
                 DeclarationNameInfo(FieldName, D->getFieldLoc()),
                 Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator,
-                RT->getDecl())) {
+                Sema::CTK_ErrorRecovery, RT->getDecl())) {
           SemaRef.diagnoseTypo(
               Corrected,
               SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
index 779d2d48e70bf3ff136f14f3e0974662969534f8..c0d49a7dd94a9b165e7c172b49bb869d329d6330 100644 (file)
@@ -23,6 +23,9 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/Sema/Overload.h"
@@ -32,6 +35,8 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/TypoCorrection.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/Module.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -3924,6 +3929,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
                                  Sema::LookupNameKind LookupKind,
                                  Scope *S, CXXScopeSpec *SS,
                                  CorrectionCandidateCallback &CCC,
+                                 CorrectTypoKind Mode,
                                  DeclContext *MemberContext,
                                  bool EnteringContext,
                                  const ObjCObjectPointerType *OPT,
@@ -3978,10 +3984,36 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
   if (getLangOpts().AltiVec && Typo->isStr("vector"))
     return TypoCorrection();
 
-  NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
-
   TypoCorrectionConsumer Consumer(*this, Typo);
 
+  // Get the module loader (usually compiler instance).
+  ModuleLoader &Loader = PP.getModuleLoader();
+
+  // Look for the symbol in non-imported modules, but only if an error
+  // actually occurred.
+  if ((Mode == CTK_ErrorRecovery) && !Loader.buildingModule() &&
+      getLangOpts().Modules && getLangOpts().ModulesSearchAll) {
+    // Load global module index, or retrieve a previously loaded one.
+    GlobalModuleIndex *GlobalIndex = Loader.loadGlobalModuleIndex(
+      TypoName.getLocStart());
+
+    // Only if we have a global index.
+    if (GlobalIndex) {
+      GlobalModuleIndex::HitSet FoundModules;
+
+      // Find the modules that reference the identifier.
+      // Note that this only finds top-level modules.
+      // We'll let diagnoseTypo find the actual declaration module.
+      if (GlobalIndex->lookupIdentifier(Typo->getName(), FoundModules)) {
+        TypoCorrection TC(TypoName.getName(), (NestedNameSpecifier *)0, 0);
+        TC.setCorrectionRange(SS, TypoName);
+        TC.setRequiresImport(true);
+      }
+    }
+  }
+
+  NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
+
   // If a callback object considers an empty typo correction candidate to be
   // viable, assume it does not do any actual validation of the candidates.
   TypoCorrection EmptyCorrection;
index 0c592a6144188c78e5aa78ea5491a0c3326e05e4..b4d359edb4f3f3f2bd727b4ddc7fe4cf4641ae64 100644 (file)
@@ -429,7 +429,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
   if (!Lookup.isSingleResult()) {
     VarDeclFilterCCC Validator(*this);
     if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
-                                               0, Validator)) {
+                                               0, Validator, CTK_ErrorRecovery)) {
       diagnoseTypo(Corrected,
                    PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
                                        : diag::err_omp_expected_var_arg_suggest)
index a7764d8df926c3661904a584b58628b03317eb33..64c3263805135b1498a2821fec2d94030196b90c 100644 (file)
@@ -325,7 +325,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
     FilterCCC.WantCXXNamedCasts = true;
     if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
                                                Found.getLookupKind(), S, &SS,
-                                               FilterCCC, LookupCtx)) {
+                                               FilterCCC, CTK_ErrorRecovery,
+                                               LookupCtx)) {
       Found.setLookupName(Corrected.getCorrection());
       if (Corrected.getCorrectionDecl())
         Found.addDecl(Corrected.getCorrectionDecl());
index de850e3901200eecce1555316a6b5b463365ba44..8439f9f7d0a9394e098f58b99fede1b594d18968 100644 (file)
@@ -810,7 +810,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
   case LookupResult::NotFoundInCurrentInstantiation:
     if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
                                                R.getLookupKind(), S, 0,
-                                               Validator)) {
+                                               Validator, CTK_ErrorRecovery)) {
       diagnoseTypo(Corrected,
                    PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
                    PDiag(diag::note_parameter_pack_here));
diff --git a/test/Modules/Inputs/undefined-type-fixit/module.map b/test/Modules/Inputs/undefined-type-fixit/module.map
new file mode 100644 (file)
index 0000000..f5ce34b
--- /dev/null
@@ -0,0 +1,9 @@
+module public1 {
+  header "public1.h"
+}
+module public2 {
+  header "public2.h"
+  module public2sub {
+    header "public2sub.h"
+  }
+}
diff --git a/test/Modules/Inputs/undefined-type-fixit/public1.h b/test/Modules/Inputs/undefined-type-fixit/public1.h
new file mode 100644 (file)
index 0000000..bc98ca9
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PUBLIC1_H
+#define PUBLIC1_H
+
+struct use_this1 { int field; };
+
+#endif
diff --git a/test/Modules/Inputs/undefined-type-fixit/public2.h b/test/Modules/Inputs/undefined-type-fixit/public2.h
new file mode 100644 (file)
index 0000000..2aa3e96
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2_H
+#define PUBLIC2_H
+
+struct use_this2 { int field; };
+
+#endif
diff --git a/test/Modules/Inputs/undefined-type-fixit/public2sub.h b/test/Modules/Inputs/undefined-type-fixit/public2sub.h
new file mode 100644 (file)
index 0000000..4c8c3cc
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2SUB_H
+#define PUBLIC2SUB_H
+
+struct use_this2sub { int field; };
+
+#endif
diff --git a/test/Modules/undefined-type-fixit1.cpp b/test/Modules/undefined-type-fixit1.cpp
new file mode 100644 (file)
index 0000000..78ce174
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-search-all -I %S/Inputs/undefined-type-fixit %s -verify
+
+//#include "public1.h"
+#include "public2.h"
+#include "public2sub.h"
+
+use_this1 client_variable1; // expected-error{{declaration of 'use_this1' must be imported from module 'public1' before it is required}}
+use_this2 client_variable2;
+use_this2sub client_variable2sub;
+
+// expected-note@Inputs/undefined-type-fixit/public1.h:4 {{previous declaration is here}}
index d94cfe9c3fab0baeeb0af5c6c53b6b5eb6599656..b3796c34fecce5f11002a25285ae2837d8ba2f6f 100644 (file)
@@ -63,6 +63,9 @@ class VoidModuleLoader : public ModuleLoader {
                                  Module::NameVisibilityKind Visibility,
                                  SourceLocation ImportLoc,
                                  bool Complain) { }
+
+  virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
+    { return 0; }
 };
 
 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
index 461e0d95fc87efe2bf63a5d1146336454b447981..1fb57cfdfba0770d1a8267db98cd230d781eb59e 100644 (file)
@@ -14,4 +14,5 @@ target_link_libraries(LexTests
   clangLex
   clangParse
   clangSema
+  clangSerialization
   )
index 40ce928014d5462b4c5ac7193f4f6b1768f0aaac..8aa95c966ad58410fe480024d8fa1e36c8c1a3aa 100644 (file)
@@ -40,6 +40,9 @@ class VoidModuleLoader : public ModuleLoader {
                                  Module::NameVisibilityKind Visibility,
                                  SourceLocation ImportLoc,
                                  bool Complain) { }
+
+  virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
+    { return 0; }
 };
 
 // The test fixture.
index fa233ce25f3339c112bb8574cda87cbdbd1dec03..071d01c8b567bb27dd295cbbacdd4323df27948f 100644 (file)
@@ -9,8 +9,8 @@
 
 CLANG_LEVEL = ../..
 TESTNAME = Lex
-LINK_COMPONENTS := mcparser support mc
+LINK_COMPONENTS := mcparser support mc bitreader
 USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \
-       clangAST.a clangLex.a clangBasic.a 
+       clangSerialization.a clangAST.a clangLex.a clangBasic.a 
 
 include $(CLANG_LEVEL)/unittests/Makefile
index e3a4a76a774c7fa418a243c7ef8aaa4ed0b71e38..3c953c209124900f1152d99e6b0ed71156c3c29b 100644 (file)
@@ -45,6 +45,9 @@ class VoidModuleLoader : public ModuleLoader {
                                  Module::NameVisibilityKind Visibility,
                                  SourceLocation ImportLoc,
                                  bool Complain) { }
+
+  virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
+    { return 0; }
 };
 
 // Stub to collect data from InclusionDirective callbacks.
index 58857fa5a133563f43fef4f61a9c3d1c1d80f848..4e22589069dd48a0d33eb300970657fbf5c22633 100644 (file)
@@ -64,6 +64,9 @@ class VoidModuleLoader : public ModuleLoader {
                                  Module::NameVisibilityKind Visibility,
                                  SourceLocation ImportLoc,
                                  bool Complain) { }
+
+  virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
+    { return 0; }
 };
 
 TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {