summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/docs/ModularizeUsage.rst17
-rw-r--r--clang-tools-extra/docs/modularize.rst4
-rw-r--r--clang-tools-extra/modularize/Modularize.cpp144
-rw-r--r--clang-tools-extra/modularize/Modularize.h2
-rw-r--r--clang-tools-extra/modularize/ModularizeUtilities.cpp163
-rw-r--r--clang-tools-extra/modularize/ModularizeUtilities.h40
-rw-r--r--clang-tools-extra/modularize/ModuleAssistant.cpp38
-rw-r--r--clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h2
-rw-r--r--clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h1
-rw-r--r--clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap10
-rw-r--r--clang-tools-extra/test/modularize/ProblemsCompileError.modularize3
-rw-r--r--clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize16
12 files changed, 403 insertions, 37 deletions
diff --git a/clang-tools-extra/docs/ModularizeUsage.rst b/clang-tools-extra/docs/ModularizeUsage.rst
index c1e3c87fac9..b7c4b65c09e 100644
--- a/clang-tools-extra/docs/ModularizeUsage.rst
+++ b/clang-tools-extra/docs/ModularizeUsage.rst
@@ -59,6 +59,13 @@ Modularize Command Line Options
Generate a module map and output it to the given file. See the description
in :ref:`module-map-generation`.
+
+.. option:: -problem-files-list=<problem-files-list-file-name>
+
+ For use only with module map assistant. Input list of files that
+ have problems with respect to modules. These will still be
+ included in the generated module map, but will be marked as
+ "excluded" headers.
.. option:: -root-module=<root-name>
@@ -79,3 +86,13 @@ Modularize Command Line Options
.. option:: -coverage-check-only
Only do the coverage check for a module map.
+
+.. option:: -display-file-lists
+
+ Display lists of good files (no compile errors), problem files,
+ and a combined list with problem files preceded by a '#'.
+ This can be used to quickly determine which files have problems.
+ The latter combined list might be useful in starting to modularize
+ a set of headers. You can start with a full list of headers,
+ use -display-file-lists option, and then use the combined list as
+ your intermediate list, uncommenting-out headers as you fix them.
diff --git a/clang-tools-extra/docs/modularize.rst b/clang-tools-extra/docs/modularize.rst
index 2612461aa1a..98bb8a08c0d 100644
--- a/clang-tools-extra/docs/modularize.rst
+++ b/clang-tools-extra/docs/modularize.rst
@@ -210,6 +210,10 @@ The following module map will be generated::
An optional ``-root-module=<root-name>`` option can be used to cause a root module
to be created which encloses all the modules.
+An optional ``-problem-files-list=<problem-file-name> can be used to input
+a list of files to be excluded, perhaps as a temporary stop-gap measure until
+problem headers can be fixed.
+
For example, with the same header list from above::
// Output/NoProblemsAssistant.txt
diff --git a/clang-tools-extra/modularize/Modularize.cpp b/clang-tools-extra/modularize/Modularize.cpp
index 462add52e12..2a917949972 100644
--- a/clang-tools-extra/modularize/Modularize.cpp
+++ b/clang-tools-extra/modularize/Modularize.cpp
@@ -58,6 +58,11 @@
// module to be created in the generated module.map file. Note that
// you will likely need to edit this file to suit the needs of your
// headers.
+// -problem-files-list=(problem files list file name)
+// For use only with module map assistant. Input list of files that
+// have problems with respect to modules. These will still be
+// included in the generated module map, but will be marked as
+// "excluded" headers.
// -root-module=(root module name)
// Specifies a root module to be created in the generated module.map
// file.
@@ -68,6 +73,14 @@
// Don't do the coverage check.
// -coverage-check-only
// Only do the coverage check.
+// -display-file-lists
+// Display lists of good files (no compile errors), problem files,
+// and a combined list with problem files preceded by a '#'.
+// This can be used to quickly determine which files have problems.
+// The latter combined list might be useful in starting to modularize
+// a set of headers. You can start with a full list of headers,
+// use -display-file-lists option, and then use the combined list as
+// your intermediate list, uncommenting-out headers as you fix them.
//
// Note that by default, the modularize assumes .h files contain C++ source.
// If your .h files in the file list contain another language, you should
@@ -274,8 +287,15 @@ static cl::opt<std::string> ModuleMapPath(
" If no path is specified and if prefix option is specified,"
" use prefix for file path."));
-// Option for assistant mode, telling modularize to output a module map
-// based on the headers list, and where to put it.
+// Option to specify list of problem files for assistant.
+// This will cause assistant to exclude these files.
+static cl::opt<std::string> ProblemFilesList(
+ "problem-files-list", cl::init(""),
+ cl::desc(
+ "List of files with compilation or modularization problems for"
+ " assistant mode. This will be excluded."));
+
+// Option for assistant mode, telling modularize the name of the root module.
static cl::opt<std::string>
RootModule("root-module", cl::init(""),
cl::desc("Specify the name of the root module."));
@@ -304,6 +324,12 @@ static cl::opt<bool>
CoverageCheckOnly("coverage-check-only", cl::init(false),
cl::desc("Only do the coverage check."));
+// Option for displaying lists of good, bad, and mixed files.
+static cl::opt<bool>
+DisplayFileLists("display-file-lists", cl::init(false),
+cl::desc("Display lists of good files (no compile errors), problem files,"
+ " and a combined list with problem files preceded by a '#'."));
+
// Save the program name for error messages.
const char *Argv0;
// Save the command line for comments.
@@ -704,6 +730,78 @@ private:
int &HadErrors;
};
+class CompileCheckVisitor
+ : public RecursiveASTVisitor<CompileCheckVisitor> {
+public:
+ CompileCheckVisitor() {}
+
+ bool TraverseStmt(Stmt *S) { return true; }
+ bool TraverseType(QualType T) { return true; }
+ bool TraverseTypeLoc(TypeLoc TL) { return true; }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ return true;
+ }
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
+ return true;
+ }
+ bool TraverseTemplateName(TemplateName Template) { return true; }
+ bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ return true;
+ }
+ bool TraverseTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ return true;
+ }
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
+ bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+
+ // Check 'extern "*" {}' block for #include directives.
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ return true;
+ }
+
+ // Check 'namespace (name) {}' block for #include directives.
+ bool VisitNamespaceDecl(const NamespaceDecl *D) {
+ return true;
+ }
+
+ // Collect definition entities.
+ bool VisitNamedDecl(NamedDecl *ND) {
+ return true;
+ }
+};
+
+class CompileCheckConsumer : public ASTConsumer {
+public:
+ CompileCheckConsumer() {}
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ CompileCheckVisitor().TraverseDecl(Ctx.getTranslationUnitDecl());
+ }
+};
+
+class CompileCheckAction : public SyntaxOnlyAction {
+public:
+ CompileCheckAction() {}
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ return llvm::make_unique<CompileCheckConsumer>();
+ }
+};
+
+class CompileCheckFrontendActionFactory : public FrontendActionFactory {
+public:
+ CompileCheckFrontendActionFactory() {}
+
+ CompileCheckAction *create() override {
+ return new CompileCheckAction();
+ }
+};
+
int main(int Argc, const char **Argv) {
// Save program name for error messages.
@@ -730,7 +828,7 @@ int main(int Argc, const char **Argv) {
ModUtil.reset(
ModularizeUtilities::createModularizeUtilities(
- ListFileNames, HeaderPrefix));
+ ListFileNames, HeaderPrefix, ProblemFilesList));
// Get header file names and dependencies.
if (ModUtil->loadAllHeaderListsAndDependencies())
@@ -739,6 +837,7 @@ int main(int Argc, const char **Argv) {
// If we are in assistant mode, output the module map and quit.
if (ModuleMapPath.length() != 0) {
if (!createModuleMap(ModuleMapPath, ModUtil->HeaderFileNames,
+ ModUtil->ProblemFileNames,
ModUtil->Dependencies, HeaderPrefix, RootModule))
return 1; // Failed.
return 0; // Success - Skip checks in assistant mode.
@@ -767,9 +866,36 @@ int main(int Argc, const char **Argv) {
PreprocessorTracker::create(ModUtil->HeaderFileNames,
BlockCheckHeaderListOnly));
- // Parse all of the headers, detecting duplicates.
+ // Coolect entities here.
EntityMap Entities;
- ClangTool Tool(*Compilations, ModUtil->HeaderFileNames);
+
+ // Because we can't easily determine which files failed
+ // during the tool run, if we're collecting the file lists
+ // for display, we do a first compile pass on individual
+ // files to find which ones don't compile stand-alone.
+ if (DisplayFileLists) {
+ // First, make a pass to just get compile errors.
+ for (auto &CompileCheckFile : ModUtil->HeaderFileNames) {
+ llvm::SmallVector<std::string, 32> CompileCheckFileArray;
+ CompileCheckFileArray.push_back(CompileCheckFile);
+ ClangTool CompileCheckTool(*Compilations, CompileCheckFileArray);
+ CompileCheckTool.appendArgumentsAdjuster(
+ getModularizeArgumentsAdjuster(ModUtil->Dependencies));
+ int CompileCheckFileErrors = 0;
+ CompileCheckFrontendActionFactory CompileCheckFactory;
+ CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
+ if (CompileCheckFileErrors != 0) {
+ ModUtil->addUniqueProblemFile(CompileCheckFile); // Save problem file.
+ HadErrors |= 1;
+ }
+ else
+ ModUtil->addNoCompileErrorsFile(CompileCheckFile); // Save good file.
+ }
+ }
+
+ // Then we make another pass on the good files to do the rest of the work.
+ ClangTool Tool(*Compilations,
+ (DisplayFileLists ? ModUtil->GoodFileNames : ModUtil->HeaderFileNames));
Tool.appendArgumentsAdjuster(
getModularizeArgumentsAdjuster(ModUtil->Dependencies));
ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
@@ -816,6 +942,7 @@ int main(int Argc, const char **Argv) {
for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) {
errs() << " " << FI->File->getName() << ":" << FI->Line << ":"
<< FI->Column << "\n";
+ ModUtil->addUniqueProblemFile(FI->File->getName());
}
HadErrors = 1;
}
@@ -845,6 +972,7 @@ int main(int Argc, const char **Argv) {
}
HadErrors = 1;
+ ModUtil->addUniqueProblemFile(H->first->getName());
errs() << "error: header '" << H->first->getName()
<< "' has different contents depending on how it was included.\n";
for (unsigned I = 0, N = H->second.size(); I != N; ++I) {
@@ -855,5 +983,11 @@ int main(int Argc, const char **Argv) {
}
}
+ if (DisplayFileLists) {
+ ModUtil->displayProblemFiles();
+ ModUtil->displayGoodFiles();
+ ModUtil->displayCombinedFiles();
+ }
+
return HadErrors;
}
diff --git a/clang-tools-extra/modularize/Modularize.h b/clang-tools-extra/modularize/Modularize.h
index ef24fc6b3e7..a3f2ad3e069 100644
--- a/clang-tools-extra/modularize/Modularize.h
+++ b/clang-tools-extra/modularize/Modularize.h
@@ -37,6 +37,7 @@ typedef llvm::StringMap<DependentsVector> DependencyMap;
/// Create the module map file.
/// \param ModuleMapPath The path to the module map file to be generated.
/// \param HeaderFileNames The list of header files, absolute native paths.
+/// \param ProblemFileNames The list of problem header files.
/// \param Dependencies Map of headers that depend on other headers.
/// \param HeaderPrefix Tells the code where the headers are, if they
/// aren's in the current directory, allowing the generator to strip
@@ -46,6 +47,7 @@ typedef llvm::StringMap<DependentsVector> DependencyMap;
/// \returns True if successful.
bool createModuleMap(llvm::StringRef ModuleMapPath,
llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
DependencyMap &Dependencies, llvm::StringRef HeaderPrefix,
llvm::StringRef RootModuleName);
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index 7594b6725cc..08c92fc90c0 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -42,9 +42,11 @@ public:
// Constructor.
ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
- llvm::StringRef Prefix)
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath)
: InputFilePaths(InputPaths),
HeaderPrefix(Prefix),
+ ProblemFilesPath(ProblemFilesListPath),
HasModuleMap(false),
MissingHeaderCount(0),
// Init clang stuff needed for loading the module map and preprocessing.
@@ -65,9 +67,10 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
// Create instance of ModularizeUtilities, to simplify setting up
// subordinate objects.
ModularizeUtilities *ModularizeUtilities::createModularizeUtilities(
- std::vector<std::string> &InputPaths, llvm::StringRef Prefix) {
+ std::vector<std::string> &InputPaths, llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath) {
- return new ModularizeUtilities(InputPaths, Prefix);
+ return new ModularizeUtilities(InputPaths, Prefix, ProblemFilesListPath);
}
// Load all header lists and dependencies.
@@ -91,6 +94,15 @@ std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() {
}
}
}
+ // If we have a problem files list.
+ if (ProblemFilesPath.size() != 0) {
+ // Load problem files list.
+ if (std::error_code EC = loadProblemHeaderList(ProblemFilesPath)) {
+ errs() << "modularize: error: Unable to get problem header list '" << ProblemFilesPath
+ << "': " << EC.message() << '\n';
+ return EC;
+ }
+ }
return std::error_code();
}
@@ -194,6 +206,58 @@ std::error_code ModularizeUtilities::loadSingleHeaderListsAndDependencies(
return std::error_code();
}
+// Load problem header list.
+std::error_code ModularizeUtilities::loadProblemHeaderList(
+ llvm::StringRef InputPath) {
+
+ // By default, use the path component of the list file name.
+ SmallString<256> HeaderDirectory(InputPath);
+ llvm::sys::path::remove_filename(HeaderDirectory);
+ SmallString<256> CurrentDirectory;
+ llvm::sys::fs::current_path(CurrentDirectory);
+
+ // Get the prefix if we have one.
+ if (HeaderPrefix.size() != 0)
+ HeaderDirectory = HeaderPrefix;
+
+ // Read the header list file into a buffer.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
+ MemoryBuffer::getFile(InputPath);
+ if (std::error_code EC = listBuffer.getError())
+ return EC;
+
+ // Parse the header list into strings.
+ SmallVector<StringRef, 32> Strings;
+ listBuffer.get()->getBuffer().split(Strings, "\n", -1, false);
+
+ // Collect the header file names from the string list.
+ for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
+ E = Strings.end();
+ I != E; ++I) {
+ StringRef Line = I->trim();
+ // Ignore comments and empty lines.
+ if (Line.empty() || (Line[0] == '#'))
+ continue;
+ SmallString<256> HeaderFileName;
+ // Prepend header file name prefix if it's not absolute.
+ if (llvm::sys::path::is_absolute(Line))
+ llvm::sys::path::native(Line, HeaderFileName);
+ else {
+ if (HeaderDirectory.size() != 0)
+ HeaderFileName = HeaderDirectory;
+ else
+ HeaderFileName = CurrentDirectory;
+ llvm::sys::path::append(HeaderFileName, Line);
+ llvm::sys::path::native(HeaderFileName);
+ }
+ // Get canonical form.
+ HeaderFileName = getCanonicalPath(HeaderFileName);
+ // Save the resulting header file path.
+ ProblemFileNames.push_back(HeaderFileName.str());
+ }
+ return std::error_code();
+}
+
// Load single module map and extract header file list.
std::error_code ModularizeUtilities::loadModuleMap(
llvm::StringRef InputPath) {
@@ -364,24 +428,24 @@ bool ModularizeUtilities::collectUmbrellaHeaders(StringRef UmbrellaDirName,
}
// Replace .. embedded in path for purposes of having
-// a canonical path.
+// a canonical path.
static std::string replaceDotDot(StringRef Path) {
- SmallString<128> Buffer;
- llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
- E = llvm::sys::path::end(Path);
- while (B != E) {
- if (B->compare(".") == 0) {
- }
- else if (B->compare("..") == 0)
- llvm::sys::path::remove_filename(Buffer);
- else
- llvm::sys::path::append(Buffer, *B);
- ++B;
- }
- if (Path.endswith("/") || Path.endswith("\\"))
- Buffer.append(1, Path.back());
- return Buffer.c_str();
-}
+ SmallString<128> Buffer;
+ llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
+ E = llvm::sys::path::end(Path);
+ while (B != E) {
+ if (B->compare(".") == 0) {
+ }
+ else if (B->compare("..") == 0)
+ llvm::sys::path::remove_filename(Buffer);
+ else
+ llvm::sys::path::append(Buffer, *B);
+ ++B;
+ }
+ if (Path.endswith("/") || Path.endswith("\\"))
+ Buffer.append(1, Path.back());
+ return Buffer.c_str();
+}
// Convert header path to canonical form.
// The canonical form is basically just use forward slashes, and remove "./".
@@ -424,3 +488,62 @@ std::string ModularizeUtilities::getDirectoryFromPath(StringRef Path) {
return ".";
return Directory.str();
}
+
+// Add unique problem file.
+// Also standardizes the path.
+void ModularizeUtilities::addUniqueProblemFile(std::string FilePath) {
+ FilePath = getCanonicalPath(FilePath);
+ // Don't add if already present.
+ for(auto &TestFilePath : ProblemFileNames) {
+ if (TestFilePath == FilePath)
+ return;
+ }
+ ProblemFileNames.push_back(FilePath);
+}
+
+// Add file with no compile errors.
+// Also standardizes the path.
+void ModularizeUtilities::addNoCompileErrorsFile(std::string FilePath) {
+ FilePath = getCanonicalPath(FilePath);
+ GoodFileNames.push_back(FilePath);
+}
+
+// List problem files.
+void ModularizeUtilities::displayProblemFiles() {
+ errs() << "\nThese are the files with possible errors:\n\n";
+ for (auto &ProblemFile : ProblemFileNames) {
+ errs() << ProblemFile << "\n";
+ }
+}
+
+// List files with no problems.
+void ModularizeUtilities::displayGoodFiles() {
+ errs() << "\nThese are the files with no detected errors:\n\n";
+ for (auto &GoodFile : HeaderFileNames) {
+ bool Good = true;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == GoodFile) {
+ Good = false;
+ break;
+ }
+ }
+ if (Good)
+ errs() << GoodFile << "\n";
+ }
+}
+
+// List files with problem files commented out.
+void ModularizeUtilities::displayCombinedFiles() {
+ errs() <<
+ "\nThese are the combined files, with problem files preceded by #:\n\n";
+ for (auto &File : HeaderFileNames) {
+ bool Good = true;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == File) {
+ Good = false;
+ break;
+ }
+ }
+ errs() << (Good ? "" : "#") << File << "\n";
+ }
+}
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.h b/clang-tools-extra/modularize/ModularizeUtilities.h
index 9c1ee74107d..a3c412e43de 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.h
+++ b/clang-tools-extra/modularize/ModularizeUtilities.h
@@ -43,6 +43,8 @@ public:
std::vector<std::string> InputFilePaths;
/// The header prefix.
llvm::StringRef HeaderPrefix;
+ /// The path of problem files list file.
+ llvm::StringRef ProblemFilesPath;
// Output data.
@@ -54,6 +56,11 @@ public:
bool HasModuleMap;
/// Missing header count.
int MissingHeaderCount;
+ /// List of header files with no problems during the first pass,
+ /// that is, no compile errors.
+ llvm::SmallVector<std::string, 32> GoodFileNames;
+ /// List of header files with problems.
+ llvm::SmallVector<std::string, 32> ProblemFileNames;
// Functions.
@@ -62,16 +69,20 @@ public:
/// of this object.
/// \param InputPaths The input file paths.
/// \param Prefix The headear path prefix.
+ /// \param ProblemFilesListPath The problem header list path.
ModularizeUtilities(std::vector<std::string> &InputPaths,
- llvm::StringRef Prefix);
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath);
/// Create instance of ModularizeUtilities.
/// \param InputPaths The input file paths.
/// \param Prefix The headear path prefix.
+ /// \param ProblemFilesListPath The problem header list path.
/// \returns Initialized ModularizeUtilities object.
static ModularizeUtilities *createModularizeUtilities(
std::vector<std::string> &InputPaths,
- llvm::StringRef Prefix);
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath);
/// Load header list and dependencies.
/// \returns std::error_code.
@@ -95,6 +106,25 @@ public:
std::error_code doCoverageCheck(std::vector<std::string> &IncludePaths,
llvm::ArrayRef<std::string> CommandLine);
+ /// Add unique problem file.
+ /// Also standardizes the path.
+ /// \param FilePath Problem file path.
+ void addUniqueProblemFile(std::string FilePath);
+
+ /// Add file with no compile errors.
+ /// Also standardizes the path.
+ /// \param FilePath Problem file path.
+ void addNoCompileErrorsFile(std::string FilePath);
+
+ /// List problem files.
+ void displayProblemFiles();
+
+ /// List files with no problems.
+ void displayGoodFiles();
+
+ /// List files with problem files commented out.
+ void displayCombinedFiles();
+
// Internal.
protected:
@@ -105,6 +135,12 @@ protected:
std::error_code loadSingleHeaderListsAndDependencies(
llvm::StringRef InputPath);
+ /// Load problem header list.
+ /// \param InputPath The input file path.
+ /// \returns std::error_code.
+ std::error_code loadProblemHeaderList(
+ llvm::StringRef InputPath);
+
/// Load single module map and extract header file list.
/// \param InputPath The input file path.
/// \returns std::error_code.
diff --git a/clang-tools-extra/modularize/ModuleAssistant.cpp b/clang-tools-extra/modularize/ModuleAssistant.cpp
index 8a9b0c43f73..f982f17e8af 100644
--- a/clang-tools-extra/modularize/ModuleAssistant.cpp
+++ b/clang-tools-extra/modularize/ModuleAssistant.cpp
@@ -45,7 +45,7 @@ namespace {
// Represents a module.
class Module {
public:
- Module(llvm::StringRef Name);
+ Module(llvm::StringRef Name, bool Problem);
Module();
~Module();
bool output(llvm::raw_fd_ostream &OS, int Indent);
@@ -55,6 +55,7 @@ public:
std::string Name;
std::vector<std::string> HeaderFileNames;
std::vector<Module *> SubModules;
+ bool IsProblem;
};
} // end anonymous namespace.
@@ -62,8 +63,9 @@ public:
// Module functions:
// Constructors.
-Module::Module(llvm::StringRef Name) : Name(Name) {}
-Module::Module() {}
+Module::Module(llvm::StringRef Name, bool Problem)
+ : Name(Name), IsProblem(Problem) {}
+Module::Module() : IsProblem(false) {}
// Destructor.
Module::~Module() {
@@ -97,7 +99,10 @@ bool Module::output(llvm::raw_fd_ostream &OS, int Indent) {
E = HeaderFileNames.end();
I != E; ++I) {
OS.indent(Indent);
- OS << "header \"" << *I << "\"\n";
+ if (IsProblem)
+ OS << "exclude header \"" << *I << "\"\n";
+ else
+ OS << "header \"" << *I << "\"\n";
}
// If this module has header files, output export directive.
@@ -156,7 +161,8 @@ ensureNoCollisionWithReservedName(llvm::StringRef MightBeReservedName) {
static bool addModuleDescription(Module *RootModule,
llvm::StringRef HeaderFilePath,
llvm::StringRef HeaderPrefix,
- DependencyMap &Dependencies) {
+ DependencyMap &Dependencies,
+ bool IsProblemFile) {
Module *CurrentModule = RootModule;
DependentsVector &FileDependents = Dependencies[HeaderFilePath];
std::string FilePath;
@@ -191,7 +197,7 @@ static bool addModuleDescription(Module *RootModule,
Stem = ensureNoCollisionWithReservedName(Stem);
Module *SubModule = CurrentModule->findSubModule(Stem);
if (!SubModule) {
- SubModule = new Module(Stem);
+ SubModule = new Module(Stem, IsProblemFile);
CurrentModule->SubModules.push_back(SubModule);
}
CurrentModule = SubModule;
@@ -204,10 +210,11 @@ static bool addModuleDescription(Module *RootModule,
// Create the internal module tree representation.
static Module *loadModuleDescriptions(
llvm::StringRef RootModuleName, llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
DependencyMap &Dependencies, llvm::StringRef HeaderPrefix) {
// Create root module.
- Module *RootModule = new Module(RootModuleName);
+ Module *RootModule = new Module(RootModuleName, false);
llvm::SmallString<256> CurrentDirectory;
llvm::sys::fs::current_path(CurrentDirectory);
@@ -220,8 +227,16 @@ static Module *loadModuleDescriptions(
for (llvm::ArrayRef<std::string>::iterator I = HeaderFileNames.begin(),
E = HeaderFileNames.end();
I != E; ++I) {
+ std::string Header(*I);
+ bool IsProblemFile = false;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == Header) {
+ IsProblemFile = true;
+ break;
+ }
+ }
// Add as a module.
- if (!addModuleDescription(RootModule, *I, HeaderPrefix, Dependencies))
+ if (!addModuleDescription(RootModule, Header, HeaderPrefix, Dependencies, IsProblemFile))
return nullptr;
}
@@ -277,11 +292,14 @@ static bool writeModuleMap(llvm::StringRef ModuleMapPath,
// Module map generation entry point.
bool createModuleMap(llvm::StringRef ModuleMapPath,
llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
DependencyMap &Dependencies, llvm::StringRef HeaderPrefix,
llvm::StringRef RootModuleName) {
// Load internal representation of modules.
- std::unique_ptr<Module> RootModule(loadModuleDescriptions(
- RootModuleName, HeaderFileNames, Dependencies, HeaderPrefix));
+ std::unique_ptr<Module> RootModule(
+ loadModuleDescriptions(
+ RootModuleName, HeaderFileNames, ProblemFileNames, Dependencies,
+ HeaderPrefix));
if (!RootModule.get())
return false;
diff --git a/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h b/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h
new file mode 100644
index 00000000000..4395cb166de
--- /dev/null
+++ b/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h
@@ -0,0 +1,2 @@
+typedef WithoutDep BadType;
+
diff --git a/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h b/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h
new file mode 100644
index 00000000000..10eef6787e4
--- /dev/null
+++ b/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h
@@ -0,0 +1 @@
+#define MACRO_1A 1
diff --git a/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap b/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap
new file mode 100644
index 00000000000..fbb8e7db4d1
--- /dev/null
+++ b/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap
@@ -0,0 +1,10 @@
+// module.map
+
+module Level1A {
+ header "Level1A.h"
+ export *
+}
+module HasError {
+ header "HasError.h"
+ export *
+}
diff --git a/clang-tools-extra/test/modularize/ProblemsCompileError.modularize b/clang-tools-extra/test/modularize/ProblemsCompileError.modularize
new file mode 100644
index 00000000000..a7ad29862b1
--- /dev/null
+++ b/clang-tools-extra/test/modularize/ProblemsCompileError.modularize
@@ -0,0 +1,3 @@
+# RUN: not modularize %S/Inputs/CompileError/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}CompileError{{[/\\]}}HasError.h:1:9: error: unknown type name 'WithoutDep'
diff --git a/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize b/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize
new file mode 100644
index 00000000000..31be95c6b6b
--- /dev/null
+++ b/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize
@@ -0,0 +1,16 @@
+# RUN: not modularize -display-file-lists %S/Inputs/CompileError/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}CompileError{{[/\\]}}HasError.h:1:9: error: unknown type name 'WithoutDep'
+
+# CHECK: These are the files with possible errors:
+
+# CHECK: Inputs/CompileError/HasError.h
+
+# CHECK: These are the files with no detected errors:
+
+# CHECK: Inputs/CompileError/Level1A.h
+
+# CHECK: These are the combined files, with problem files preceded by #:
+
+# CHECK: {{.*}}Inputs/CompileError/HasError.h
+# CHECK: Inputs/CompileError/Level1A.h
OpenPOWER on IntegriCloud