55 #include "clang/AST/ASTConsumer.h"
57 #include "clang/AST/ASTContext.h"
58 #include "clang/AST/RecursiveASTVisitor.h"
59 #include "clang/Basic/SourceManager.h"
60 #include "clang/Driver/Options.h"
61 #include "clang/Frontend/CompilerInstance.h"
62 #include "clang/Frontend/FrontendActions.h"
63 #include "clang/Lex/PPCallbacks.h"
64 #include "clang/Lex/Preprocessor.h"
65 #include "clang/Tooling/CompilationDatabase.h"
66 #include "clang/Tooling/Tooling.h"
67 #include "llvm/Option/Option.h"
68 #include "llvm/Support/CommandLine.h"
69 #include "llvm/Support/FileSystem.h"
70 #include "llvm/Support/Path.h"
71 #include "llvm/Support/raw_ostream.h"
73 using namespace Modularize;
74 using namespace clang;
75 using namespace clang::driver;
76 using namespace clang::driver::options;
77 using namespace clang::tooling;
78 namespace cl = llvm::cl;
79 namespace sys = llvm::sys;
91 CharSourceRange FilenameRange,
const FileEntry *
File,
92 StringRef SearchPath, StringRef RelativePath,
93 const Module *Imported)
override {
94 Checker.collectUmbrellaHeaderHeader(File->getName());
108 PP.addPPCallbacks(llvm::make_unique<CoverageCheckerCallbacks>(Checker));
118 StringRef InFile)
override {
119 return llvm::make_unique<CoverageCheckerConsumer>(Checker,
120 CI.getPreprocessor());
130 : Checker(Checker) {}
146 clang::ModuleMap *ModuleMap)
147 : ModuleMapPath(ModuleMapPath), IncludePaths(IncludePaths),
148 CommandLine(CommandLine),
155 ArrayRef<std::string>
CommandLine, clang::ModuleMap *ModuleMap) {
171 std::error_code returnValue;
178 return std::error_code(2, std::generic_category());
184 if (!UnaccountedForHeaders.empty())
185 returnValue = std::error_code(1, std::generic_category());
196 for (ModuleMap::module_iterator I = ModMap->module_begin(),
197 E = ModMap->module_end();
209 if (
const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader().Entry) {
212 UmbrellaHeader->getName()));
217 else if (
const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir().Entry) {
223 for (
auto &HeaderKind : Mod.Headers)
224 for (
auto &Header : HeaderKind)
226 Header.Entry->getName()));
228 for (
auto MI = Mod.submodule_begin(), MIEnd = Mod.submodule_end();
238 SmallString<256>
Directory(ModuleMapDirectory);
239 if (UmbrellaDirName.size())
240 sys::path::append(Directory, UmbrellaDirName);
241 if (Directory.size() == 0)
245 sys::fs::file_status Status;
246 for (sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
250 std::string
File(I->path());
252 sys::fs::file_type Type = Status.type();
254 if (Type == sys::fs::file_type::directory_file) {
272 SmallString<256> PathBuf(ModuleMapDirectory);
275 if (ModuleMapDirectory.length() == 0)
276 sys::fs::current_path(PathBuf);
279 std::unique_ptr<CompilationDatabase> Compilations;
280 Compilations.reset(
new FixedCompilationDatabase(Twine(PathBuf), CommandLine));
282 std::vector<std::string> HeaderPath;
283 HeaderPath.push_back(UmbrellaHeaderName);
286 ClangTool Tool(*Compilations, HeaderPath);
297 SmallString<256> PathBuf(ModuleMapDirectory);
299 if (ModuleMapDirectory.length() == 0)
300 sys::fs::current_path(PathBuf);
303 if (HeaderName.startswith(PathBuf))
304 HeaderName = HeaderName.substr(PathBuf.size() + 1);
323 if (IncludePaths.size() == 0) {
330 for (std::vector<std::string>::const_iterator I = IncludePaths.begin(),
331 E = IncludePaths.end();
339 std::sort(FileSystemHeaders.begin(), FileSystemHeaders.end());
352 SmallString<256>
Directory(ModuleMapDirectory);
353 if (IncludePath.size())
354 sys::path::append(
Directory, IncludePath);
357 if (IncludePath.startswith(
"/") || IncludePath.startswith(
"\\") ||
358 ((IncludePath.size() >= 2) && (IncludePath[1] ==
':'))) {
359 llvm::errs() <<
"error: Include path \"" << IncludePath
360 <<
"\" is not relative to the module map file.\n";
366 sys::fs::file_status Status;
368 for (sys::fs::recursive_directory_iterator I(
Directory.str(), EC), E; I != E;
373 StringRef file(I->path());
375 sys::fs::file_type type = Status.type();
377 if (type == sys::fs::file_type::directory_file)
381 if ((file.find(
"\\.") != StringRef::npos) ||
382 (file.find(
"/.") != StringRef::npos))
392 llvm::errs() <<
"warning: No headers found in include path: \""
393 << IncludePath <<
"\"\n";
410 for (std::vector<std::string>::const_iterator I = FileSystemHeaders.begin(),
411 E = FileSystemHeaders.end();
414 if (ModuleMapHeadersSet.insert(*I).second) {
415 UnaccountedForHeaders.push_back(*I);
416 llvm::errs() <<
"warning: " << ModuleMapPath
417 <<
" does not account for file: " << *I <<
"\n";
bool collectUmbrellaHeaders(llvm::StringRef UmbrellaDirName)
Collect headers from an umbrella directory.
static std::string getCanonicalPath(llvm::StringRef FilePath)
Convert header path to canonical form.
CoverageChecker(llvm::StringRef ModuleMapPath, std::vector< std::string > &IncludePaths, llvm::ArrayRef< std::string > CommandLine, clang::ModuleMap *ModuleMap)
Constructor.
CoverageCheckerCallbacks(CoverageChecker &Checker)
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
static std::string getDirectoryFromPath(llvm::StringRef Path)
Get directory path component from file path.
void collectModuleHeaders()
Collect module headers.
CoverageCheckerAction(CoverageChecker &Checker)
void collectUmbrellaHeaderHeader(llvm::StringRef HeaderName)
Called from CoverageCheckerCallbacks to track a header included from an umbrella header.
CoverageCheckerFrontendActionFactory(CoverageChecker &Checker)
ModularizeUtilities class definition.
void findUnaccountedForHeaders()
Find headers unaccounted-for in module map.
~CoverageCheckerCallbacks() override
bool collectUmbrellaHeaderHeaders(llvm::StringRef UmbrellaHeaderName)
Collect headers rferenced from an umbrella file.
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
Definitions for CoverageChecker.
static cl::opt< std::string > ModuleMapPath("module-map-path", cl::init(""), cl::desc("Turn on module map output and specify output path or file name."" If no path is specified and if prefix option is specified,"" use prefix for file path."))
bool IsAngled
true if this was an include with angle brackets
CoverageCheckerAction * create() override
std::error_code doChecks()
Do checks.
static cl::list< std::string > IncludePaths("I", cl::desc("Include path for coverage check."), cl::ZeroOrMore, cl::value_desc("path"))
bool collectFileSystemHeaders()
Collect file system header files.
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, StringRef SearchPath, StringRef RelativePath, const Module *Imported) override
CoverageCheckerConsumer(CoverageChecker &Checker, Preprocessor &PP)
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.
static bool isHeader(llvm::StringRef FileName)
Check for header file extension.