I've reworked this to do the check in CorrectTypo as suggested. This is just
a partial post, as I've omitted needed changes to other tests so we can focus
on the key parts. I basically would like to know if this is the right
approach, and what needs to be done to make it right/better.
Question: I saw that there was some code for handling missing imports, but I
couldn't see where it searched the global module index, and my new test case
(with the new code disabled) didn't trigger it. Was it just for some special
cases?
Thanks.
-John
Hi doug.gregor, rsmith,
http://llvm-reviews.chandlerc.com/D2671
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2671?vs=6814&id=8146#toc
Files:
include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/ASTUnit.h
include/clang/Basic/LangOptions.def
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Lex/ModuleLoader.h
include/clang/Lex/HeaderSearch.h
include/clang/Driver/Options.td
include/clang/Serialization/ASTReader.h
include/clang/Serialization/GlobalModuleIndex.h
lib/Frontend/CompilerInstance.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaLookup.cpp
lib/Lex/HeaderSearch.cpp
lib/Serialization/GlobalModuleIndex.cpp
test/Modules/undefined-type-fixit1.cpp
test/Modules/Inputs/undefined-type-fixit/public2sub.h
test/Modules/Inputs/undefined-type-fixit/module.map
test/Modules/Inputs/undefined-type-fixit/public1.h
test/Modules/Inputs/undefined-type-fixit/public2.h
Index: include/clang/Frontend/CompilerInstance.h
===================================================================
--- include/clang/Frontend/CompilerInstance.h
+++ include/clang/Frontend/CompilerInstance.h
@@ -124,6 +124,9 @@
/// 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;
@@ -683,6 +686,9 @@
/// }
+ // Create module manager.
+ void createModuleManager();
+
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
@@ -694,6 +700,8 @@
return ModuleLoader::HadFatalFailure;
}
+ virtual GlobalModuleIndex *loadGlobalModuleIndex();
+
};
} // end namespace clang
Index: include/clang/Frontend/ASTUnit.h
===================================================================
--- include/clang/Frontend/ASTUnit.h
+++ include/clang/Frontend/ASTUnit.h
@@ -869,6 +869,8 @@
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc, bool Complain) override {}
+
+ GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
} // namespace clang
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -96,6 +96,7 @@
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(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -213,6 +213,7 @@
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def ModuleConflict : DiagGroup<"module-conflict">;
+def NeedImport : DiagGroup<"need-import">;
def NewlineEOF : DiagGroup<"newline-eof">;
def NullArithmetic : DiagGroup<"null-arithmetic">;
def NullCharacter : DiagGroup<"null-character">;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6946,6 +6946,9 @@
"declaration of %0 must be imported from module '%1' before it is required">;
def err_module_private_definition : Error<
"definition of %0 must be imported from module '%1' before it is required">;
+def warn_need_module_import : Warning<
+ "use of identifier '%0' requires import/inclusion of the module '%1'">,
+ InGroup<NeedImport>;
def err_module_import_in_extern_c : Error<
"import of C++ module '%0' appears within extern \"C\" language linkage "
"specification">;
Index: include/clang/Lex/ModuleLoader.h
===================================================================
--- include/clang/Lex/ModuleLoader.h
+++ include/clang/Lex/ModuleLoader.h
@@ -21,6 +21,7 @@
namespace clang {
+class GlobalModuleIndex;
class IdentifierInfo;
class Module;
@@ -88,6 +89,17 @@
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.
+ /// \returns Returns null if load failed.
+ virtual GlobalModuleIndex *loadGlobalModuleIndex() = 0;
+
bool HadFatalFailure;
};
Index: include/clang/Lex/HeaderSearch.h
===================================================================
--- include/clang/Lex/HeaderSearch.h
+++ include/clang/Lex/HeaderSearch.h
@@ -503,6 +503,13 @@
/// \returns The module with the given name.
Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
+ /// \brief Lookup a top level module given its file name.
+ ///
+ /// \param ModuleFileName The name of the module file.
+ ///
+ /// \returns The module with the given name.
+ Module *lookupModuleFromFile(StringRef ModuleFileName);
+
/// \brief Try to find a module map file in the given directory, returning
/// \c nullptr if none is found.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -579,6 +579,9 @@
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">;
@@ -665,6 +668,9 @@
Flags<[DriverOption]>;
def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
Flags<[DriverOption]>;
+def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>,
+ Flags<[DriverOption, CC1Option]>,
+ HelpText<"Inhibit search of non-imported modules to resolve references">;
def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>;
def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>;
Index: include/clang/Serialization/ASTReader.h
===================================================================
--- include/clang/Serialization/ASTReader.h
+++ include/clang/Serialization/ASTReader.h
@@ -1358,6 +1358,12 @@
/// \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.
///
/// \returns true if loading the global index has failed for any reason.
Index: include/clang/Serialization/GlobalModuleIndex.h
===================================================================
--- include/clang/Serialization/GlobalModuleIndex.h
+++ include/clang/Serialization/GlobalModuleIndex.h
@@ -186,6 +186,9 @@
/// \brief Print statistics to standard error.
void printStats();
+ /// \brief Print debugging view to standard error.
+ void dump();
+
/// \brief Write a global index into the given
///
/// \param FileMgr The file manager to use to load module files.
Index: lib/Frontend/CompilerInstance.cpp
===================================================================
--- lib/Frontend/CompilerInstance.cpp
+++ lib/Frontend/CompilerInstance.cpp
@@ -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"
@@ -51,7 +52,8 @@
CompilerInstance::CompilerInstance()
: Invocation(new CompilerInvocation()), ModuleManager(0),
- BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
+ BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
+ ModuleBuildFailed(false) {
}
CompilerInstance::~CompilerInstance() {
@@ -1085,6 +1087,43 @@
}
}
+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,
@@ -1131,40 +1170,8 @@
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);
@@ -1391,3 +1398,59 @@
ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
+GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex() {
+ 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 load 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) {
+ 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) {
+ SourceLocation dummyLoc;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ for (Module *Mod = TheModule; Mod; Mod = Mod->Parent)
+ Path.push_back(std::make_pair(
+ getPreprocessor().getIdentifierInfo(Mod->Name), Mod->DefinitionLoc));
+ 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: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1343,6 +1343,9 @@
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
+ 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: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -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"
@@ -4050,10 +4055,60 @@
if (getLangOpts().AltiVec && Typo->isStr("vector"))
return TypoCorrection();
- NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
-
TypoCorrectionConsumer Consumer(*this, Typo);
+ // Look for the symbol in non-imported modules.
+ if (getLangOpts().Modules && getLangOpts().ModulesSearchAll) {
+ // Try to find the type in modules via the global module index.
+ ModuleLoader &Loader = PP.getModuleLoader();
+ // Load global module index, or retrieve a previously loaded one.
+ GlobalModuleIndex *GlobalIndex = Loader.loadGlobalModuleIndex();
+
+ // 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);
+ // Walk the found modules that reference the identifier.
+ for (GlobalModuleIndex::HitSet::iterator I = FoundModules.begin(),
+ E = FoundModules.end(); I != E; ++I) {
+ ModuleFile *TheModuleFile = *I;
+ // Find the module from the file name.
+ Module *TheModule = PP.getHeaderSearchInfo().lookupModuleFromFile(
+ TheModuleFile->FileName);
+ assert(TheModule && "Should be able to find the module.");
+ // Make the module visible so we can do a name lookup.
+ Loader.makeModuleVisible(TheModule, Module::AllVisible,
+ TypoName.getLoc(), false);
+ // Do a name lookup.
+ LookupResult ModRes(*this, TypoName, LookupKind);
+ LookupPotentialTypoResult(*this, ModRes, Typo, S, SS, MemberContext,
+ EnteringContext, OPT, false);
+ // If we have an exact match, save the decl in the coorection
+ // to let diagnoseTypo do a fixit message.
+ if (ModRes.getResultKind() == LookupResult::Found)
+ TC.setCorrectionDecl(ModRes.getAsSingle<NamedDecl>());
+ // Hide the module again. diagnoseTypo will unhide the decl module.
+ Loader.makeModuleVisible(TheModule, Module::Hidden,
+ TypoName.getLoc(), false);
+ }
+ // If the name lookup found something, we set a flag to tell
+ // diagnoseTypo we have a case of possibly missing module import.
+ if (TC.isResolved()) {
+ TC.setRequiresImport(true);
+ return TC;
+ }
+ }
+ }
+ }
+
+ 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;
@@ -4127,6 +4182,8 @@
unsigned TypoLen = Typo->getName().size();
bool AllowOnlyNNSChanges = TypoLen < 3;
+ // FIXME: Can we do this partial match check on modules known but not
+ // imported via the global module index?
if (IsUnqualifiedLookup || SearchNamespaces) {
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
@@ -4629,9 +4686,14 @@
Module *Owner = Def->getOwningModule();
assert(Owner && "definition of hidden declaration is not in a module");
- Diag(Correction.getCorrectionRange().getBegin(),
- diag::err_module_private_declaration)
- << Def << Owner->getFullModuleName();
+ std::string fixit = "#import ";
+ fixit += Owner->Name;
+ SourceLocation TypoLoc = Correction.getCorrectionRange().getBegin();
+ // FIXME: Figure out how to find the right insertion point,
+ // For now we just use the type location.
+ Diag(TypoLoc, diag::warn_need_module_import)
+ << CorrectedStr << Owner->getFullModuleName() <<
+ FixItHint::CreateInsertion(TypoLoc, fixit);
Diag(Def->getLocation(), diag::note_previous_declaration);
// Recover by implicitly importing this module.
Index: lib/Lex/HeaderSearch.cpp
===================================================================
--- lib/Lex/HeaderSearch.cpp
+++ lib/Lex/HeaderSearch.cpp
@@ -205,6 +205,10 @@
return Module;
}
+Module *HeaderSearch::lookupModuleFromFile(StringRef ModuleFileName) {
+ return lookupModule(llvm::sys::path::stem(ModuleFileName), false);
+}
+
//===----------------------------------------------------------------------===//
// File lookup within a DirectoryLookup scope
//===----------------------------------------------------------------------===//
Index: lib/Serialization/GlobalModuleIndex.cpp
===================================================================
--- lib/Serialization/GlobalModuleIndex.cpp
+++ lib/Serialization/GlobalModuleIndex.cpp
@@ -342,6 +342,21 @@
std::fprintf(stderr, "\n");
}
+void GlobalModuleIndex::dump() {
+ std::fprintf(stderr, "*** Global Module Index Dump:\n");
+ std::fprintf(stderr, "Module files:\n");
+ for (llvm::SmallVector<ModuleInfo, 16>::iterator I = Modules.begin(),
+ E = Modules.end(); I != E; ++I) {
+ ModuleInfo *MI = (ModuleInfo*)I;
+ std::fprintf(stderr, "** %s\n", MI->FileName.c_str());
+ if (MI->File)
+ MI->File->dump();
+ else
+ std::fprintf(stderr, "\n");
+ }
+ std::fprintf(stderr, "\n");
+}
+
//----------------------------------------------------------------------------//
// Global module index writer.
//----------------------------------------------------------------------------//
Index: test/Modules/undefined-type-fixit1.cpp
===================================================================
--- test/Modules/undefined-type-fixit1.cpp
+++ test/Modules/undefined-type-fixit1.cpp
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -I %S/Inputs/undefined-type-fixit %s -verify
+
+//#include "public1.h"
+#include "public2.h"
+#include "public2sub.h"
+
+use_this1 client_variable1; // expected-warning {{use of identifier 'use_this1' requires import/inclusion of the module 'public1'}}
+use_this2 client_variable2;
+use_this2sub client_variable2sub;
+
+// expected-note@Inputs/undefined-type-fixit/public1.h:4 {{previous declaration is here}}
Index: test/Modules/Inputs/undefined-type-fixit/public2sub.h
===================================================================
--- test/Modules/Inputs/undefined-type-fixit/public2sub.h
+++ test/Modules/Inputs/undefined-type-fixit/public2sub.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2SUB_H
+#define PUBLIC2SUB_H
+
+struct use_this2sub { int field; };
+
+#endif
Index: test/Modules/Inputs/undefined-type-fixit/module.map
===================================================================
--- test/Modules/Inputs/undefined-type-fixit/module.map
+++ test/Modules/Inputs/undefined-type-fixit/module.map
@@ -0,0 +1,9 @@
+module public1 {
+ header "public1.h"
+}
+module public2 {
+ header "public2.h"
+ module public2sub {
+ header "public2sub.h"
+ }
+}
Index: test/Modules/Inputs/undefined-type-fixit/public1.h
===================================================================
--- test/Modules/Inputs/undefined-type-fixit/public1.h
+++ test/Modules/Inputs/undefined-type-fixit/public1.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC1_H
+#define PUBLIC1_H
+
+struct use_this1 { int field; };
+
+#endif
Index: test/Modules/Inputs/undefined-type-fixit/public2.h
===================================================================
--- test/Modules/Inputs/undefined-type-fixit/public2.h
+++ test/Modules/Inputs/undefined-type-fixit/public2.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2_H
+#define PUBLIC2_H
+
+struct use_this2 { int field; };
+
+#endif
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits