16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Driver/Options.h"
18 #include "clang/Frontend/CompilerInstance.h"
19 #include "clang/Frontend/FrontendActions.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Support/FileUtilities.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/raw_ostream.h"
28 using namespace clang;
30 using namespace Modularize;
35 class ModuleMapTargetOptions :
public clang::TargetOptions {
37 ModuleMapTargetOptions() { Triple = llvm::sys::getDefaultTargetTriple(); }
44 ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
45 llvm::StringRef Prefix,
46 llvm::StringRef ProblemFilesListPath)
47 : InputFilePaths(InputPaths),
49 ProblemFilesPath(ProblemFilesListPath),
51 MissingHeaderCount(0),
53 LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
54 DiagnosticOpts(new DiagnosticOptions()),
55 DC(llvm::errs(), DiagnosticOpts.get()),
57 new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
58 TargetOpts(new ModuleMapTargetOptions()),
59 Target(TargetInfo::CreateTargetInfo(*Diagnostics, TargetOpts)),
60 FileMgr(new FileManager(FileSystemOpts)),
61 SourceMgr(new SourceManager(*Diagnostics, *FileMgr, false)),
62 HeaderSearchOpts(new HeaderSearchOptions()),
63 HeaderInfo(new HeaderSearch(HeaderSearchOpts, *
SourceMgr, *Diagnostics,
70 std::vector<std::string> &InputPaths, llvm::StringRef Prefix,
71 llvm::StringRef ProblemFilesListPath) {
78 typedef std::vector<std::string>::iterator Iter;
81 llvm::StringRef InputPath = *I;
83 if (InputPath.endswith(
".modulemap")) {
91 errs() <<
"modularize: error: Unable to get header list '" << InputPath
92 <<
"': " << EC.message() <<
'\n';
101 errs() <<
"modularize: error: Unable to get problem header list '" <<
ProblemFilesPath
102 <<
"': " << EC.message() <<
'\n';
106 return std::error_code();
125 for (ModuleMapIndex = 0; ModuleMapIndex < ModuleMapCount; ++ModuleMapIndex) {
126 std::unique_ptr<clang::ModuleMap> &ModMap =
ModuleMaps[ModuleMapIndex];
128 InputFilePaths[ModuleMapIndex], IncludePaths, CommandLine, ModMap.get());
129 std::error_code LocalEC = Checker->
doChecks();
130 if (LocalEC.value() > 0)
138 llvm::StringRef InputPath) {
141 SmallString<256> HeaderDirectory(InputPath);
142 llvm::sys::path::remove_filename(HeaderDirectory);
143 SmallString<256> CurrentDirectory;
144 llvm::sys::fs::current_path(CurrentDirectory);
151 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
152 MemoryBuffer::getFile(InputPath);
153 if (std::error_code EC = listBuffer.getError())
157 SmallVector<StringRef, 32>
Strings;
158 listBuffer.get()->getBuffer().split(Strings,
"\n", -1,
false);
161 for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
164 StringRef
Line = I->trim();
166 if (Line.empty() || (Line[0] ==
'#'))
168 std::pair<StringRef, StringRef> TargetAndDependents = Line.split(
':');
169 SmallString<256> HeaderFileName;
171 if (llvm::sys::path::is_absolute(TargetAndDependents.first))
172 llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
174 if (HeaderDirectory.size() != 0)
175 HeaderFileName = HeaderDirectory;
177 HeaderFileName = CurrentDirectory;
178 llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
179 llvm::sys::path::native(HeaderFileName);
183 SmallVector<StringRef, 4> DependentsList;
184 TargetAndDependents.second.split(DependentsList,
" ", -1,
false);
185 int Count = DependentsList.size();
186 for (
int Index = 0; Index < Count; ++Index) {
187 SmallString<256> Dependent;
188 if (llvm::sys::path::is_absolute(DependentsList[Index]))
189 Dependent = DependentsList[Index];
191 if (HeaderDirectory.size() != 0)
192 Dependent = HeaderDirectory;
194 Dependent = CurrentDirectory;
195 llvm::sys::path::append(Dependent, DependentsList[Index]);
197 llvm::sys::path::native(Dependent);
206 return std::error_code();
211 llvm::StringRef InputPath) {
214 SmallString<256> HeaderDirectory(InputPath);
215 llvm::sys::path::remove_filename(HeaderDirectory);
216 SmallString<256> CurrentDirectory;
217 llvm::sys::fs::current_path(CurrentDirectory);
224 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
225 MemoryBuffer::getFile(InputPath);
226 if (std::error_code EC = listBuffer.getError())
230 SmallVector<StringRef, 32>
Strings;
231 listBuffer.get()->getBuffer().split(Strings,
"\n", -1,
false);
234 for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
237 StringRef
Line = I->trim();
239 if (Line.empty() || (Line[0] ==
'#'))
241 SmallString<256> HeaderFileName;
243 if (llvm::sys::path::is_absolute(Line))
244 llvm::sys::path::native(Line, HeaderFileName);
246 if (HeaderDirectory.size() != 0)
247 HeaderFileName = HeaderDirectory;
249 HeaderFileName = CurrentDirectory;
250 llvm::sys::path::append(HeaderFileName, Line);
251 llvm::sys::path::native(HeaderFileName);
258 return std::error_code();
263 llvm::StringRef InputPath) {
265 const FileEntry *ModuleMapEntry =
266 SourceMgr->getFileManager().getFile(InputPath);
269 if (!ModuleMapEntry) {
270 llvm::errs() <<
"error: File \"" << InputPath <<
"\" not found.\n";
271 return std::error_code(1, std::generic_category());
279 const DirectoryEntry *Dir = ModuleMapEntry->getDir();
280 StringRef DirName(Dir->getName());
281 if (llvm::sys::path::filename(DirName) ==
"Modules") {
282 DirName = llvm::sys::path::parent_path(DirName);
283 if (DirName.endswith(
".framework"))
284 Dir =
FileMgr->getDirectory(DirName);
287 assert(Dir &&
"parent must exist");
290 std::unique_ptr<ModuleMap> ModMap;
295 if (ModMap->parseModuleMapFile(ModuleMapEntry,
false, Dir)) {
296 return std::error_code(1, std::generic_category());
306 return std::error_code(1, std::generic_category());
316 return std::error_code(1, std::generic_category());
318 return std::error_code();
325 for (ModuleMap::module_iterator I = ModMap->module_begin(),
326 E = ModMap->module_end();
348 for (Module::submodule_const_iterator MI = Mod.submodule_begin(),
349 MIEnd = Mod.submodule_end();
353 if (
const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader().Entry) {
360 else if (
const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir().Entry) {
362 if (Mod.Headers->size() == 0) {
374 int NormalHeaderCount = Mod.Headers[clang::Module::HK_Normal].size();
376 for (
int Index = 0; Index < NormalHeaderCount; ++Index) {
379 const clang::Module::Header &Header(
380 Mod.Headers[clang::Module::HK_Normal][Index]);
385 int MissingCountThisModule = Mod.MissingHeaders.size();
387 for (
int Index = 0; Index < MissingCountThisModule; ++Index) {
388 std::string MissingFile = Mod.MissingHeaders[Index].FileName;
389 SourceLocation
Loc = Mod.MissingHeaders[Index].FileNameLoc;
391 <<
": error : Header not found: " << MissingFile <<
"\n";
403 SmallString<256>
Directory(UmbrellaDirName);
406 llvm::sys::fs::file_status Status;
407 for (llvm::sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
411 std::string
File(I->path());
413 llvm::sys::fs::file_type Type = Status.type();
415 if (Type == llvm::sys::fs::file_type::directory_file) {
425 Dependents.push_back(HeaderPath);
433 SmallString<128> Buffer;
434 llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
435 E = llvm::sys::path::end(Path);
437 if (B->compare(
".") == 0) {
439 else if (B->compare(
"..") == 0)
440 llvm::sys::path::remove_filename(Buffer);
442 llvm::sys::path::append(Buffer, *B);
445 if (Path.endswith(
"/") || Path.endswith(
"\\"))
446 Buffer.append(1, Path.back());
447 return Buffer.c_str();
456 std::replace(Tmp.begin(), Tmp.end(),
'\\',
'/');
458 if (Tmp2.startswith(
"./"))
459 Tmp = Tmp2.substr(2);
469 StringRef Extension = llvm::sys::path::extension(FileName);
470 if (Extension.size() == 0)
472 if (Extension.equals_lower(
".h"))
474 if (Extension.equals_lower(
".inc"))
486 sys::path::remove_filename(Directory);
487 if (Directory.size() == 0)
489 return Directory.str();
498 if (TestFilePath == FilePath)
501 ProblemFileNames.push_back(FilePath);
513 errs() <<
"\nThese are the files with possible errors:\n\n";
515 errs() << ProblemFile <<
"\n";
521 errs() <<
"\nThese are the files with no detected errors:\n\n";
525 if (ProblemFile == GoodFile) {
531 errs() << GoodFile <<
"\n";
538 "\nThese are the combined files, with problem files preceded by #:\n\n";
542 if (ProblemFile ==
File) {
547 errs() << (Good ?
"" :
"#") <<
File <<
"\n";
ModularizeUtilities(std::vector< std::string > &InputPaths, llvm::StringRef Prefix, llvm::StringRef ProblemFilesListPath)
Constructor.
SourceLocation Loc
'#' location in the include directive
void displayGoodFiles()
List files with no problems.
DependencyMap Dependencies
Map of top-level header file dependencies.
std::error_code doCoverageCheck(std::vector< std::string > &IncludePaths, llvm::ArrayRef< std::string > CommandLine)
Do coverage checks.
llvm::IntrusiveRefCntPtr< clang::DiagnosticsEngine > Diagnostics
Diagnostic engine.
static std::string getCanonicalPath(llvm::StringRef FilePath)
Convert header path to canonical form.
llvm::SmallVector< std::string, 4 > DependentsVector
void displayCombinedFiles()
List files with problem files commented out.
std::error_code loadProblemHeaderList(llvm::StringRef InputPath)
Load problem header list.
static std::string getDirectoryFromPath(llvm::StringRef Path)
Get directory path component from file path.
bool HasModuleMap
True if we have module maps.
static cl::opt< std::string > HeaderPrefix("prefix", cl::init(""), cl::desc("Prepend header file paths with this prefix."" If not specified,"" the files are considered to be relative to the header list file."))
std::error_code loadSingleHeaderListsAndDependencies(llvm::StringRef InputPath)
Load single header list and dependencies.
llvm::IntrusiveRefCntPtr< clang::TargetInfo > Target
Target information.
static ModularizeUtilities * createModularizeUtilities(std::vector< std::string > &InputPaths, llvm::StringRef Prefix, llvm::StringRef ProblemFilesListPath)
Create instance of ModularizeUtilities.
llvm::IntrusiveRefCntPtr< clang::FileManager > FileMgr
File system manager.
clang::TextDiagnosticPrinter DC
Diagnostic consumer.
std::unique_ptr< clang::HeaderSearch > HeaderInfo
Header search manager.
std::vector< HeaderHandle > Path
ModularizeUtilities class definition.
std::shared_ptr< clang::LangOptions > LangOpts
Options controlling the language variant.
bool collectModuleMapHeaders(clang::ModuleMap *ModMap)
Collect module Map headers.
llvm::StringRef ProblemFilesPath
The path of problem files list file.
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
Definitions for CoverageChecker.
int MissingHeaderCount
Missing header count.
std::error_code loadModuleMap(llvm::StringRef InputPath)
Load single module map and extract header file list.
std::error_code loadAllHeaderListsAndDependencies()
Load header list and dependencies.
llvm::SmallVector< std::string, 32 > ProblemFileNames
List of header files with problems.
std::error_code doChecks()
Do checks.
llvm::SmallVector< std::string, 32 > GoodFileNames
List of header files with no problems during the first pass, that is, no compile errors.
Modularize utilities class.
llvm::SmallVector< std::string, 32 > HeaderFileNames
List of top-level header files.
llvm::IntrusiveRefCntPtr< clang::SourceManager > SourceMgr
Source manager.
static cl::list< std::string > IncludePaths("I", cl::desc("Include path for coverage check."), cl::ZeroOrMore, cl::value_desc("path"))
llvm::StringRef HeaderPrefix
The header prefix.
bool collectModuleHeaders(const clang::Module &Mod)
Collect referenced headers from one module.
static CoverageChecker * createCoverageChecker(llvm::StringRef ModuleMapPath, std::vector< std::string > &IncludePaths, llvm::ArrayRef< std::string > CommandLine, clang::ModuleMap *ModuleMap)
Create instance of CoverageChecker.
Module map checker class.
std::vector< std::unique_ptr< clang::ModuleMap > > ModuleMaps
bool collectUmbrellaHeaders(llvm::StringRef UmbrellaDirName, DependentsVector &Dependents)
Collect headers from an umbrella directory.
void addUniqueProblemFile(std::string FilePath)
Add unique problem file.
void displayProblemFiles()
List problem files.
std::vector< std::string > InputFilePaths
The input file paths.
static std::string replaceDotDot(StringRef Path)
static bool isHeader(llvm::StringRef FileName)
Check for header file extension.
void addNoCompileErrorsFile(std::string FilePath)
Add file with no compile errors.