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 (Module::submodule_const_iterator MI = Mod.submodule_begin(),
229 MIEnd = Mod.submodule_end();
239 SmallString<256>
Directory(ModuleMapDirectory);
240 if (UmbrellaDirName.size())
241 sys::path::append(Directory, UmbrellaDirName);
242 if (Directory.size() == 0)
246 sys::fs::file_status Status;
247 for (sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
251 std::string
File(I->path());
253 sys::fs::file_type Type = Status.type();
255 if (Type == sys::fs::file_type::directory_file) {
273 SmallString<256> PathBuf(ModuleMapDirectory);
276 if (ModuleMapDirectory.length() == 0)
277 sys::fs::current_path(PathBuf);
280 std::unique_ptr<CompilationDatabase> Compilations;
281 Compilations.reset(
new FixedCompilationDatabase(Twine(PathBuf), CommandLine));
283 std::vector<std::string> HeaderPath;
284 HeaderPath.push_back(UmbrellaHeaderName);
287 ClangTool Tool(*Compilations, HeaderPath);
298 SmallString<256> PathBuf(ModuleMapDirectory);
300 if (ModuleMapDirectory.length() == 0)
301 sys::fs::current_path(PathBuf);
304 if (HeaderName.startswith(PathBuf))
305 HeaderName = HeaderName.substr(PathBuf.size() + 1);
324 if (IncludePaths.size() == 0) {
331 for (std::vector<std::string>::const_iterator I = IncludePaths.begin(),
332 E = IncludePaths.end();
340 std::sort(FileSystemHeaders.begin(), FileSystemHeaders.end());
353 SmallString<256>
Directory(ModuleMapDirectory);
354 if (IncludePath.size())
355 sys::path::append(
Directory, IncludePath);
358 if (IncludePath.startswith(
"/") || IncludePath.startswith(
"\\") ||
359 ((IncludePath.size() >= 2) && (IncludePath[1] ==
':'))) {
360 llvm::errs() <<
"error: Include path \"" << IncludePath
361 <<
"\" is not relative to the module map file.\n";
367 sys::fs::file_status Status;
369 for (sys::fs::recursive_directory_iterator I(
Directory.str(), EC), E; I != E;
374 StringRef file(I->path());
376 sys::fs::file_type type = Status.type();
378 if (type == sys::fs::file_type::directory_file)
382 if ((file.find(
"\\.") != StringRef::npos) ||
383 (file.find(
"/.") != StringRef::npos))
393 llvm::errs() <<
"warning: No headers found in include path: \""
394 << IncludePath <<
"\"\n";
411 for (std::vector<std::string>::const_iterator I = FileSystemHeaders.begin(),
412 E = FileSystemHeaders.end();
415 if (ModuleMapHeadersSet.insert(*I).second) {
416 UnaccountedForHeaders.push_back(*I);
417 llvm::errs() <<
"warning: " << ModuleMapPath
418 <<
" 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.