15#include "clang/Basic/SourceManager.h"
16#include "clang/Driver/Options.h"
17#include "clang/Frontend/CompilerInstance.h"
18#include "clang/Frontend/FrontendActions.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/Support/FileUtilities.h"
22#include "llvm/Support/MemoryBuffer.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/raw_ostream.h"
34class ModuleMapTargetOptions :
public clang::TargetOptions {
36 ModuleMapTargetOptions() { Triple = llvm::sys::getDefaultTargetTriple(); }
44 llvm::StringRef Prefix,
45 llvm::StringRef ProblemFilesListPath)
63 std::vector<std::string> &InputPaths, llvm::StringRef Prefix,
64 llvm::StringRef ProblemFilesListPath) {
74 if (InputPath.ends_with(
".modulemap")) {
81 errs() <<
"modularize: error: Unable to get header list '" << InputPath
82 <<
"': " << EC.message() <<
'\n';
91 errs() <<
"modularize: error: Unable to get problem header list '" <<
ProblemFilesPath
92 <<
"': " << EC.message() <<
'\n';
96 return std::error_code();
115 for (ModuleMapIndex = 0; ModuleMapIndex < ModuleMapCount; ++ModuleMapIndex) {
116 std::unique_ptr<clang::ModuleMap> &ModMap =
ModuleMaps[ModuleMapIndex];
120 std::error_code LocalEC = Checker->doChecks();
121 if (LocalEC.value() > 0)
129 llvm::StringRef InputPath) {
132 SmallString<256> HeaderDirectory(InputPath);
133 llvm::sys::path::remove_filename(HeaderDirectory);
134 SmallString<256> CurrentDirectory;
135 llvm::sys::fs::current_path(CurrentDirectory);
142 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
143 MemoryBuffer::getFile(InputPath);
144 if (std::error_code EC = listBuffer.getError())
148 SmallVector<StringRef, 32> Strings;
149 listBuffer.get()->getBuffer().split(Strings,
"\n", -1,
false);
155 StringRef Line = I->trim();
157 if (Line.empty() || (Line[0] ==
'#'))
159 std::pair<StringRef, StringRef> TargetAndDependents = Line.split(
':');
160 SmallString<256> HeaderFileName;
162 if (llvm::sys::path::is_absolute(TargetAndDependents.first))
163 llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
165 if (HeaderDirectory.size() != 0)
166 HeaderFileName = HeaderDirectory;
168 HeaderFileName = CurrentDirectory;
169 llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
170 llvm::sys::path::native(HeaderFileName);
174 SmallVector<StringRef, 4> DependentsList;
175 TargetAndDependents.second.split(DependentsList,
" ", -1,
false);
176 int Count = DependentsList.size();
177 for (
int Index = 0; Index < Count; ++Index) {
178 SmallString<256> Dependent;
179 if (llvm::sys::path::is_absolute(DependentsList[Index]))
180 Dependent = DependentsList[Index];
182 if (HeaderDirectory.size() != 0)
183 Dependent = HeaderDirectory;
185 Dependent = CurrentDirectory;
186 llvm::sys::path::append(Dependent, DependentsList[Index]);
188 llvm::sys::path::native(Dependent);
197 return std::error_code();
202 llvm::StringRef InputPath) {
205 SmallString<256> HeaderDirectory(InputPath);
206 llvm::sys::path::remove_filename(HeaderDirectory);
207 SmallString<256> CurrentDirectory;
208 llvm::sys::fs::current_path(CurrentDirectory);
215 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
216 MemoryBuffer::getFile(InputPath);
217 if (std::error_code EC = listBuffer.getError())
221 SmallVector<StringRef, 32> Strings;
222 listBuffer.get()->getBuffer().split(Strings,
"\n", -1,
false);
228 StringRef Line = I->trim();
230 if (Line.empty() || (Line[0] ==
'#'))
232 SmallString<256> HeaderFileName;
234 if (llvm::sys::path::is_absolute(Line))
235 llvm::sys::path::native(Line, HeaderFileName);
237 if (HeaderDirectory.size() != 0)
238 HeaderFileName = HeaderDirectory;
240 HeaderFileName = CurrentDirectory;
241 llvm::sys::path::append(HeaderFileName, Line);
242 llvm::sys::path::native(HeaderFileName);
249 return std::error_code();
254 llvm::StringRef InputPath) {
256 auto ModuleMapEntryOrErr =
SourceMgr->getFileManager().getFileRef(InputPath);
259 if (!ModuleMapEntryOrErr) {
260 llvm::errs() <<
"error: File \"" << InputPath <<
"\" not found.\n";
261 return errorToErrorCode(ModuleMapEntryOrErr.takeError());
263 FileEntryRef ModuleMapEntry = *ModuleMapEntryOrErr;
270 DirectoryEntryRef Dir = ModuleMapEntry.getDir();
271 StringRef DirName(Dir.getName());
272 if (llvm::sys::path::filename(DirName) ==
"Modules") {
273 DirName = llvm::sys::path::parent_path(DirName);
274 if (DirName.ends_with(
".framework")) {
275 auto FrameworkDirOrErr =
FileMgr->getDirectoryRef(DirName);
276 if (!FrameworkDirOrErr) {
279 return errorToErrorCode(FrameworkDirOrErr.takeError());
281 Dir = *FrameworkDirOrErr;
285 std::unique_ptr<ModuleMap> ModMap;
290 if (ModMap->parseAndLoadModuleMapFile(ModuleMapEntry,
false, Dir)) {
291 return std::error_code(1, std::generic_category());
301 return std::error_code(1, std::generic_category());
311 return std::error_code(1, std::generic_category());
313 return std::error_code();
320 SmallVector<std::pair<StringRef, const clang::Module *>, 0> Vec;
321 for (
auto &M : ModMap->modules())
322 Vec.emplace_back(M.first(), M.second);
323 llvm::sort(Vec, llvm::less_first());
344 for (
auto *Submodule : Mod.submodules())
347 if (std::optional<clang::Module::Header> UmbrellaHeader =
348 Mod.getUmbrellaHeaderAsWritten()) {
354 }
else if (std::optional<clang::Module::DirectoryName> UmbrellaDir =
355 Mod.getUmbrellaDirAsWritten()) {
357 if (Mod.getHeaders(Module::HK_Normal).empty()) {
370 for (
const auto &Header : Mod.getHeaders(clang::Module::HK_Normal))
373 int MissingCountThisModule = Mod.MissingHeaders.size();
375 for (
int Index = 0; Index < MissingCountThisModule; ++Index) {
376 std::string MissingFile = Mod.MissingHeaders[Index].FileName;
377 SourceLocation Loc = Mod.MissingHeaders[Index].FileNameLoc;
379 <<
": error : Header not found: " << MissingFile <<
"\n";
391 SmallString<256>
Directory(UmbrellaDirName);
394 for (llvm::sys::fs::directory_iterator I(
Directory.str(), EC), E; I != E;
398 std::string File(I->path());
399 llvm::ErrorOr<llvm::sys::fs::basic_file_status> Status = I->status();
402 llvm::sys::fs::file_type Type = Status->type();
404 if (Type == llvm::sys::fs::file_type::directory_file) {
414 Dependents.push_back(HeaderPath);
422 SmallString<128> Buffer;
423 llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
424 E = llvm::sys::path::end(Path);
427 llvm::sys::path::remove_filename(Buffer);
429 llvm::sys::path::append(Buffer, *B);
432 if (Path.ends_with(
"/") || Path.ends_with(
"\\"))
433 Buffer.append(1, Path.back());
434 return Buffer.c_str();
443 llvm::replace(Tmp,
'\\',
'/');
445 if (Tmp2.starts_with(
"./"))
446 Tmp = std::string(Tmp2.substr(2));
456 StringRef Extension = llvm::sys::path::extension(FileName);
457 if (Extension.size() == 0)
459 if (Extension.equals_insensitive(
".h"))
461 if (Extension.equals_insensitive(
".inc"))
485 if (TestFilePath == FilePath)
500 errs() <<
"\nThese are the files with possible errors:\n\n";
502 errs() << ProblemFile <<
"\n";
508 errs() <<
"\nThese are the files with no detected errors:\n\n";
512 if (ProblemFile == GoodFile) {
518 errs() << GoodFile <<
"\n";
525 "\nThese are the combined files, with problem files preceded by #:\n\n";
529 if (ProblemFile == File) {
534 errs() << (Good ?
"" :
"#") << File <<
"\n";
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
Definitions for CoverageChecker.
static std::string replaceDotDot(StringRef Path)
ModularizeUtilities class definition.
static cl::list< std::string > IncludePaths("I", cl::desc("Include path for coverage check."), cl::value_desc("path"))
llvm::SmallVector< std::string, 4 > DependentsVector
static std::unique_ptr< CoverageChecker > createCoverageChecker(llvm::StringRef ModuleMapPath, std::vector< std::string > &IncludePaths, llvm::ArrayRef< std::string > CommandLine, clang::ModuleMap *ModuleMap)
Create instance of CoverageChecker.
llvm::SmallVector< std::string, 32 > GoodFileNames
List of header files with no problems during the first pass, that is, no compile errors.
ModularizeUtilities(std::vector< std::string > &InputPaths, llvm::StringRef Prefix, llvm::StringRef ProblemFilesListPath)
Constructor.
static std::string getCanonicalPath(llvm::StringRef FilePath)
Convert header path to canonical form.
std::vector< std::string > InputFilePaths
The input file paths.
clang::HeaderSearchOptions HSOpts
Header search options.
std::error_code loadAllHeaderListsAndDependencies()
Load header list and dependencies.
bool collectModuleMapHeaders(clang::ModuleMap *ModMap)
Collect module Map headers.
void displayProblemFiles()
List problem files.
const llvm::IntrusiveRefCntPtr< clang::DiagnosticIDs > DiagIDs
Diagnostic IDs.
std::error_code loadModuleMap(llvm::StringRef InputPath)
Load single module map and extract header file list.
clang::TextDiagnosticPrinter DC
Diagnostic consumer.
std::shared_ptr< clang::TargetOptions > TargetOpts
Options controlling the target.
DependencyMap Dependencies
Map of top-level header file dependencies.
static ModularizeUtilities * createModularizeUtilities(std::vector< std::string > &InputPaths, llvm::StringRef Prefix, llvm::StringRef ProblemFilesListPath)
Create instance of ModularizeUtilities.
llvm::IntrusiveRefCntPtr< clang::SourceManager > SourceMgr
Source manager.
std::error_code loadProblemHeaderList(llvm::StringRef InputPath)
Load problem header list.
bool collectModuleHeaders(const clang::Module &Mod)
Collect referenced headers from one module.
llvm::SmallVector< std::string, 32 > ProblemFileNames
List of header files with problems.
std::unique_ptr< clang::HeaderSearch > HeaderInfo
Header search manager.
llvm::IntrusiveRefCntPtr< clang::TargetInfo > Target
Target information.
llvm::StringRef HeaderPrefix
The header prefix.
std::vector< std::unique_ptr< clang::ModuleMap > > ModuleMaps
void displayCombinedFiles()
List files with problem files commented out.
void addNoCompileErrorsFile(std::string FilePath)
Add file with no compile errors.
void displayGoodFiles()
List files with no problems.
std::shared_ptr< clang::LangOptions > LangOpts
Options controlling the language variant.
llvm::IntrusiveRefCntPtr< clang::FileManager > FileMgr
File system manager.
bool collectUmbrellaHeaders(llvm::StringRef UmbrellaDirName, DependentsVector &Dependents)
Collect headers from an umbrella directory.
llvm::IntrusiveRefCntPtr< clang::DiagnosticsEngine > Diagnostics
Diagnostic engine.
clang::DiagnosticOptions DiagnosticOpts
Options controlling the diagnostic engine.
int MissingHeaderCount
Missing header count.
static bool isHeader(llvm::StringRef FileName)
Check for header file extension.
llvm::StringRef ProblemFilesPath
The path of problem files list file.
std::error_code loadSingleHeaderListsAndDependencies(llvm::StringRef InputPath)
Load single header list and dependencies.
llvm::SmallVector< std::string, 32 > HeaderFileNames
List of top-level header files.
std::error_code doCoverageCheck(std::vector< std::string > &IncludePaths, llvm::ArrayRef< std::string > CommandLine)
Do coverage checks.
bool HasModuleMap
True if we have module maps.
clang::FileSystemOptions FileSystemOpts
Options controlling the file system manager.
void addUniqueProblemFile(std::string FilePath)
Add unique problem file.
static std::string getDirectoryFromPath(llvm::StringRef Path)
Get directory path component from file path.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.