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)
47 ProblemFilesPath(ProblemFilesListPath), HasModuleMap(false),
48 MissingHeaderCount(0),
50 LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
51 DiagnosticOpts(new DiagnosticOptions()),
52 DC(
llvm::errs(), DiagnosticOpts.get()),
54 new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
55 TargetOpts(new ModuleMapTargetOptions()),
56 Target(TargetInfo::CreateTargetInfo(*
Diagnostics, TargetOpts)),
57 FileMgr(new FileManager(FileSystemOpts)),
58 SourceMgr(new SourceManager(*
Diagnostics, *FileMgr, false)),
59 HeaderInfo(new HeaderSearch(std::make_shared<HeaderSearchOptions>(),
66 std::vector<std::string> &InputPaths, llvm::StringRef Prefix,
67 llvm::StringRef ProblemFilesListPath) {
76 llvm::StringRef InputPath = *I;
78 if (InputPath.ends_with(
".modulemap")) {
85 errs() <<
"modularize: error: Unable to get header list '" << InputPath
86 <<
"': " << EC.message() <<
'\n';
95 errs() <<
"modularize: error: Unable to get problem header list '" <<
ProblemFilesPath
96 <<
"': " << EC.message() <<
'\n';
100 return std::error_code();
119 for (ModuleMapIndex = 0; ModuleMapIndex < ModuleMapCount; ++ModuleMapIndex) {
120 std::unique_ptr<clang::ModuleMap> &ModMap =
ModuleMaps[ModuleMapIndex];
124 std::error_code LocalEC = Checker->doChecks();
125 if (LocalEC.value() > 0)
133 llvm::StringRef InputPath) {
136 SmallString<256> HeaderDirectory(InputPath);
137 llvm::sys::path::remove_filename(HeaderDirectory);
138 SmallString<256> CurrentDirectory;
139 llvm::sys::fs::current_path(CurrentDirectory);
146 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
147 MemoryBuffer::getFile(InputPath);
148 if (std::error_code EC = listBuffer.getError())
152 SmallVector<StringRef, 32>
Strings;
153 listBuffer.get()->getBuffer().split(
Strings,
"\n", -1,
false);
159 StringRef
Line = I->trim();
161 if (
Line.empty() || (
Line[0] ==
'#'))
163 std::pair<StringRef, StringRef> TargetAndDependents =
Line.split(
':');
164 SmallString<256> HeaderFileName;
166 if (llvm::sys::path::is_absolute(TargetAndDependents.first))
167 llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
169 if (HeaderDirectory.size() != 0)
170 HeaderFileName = HeaderDirectory;
172 HeaderFileName = CurrentDirectory;
173 llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
174 llvm::sys::path::native(HeaderFileName);
178 SmallVector<StringRef, 4> DependentsList;
179 TargetAndDependents.second.split(DependentsList,
" ", -1,
false);
180 int Count = DependentsList.size();
181 for (
int Index = 0; Index < Count; ++Index) {
182 SmallString<256> Dependent;
183 if (llvm::sys::path::is_absolute(DependentsList[Index]))
184 Dependent = DependentsList[Index];
186 if (HeaderDirectory.size() != 0)
187 Dependent = HeaderDirectory;
189 Dependent = CurrentDirectory;
190 llvm::sys::path::append(Dependent, DependentsList[Index]);
192 llvm::sys::path::native(Dependent);
201 return std::error_code();
206 llvm::StringRef InputPath) {
209 SmallString<256> HeaderDirectory(InputPath);
210 llvm::sys::path::remove_filename(HeaderDirectory);
211 SmallString<256> CurrentDirectory;
212 llvm::sys::fs::current_path(CurrentDirectory);
219 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
220 MemoryBuffer::getFile(InputPath);
221 if (std::error_code EC = listBuffer.getError())
225 SmallVector<StringRef, 32>
Strings;
226 listBuffer.get()->getBuffer().split(
Strings,
"\n", -1,
false);
232 StringRef
Line = I->trim();
234 if (
Line.empty() || (
Line[0] ==
'#'))
236 SmallString<256> HeaderFileName;
238 if (llvm::sys::path::is_absolute(
Line))
239 llvm::sys::path::native(
Line, HeaderFileName);
241 if (HeaderDirectory.size() != 0)
242 HeaderFileName = HeaderDirectory;
244 HeaderFileName = CurrentDirectory;
245 llvm::sys::path::append(HeaderFileName,
Line);
246 llvm::sys::path::native(HeaderFileName);
253 return std::error_code();
258 llvm::StringRef InputPath) {
260 auto ModuleMapEntryOrErr =
SourceMgr->getFileManager().getFileRef(InputPath);
263 if (!ModuleMapEntryOrErr) {
264 llvm::errs() <<
"error: File \"" << InputPath <<
"\" not found.\n";
265 return errorToErrorCode(ModuleMapEntryOrErr.takeError());
267 FileEntryRef ModuleMapEntry = *ModuleMapEntryOrErr;
274 DirectoryEntryRef Dir = ModuleMapEntry.getDir();
275 StringRef DirName(Dir.getName());
276 if (llvm::sys::path::filename(DirName) ==
"Modules") {
277 DirName = llvm::sys::path::parent_path(DirName);
278 if (DirName.ends_with(
".framework")) {
279 auto FrameworkDirOrErr =
FileMgr->getDirectoryRef(DirName);
280 if (!FrameworkDirOrErr) {
283 return errorToErrorCode(FrameworkDirOrErr.takeError());
285 Dir = *FrameworkDirOrErr;
289 std::unique_ptr<ModuleMap> ModMap;
294 if (ModMap->parseModuleMapFile(ModuleMapEntry,
false, Dir)) {
295 return std::error_code(1, std::generic_category());
305 return std::error_code(1, std::generic_category());
315 return std::error_code(1, std::generic_category());
317 return std::error_code();
324 SmallVector<std::pair<StringRef, const clang::Module *>, 0> Vec;
325 for (
auto &
M : ModMap->modules())
326 Vec.emplace_back(
M.first(),
M.second);
327 llvm::sort(Vec, llvm::less_first());
348 for (
auto *Submodule : Mod.submodules())
351 if (std::optional<clang::Module::Header> UmbrellaHeader =
352 Mod.getUmbrellaHeaderAsWritten()) {
358 }
else if (std::optional<clang::Module::DirectoryName> UmbrellaDir =
359 Mod.getUmbrellaDirAsWritten()) {
361 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 for (llvm::sys::fs::directory_iterator I(
Directory.str(), EC),
E; I !=
E;
410 std::string File(I->path());
411 llvm::ErrorOr<llvm::sys::fs::basic_file_status> Status = I->status();
414 llvm::sys::fs::file_type
Type = Status->type();
416 if (
Type == llvm::sys::fs::file_type::directory_file) {
426 Dependents.push_back(HeaderPath);
434 SmallString<128> Buffer;
435 llvm::sys::path::const_iterator B = llvm::sys::path::begin(
Path),
436 E = llvm::sys::path::end(
Path);
439 llvm::sys::path::remove_filename(Buffer);
441 llvm::sys::path::append(Buffer, *B);
444 if (
Path.ends_with(
"/") ||
Path.ends_with(
"\\"))
445 Buffer.append(1,
Path.back());
446 return Buffer.c_str();
455 std::replace(Tmp.begin(), Tmp.end(),
'\\',
'/');
457 if (Tmp2.starts_with(
"./"))
458 Tmp = std::string(Tmp2.substr(2));
468 StringRef Extension = llvm::sys::path::extension(
FileName);
469 if (Extension.size() == 0)
471 if (Extension.equals_insensitive(
".h"))
473 if (Extension.equals_insensitive(
".inc"))
497 if (TestFilePath == FilePath)
512 errs() <<
"\nThese are the files with possible errors:\n\n";
514 errs() << ProblemFile <<
"\n";
520 errs() <<
"\nThese are the files with no detected errors:\n\n";
524 if (ProblemFile == GoodFile) {
530 errs() << GoodFile <<
"\n";
537 "\nThese are the combined files, with problem files preceded by #:\n\n";
541 if (ProblemFile == File) {
546 errs() << (Good ?
"" :
"#") << File <<
"\n";
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"))
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."))
llvm::SmallVector< std::string, 4 > DependentsVector
std::vector< HeaderHandle > Path
std::vector< llvm::StringRef > Strings
std::vector< llvm::StringRef > CommandLine
llvm::StringRef Directory
const google::protobuf::Message & M
WantDiagnostics Diagnostics
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.
Modularize utilities class.
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.
std::error_code loadAllHeaderListsAndDependencies()
Load header list and dependencies.
bool collectModuleMapHeaders(clang::ModuleMap *ModMap)
Collect module Map headers.
void displayProblemFiles()
List problem files.
std::error_code loadModuleMap(llvm::StringRef InputPath)
Load single module map and extract header file list.
clang::TextDiagnosticPrinter DC
Diagnostic consumer.
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.
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.
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.