jtsoftware added you to the CC list for the revision "preview patch for fixit
for finding modules needing import/inclusion".
Hi doug.gregor, rsmith,
This is the beginnings of a patch to add a fixit for automatically loading a
module to resolve a type or symbol reference and outputting a fixit message.
I wanted to get some early feedback to make sure I'm on the right path, and
also some answers for questions about a couple of difficult areas.
A problematic part is that the global module index seems to only include
modules that have been imported before, and has not necessarily already been
created or loaded yet. To handle this, I added a loadGlobalModuleIndex to
ModuleLoader that will create the module index if it doesn't yet exist, and
will walk the top level modules in the module map and load any modules not
already loaded (it will load them as hidden), for the side effect of loading
the global module index with identifiers from all the modules. This might
involves two calls to create the index, as I can't compare it against the
module map unless I have an index already. This is one area I need feedback
from someone who knows the module system, as there might be a better way. I
suppose we don't create a full index right off, because of the performance cost.
Then, in Sema I added a getTypeNameWithModuleCheck function to be used instead
of getTypeName, which, if the type is not found, will do the load global index
check, look up in the index any modules with the type identifier, and if found,
make the module visible, redo the type search, and if found, display the fixit
and continue. If the type is not found, the module is made hidden again.
Another probable problem with this scheme is that apparently only top-level
modules correspond to a module AST file, and the global module index only lists
those top-level modules. Is there code somewhere to find the module a symbol
belongs to such that I can just make that module visible?
There's some other FIXME's in the code, such as one for figuring out the
SourceLocation for where to put the fixit. Any suggestions?
Perhaps the fixit message itself needs some revision, I just took a stab at it,
as I wanted to get something out for feedback.
I added -fmodules-search-all and -fno-modules-search-all to enable or disable
this (enabed by default). I also added a need-import warning group.
This affected a few of the Modules tests. I punted on it by just added a
-fno-modules-search-all option to their command lines.
I added one new bare-bones test for this fixit, in
test/Modules/undefined-type-fixit1.cpp. More needs to be done to it to check
the various scenarios of the global module index existing.
Because of the addition of an abstract function to ModuleLoader, I needed to
put a stub for it in some unit tests that derive from it.
The formatting might be a bit spotty, as the focus here is to get some early
feedback.
When and if this fixit and the infrastructure is good enough, then I can find
other places to do similar fixit's for resolving identifiers.
Thanks.
-John
http://llvm-reviews.chandlerc.com/D2671
Files:
test/Modules/auto-module-import.m
test/Modules/undefined-type-fixit1.cpp
test/Modules/module-private.cpp
test/Modules/decldef.m
test/Modules/cxx-inline-namespace.cpp
test/Modules/decldef.mm
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
test/Modules/cxx-linkage-cache.cpp
test/Modules/submodules.cpp
include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/ASTUnit.h
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/LangOptions.def
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
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
unittests/Basic/SourceManagerTest.cpp
unittests/Lex/LexerTest.cpp
unittests/Lex/PPCallbacksTest.cpp
unittests/Lex/PPConditionalDirectiveRecordTest.cpp
unittests/Lex/CMakeLists.txt
unittests/Lex/Makefile
lib/Frontend/CompilerInstance.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaDecl.cpp
lib/Lex/HeaderSearch.cpp
lib/Parse/ParseDecl.cpp
lib/Serialization/GlobalModuleIndex.cpp
Index: test/Modules/auto-module-import.m
===================================================================
--- test/Modules/auto-module-import.m
+++ test/Modules/auto-module-import.m
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify -DERRORS
-// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fno-modules-search-all -F %S/Inputs %s -verify -DERRORS
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fno-modules-search-all -F %S/Inputs %s -verify
//
// Test both with and without the declarations that refer to unimported
// entities. For error recovery, those cases implicitly trigger an import.
Index: test/Modules/undefined-type-fixit1.cpp
===================================================================
--- test/Modules/undefined-type-fixit1.cpp
+++ test/Modules/undefined-type-fixit1.cpp
@@ -0,0 +1,10 @@
+// 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;
Index: test/Modules/module-private.cpp
===================================================================
--- test/Modules/module-private.cpp
+++ test/Modules/module-private.cpp
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -I %S/Inputs %s -verify
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -x objective-c++ -fmodules-cache-path=%t -I %S/Inputs %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
@import module_private_left;
Index: test/Modules/decldef.m
===================================================================
--- test/Modules/decldef.m
+++ test/Modules/decldef.m
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
-// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
// expected-note@Inputs/def.h:5 {{previous}}
Index: test/Modules/cxx-inline-namespace.cpp
===================================================================
--- test/Modules/cxx-inline-namespace.cpp
+++ test/Modules/cxx-inline-namespace.cpp
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-search-all -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
@import cxx_inline_namespace;
Index: test/Modules/decldef.mm
===================================================================
--- test/Modules/decldef.mm
+++ test/Modules/decldef.mm
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
-// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
+// RUN: %clang_cc1 -fmodules -fno-modules-search-all -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
// expected-note@Inputs/def.h:5 {{previous}}
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
Index: test/Modules/cxx-linkage-cache.cpp
===================================================================
--- test/Modules/cxx-linkage-cache.cpp
+++ test/Modules/cxx-linkage-cache.cpp
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-search-all -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
@import cxx_linkage_cache;
Index: test/Modules/submodules.cpp
===================================================================
--- test/Modules/submodules.cpp
+++ test/Modules/submodules.cpp
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fno-modules-search-all -I %S/Inputs/submodules %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
@import std.vector;
Index: include/clang/Frontend/CompilerInstance.h
===================================================================
--- include/clang/Frontend/CompilerInstance.h
+++ include/clang/Frontend/CompilerInstance.h
@@ -118,6 +118,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;
@@ -658,7 +661,10 @@
const FrontendOptions &Opts);
/// }
-
+
+ // Create module manager.
+ void createModuleManager();
+
virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
@@ -673,6 +679,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
@@ -873,6 +873,8 @@
SourceLocation ImportLoc,
bool Complain) { }
+
+ GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
} // namespace clang
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -210,6 +210,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/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -95,6 +95,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/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6846,6 +6846,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>;
}
let CategoryName = "Documentation Issue" in {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1322,6 +1322,18 @@
bool IsCtorOrDtorName = false,
bool WantNontrivialTypeSourceInfo = false,
IdentifierInfo **CorrectedII = 0);
+
+ // Calls getTypeName, and if not found, will search for a module with the
+ // type, implicitly importing it and displaying a fixit message.
+ ParsedType getTypeNameWithModuleCheck(const IdentifierInfo &II,
+ SourceLocation NameLoc,
+ Scope *S, CXXScopeSpec *SS = 0,
+ bool isClassName = false,
+ bool HasTrailingDot = false,
+ ParsedType ObjectType = ParsedType(),
+ bool IsCtorOrDtorName = false,
+ bool WantNontrivialTypeSourceInfo = false,
+ IdentifierInfo **CorrectedII = 0);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
bool DiagnoseUnknownTypeName(IdentifierInfo *&II,
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
@@ -494,6 +494,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);
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -578,6 +578,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 fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
HelpText<"Enable the 'modules' language feature">;
@@ -654,6 +657,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
@@ -1256,6 +1256,12 @@
/// \brief Determine whether this AST reader has a global index.
bool hasGlobalIndex() const { return GlobalIndex.isValid(); }
+ /// \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: unittests/Basic/SourceManagerTest.cpp
===================================================================
--- unittests/Basic/SourceManagerTest.cpp
+++ unittests/Basic/SourceManagerTest.cpp
@@ -63,6 +63,8 @@
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }
+
+ virtual GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
Index: unittests/Lex/LexerTest.cpp
===================================================================
--- unittests/Lex/LexerTest.cpp
+++ unittests/Lex/LexerTest.cpp
@@ -40,6 +40,8 @@
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }
+
+ virtual GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
// The test fixture.
Index: unittests/Lex/PPCallbacksTest.cpp
===================================================================
--- unittests/Lex/PPCallbacksTest.cpp
+++ unittests/Lex/PPCallbacksTest.cpp
@@ -45,6 +45,8 @@
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }
+
+ virtual GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
// Stub to collect data from InclusionDirective callbacks.
Index: unittests/Lex/PPConditionalDirectiveRecordTest.cpp
===================================================================
--- unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -64,6 +64,8 @@
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }
+
+ virtual GlobalModuleIndex *loadGlobalModuleIndex() { return 0; }
};
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
Index: unittests/Lex/CMakeLists.txt
===================================================================
--- unittests/Lex/CMakeLists.txt
+++ unittests/Lex/CMakeLists.txt
@@ -14,4 +14,5 @@
clangLex
clangParse
clangSema
+ clangSerialization
)
Index: unittests/Lex/Makefile
===================================================================
--- unittests/Lex/Makefile
+++ unittests/Lex/Makefile
@@ -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: 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() {
@@ -1094,6 +1096,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());
+ }
+
+ std::string Sysroot = getHeaderSearchOpts().Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), *Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ getFrontendOpts().UseGlobalModuleIndex);
+ if (hasASTConsumer()) {
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
+ }
+
+ OwningPtr<ExternalASTSource> Source;
+ Source.reset(ModuleManager);
+ getASTContext().setExternalSource(Source);
+ if (hasSema())
+ ModuleManager->InitializeSema(getSema());
+ if (hasASTConsumer())
+ ModuleManager->StartTranslationUnit(&getASTConsumer());
+ }
+}
+
ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
@@ -1141,37 +1180,7 @@
// 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());
- }
-
- std::string Sysroot = getHeaderSearchOpts().Sysroot;
- const PreprocessorOptions &PPOpts = getPreprocessorOpts();
- ModuleManager = new ASTReader(getPreprocessor(), *Context,
- Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- /*AllowASTWithCompilerErrors=*/false,
- getFrontendOpts().UseGlobalModuleIndex);
- if (hasASTConsumer()) {
- ModuleManager->setDeserializationListener(
- getASTConsumer().GetASTDeserializationListener());
- getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
- }
- OwningPtr<ExternalASTSource> Source;
- Source.reset(ModuleManager);
- getASTContext().setExternalSource(Source);
- if (hasSema())
- ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
- ModuleManager->StartTranslationUnit(&getASTConsumer());
+ createModuleManager();
}
// Try to load the module file.
@@ -1396,3 +1405,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
@@ -1324,6 +1324,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.hasArg(OPT_fshort_wchar);
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -41,6 +42,8 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Template.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/Module.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
@@ -338,6 +341,79 @@
return ParsedType::make(T);
}
+// Calls getTypeName, and if not found, will search for a module with the
+// type, implicitly importing it and displaying a fixit message.
+// FIXME: Apparently, the global index only finds top-level modules, so
+// perhaps this isn't the right implementation, but it's a starting point,
+// and given the fixit message output, the user can probably figure out the
+// right import statement.
+// FIXME: Can we figure out the submodule from the type and refine the
+// visibility to just the submodule?
+// FIXME: Can we figure out where to put the fixit import/include?
+ParsedType Sema::getTypeNameWithModuleCheck(const IdentifierInfo &II,
+ SourceLocation NameLoc,
+ Scope *S, CXXScopeSpec *SS,
+ bool isClassName,
+ bool HasTrailingDot,
+ ParsedType ObjectType,
+ bool IsCtorOrDtorName,
+ bool WantNontrivialTypeSourceInfo,
+ IdentifierInfo **CorrectedII) {
+ // Do main look up, before checking non-imported modules.
+ ParsedType TypeRep = getTypeName(II, NameLoc, S, SS, isClassName,
+ HasTrailingDot, ObjectType, IsCtorOrDtorName,
+ WantNontrivialTypeSourceInfo, CorrectedII);
+
+ // If found exit now with the type. Also exit if modules not enabled.
+ if (TypeRep || !getLangOpts().Modules || !getLangOpts().ModulesSearchAll)
+ return TypeRep;
+
+ // Otherwise try to find the type in modules via the global module index.
+ ModuleLoader &Loader = PP.getModuleLoader();
+ GlobalModuleIndex *GlobalIndex = Loader.loadGlobalModuleIndex();
+
+ if (!GlobalIndex)
+ return TypeRep;
+
+ GlobalModuleIndex::HitSet FoundModules;
+
+ // Find the modules that reference the identifier.
+ if (GlobalIndex->lookupIdentifier(II.getName(), FoundModules)) {
+ // 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 repeat the type lookup.
+ Loader.makeModuleVisible(TheModule, Module::AllVisible, NameLoc, false);
+ // Try the type lookup again.
+ TypeRep = getTypeName(II, NameLoc, S, SS, isClassName,
+ HasTrailingDot, ObjectType, IsCtorOrDtorName,
+ WantNontrivialTypeSourceInfo, CorrectedII);
+ // If we found the type, display a fixit warning and exit.
+ if (TypeRep) {
+ // FIXME: Can we figure out the submodule from the type and refine
+ // the visibility to just the submodule?
+ std::string fixit = "#import ";
+ fixit += TheModule->Name;
+ // FIXME: Figure out how to find the right insertion point,
+ // For now we just use the type location.
+ Diag(NameLoc, diag::warn_need_module_import)
+ << II.getName() << TheModule->getFullModuleName() <<
+ FixItHint::CreateInsertion(NameLoc, fixit);
+ break;
+ }
+ // Otherwise hide the module.
+ Loader.makeModuleVisible(TheModule, Module::Hidden, NameLoc, false);
+ }
+ }
+
+ return TypeRep;
+}
+
/// isTagName() - This method is called *for error recovery purposes only*
/// to determine if the specified name is a valid tag name ("struct foo"). If
/// so, this returns the TST for the tag corresponding to it (TST_enum,
Index: lib/Lex/HeaderSearch.cpp
===================================================================
--- lib/Lex/HeaderSearch.cpp
+++ lib/Lex/HeaderSearch.cpp
@@ -204,6 +204,10 @@
return Module;
}
+Module *HeaderSearch::lookupModuleFromFile(StringRef ModuleFileName) {
+ return lookupModule(llvm::sys::path::stem(ModuleFileName), false);
+}
+
//===----------------------------------------------------------------------===//
// File lookup within a DirectoryLookup scope
//===----------------------------------------------------------------------===//
@@ -690,6 +694,17 @@
}
}
+ // If no includers (as in case of module build), and not an angled
+ // include, do a final check in the current directory
+ if (Includers.empty() && !isAngled && !NoCurDirSearch) {
+ const FileEntry *Result = FileMgr.getFile(Filename, /*openFile=*/true);
+ if (Result) {
+ CacheLookup.second
+ = LookupFileCache.GetOrCreateValue(Filename).getValue().second;
+ return Result;
+ }
+ }
+
// Otherwise, didn't find it. Remember we didn't find this.
CacheLookup.second = SearchDirs.size();
return 0;
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2766,7 +2766,7 @@
goto DoneWithDeclSpec;
ParsedType TypeRep =
- Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Actions.getTypeNameWithModuleCheck(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
// If this is not a typedef name, don't parse it as part of the declspec,
Index: lib/Serialization/GlobalModuleIndex.cpp
===================================================================
--- lib/Serialization/GlobalModuleIndex.cpp
+++ lib/Serialization/GlobalModuleIndex.cpp
@@ -341,6 +341,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.
//----------------------------------------------------------------------------//
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits