54 #include "clang/AST/ASTConsumer.h" 56 #include "clang/AST/ASTContext.h" 57 #include "clang/AST/RecursiveASTVisitor.h" 58 #include "clang/Basic/SourceManager.h" 59 #include "clang/Driver/Options.h" 60 #include "clang/Frontend/CompilerInstance.h" 61 #include "clang/Frontend/FrontendActions.h" 62 #include "clang/Lex/PPCallbacks.h" 63 #include "clang/Lex/Preprocessor.h" 64 #include "clang/Tooling/CompilationDatabase.h" 65 #include "clang/Tooling/Tooling.h" 66 #include "llvm/Option/Option.h" 67 #include "llvm/Support/CommandLine.h" 68 #include "llvm/Support/FileSystem.h" 69 #include "llvm/Support/Path.h" 70 #include "llvm/Support/raw_ostream.h" 73 using namespace clang;
77 namespace cl = llvm::cl;
90 CharSourceRange FilenameRange,
const FileEntry *File,
91 StringRef SearchPath, StringRef RelativePath,
92 const Module *Imported,
93 SrcMgr::CharacteristicKind FileType)
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),
154 StringRef ModuleMapPath, std::vector<std::string> &IncludePaths,
155 ArrayRef<std::string> CommandLine, clang::ModuleMap *ModuleMap) {
157 return llvm::make_unique<CoverageChecker>(ModuleMapPath, IncludePaths,
158 CommandLine, 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 for (sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
249 std::string File(I->path());
250 llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
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);
356 if (Directory.size() == 0)
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";
368 for (sys::fs::recursive_directory_iterator I(Directory.str(), EC), E; I != E;
373 StringRef file(I->path());
374 llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
377 sys::fs::file_type type = Status->type();
379 if (type == sys::fs::file_type::directory_file)
383 if ((file.find(
"\\.") != StringRef::npos) ||
384 (file.find(
"/.") != StringRef::npos))
394 llvm::errs() <<
"warning: No headers found in include path: \"" 395 << IncludePath <<
"\"\n";
412 for (std::vector<std::string>::const_iterator I = FileSystemHeaders.begin(),
413 E = FileSystemHeaders.end();
416 if (ModuleMapHeadersSet.insert(*I).second) {
417 UnaccountedForHeaders.push_back(*I);
418 llvm::errs() <<
"warning: " << ModuleMapPath
419 <<
" 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.
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."))
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.
std::vector< llvm::StringRef > CommandLine
void findUnaccountedForHeaders()
Find headers unaccounted-for in module map.
~CoverageCheckerCallbacks() override
bool collectUmbrellaHeaderHeaders(llvm::StringRef UmbrellaHeaderName)
Collect headers rferenced from an umbrella file.
Definitions for CoverageChecker.
bool IsAngled
true if this was an include with angle brackets
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.
CoverageCheckerAction * create() override
std::error_code doChecks()
Do checks.
llvm::StringRef Directory
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.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override
CoverageCheckerConsumer(CoverageChecker &Checker, Preprocessor &PP)
Module map checker class.
static bool isHeader(llvm::StringRef FileName)
Check for header file extension.