1 //===- extra/modularize/Modularize.cpp - Check modularized headers --------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements a tool that checks whether a set of headers provides 11 // the consistent definitions required to use modules. For example, it detects 12 // whether the same entity (say, a NULL macro or size_t typedef) is defined in 13 // multiple headers or whether a header produces different definitions under 14 // different circumstances. These conditions cause modules built from the 15 // headers to behave poorly, and should be fixed before introducing a module 16 // map. 17 // 18 // Modularize takes as argument a file name for a file containing the 19 // newline-separated list of headers to check with respect to each other. 20 // Lines beginning with '#' and empty lines are ignored. 21 // Header file names followed by a colon and other space-separated 22 // file names will include those extra files as dependencies. 23 // The file names can be relative or full paths, but must be on the 24 // same line. 25 // 26 // Modularize also accepts regular front-end arguments. 27 // 28 // Usage: modularize [-prefix (optional header path prefix)] 29 // (include-files_list) [(front-end-options) ...] 30 // 31 // Note that unless a "-prefix (header path)" option is specified, 32 // non-absolute file paths in the header list file will be relative 33 // to the header list file directory. Use -prefix to specify a different 34 // directory. 35 // 36 // Note that by default, the underlying Clang front end assumes .h files 37 // contain C source. If your .h files in the file list contain C++ source, 38 // you should append the following to your command lines: -x c++ 39 // 40 // Modularize will do normal parsing, reporting normal errors and warnings, 41 // but will also report special error messages like the following: 42 // 43 // error: '(symbol)' defined at multiple locations: 44 // (file):(row):(column) 45 // (file):(row):(column) 46 // 47 // error: header '(file)' has different contents depending on how it was 48 // included 49 // 50 // The latter might be followed by messages like the following: 51 // 52 // note: '(symbol)' in (file) at (row):(column) not always provided 53 // 54 // Checks will also be performed for macro expansions, defined(macro) 55 // expressions, and preprocessor conditional directives that evaluate 56 // inconsistently, and can produce error messages like the following: 57 // 58 // (...)/SubHeader.h:11:5: 59 // #if SYMBOL == 1 60 // ^ 61 // error: Macro instance 'SYMBOL' has different values in this header, 62 // depending on how it was included. 63 // 'SYMBOL' expanded to: '1' with respect to these inclusion paths: 64 // (...)/Header1.h 65 // (...)/SubHeader.h 66 // (...)/SubHeader.h:3:9: 67 // #define SYMBOL 1 68 // ^ 69 // Macro defined here. 70 // 'SYMBOL' expanded to: '2' with respect to these inclusion paths: 71 // (...)/Header2.h 72 // (...)/SubHeader.h 73 // (...)/SubHeader.h:7:9: 74 // #define SYMBOL 2 75 // ^ 76 // Macro defined here. 77 // 78 // Checks will also be performed for '#include' directives that are 79 // nested inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks, 80 // and can produce error message like the following: 81 // 82 // IncludeInExtern.h:2:3 83 // #include "Empty.h" 84 // ^ 85 // error: Include directive within extern "C" {}. 86 // IncludeInExtern.h:1:1 87 // extern "C" { 88 // ^ 89 // The "extern "C" {}" block is here. 90 // 91 // See PreprocessorTracker.cpp for additional details. 92 // 93 // Future directions: 94 // 95 // Basically, we want to add new checks for whatever we can check with respect 96 // to checking headers for module'ability. 97 // 98 // Some ideas: 99 // 100 // 1. Omit duplicate "not always provided" messages 101 // 102 // 2. Add options to disable any of the checks, in case 103 // there is some problem with them, or the messages get too verbose. 104 // 105 // 3. Try to figure out the preprocessor conditional directives that 106 // contribute to problems and tie them to the inconsistent definitions. 107 // 108 // 4. There are some legitimate uses of preprocessor macros that 109 // modularize will flag as errors, such as repeatedly #include'ing 110 // a file and using interleaving defined/undefined macros 111 // to change declarations in the included file. Is there a way 112 // to address this? Maybe have modularize accept a list of macros 113 // to ignore. Otherwise you can just exclude the file, after checking 114 // for legitimate errors. 115 // 116 // 5. What else? 117 // 118 // General clean-up and refactoring: 119 // 120 // 1. The Location class seems to be something that we might 121 // want to design to be applicable to a wider range of tools, and stick it 122 // somewhere into Tooling/ in mainline 123 // 124 //===----------------------------------------------------------------------===// 125 126 #include "clang/AST/ASTConsumer.h" 127 #include "clang/AST/ASTContext.h" 128 #include "clang/AST/RecursiveASTVisitor.h" 129 #include "clang/Basic/SourceManager.h" 130 #include "clang/Driver/Options.h" 131 #include "clang/Frontend/CompilerInstance.h" 132 #include "clang/Frontend/FrontendActions.h" 133 #include "clang/Lex/Preprocessor.h" 134 #include "clang/Tooling/CompilationDatabase.h" 135 #include "clang/Tooling/Tooling.h" 136 #include "llvm/ADT/OwningPtr.h" 137 #include "llvm/ADT/StringRef.h" 138 #include "llvm/ADT/StringMap.h" 139 #include "llvm/Config/config.h" 140 #include "llvm/Option/Arg.h" 141 #include "llvm/Option/ArgList.h" 142 #include "llvm/Option/OptTable.h" 143 #include "llvm/Option/Option.h" 144 #include "llvm/Support/CommandLine.h" 145 #include "llvm/Support/FileSystem.h" 146 #include "llvm/Support/MemoryBuffer.h" 147 #include "llvm/Support/Path.h" 148 #include <algorithm> 149 #include <fstream> 150 #include <iterator> 151 #include <string> 152 #include <vector> 153 #include "PreprocessorTracker.h" 154 155 using namespace clang; 156 using namespace clang::driver; 157 using namespace clang::driver::options; 158 using namespace clang::tooling; 159 using namespace llvm; 160 using namespace llvm::opt; 161 using namespace Modularize; 162 163 // Option to specify a file name for a list of header files to check. 164 cl::opt<std::string> 165 ListFileName(cl::Positional, 166 cl::desc("<name of file containing list of headers to check>")); 167 168 // Collect all other arguments, which will be passed to the front end. 169 cl::list<std::string> 170 CC1Arguments(cl::ConsumeAfter, 171 cl::desc("<arguments to be passed to front end>...")); 172 173 // Option to specify a prefix to be prepended to the header names. 174 cl::opt<std::string> HeaderPrefix( 175 "prefix", cl::init(""), 176 cl::desc( 177 "Prepend header file paths with this prefix." 178 " If not specified," 179 " the files are considered to be relative to the header list file.")); 180 181 typedef SmallVector<std::string, 4> DependentsVector; 182 typedef StringMap<DependentsVector> DependencyMap; 183 184 // Read the header list file and collect the header file names and 185 // optional dependencies. 186 error_code getHeaderFileNames(SmallVectorImpl<std::string> &HeaderFileNames, 187 DependencyMap &Dependencies, 188 StringRef ListFileName, StringRef HeaderPrefix) { 189 // By default, use the path component of the list file name. 190 SmallString<256> HeaderDirectory(ListFileName); 191 sys::path::remove_filename(HeaderDirectory); 192 SmallString<256> CurrentDirectory; 193 sys::fs::current_path(CurrentDirectory); 194 195 // Get the prefix if we have one. 196 if (HeaderPrefix.size() != 0) 197 HeaderDirectory = HeaderPrefix; 198 199 // Read the header list file into a buffer. 200 OwningPtr<MemoryBuffer> listBuffer; 201 if (error_code ec = MemoryBuffer::getFile(ListFileName, listBuffer)) { 202 return ec; 203 } 204 205 // Parse the header list into strings. 206 SmallVector<StringRef, 32> Strings; 207 listBuffer->getBuffer().split(Strings, "\n", -1, false); 208 209 // Collect the header file names from the string list. 210 for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(), 211 E = Strings.end(); 212 I != E; ++I) { 213 StringRef Line = I->trim(); 214 // Ignore comments and empty lines. 215 if (Line.empty() || (Line[0] == '#')) 216 continue; 217 std::pair<StringRef, StringRef> TargetAndDependents = Line.split(':'); 218 SmallString<256> HeaderFileName; 219 // Prepend header file name prefix if it's not absolute. 220 if (sys::path::is_absolute(TargetAndDependents.first)) 221 llvm::sys::path::native(TargetAndDependents.first, HeaderFileName); 222 else { 223 if (HeaderDirectory.size() != 0) 224 HeaderFileName = HeaderDirectory; 225 else 226 HeaderFileName = CurrentDirectory; 227 sys::path::append(HeaderFileName, TargetAndDependents.first); 228 sys::path::native(HeaderFileName); 229 } 230 // Handle optional dependencies. 231 DependentsVector Dependents; 232 SmallVector<StringRef, 4> DependentsList; 233 TargetAndDependents.second.split(DependentsList, " ", -1, false); 234 int Count = DependentsList.size(); 235 for (int Index = 0; Index < Count; ++Index) { 236 SmallString<256> Dependent; 237 if (sys::path::is_absolute(DependentsList[Index])) 238 Dependent = DependentsList[Index]; 239 else { 240 if (HeaderDirectory.size() != 0) 241 Dependent = HeaderDirectory; 242 else 243 Dependent = CurrentDirectory; 244 sys::path::append(Dependent, DependentsList[Index]); 245 } 246 sys::path::native(Dependent); 247 Dependents.push_back(Dependent.str()); 248 } 249 // Save the resulting header file path and dependencies. 250 HeaderFileNames.push_back(HeaderFileName.str()); 251 Dependencies[HeaderFileName.str()] = Dependents; 252 } 253 254 return error_code::success(); 255 } 256 257 // Helper function for finding the input file in an arguments list. 258 std::string findInputFile(const CommandLineArguments &CLArgs) { 259 OwningPtr<OptTable> Opts(createDriverOptTable()); 260 const unsigned IncludedFlagsBitmask = options::CC1Option; 261 unsigned MissingArgIndex, MissingArgCount; 262 SmallVector<const char *, 256> Argv; 263 for (CommandLineArguments::const_iterator I = CLArgs.begin(), 264 E = CLArgs.end(); 265 I != E; ++I) 266 Argv.push_back(I->c_str()); 267 OwningPtr<InputArgList> Args( 268 Opts->ParseArgs(Argv.data(), Argv.data() + Argv.size(), MissingArgIndex, 269 MissingArgCount, IncludedFlagsBitmask)); 270 std::vector<std::string> Inputs = Args->getAllArgValues(OPT_INPUT); 271 return Inputs.back(); 272 } 273 274 // We provide this derivation to add in "-include (file)" arguments for header 275 // dependencies. 276 class AddDependenciesAdjuster : public ArgumentsAdjuster { 277 public: 278 AddDependenciesAdjuster(DependencyMap &Dependencies) 279 : Dependencies(Dependencies) {} 280 281 private: 282 // Callback for adjusting commandline arguments. 283 CommandLineArguments Adjust(const CommandLineArguments &Args) { 284 std::string InputFile = findInputFile(Args); 285 DependentsVector &FileDependents = Dependencies[InputFile]; 286 int Count = FileDependents.size(); 287 if (Count == 0) 288 return Args; 289 CommandLineArguments NewArgs(Args); 290 for (int Index = 0; Index < Count; ++Index) { 291 NewArgs.push_back("-include"); 292 std::string File(std::string("\"") + FileDependents[Index] + 293 std::string("\"")); 294 NewArgs.push_back(FileDependents[Index]); 295 } 296 return NewArgs; 297 } 298 DependencyMap &Dependencies; 299 }; 300 301 // FIXME: The Location class seems to be something that we might 302 // want to design to be applicable to a wider range of tools, and stick it 303 // somewhere into Tooling/ in mainline 304 struct Location { 305 const FileEntry *File; 306 unsigned Line, Column; 307 308 Location() : File(), Line(), Column() {} 309 310 Location(SourceManager &SM, SourceLocation Loc) : File(), Line(), Column() { 311 Loc = SM.getExpansionLoc(Loc); 312 if (Loc.isInvalid()) 313 return; 314 315 std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc); 316 File = SM.getFileEntryForID(Decomposed.first); 317 if (!File) 318 return; 319 320 Line = SM.getLineNumber(Decomposed.first, Decomposed.second); 321 Column = SM.getColumnNumber(Decomposed.first, Decomposed.second); 322 } 323 324 operator bool() const { return File != 0; } 325 326 friend bool operator==(const Location &X, const Location &Y) { 327 return X.File == Y.File && X.Line == Y.Line && X.Column == Y.Column; 328 } 329 330 friend bool operator!=(const Location &X, const Location &Y) { 331 return !(X == Y); 332 } 333 334 friend bool operator<(const Location &X, const Location &Y) { 335 if (X.File != Y.File) 336 return X.File < Y.File; 337 if (X.Line != Y.Line) 338 return X.Line < Y.Line; 339 return X.Column < Y.Column; 340 } 341 friend bool operator>(const Location &X, const Location &Y) { return Y < X; } 342 friend bool operator<=(const Location &X, const Location &Y) { 343 return !(Y < X); 344 } 345 friend bool operator>=(const Location &X, const Location &Y) { 346 return !(X < Y); 347 } 348 }; 349 350 struct Entry { 351 enum EntryKind { 352 EK_Tag, 353 EK_Value, 354 EK_Macro, 355 356 EK_NumberOfKinds 357 } Kind; 358 359 Location Loc; 360 361 StringRef getKindName() { return getKindName(Kind); } 362 static StringRef getKindName(EntryKind kind); 363 }; 364 365 // Return a string representing the given kind. 366 StringRef Entry::getKindName(Entry::EntryKind kind) { 367 switch (kind) { 368 case EK_Tag: 369 return "tag"; 370 case EK_Value: 371 return "value"; 372 case EK_Macro: 373 return "macro"; 374 case EK_NumberOfKinds: 375 break; 376 } 377 llvm_unreachable("invalid Entry kind"); 378 } 379 380 struct HeaderEntry { 381 std::string Name; 382 Location Loc; 383 384 friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y) { 385 return X.Loc == Y.Loc && X.Name == Y.Name; 386 } 387 friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y) { 388 return !(X == Y); 389 } 390 friend bool operator<(const HeaderEntry &X, const HeaderEntry &Y) { 391 return X.Loc < Y.Loc || (X.Loc == Y.Loc && X.Name < Y.Name); 392 } 393 friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y) { 394 return Y < X; 395 } 396 friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y) { 397 return !(Y < X); 398 } 399 friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y) { 400 return !(X < Y); 401 } 402 }; 403 404 typedef std::vector<HeaderEntry> HeaderContents; 405 406 class EntityMap : public StringMap<SmallVector<Entry, 2> > { 407 public: 408 DenseMap<const FileEntry *, HeaderContents> HeaderContentMismatches; 409 410 void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc) { 411 // Record this entity in its header. 412 HeaderEntry HE = { Name, Loc }; 413 CurHeaderContents[Loc.File].push_back(HE); 414 415 // Check whether we've seen this entry before. 416 SmallVector<Entry, 2> &Entries = (*this)[Name]; 417 for (unsigned I = 0, N = Entries.size(); I != N; ++I) { 418 if (Entries[I].Kind == Kind && Entries[I].Loc == Loc) 419 return; 420 } 421 422 // We have not seen this entry before; record it. 423 Entry E = { Kind, Loc }; 424 Entries.push_back(E); 425 } 426 427 void mergeCurHeaderContents() { 428 for (DenseMap<const FileEntry *, HeaderContents>::iterator 429 H = CurHeaderContents.begin(), 430 HEnd = CurHeaderContents.end(); 431 H != HEnd; ++H) { 432 // Sort contents. 433 std::sort(H->second.begin(), H->second.end()); 434 435 // Check whether we've seen this header before. 436 DenseMap<const FileEntry *, HeaderContents>::iterator KnownH = 437 AllHeaderContents.find(H->first); 438 if (KnownH == AllHeaderContents.end()) { 439 // We haven't seen this header before; record its contents. 440 AllHeaderContents.insert(*H); 441 continue; 442 } 443 444 // If the header contents are the same, we're done. 445 if (H->second == KnownH->second) 446 continue; 447 448 // Determine what changed. 449 std::set_symmetric_difference( 450 H->second.begin(), H->second.end(), KnownH->second.begin(), 451 KnownH->second.end(), 452 std::back_inserter(HeaderContentMismatches[H->first])); 453 } 454 455 CurHeaderContents.clear(); 456 } 457 458 private: 459 DenseMap<const FileEntry *, HeaderContents> CurHeaderContents; 460 DenseMap<const FileEntry *, HeaderContents> AllHeaderContents; 461 }; 462 463 class CollectEntitiesVisitor 464 : public RecursiveASTVisitor<CollectEntitiesVisitor> { 465 public: 466 CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities, 467 Preprocessor &PP, PreprocessorTracker &PPTracker, 468 int &HadErrors) 469 : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker), 470 HadErrors(HadErrors) {} 471 472 bool TraverseStmt(Stmt *S) { return true; } 473 bool TraverseType(QualType T) { return true; } 474 bool TraverseTypeLoc(TypeLoc TL) { return true; } 475 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; } 476 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { 477 return true; 478 } 479 bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) { 480 return true; 481 } 482 bool TraverseTemplateName(TemplateName Template) { return true; } 483 bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; } 484 bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { 485 return true; 486 } 487 bool TraverseTemplateArguments(const TemplateArgument *Args, 488 unsigned NumArgs) { 489 return true; 490 } 491 bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; } 492 bool TraverseLambdaCapture(LambdaExpr::Capture C) { return true; } 493 494 // Check 'extern "*" {}' block for #include directives. 495 bool VisitLinkageSpecDecl(LinkageSpecDecl *D) { 496 // Bail if not a block. 497 if (!D->hasBraces()) 498 return true; 499 SourceRange BlockRange = D->getSourceRange(); 500 const char *LinkageLabel; 501 switch (D->getLanguage()) { 502 case LinkageSpecDecl::lang_c: 503 LinkageLabel = "extern \"C\" {}"; 504 break; 505 case LinkageSpecDecl::lang_cxx: 506 LinkageLabel = "extern \"C++\" {}"; 507 break; 508 } 509 if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel, 510 errs())) 511 HadErrors = 1; 512 return true; 513 } 514 515 // Check 'namespace (name) {}' block for #include directives. 516 bool VisitNamespaceDecl(const NamespaceDecl *D) { 517 SourceRange BlockRange = D->getSourceRange(); 518 std::string Label("namespace "); 519 Label += D->getName(); 520 Label += " {}"; 521 if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(), 522 errs())) 523 HadErrors = 1; 524 return true; 525 } 526 527 // Collect definition entities. 528 bool VisitNamedDecl(NamedDecl *ND) { 529 // We only care about file-context variables. 530 if (!ND->getDeclContext()->isFileContext()) 531 return true; 532 533 // Skip declarations that tend to be properly multiply-declared. 534 if (isa<NamespaceDecl>(ND) || isa<UsingDirectiveDecl>(ND) || 535 isa<NamespaceAliasDecl>(ND) || 536 isa<ClassTemplateSpecializationDecl>(ND) || isa<UsingDecl>(ND) || 537 isa<ClassTemplateDecl>(ND) || isa<TemplateTypeParmDecl>(ND) || 538 isa<TypeAliasTemplateDecl>(ND) || isa<UsingShadowDecl>(ND) || 539 isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) || 540 (isa<TagDecl>(ND) && 541 !cast<TagDecl>(ND)->isThisDeclarationADefinition())) 542 return true; 543 544 // Skip anonymous declarations. 545 if (!ND->getDeclName()) 546 return true; 547 548 // Get the qualified name. 549 std::string Name; 550 llvm::raw_string_ostream OS(Name); 551 ND->printQualifiedName(OS); 552 OS.flush(); 553 if (Name.empty()) 554 return true; 555 556 Location Loc(SM, ND->getLocation()); 557 if (!Loc) 558 return true; 559 560 Entities.add(Name, isa<TagDecl>(ND) ? Entry::EK_Tag : Entry::EK_Value, Loc); 561 return true; 562 } 563 564 private: 565 SourceManager &SM; 566 EntityMap &Entities; 567 Preprocessor &PP; 568 PreprocessorTracker &PPTracker; 569 int &HadErrors; 570 }; 571 572 class CollectEntitiesConsumer : public ASTConsumer { 573 public: 574 CollectEntitiesConsumer(EntityMap &Entities, 575 PreprocessorTracker &preprocessorTracker, 576 Preprocessor &PP, StringRef InFile, int &HadErrors) 577 : Entities(Entities), PPTracker(preprocessorTracker), PP(PP), 578 HadErrors(HadErrors) { 579 PPTracker.handlePreprocessorEntry(PP, InFile); 580 } 581 582 ~CollectEntitiesConsumer() { PPTracker.handlePreprocessorExit(); } 583 584 virtual void HandleTranslationUnit(ASTContext &Ctx) { 585 SourceManager &SM = Ctx.getSourceManager(); 586 587 // Collect declared entities. 588 CollectEntitiesVisitor(SM, Entities, PP, PPTracker, HadErrors) 589 .TraverseDecl(Ctx.getTranslationUnitDecl()); 590 591 // Collect macro definitions. 592 for (Preprocessor::macro_iterator M = PP.macro_begin(), 593 MEnd = PP.macro_end(); 594 M != MEnd; ++M) { 595 Location Loc(SM, M->second->getLocation()); 596 if (!Loc) 597 continue; 598 599 Entities.add(M->first->getName().str(), Entry::EK_Macro, Loc); 600 } 601 602 // Merge header contents. 603 Entities.mergeCurHeaderContents(); 604 } 605 606 private: 607 EntityMap &Entities; 608 PreprocessorTracker &PPTracker; 609 Preprocessor &PP; 610 int &HadErrors; 611 }; 612 613 class CollectEntitiesAction : public SyntaxOnlyAction { 614 public: 615 CollectEntitiesAction(EntityMap &Entities, 616 PreprocessorTracker &preprocessorTracker, 617 int &HadErrors) 618 : Entities(Entities), PPTracker(preprocessorTracker), 619 HadErrors(HadErrors) {} 620 621 protected: 622 virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 623 StringRef InFile) { 624 return new CollectEntitiesConsumer(Entities, PPTracker, 625 CI.getPreprocessor(), InFile, HadErrors); 626 } 627 628 private: 629 EntityMap &Entities; 630 PreprocessorTracker &PPTracker; 631 int &HadErrors; 632 }; 633 634 class ModularizeFrontendActionFactory : public FrontendActionFactory { 635 public: 636 ModularizeFrontendActionFactory(EntityMap &Entities, 637 PreprocessorTracker &preprocessorTracker, 638 int &HadErrors) 639 : Entities(Entities), PPTracker(preprocessorTracker), 640 HadErrors(HadErrors) {} 641 642 virtual CollectEntitiesAction *create() { 643 return new CollectEntitiesAction(Entities, PPTracker, HadErrors); 644 } 645 646 private: 647 EntityMap &Entities; 648 PreprocessorTracker &PPTracker; 649 int &HadErrors; 650 }; 651 652 int main(int Argc, const char **Argv) { 653 654 // This causes options to be parsed. 655 cl::ParseCommandLineOptions(Argc, Argv, "modularize.\n"); 656 657 // No go if we have no header list file. 658 if (ListFileName.size() == 0) { 659 cl::PrintHelpMessage(); 660 return 1; 661 } 662 663 // Get header file names and dependencies. 664 SmallVector<std::string, 32> Headers; 665 DependencyMap Dependencies; 666 if (error_code EC = getHeaderFileNames(Headers, Dependencies, ListFileName, 667 HeaderPrefix)) { 668 errs() << Argv[0] << ": error: Unable to get header list '" << ListFileName 669 << "': " << EC.message() << '\n'; 670 return 1; 671 } 672 673 // Create the compilation database. 674 SmallString<256> PathBuf; 675 sys::fs::current_path(PathBuf); 676 OwningPtr<CompilationDatabase> Compilations; 677 Compilations.reset( 678 new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments)); 679 680 // Create preprocessor tracker, to watch for macro and conditional problems. 681 OwningPtr<PreprocessorTracker> PPTracker(PreprocessorTracker::create()); 682 683 // Parse all of the headers, detecting duplicates. 684 EntityMap Entities; 685 ClangTool Tool(*Compilations, Headers); 686 Tool.appendArgumentsAdjuster(new AddDependenciesAdjuster(Dependencies)); 687 int HadErrors = 0; 688 HadErrors |= Tool.run( 689 new ModularizeFrontendActionFactory(Entities, *PPTracker, HadErrors)); 690 691 // Create a place to save duplicate entity locations, separate bins per kind. 692 typedef SmallVector<Location, 8> LocationArray; 693 typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray; 694 EntryBinArray EntryBins; 695 int KindIndex; 696 for (KindIndex = 0; KindIndex < Entry::EK_NumberOfKinds; ++KindIndex) { 697 LocationArray Array; 698 EntryBins.push_back(Array); 699 } 700 701 // Check for the same entity being defined in multiple places. 702 for (EntityMap::iterator E = Entities.begin(), EEnd = Entities.end(); 703 E != EEnd; ++E) { 704 // If only one occurance, exit early. 705 if (E->second.size() == 1) 706 continue; 707 // Clear entity locations. 708 for (EntryBinArray::iterator CI = EntryBins.begin(), CE = EntryBins.end(); 709 CI != CE; ++CI) { 710 CI->clear(); 711 } 712 // Walk the entities of a single name, collecting the locations, 713 // separated into separate bins. 714 for (unsigned I = 0, N = E->second.size(); I != N; ++I) { 715 EntryBins[E->second[I].Kind].push_back(E->second[I].Loc); 716 } 717 // Report any duplicate entity definition errors. 718 int KindIndex = 0; 719 for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end(); 720 DI != DE; ++DI, ++KindIndex) { 721 int ECount = DI->size(); 722 // If only 1 occurance, skip; 723 if (ECount <= 1) 724 continue; 725 LocationArray::iterator FI = DI->begin(); 726 StringRef kindName = Entry::getKindName((Entry::EntryKind)KindIndex); 727 errs() << "error: " << kindName << " '" << E->first() 728 << "' defined at multiple locations:\n"; 729 for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) { 730 errs() << " " << FI->File->getName() << ":" << FI->Line << ":" 731 << FI->Column << "\n"; 732 } 733 HadErrors = 1; 734 } 735 } 736 737 // Complain about macro instance in header files that differ based on how 738 // they are included. 739 if (PPTracker->reportInconsistentMacros(errs())) 740 HadErrors = 1; 741 742 // Complain about preprocessor conditional directives in header files that 743 // differ based on how they are included. 744 if (PPTracker->reportInconsistentConditionals(errs())) 745 HadErrors = 1; 746 747 // Complain about any headers that have contents that differ based on how 748 // they are included. 749 // FIXME: Could we provide information about which preprocessor conditionals 750 // are involved? 751 for (DenseMap<const FileEntry *, HeaderContents>::iterator 752 H = Entities.HeaderContentMismatches.begin(), 753 HEnd = Entities.HeaderContentMismatches.end(); 754 H != HEnd; ++H) { 755 if (H->second.empty()) { 756 errs() << "internal error: phantom header content mismatch\n"; 757 continue; 758 } 759 760 HadErrors = 1; 761 errs() << "error: header '" << H->first->getName() 762 << "' has different contents depending on how it was included.\n"; 763 for (unsigned I = 0, N = H->second.size(); I != N; ++I) { 764 errs() << "note: '" << H->second[I].Name << "' in " 765 << H->second[I].Loc.File->getName() << " at " 766 << H->second[I].Loc.Line << ":" << H->second[I].Loc.Column 767 << " not always provided\n"; 768 } 769 } 770 771 return HadErrors; 772 } 773