231 #include "clang/AST/ASTConsumer.h" 232 #include "clang/AST/ASTContext.h" 233 #include "clang/AST/RecursiveASTVisitor.h" 234 #include "clang/Basic/SourceManager.h" 235 #include "clang/Driver/Options.h" 236 #include "clang/Frontend/CompilerInstance.h" 237 #include "clang/Frontend/FrontendActions.h" 238 #include "clang/Lex/Preprocessor.h" 239 #include "clang/Tooling/CompilationDatabase.h" 240 #include "clang/Tooling/Tooling.h" 241 #include "llvm/Option/Arg.h" 242 #include "llvm/Option/ArgList.h" 243 #include "llvm/Option/OptTable.h" 244 #include "llvm/Option/Option.h" 245 #include "llvm/Support/CommandLine.h" 246 #include "llvm/Support/FileSystem.h" 247 #include "llvm/Support/MemoryBuffer.h" 248 #include "llvm/Support/Path.h" 255 using namespace clang;
259 using namespace llvm;
264 static cl::list<std::string>
266 cl::desc(
"<list of one or more header list files>"),
270 static cl::list<std::string>
272 cl::desc(
"<arguments to be passed to front end>..."));
276 "prefix", cl::init(
""),
278 "Prepend header file paths with this prefix." 280 " the files are considered to be relative to the header list file."));
285 "module-map-path", cl::init(
""),
286 cl::desc(
"Turn on module map output and specify output path or file name." 287 " If no path is specified and if prefix option is specified," 288 " use prefix for file path."));
293 "problem-files-list", cl::init(
""),
295 "List of files with compilation or modularization problems for" 296 " assistant mode. This will be excluded."));
299 static cl::opt<std::string>
301 cl::desc(
"Specify the name of the root module."));
309 cl::desc(
"Only warn if #include directives are inside extern or namespace" 310 " blocks if the included header is in the header list."));
313 static cl::list<std::string>
314 IncludePaths(
"I", cl::desc(
"Include path for coverage check."),
315 cl::ZeroOrMore, cl::value_desc(
"path"));
320 cl::desc(
"Don't do the coverage check."));
325 cl::desc(
"Only do the coverage check."));
330 cl::desc(
"Display lists of good files (no compile errors), problem files," 331 " and a combined list with problem files preceded by a '#'."));
340 std::unique_ptr<OptTable> Opts(createDriverOptTable());
341 const unsigned IncludedFlagsBitmask = options::CC1Option;
342 unsigned MissingArgIndex, MissingArgCount;
343 SmallVector<const char *, 256> Argv;
344 for (
auto I = CLArgs.begin(), E = CLArgs.end(); I != E; ++I)
345 Argv.push_back(I->c_str());
346 InputArgList Args = Opts->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
347 IncludedFlagsBitmask);
348 std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
355 static ArgumentsAdjuster
357 return [&Dependencies](
const CommandLineArguments &Args,
361 CommandLineArguments NewArgs(Args);
362 if (
int Count = FileDependents.size()) {
364 NewArgs.push_back(
"-include");
365 std::string File(std::string(
"\"") + FileDependents[
Index] +
367 NewArgs.push_back(FileDependents[
Index]);
371 NewArgs.insert(NewArgs.begin() + 1,
"-w");
373 if (std::find(NewArgs.begin(), NewArgs.end(),
"-x") == NewArgs.end()) {
374 NewArgs.insert(NewArgs.begin() + 2,
"-x");
375 NewArgs.insert(NewArgs.begin() + 3,
"c++");
390 Location(SourceManager &SM, SourceLocation
Loc) : File(), Line(), Column() {
391 Loc = SM.getExpansionLoc(Loc);
395 std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc);
396 File = SM.getFileEntryForID(Decomposed.first);
400 Line = SM.getLineNumber(Decomposed.first, Decomposed.second);
401 Column = SM.getColumnNumber(Decomposed.first, Decomposed.second);
404 operator bool()
const {
return File !=
nullptr; }
442 static StringRef getKindName(
EntryKind kind);
454 case EK_NumberOfKinds:
457 llvm_unreachable(
"invalid Entry kind");
493 CurHeaderContents[Loc.File].push_back(HE);
496 SmallVector<Entry, 2> &Entries = (*this)[
Name];
497 for (
unsigned I = 0, N = Entries.size(); I != N; ++I) {
498 if (Entries[I].Kind == Kind && Entries[I].Loc == Loc)
504 Entries.push_back(E);
508 for (DenseMap<const FileEntry *, HeaderContents>::iterator
509 H = CurHeaderContents.begin(),
510 HEnd = CurHeaderContents.end();
513 std::sort(H->second.begin(), H->second.end());
516 DenseMap<const FileEntry *, HeaderContents>::iterator KnownH =
517 AllHeaderContents.find(H->first);
518 if (KnownH == AllHeaderContents.end()) {
520 AllHeaderContents.insert(*H);
525 if (H->second == KnownH->second)
529 std::set_symmetric_difference(
530 H->second.begin(), H->second.end(), KnownH->second.begin(),
531 KnownH->second.end(),
532 std::back_inserter(HeaderContentMismatches[H->first]));
535 CurHeaderContents.clear();
539 DenseMap<const FileEntry *, HeaderContents> CurHeaderContents;
540 DenseMap<const FileEntry *, HeaderContents> AllHeaderContents;
544 :
public RecursiveASTVisitor<CollectEntitiesVisitor> {
549 : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
550 HadErrors(HadErrors) {}
582 SourceRange BlockRange = D->getSourceRange();
583 const char *LinkageLabel;
584 switch (D->getLanguage()) {
585 case LinkageSpecDecl::lang_c:
586 LinkageLabel =
"extern \"C\" {}";
588 case LinkageSpecDecl::lang_cxx:
589 LinkageLabel =
"extern \"C++\" {}";
592 if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel,
600 SourceRange BlockRange = D->getSourceRange();
601 std::string Label(
"namespace ");
602 Label += D->getName();
604 if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(),
613 if (!ND->getDeclContext()->isFileContext())
617 if (isa<NamespaceDecl>(ND) || isa<UsingDirectiveDecl>(ND) ||
618 isa<NamespaceAliasDecl>(ND) ||
619 isa<ClassTemplateSpecializationDecl>(ND) || isa<UsingDecl>(ND) ||
620 isa<ClassTemplateDecl>(ND) || isa<TemplateTypeParmDecl>(ND) ||
621 isa<TypeAliasTemplateDecl>(ND) || isa<UsingShadowDecl>(ND) ||
622 isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
624 !cast<TagDecl>(ND)->isThisDeclarationADefinition()))
628 if (!ND->getDeclName())
633 llvm::raw_string_ostream OS(Name);
634 ND->printQualifiedName(OS);
659 Preprocessor &PP, StringRef InFile,
int &HadErrors)
660 : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
661 HadErrors(HadErrors) {
662 PPTracker.handlePreprocessorEntry(PP, InFile);
668 SourceManager &SM = Ctx.getSourceManager();
672 .TraverseDecl(Ctx.getTranslationUnitDecl());
675 for (Preprocessor::macro_iterator M = PP.macro_begin(),
676 MEnd = PP.macro_end();
678 Location Loc(SM, M->second.getLatest()->getLocation());
686 Entities.mergeCurHeaderContents();
701 : Entities(Entities), PPTracker(preprocessorTracker),
702 HadErrors(HadErrors) {}
705 std::unique_ptr<clang::ASTConsumer>
707 return llvm::make_unique<CollectEntitiesConsumer>(
708 Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
722 : Entities(Entities), PPTracker(preprocessorTracker),
723 HadErrors(HadErrors) {}
736 :
public RecursiveASTVisitor<CompileCheckVisitor> {
795 std::unique_ptr<clang::ASTConsumer>
797 return llvm::make_unique<CompileCheckConsumer>();
810 int main(
int Argc,
const char **Argv) {
816 CommandLine = sys::path::stem(sys::path::filename(Argv0));
817 for (
int ArgIndex = 1; ArgIndex < Argc; ArgIndex++) {
818 CommandLine.append(
" ");
819 CommandLine.append(Argv[ArgIndex]);
823 cl::ParseCommandLineOptions(Argc, Argv,
"modularize.\n");
827 cl::PrintHelpMessage();
831 std::unique_ptr<ModularizeUtilities> ModUtil;
835 ModularizeUtilities::createModularizeUtilities(
839 if (ModUtil->loadAllHeaderListsAndDependencies())
845 ModUtil->ProblemFileNames,
854 if (ModUtil->doCoverageCheck(
IncludePaths, CommandLine))
863 SmallString<256> PathBuf;
864 sys::fs::current_path(PathBuf);
865 std::unique_ptr<CompilationDatabase> Compilations;
867 new FixedCompilationDatabase(Twine(PathBuf),
CC1Arguments));
870 std::unique_ptr<PreprocessorTracker> PPTracker(
871 PreprocessorTracker::create(ModUtil->HeaderFileNames,
883 for (
auto &CompileCheckFile : ModUtil->HeaderFileNames) {
884 llvm::SmallVector<std::string, 32> CompileCheckFileArray;
885 CompileCheckFileArray.push_back(CompileCheckFile);
886 ClangTool CompileCheckTool(*Compilations, CompileCheckFileArray);
887 CompileCheckTool.appendArgumentsAdjuster(
889 int CompileCheckFileErrors = 0;
891 CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
892 if (CompileCheckFileErrors != 0) {
893 ModUtil->addUniqueProblemFile(CompileCheckFile);
897 ModUtil->addNoCompileErrorsFile(CompileCheckFile);
902 ClangTool Tool(*Compilations,
904 Tool.appendArgumentsAdjuster(
907 HadErrors |= Tool.run(&Factory);
910 typedef SmallVector<Location, 8> LocationArray;
911 typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray;
912 EntryBinArray EntryBins;
916 EntryBins.push_back(Array);
920 for (EntityMap::iterator E = Entities.begin(), EEnd = Entities.end();
923 if (E->second.size() == 1)
926 for (EntryBinArray::iterator CI = EntryBins.begin(), CE = EntryBins.end();
932 for (
unsigned I = 0, N = E->second.size(); I != N; ++I) {
933 EntryBins[E->second[I].Kind].push_back(E->second[I].Loc);
937 for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end();
938 DI != DE; ++DI, ++KindIndex) {
939 int ECount = DI->size();
943 LocationArray::iterator FI = DI->begin();
945 errs() <<
"error: " << kindName <<
" '" << E->first()
946 <<
"' defined at multiple locations:\n";
947 for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) {
948 errs() <<
" " << FI->File->getName() <<
":" << FI->Line <<
":" 949 << FI->Column <<
"\n";
950 ModUtil->addUniqueProblemFile(FI->File->getName());
958 if (PPTracker->reportInconsistentMacros(errs()))
963 if (PPTracker->reportInconsistentConditionals(errs()))
970 for (DenseMap<const FileEntry *, HeaderContents>::iterator
974 if (H->second.empty()) {
975 errs() <<
"internal error: phantom header content mismatch\n";
980 ModUtil->addUniqueProblemFile(H->first->getName());
981 errs() <<
"error: header '" << H->first->getName()
982 <<
"' has different contents depending on how it was included.\n";
983 for (
unsigned I = 0, N = H->second.size(); I != N; ++I) {
984 errs() <<
"note: '" << H->second[I].Name <<
"' in " 985 << H->second[I].Loc.File->getName() <<
" at " 986 << H->second[I].Loc.Line <<
":" << H->second[I].Loc.Column
987 <<
" not always provided\n";
992 ModUtil->displayProblemFiles();
993 ModUtil->displayGoodFiles();
994 ModUtil->displayCombinedFiles();
static cl::opt< bool > DisplayFileLists("display-file-lists", cl::init(false), cl::desc("Display lists of good files (no compile errors), problem files," " and a combined list with problem files preceded by a '#'."))
SourceLocation Loc
'#' location in the include directive
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
friend bool operator>(const Location &X, const Location &Y)
void HandleTranslationUnit(ASTContext &Ctx) override
void HandleTranslationUnit(ASTContext &Ctx) override
DenseMap< const FileEntry *, HeaderContents > HeaderContentMismatches
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Some operations such as code completion produce a set of candidates.
static cl::list< std::string > CC1Arguments(cl::ConsumeAfter, cl::desc("<arguments to be passed to front end>..."))
Common definitions for Modularize.
friend bool operator!=(const Location &X, const Location &Y)
static cl::opt< bool > CoverageCheckOnly("coverage-check-only", cl::init(false), cl::desc("Only do the coverage check."))
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
friend bool operator<=(const Location &X, const Location &Y)
llvm::SmallVector< std::string, 4 > DependentsVector
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
bool TraverseTemplateName(TemplateName Template)
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."))
CollectEntitiesAction(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
bool VisitNamedDecl(NamedDecl *ND)
static ArgumentsAdjuster getModularizeArgumentsAdjuster(DependencyMap &Dependencies)
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."))
static cl::list< std::string > ListFileNames(cl::Positional, cl::value_desc("list"), cl::desc("<list of one or more header list files>"), cl::CommaSeparated)
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
ModularizeFrontendActionFactory(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
ModularizeUtilities class definition.
void mergeCurHeaderContents()
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
static ClangTidyModuleRegistry::Add< AbseilModule > X("abseil-module", "Add Abseil checks.")
static cl::opt< bool > BlockCheckHeaderListOnly("block-check-header-list-only", cl::init(false), cl::desc("Only warn if #include directives are inside extern or namespace" " blocks if the included header is in the header list."))
static std::string findInputFile(const CommandLineArguments &CLArgs)
friend bool operator<(const Location &X, const Location &Y)
void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc)
bool VisitNamespaceDecl(const NamespaceDecl *D)
bool TraverseStmt(Stmt *S)
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
bool VisitNamespaceDecl(const NamespaceDecl *D)
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
bool createModuleMap(llvm::StringRef ModuleMapPath, llvm::ArrayRef< std::string > HeaderFileNames, llvm::ArrayRef< std::string > ProblemFileNames, DependencyMap &Dependencies, llvm::StringRef HeaderPrefix, llvm::StringRef RootModuleName)
Create the module map file.
static constexpr llvm::StringLiteral Name
bool TraverseStmt(Stmt *S)
int main(int Argc, const char **Argv)
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
~CollectEntitiesConsumer() override
CompileCheckAction * create() override
bool TraverseTypeLoc(TypeLoc TL)
llvm::StringMap< DependentsVector > DependencyMap
static cl::opt< bool > NoCoverageCheck("no-coverage-check", cl::init(false), cl::desc("Don't do the coverage check."))
CollectEntitiesAction * create() override
static cl::list< std::string > IncludePaths("I", cl::desc("Include path for coverage check."), cl::ZeroOrMore, cl::value_desc("path"))
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
static cl::opt< std::string > RootModule("root-module", cl::init(""), cl::desc("Specify the name of the root module."))
Macro expansions and preprocessor conditional consistency checker.
friend bool operator>=(const Location &X, const Location &Y)
friend bool operator==(const Location &X, const Location &Y)
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
bool TraverseTemplateName(TemplateName Template)
Location(SourceManager &SM, SourceLocation Loc)
bool TraverseType(QualType T)
static cl::opt< std::string > ProblemFilesList("problem-files-list", cl::init(""), cl::desc("List of files with compilation or modularization problems for" " assistant mode. This will be excluded."))
std::vector< HeaderEntry > HeaderContents
bool VisitNamedDecl(NamedDecl *ND)
CollectEntitiesConsumer(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, Preprocessor &PP, StringRef InFile, int &HadErrors)
Preprocessor tracker for modularize.
bool TraverseTypeLoc(TypeLoc TL)
bool TraverseType(QualType T)
bool TraverseTemplateArgument(const TemplateArgument &Arg)
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities, Preprocessor &PP, PreprocessorTracker &PPTracker, int &HadErrors)
CompileCheckFrontendActionFactory()
bool TraverseTemplateArgument(const TemplateArgument &Arg)
const SymbolIndex * Index
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)