230#include "clang/AST/ASTConsumer.h"
231#include "clang/AST/ASTContext.h"
232#include "clang/AST/RecursiveASTVisitor.h"
233#include "clang/Basic/SourceManager.h"
234#include "clang/Driver/Options.h"
235#include "clang/Frontend/CompilerInstance.h"
236#include "clang/Frontend/FrontendAction.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"
255using namespace clang;
256using namespace clang::driver;
257using namespace clang::driver::options;
260using namespace llvm::opt;
264static cl::list<std::string>
266 cl::desc(
"<list of one or more header list files>"),
270static 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."));
299static cl::opt<std::string>
301 cl::desc(
"Specify the name of the root module."));
308BlockCheckHeaderListOnly(
"block-check-header-list-only", cl::init(
false),
309cl::desc(
"Only warn if #include directives are inside extern or namespace"
310 " blocks if the included header is in the header list."));
313static cl::list<std::string>
315 cl::value_desc(
"path"));
319 cl::desc(
"Don't do the coverage check."));
324cl::desc(
"Only do the coverage check."));
329cl::desc(
"Display lists of good files (no compile errors), problem files,"
330 " and a combined list with problem files preceded by a '#'."));
339 const unsigned IncludedFlagsBitmask = options::CC1Option;
340 unsigned MissingArgIndex, MissingArgCount;
341 SmallVector<const char *, 256> Argv;
342 for (
auto I = CLArgs.begin(),
E = CLArgs.end(); I !=
E; ++I)
343 Argv.push_back(I->c_str());
344 InputArgList
Args = getDriverOptTable().ParseArgs(
345 Argv, MissingArgIndex, MissingArgCount, IncludedFlagsBitmask);
346 std::vector<std::string> Inputs =
Args.getAllArgValues(OPT_INPUT);
353static ArgumentsAdjuster
355 return [&Dependencies](
const CommandLineArguments &
Args,
359 CommandLineArguments NewArgs(
Args);
360 if (
int Count = FileDependents.size()) {
361 for (
int Index = 0; Index < Count; ++Index) {
362 NewArgs.push_back(
"-include");
363 std::string File(std::string(
"\"") + FileDependents[Index] +
365 NewArgs.push_back(FileDependents[Index]);
369 NewArgs.insert(NewArgs.begin() + 1,
"-w");
371 if (!llvm::is_contained(NewArgs,
"-x")) {
372 NewArgs.insert(NewArgs.begin() + 2,
"-x");
373 NewArgs.insert(NewArgs.begin() + 3,
"c++");
389 Loc = SM.getExpansionLoc(
Loc);
393 std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(
Loc);
394 File = SM.getFileEntryForID(Decomposed.first);
398 Line = SM.getLineNumber(Decomposed.first, Decomposed.second);
399 Column = SM.getColumnNumber(Decomposed.first, Decomposed.second);
402 operator bool()
const {
return File !=
nullptr; }
413 if (
X.File != Y.
File)
414 return X.File < Y.
File;
415 if (
X.Line != Y.
Line)
416 return X.Line < Y.
Line;
455 llvm_unreachable(
"invalid Entry kind");
463 return X.Loc == Y.
Loc &&
X.Name == Y.
Name;
484class EntityMap :
public std::map<std::string, SmallVector<Entry, 2>> {
491 CurHeaderContents[
Loc.File].push_back(HE);
494 SmallVector<Entry, 2> &Entries = (*this)[
Name];
495 for (
unsigned I = 0, N = Entries.size(); I != N; ++I) {
502 Entries.push_back(
E);
506 for (DenseMap<const FileEntry *, HeaderContents>::iterator
507 H = CurHeaderContents.begin(),
508 HEnd = CurHeaderContents.end();
511 llvm::sort(H->second);
514 DenseMap<const FileEntry *, HeaderContents>::iterator KnownH =
515 AllHeaderContents.find(H->first);
516 if (KnownH == AllHeaderContents.end()) {
518 AllHeaderContents.insert(*H);
523 if (H->second == KnownH->second)
527 std::set_symmetric_difference(
528 H->second.begin(), H->second.end(), KnownH->second.begin(),
529 KnownH->second.end(),
533 CurHeaderContents.clear();
537 DenseMap<const FileEntry *, HeaderContents> CurHeaderContents;
538 DenseMap<const FileEntry *, HeaderContents> AllHeaderContents;
542 :
public RecursiveASTVisitor<CollectEntitiesVisitor> {
547 : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
548 HadErrors(HadErrors) {}
577 SourceRange BlockRange = D->getSourceRange();
578 const char *LinkageLabel;
579 switch (D->getLanguage()) {
580 case LinkageSpecDecl::lang_c:
581 LinkageLabel =
"extern \"C\" {}";
583 case LinkageSpecDecl::lang_cxx:
584 LinkageLabel =
"extern \"C++\" {}";
595 SourceRange BlockRange = D->getSourceRange();
596 std::string
Label(
"namespace ");
597 Label += D->getName();
608 if (!ND->getDeclContext()->isFileContext())
612 if (isa<NamespaceDecl>(ND) || isa<UsingDirectiveDecl>(ND) ||
613 isa<NamespaceAliasDecl>(ND) ||
614 isa<ClassTemplateSpecializationDecl>(ND) || isa<UsingDecl>(ND) ||
615 isa<ClassTemplateDecl>(ND) || isa<TemplateTypeParmDecl>(ND) ||
616 isa<TypeAliasTemplateDecl>(ND) || isa<UsingShadowDecl>(ND) ||
617 isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
619 !cast<TagDecl>(ND)->isThisDeclarationADefinition()))
623 if (!ND->getDeclName())
628 llvm::raw_string_ostream
OS(
Name);
629 ND->printQualifiedName(
OS);
654 Preprocessor &PP, StringRef InFile,
int &HadErrors)
655 : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
656 HadErrors(HadErrors) {
663 SourceManager &SM = Ctx.getSourceManager();
667 .TraverseDecl(Ctx.getTranslationUnitDecl());
670 for (Preprocessor::macro_iterator
M = PP.macro_begin(),
671 MEnd = PP.macro_end();
696 : Entities(Entities), PPTracker(preprocessorTracker),
697 HadErrors(HadErrors) {}
700 std::unique_ptr<clang::ASTConsumer>
702 return std::make_unique<CollectEntitiesConsumer>(
703 Entities, PPTracker,
CI.getPreprocessor(), InFile, HadErrors);
717 : Entities(Entities), PPTracker(preprocessorTracker),
718 HadErrors(HadErrors) {}
720 std::unique_ptr<FrontendAction>
create()
override {
721 return std::make_unique<CollectEntitiesAction>(Entities, PPTracker,
788 std::unique_ptr<clang::ASTConsumer>
790 return std::make_unique<CompileCheckConsumer>();
798 std::unique_ptr<FrontendAction>
create()
override {
799 return std::make_unique<CompileCheckAction>();
803int main(
int Argc,
const char **Argv) {
810 for (
int ArgIndex = 1; ArgIndex < Argc; ArgIndex++) {
816 cl::ParseCommandLineOptions(Argc, Argv,
"modularize.\n");
820 cl::PrintHelpMessage();
824 std::unique_ptr<ModularizeUtilities> ModUtil;
832 if (ModUtil->loadAllHeaderListsAndDependencies())
838 ModUtil->ProblemFileNames,
856 SmallString<256> PathBuf;
857 sys::fs::current_path(PathBuf);
858 std::unique_ptr<CompilationDatabase> Compilations;
860 new FixedCompilationDatabase(Twine(PathBuf),
CC1Arguments));
863 std::unique_ptr<PreprocessorTracker> PPTracker(
865 BlockCheckHeaderListOnly));
876 for (
auto &CompileCheckFile : ModUtil->HeaderFileNames) {
877 llvm::SmallVector<std::string, 32> CompileCheckFileArray;
878 CompileCheckFileArray.push_back(CompileCheckFile);
879 ClangTool CompileCheckTool(*Compilations, CompileCheckFileArray);
880 CompileCheckTool.appendArgumentsAdjuster(
882 int CompileCheckFileErrors = 0;
885 CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
886 if (CompileCheckFileErrors != 0) {
887 ModUtil->addUniqueProblemFile(CompileCheckFile);
891 ModUtil->addNoCompileErrorsFile(CompileCheckFile);
896 ClangTool Tool(*Compilations,
898 Tool.appendArgumentsAdjuster(
901 HadErrors |= Tool.run(&Factory);
904 typedef SmallVector<Location, 8> LocationArray;
905 typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray;
906 EntryBinArray EntryBins;
910 EntryBins.push_back(Array);
914 for (EntityMap::iterator
E = Entities.begin(), EEnd = Entities.end();
917 if (
E->second.size() == 1)
920 for (EntryBinArray::iterator
CI = EntryBins.begin(),
CE = EntryBins.end();
926 for (
unsigned I = 0, N =
E->second.size(); I != N; ++I) {
927 EntryBins[
E->second[I].Kind].push_back(
E->second[I].Loc);
931 for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end();
932 DI != DE; ++DI, ++KindIndex) {
933 int ECount = DI->size();
937 LocationArray::iterator FI = DI->begin();
939 errs() <<
"error: " << kindName <<
" '" <<
E->first
940 <<
"' defined at multiple locations:\n";
941 for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) {
942 errs() <<
" " << FI->File->getName() <<
":" << FI->Line <<
":"
943 << FI->Column <<
"\n";
944 ModUtil->addUniqueProblemFile(std::string(FI->File->getName()));
952 if (PPTracker->reportInconsistentMacros(errs()))
957 if (PPTracker->reportInconsistentConditionals(errs()))
964 for (DenseMap<const FileEntry *, HeaderContents>::iterator
968 if (H->second.empty()) {
969 errs() <<
"internal error: phantom header content mismatch\n";
974 ModUtil->addUniqueProblemFile(std::string(H->first->getName()));
975 errs() <<
"error: header '" << H->first->getName()
976 <<
"' has different contents depending on how it was included.\n";
977 for (
unsigned I = 0, N = H->second.size(); I != N; ++I) {
978 errs() <<
"note: '" << H->second[I].Name <<
"' in "
979 << H->second[I].Loc.File->getName() <<
" at "
980 << H->second[I].Loc.Line <<
":" << H->second[I].Loc.Column
981 <<
" not always provided\n";
986 ModUtil->displayProblemFiles();
987 ModUtil->displayGoodFiles();
988 ModUtil->displayCombinedFiles();
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."))
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 '#'."))
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
static cl::opt< bool > CoverageCheckOnly("coverage-check-only", cl::init(false), cl::desc("Only do the coverage check."))
static cl::opt< std::string > RootModule("root-module", cl::init(""), cl::desc("Specify the name of the root module."))
static cl::opt< bool > NoCoverageCheck("no-coverage-check", cl::desc("Don't do the coverage check."))
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)
int main(int Argc, const char **Argv)
static std::string findInputFile(const CommandLineArguments &CLArgs)
static cl::list< std::string > CC1Arguments(cl::ConsumeAfter, cl::desc("<arguments to be passed to front end>..."))
Common definitions for Modularize.
llvm::SmallVector< std::string, 4 > DependentsVector
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.
llvm::StringMap< DependentsVector > DependencyMap
Macro expansions and preprocessor conditional consistency checker.
const google::protobuf::Message & M
std::unique_ptr< CompilerInvocation > CI
llvm::raw_string_ostream OS
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
CollectEntitiesAction(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
CollectEntitiesConsumer(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, Preprocessor &PP, StringRef InFile, int &HadErrors)
void HandleTranslationUnit(ASTContext &Ctx) override
~CollectEntitiesConsumer() override
bool TraverseStmt(Stmt *S)
bool VisitNamespaceDecl(const NamespaceDecl *D)
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
bool TraverseTemplateArguments(ArrayRef< TemplateArgument >)
bool TraverseTypeLoc(TypeLoc TL)
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities, Preprocessor &PP, PreprocessorTracker &PPTracker, int &HadErrors)
bool TraverseTemplateArgument(const TemplateArgument &Arg)
bool VisitNamedDecl(NamedDecl *ND)
bool TraverseType(QualType T)
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
bool TraverseTemplateName(TemplateName Template)
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
void HandleTranslationUnit(ASTContext &Ctx) override
CompileCheckFrontendActionFactory()
std::unique_ptr< FrontendAction > create() override
bool TraverseStmt(Stmt *S)
bool TraverseType(QualType T)
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
bool TraverseTypeLoc(TypeLoc TL)
bool TraverseTemplateArguments(ArrayRef< TemplateArgument >)
bool TraverseTemplateArgument(const TemplateArgument &Arg)
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
bool VisitNamespaceDecl(const NamespaceDecl *D)
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)
bool VisitNamedDecl(NamedDecl *ND)
bool TraverseTemplateName(TemplateName Template)
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
void mergeCurHeaderContents()
void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc)
DenseMap< const FileEntry *, HeaderContents > HeaderContentMismatches
std::unique_ptr< FrontendAction > create() override
ModularizeFrontendActionFactory(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
static std::string getCanonicalPath(llvm::StringRef FilePath)
Convert header path to canonical form.
static ModularizeUtilities * createModularizeUtilities(std::vector< std::string > &InputPaths, llvm::StringRef Prefix, llvm::StringRef ProblemFilesListPath)
Create instance of ModularizeUtilities.
Preprocessor tracker for modularize.
virtual bool checkForIncludesInBlock(clang::Preprocessor &PP, clang::SourceRange BlockSourceRange, const char *BlockIdentifierMessage, llvm::raw_ostream &OS)=0
virtual void handlePreprocessorEntry(clang::Preprocessor &PP, llvm::StringRef RootHeaderFile)=0
static PreprocessorTracker * create(llvm::SmallVector< std::string, 32 > &Headers, bool DoBlockCheckHeaderListOnly)
virtual void handlePreprocessorExit()=0
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
enum Entry::EntryKind Kind
friend bool operator<=(const Location &X, const Location &Y)
friend bool operator==(const Location &X, const Location &Y)
friend bool operator>=(const Location &X, const Location &Y)
Location(SourceManager &SM, SourceLocation Loc)
friend bool operator<(const Location &X, const Location &Y)
friend bool operator!=(const Location &X, const Location &Y)
friend bool operator>(const Location &X, const Location &Y)