clang-tools  5.0.0
Modularize.cpp
Go to the documentation of this file.
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 // Introduction
11 //
12 // This file implements a tool that checks whether a set of headers provides
13 // the consistent definitions required to use modules. It can also check an
14 // existing module map for full coverage of the headers in a directory tree.
15 //
16 // For example, in examining headers, it detects whether the same entity
17 // (say, a NULL macro or size_t typedef) is defined in multiple headers
18 // or whether a header produces different definitions under
19 // different circumstances. These conditions cause modules built from the
20 // headers to behave poorly, and should be fixed before introducing a module
21 // map.
22 //
23 // Modularize takes as input either one or more module maps (by default,
24 // "module.modulemap") or one or more text files contatining lists of headers
25 // to check.
26 //
27 // In the case of a module map, the module map must be well-formed in
28 // terms of syntax. Modularize will extract the header file names
29 // from the map. Only normal headers are checked, assuming headers
30 // marked "private", "textual", or "exclude" are not to be checked
31 // as a top-level include, assuming they either are included by
32 // other headers which are checked, or they are not suitable for
33 // modules.
34 //
35 // In the case of a file list, the list is a newline-separated list of headers
36 // to check with respect to each other.
37 // Lines beginning with '#' and empty lines are ignored.
38 // Header file names followed by a colon and other space-separated
39 // file names will include those extra files as dependencies.
40 // The file names can be relative or full paths, but must be on the
41 // same line.
42 //
43 // Modularize also accepts regular clang front-end arguments.
44 //
45 // Usage: modularize [(modularize options)]
46 // [(include-files_list)|(module map)]+ [(front-end-options) ...]
47 //
48 // Options:
49 // -prefix=(optional header path prefix)
50 // Note that unless a "-prefix (header path)" option is specified,
51 // non-absolute file paths in the header list file will be relative
52 // to the header list file directory. Use -prefix to specify a
53 // different directory.
54 // -module-map-path=(module map)
55 // Skip the checks, and instead act as a module.map generation
56 // assistant, generating a module map file based on the header list.
57 // An optional "-root-module=(rootName)" argument can specify a root
58 // module to be created in the generated module.map file. Note that
59 // you will likely need to edit this file to suit the needs of your
60 // headers.
61 // -problem-files-list=(problem files list file name)
62 // For use only with module map assistant. Input list of files that
63 // have problems with respect to modules. These will still be
64 // included in the generated module map, but will be marked as
65 // "excluded" headers.
66 // -root-module=(root module name)
67 // Specifies a root module to be created in the generated module.map
68 // file.
69 // -block-check-header-list-only
70 // Only warn if #include directives are inside extern or namespace
71 // blocks if the included header is in the header list.
72 // -no-coverage-check
73 // Don't do the coverage check.
74 // -coverage-check-only
75 // Only do the coverage check.
76 // -display-file-lists
77 // Display lists of good files (no compile errors), problem files,
78 // and a combined list with problem files preceded by a '#'.
79 // This can be used to quickly determine which files have problems.
80 // The latter combined list might be useful in starting to modularize
81 // a set of headers. You can start with a full list of headers,
82 // use -display-file-lists option, and then use the combined list as
83 // your intermediate list, uncommenting-out headers as you fix them.
84 //
85 // Note that by default, the modularize assumes .h files contain C++ source.
86 // If your .h files in the file list contain another language, you should
87 // append an appropriate -x option to your command line, i.e.: -x c
88 //
89 // Modularization Issue Checks
90 //
91 // In the process of checking headers for modularization issues, modularize
92 // will do normal parsing, reporting normal errors and warnings,
93 // but will also report special error messages like the following:
94 //
95 // error: '(symbol)' defined at multiple locations:
96 // (file):(row):(column)
97 // (file):(row):(column)
98 //
99 // error: header '(file)' has different contents depending on how it was
100 // included
101 //
102 // The latter might be followed by messages like the following:
103 //
104 // note: '(symbol)' in (file) at (row):(column) not always provided
105 //
106 // Checks will also be performed for macro expansions, defined(macro)
107 // expressions, and preprocessor conditional directives that evaluate
108 // inconsistently, and can produce error messages like the following:
109 //
110 // (...)/SubHeader.h:11:5:
111 // #if SYMBOL == 1
112 // ^
113 // error: Macro instance 'SYMBOL' has different values in this header,
114 // depending on how it was included.
115 // 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
116 // (...)/Header1.h
117 // (...)/SubHeader.h
118 // (...)/SubHeader.h:3:9:
119 // #define SYMBOL 1
120 // ^
121 // Macro defined here.
122 // 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
123 // (...)/Header2.h
124 // (...)/SubHeader.h
125 // (...)/SubHeader.h:7:9:
126 // #define SYMBOL 2
127 // ^
128 // Macro defined here.
129 //
130 // Checks will also be performed for '#include' directives that are
131 // nested inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks,
132 // and can produce error message like the following:
133 //
134 // IncludeInExtern.h:2:3
135 // #include "Empty.h"
136 // ^
137 // error: Include directive within extern "C" {}.
138 // IncludeInExtern.h:1:1
139 // extern "C" {
140 // ^
141 // The "extern "C" {}" block is here.
142 //
143 // See PreprocessorTracker.cpp for additional details.
144 //
145 // Module Map Coverage Check
146 //
147 // The coverage check uses the Clang ModuleMap class to read and parse the
148 // module map file. Starting at the module map file directory, or just the
149 // include paths, if specified, it will collect the names of all the files it
150 // considers headers (no extension, .h, or .inc--if you need more, modify the
151 // isHeader function). It then compares the headers against those referenced
152 // in the module map, either explicitly named, or implicitly named via an
153 // umbrella directory or umbrella file, as parsed by the ModuleMap object.
154 // If headers are found which are not referenced or covered by an umbrella
155 // directory or file, warning messages will be produced, and this program
156 // will return an error code of 1. Other errors result in an error code of 2.
157 // If no problems are found, an error code of 0 is returned.
158 //
159 // Note that in the case of umbrella headers, this tool invokes the compiler
160 // to preprocess the file, and uses a callback to collect the header files
161 // included by the umbrella header or any of its nested includes. If any
162 // front end options are needed for these compiler invocations, these
163 // can be included on the command line after the module map file argument.
164 //
165 // Warning message have the form:
166 //
167 // warning: module.modulemap does not account for file: Level3A.h
168 //
169 // Note that for the case of the module map referencing a file that does
170 // not exist, the module map parser in Clang will (at the time of this
171 // writing) display an error message.
172 //
173 // Module Map Assistant - Module Map Generation
174 //
175 // Modularize also has an option ("-module-map-path=module.modulemap") that will
176 // skip the checks, and instead act as a module.modulemap generation assistant,
177 // generating a module map file based on the header list. An optional
178 // "-root-module=(rootName)" argument can specify a root module to be
179 // created in the generated module.modulemap file. Note that you will likely
180 // need to edit this file to suit the needs of your headers.
181 //
182 // An example command line for generating a module.modulemap file:
183 //
184 // modularize -module-map-path=module.modulemap -root-module=myroot \
185 // headerlist.txt
186 //
187 // Note that if the headers in the header list have partial paths, sub-modules
188 // will be created for the subdirectires involved, assuming that the
189 // subdirectories contain headers to be grouped into a module, but still with
190 // individual modules for the headers in the subdirectory.
191 //
192 // See the ModuleAssistant.cpp file comments for additional details about the
193 // implementation of the assistant mode.
194 //
195 // Future directions:
196 //
197 // Basically, we want to add new checks for whatever we can check with respect
198 // to checking headers for module'ability.
199 //
200 // Some ideas:
201 //
202 // 1. Omit duplicate "not always provided" messages
203 //
204 // 2. Add options to disable any of the checks, in case
205 // there is some problem with them, or the messages get too verbose.
206 //
207 // 3. Try to figure out the preprocessor conditional directives that
208 // contribute to problems and tie them to the inconsistent definitions.
209 //
210 // 4. There are some legitimate uses of preprocessor macros that
211 // modularize will flag as errors, such as repeatedly #include'ing
212 // a file and using interleaving defined/undefined macros
213 // to change declarations in the included file. Is there a way
214 // to address this? Maybe have modularize accept a list of macros
215 // to ignore. Otherwise you can just exclude the file, after checking
216 // for legitimate errors.
217 //
218 // 5. What else?
219 //
220 // General clean-up and refactoring:
221 //
222 // 1. The Location class seems to be something that we might
223 // want to design to be applicable to a wider range of tools, and stick it
224 // somewhere into Tooling/ in mainline
225 //
226 //===----------------------------------------------------------------------===//
227 
228 #include "Modularize.h"
229 #include "ModularizeUtilities.h"
230 #include "PreprocessorTracker.h"
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"
249 #include <algorithm>
250 #include <fstream>
251 #include <iterator>
252 #include <string>
253 #include <vector>
254 
255 using namespace clang;
256 using namespace clang::driver;
257 using namespace clang::driver::options;
258 using namespace clang::tooling;
259 using namespace llvm;
260 using namespace llvm::opt;
261 using namespace Modularize;
262 
263 // Option to specify a file name for a list of header files to check.
264 static cl::list<std::string>
265  ListFileNames(cl::Positional, cl::value_desc("list"),
266  cl::desc("<list of one or more header list files>"),
267  cl::CommaSeparated);
268 
269 // Collect all other arguments, which will be passed to the front end.
270 static cl::list<std::string>
271  CC1Arguments(cl::ConsumeAfter,
272  cl::desc("<arguments to be passed to front end>..."));
273 
274 // Option to specify a prefix to be prepended to the header names.
275 static cl::opt<std::string> HeaderPrefix(
276  "prefix", cl::init(""),
277  cl::desc(
278  "Prepend header file paths with this prefix."
279  " If not specified,"
280  " the files are considered to be relative to the header list file."));
281 
282 // Option for assistant mode, telling modularize to output a module map
283 // based on the headers list, and where to put it.
284 static cl::opt<std::string> ModuleMapPath(
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."));
289 
290 // Option to specify list of problem files for assistant.
291 // This will cause assistant to exclude these files.
292 static cl::opt<std::string> ProblemFilesList(
293  "problem-files-list", cl::init(""),
294  cl::desc(
295  "List of files with compilation or modularization problems for"
296  " assistant mode. This will be excluded."));
297 
298 // Option for assistant mode, telling modularize the name of the root module.
299 static cl::opt<std::string>
300 RootModule("root-module", cl::init(""),
301  cl::desc("Specify the name of the root module."));
302 
303 // Option for limiting the #include-inside-extern-or-namespace-block
304 // check to only those headers explicitly listed in the header list.
305 // This is a work-around for private includes that purposefully get
306 // included inside blocks.
307 static cl::opt<bool>
308 BlockCheckHeaderListOnly("block-check-header-list-only", cl::init(false),
309 cl::desc("Only warn if #include directives are inside extern or namespace"
310  " blocks if the included header is in the header list."));
311 
312 // Option for include paths for coverage check.
313 static cl::list<std::string>
314 IncludePaths("I", cl::desc("Include path for coverage check."),
315 cl::ZeroOrMore, cl::value_desc("path"));
316 
317 // Option for disabling the coverage check.
318 static cl::opt<bool>
319 NoCoverageCheck("no-coverage-check", cl::init(false),
320 cl::desc("Don't do the coverage check."));
321 
322 // Option for just doing the coverage check.
323 static cl::opt<bool>
324 CoverageCheckOnly("coverage-check-only", cl::init(false),
325 cl::desc("Only do the coverage check."));
326 
327 // Option for displaying lists of good, bad, and mixed files.
328 static cl::opt<bool>
329 DisplayFileLists("display-file-lists", cl::init(false),
330 cl::desc("Display lists of good files (no compile errors), problem files,"
331  " and a combined list with problem files preceded by a '#'."));
332 
333 // Save the program name for error messages.
334 const char *Argv0;
335 // Save the command line for comments.
336 std::string CommandLine;
337 
338 // Helper function for finding the input file in an arguments list.
339 static std::string findInputFile(const CommandLineArguments &CLArgs) {
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);
349  return ModularizeUtilities::getCanonicalPath(Inputs.back());
350 }
351 
352 // This arguments adjuster inserts "-include (file)" arguments for header
353 // dependencies. It also inserts a "-w" option and a "-x c++",
354 // if no other "-x" option is present.
355 static ArgumentsAdjuster
357  return [&Dependencies](const CommandLineArguments &Args,
358  StringRef /*unused*/) {
359  std::string InputFile = findInputFile(Args);
360  DependentsVector &FileDependents = Dependencies[InputFile];
361  CommandLineArguments NewArgs(Args);
362  if (int Count = FileDependents.size()) {
363  for (int Index = 0; Index < Count; ++Index) {
364  NewArgs.push_back("-include");
365  std::string File(std::string("\"") + FileDependents[Index] +
366  std::string("\""));
367  NewArgs.push_back(FileDependents[Index]);
368  }
369  }
370  // Ignore warnings. (Insert after "clang_tool" at beginning.)
371  NewArgs.insert(NewArgs.begin() + 1, "-w");
372  // Since we are compiling .h files, assume C++ unless given a -x option.
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++");
376  }
377  return NewArgs;
378  };
379 }
380 
381 // FIXME: The Location class seems to be something that we might
382 // want to design to be applicable to a wider range of tools, and stick it
383 // somewhere into Tooling/ in mainline
384 struct Location {
385  const FileEntry *File;
386  unsigned Line, Column;
387 
388  Location() : File(), Line(), Column() {}
389 
390  Location(SourceManager &SM, SourceLocation Loc) : File(), Line(), Column() {
391  Loc = SM.getExpansionLoc(Loc);
392  if (Loc.isInvalid())
393  return;
394 
395  std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc);
396  File = SM.getFileEntryForID(Decomposed.first);
397  if (!File)
398  return;
399 
400  Line = SM.getLineNumber(Decomposed.first, Decomposed.second);
401  Column = SM.getColumnNumber(Decomposed.first, Decomposed.second);
402  }
403 
404  operator bool() const { return File != nullptr; }
405 
406  friend bool operator==(const Location &X, const Location &Y) {
407  return X.File == Y.File && X.Line == Y.Line && X.Column == Y.Column;
408  }
409 
410  friend bool operator!=(const Location &X, const Location &Y) {
411  return !(X == Y);
412  }
413 
414  friend bool operator<(const Location &X, const Location &Y) {
415  if (X.File != Y.File)
416  return X.File < Y.File;
417  if (X.Line != Y.Line)
418  return X.Line < Y.Line;
419  return X.Column < Y.Column;
420  }
421  friend bool operator>(const Location &X, const Location &Y) { return Y < X; }
422  friend bool operator<=(const Location &X, const Location &Y) {
423  return !(Y < X);
424  }
425  friend bool operator>=(const Location &X, const Location &Y) {
426  return !(X < Y);
427  }
428 };
429 
430 struct Entry {
431  enum EntryKind {
435 
436  EK_NumberOfKinds
437  } Kind;
438 
440 
441  StringRef getKindName() { return getKindName(Kind); }
442  static StringRef getKindName(EntryKind kind);
443 };
444 
445 // Return a string representing the given kind.
447  switch (kind) {
448  case EK_Tag:
449  return "tag";
450  case EK_Value:
451  return "value";
452  case EK_Macro:
453  return "macro";
454  case EK_NumberOfKinds:
455  break;
456  }
457  llvm_unreachable("invalid Entry kind");
458 }
459 
460 struct HeaderEntry {
461  std::string Name;
463 
464  friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y) {
465  return X.Loc == Y.Loc && X.Name == Y.Name;
466  }
467  friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y) {
468  return !(X == Y);
469  }
470  friend bool operator<(const HeaderEntry &X, const HeaderEntry &Y) {
471  return X.Loc < Y.Loc || (X.Loc == Y.Loc && X.Name < Y.Name);
472  }
473  friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y) {
474  return Y < X;
475  }
476  friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y) {
477  return !(Y < X);
478  }
479  friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y) {
480  return !(X < Y);
481  }
482 };
483 
484 typedef std::vector<HeaderEntry> HeaderContents;
485 
486 class EntityMap : public StringMap<SmallVector<Entry, 2> > {
487 public:
488  DenseMap<const FileEntry *, HeaderContents> HeaderContentMismatches;
489 
490  void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc) {
491  // Record this entity in its header.
492  HeaderEntry HE = { Name, Loc };
493  CurHeaderContents[Loc.File].push_back(HE);
494 
495  // Check whether we've seen this entry before.
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)
499  return;
500  }
501 
502  // We have not seen this entry before; record it.
503  Entry E = { Kind, Loc };
504  Entries.push_back(E);
505  }
506 
508  for (DenseMap<const FileEntry *, HeaderContents>::iterator
509  H = CurHeaderContents.begin(),
510  HEnd = CurHeaderContents.end();
511  H != HEnd; ++H) {
512  // Sort contents.
513  std::sort(H->second.begin(), H->second.end());
514 
515  // Check whether we've seen this header before.
516  DenseMap<const FileEntry *, HeaderContents>::iterator KnownH =
517  AllHeaderContents.find(H->first);
518  if (KnownH == AllHeaderContents.end()) {
519  // We haven't seen this header before; record its contents.
520  AllHeaderContents.insert(*H);
521  continue;
522  }
523 
524  // If the header contents are the same, we're done.
525  if (H->second == KnownH->second)
526  continue;
527 
528  // Determine what changed.
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]));
533  }
534 
535  CurHeaderContents.clear();
536  }
537 
538 private:
539  DenseMap<const FileEntry *, HeaderContents> CurHeaderContents;
540  DenseMap<const FileEntry *, HeaderContents> AllHeaderContents;
541 };
542 
544  : public RecursiveASTVisitor<CollectEntitiesVisitor> {
545 public:
546  CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities,
547  Preprocessor &PP, PreprocessorTracker &PPTracker,
548  int &HadErrors)
549  : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
550  HadErrors(HadErrors) {}
551 
552  bool TraverseStmt(Stmt *S) { return true; }
553  bool TraverseType(QualType T) { return true; }
554  bool TraverseTypeLoc(TypeLoc TL) { return true; }
555  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
556  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
557  return true;
558  }
559  bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
560  return true;
561  }
562  bool TraverseTemplateName(TemplateName Template) { return true; }
563  bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
564  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
565  return true;
566  }
567  bool TraverseTemplateArguments(const TemplateArgument *Args,
568  unsigned NumArgs) {
569  return true;
570  }
571  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
572  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
573  Expr *Init) {
574  return true;
575  }
576 
577  // Check 'extern "*" {}' block for #include directives.
578  bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
579  // Bail if not a block.
580  if (!D->hasBraces())
581  return true;
582  SourceRange BlockRange = D->getSourceRange();
583  const char *LinkageLabel;
584  switch (D->getLanguage()) {
585  case LinkageSpecDecl::lang_c:
586  LinkageLabel = "extern \"C\" {}";
587  break;
588  case LinkageSpecDecl::lang_cxx:
589  LinkageLabel = "extern \"C++\" {}";
590  break;
591  }
592  if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel,
593  errs()))
594  HadErrors = 1;
595  return true;
596  }
597 
598  // Check 'namespace (name) {}' block for #include directives.
599  bool VisitNamespaceDecl(const NamespaceDecl *D) {
600  SourceRange BlockRange = D->getSourceRange();
601  std::string Label("namespace ");
602  Label += D->getName();
603  Label += " {}";
604  if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(),
605  errs()))
606  HadErrors = 1;
607  return true;
608  }
609 
610  // Collect definition entities.
611  bool VisitNamedDecl(NamedDecl *ND) {
612  // We only care about file-context variables.
613  if (!ND->getDeclContext()->isFileContext())
614  return true;
615 
616  // Skip declarations that tend to be properly multiply-declared.
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) ||
623  (isa<TagDecl>(ND) &&
624  !cast<TagDecl>(ND)->isThisDeclarationADefinition()))
625  return true;
626 
627  // Skip anonymous declarations.
628  if (!ND->getDeclName())
629  return true;
630 
631  // Get the qualified name.
632  std::string Name;
633  llvm::raw_string_ostream OS(Name);
634  ND->printQualifiedName(OS);
635  OS.flush();
636  if (Name.empty())
637  return true;
638 
639  Location Loc(SM, ND->getLocation());
640  if (!Loc)
641  return true;
642 
643  Entities.add(Name, isa<TagDecl>(ND) ? Entry::EK_Tag : Entry::EK_Value, Loc);
644  return true;
645  }
646 
647 private:
648  SourceManager &SM;
649  EntityMap &Entities;
650  Preprocessor &PP;
652  int &HadErrors;
653 };
654 
656 public:
658  PreprocessorTracker &preprocessorTracker,
659  Preprocessor &PP, StringRef InFile, int &HadErrors)
660  : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
661  HadErrors(HadErrors) {
662  PPTracker.handlePreprocessorEntry(PP, InFile);
663  }
664 
665  ~CollectEntitiesConsumer() override { PPTracker.handlePreprocessorExit(); }
666 
667  void HandleTranslationUnit(ASTContext &Ctx) override {
668  SourceManager &SM = Ctx.getSourceManager();
669 
670  // Collect declared entities.
671  CollectEntitiesVisitor(SM, Entities, PP, PPTracker, HadErrors)
672  .TraverseDecl(Ctx.getTranslationUnitDecl());
673 
674  // Collect macro definitions.
675  for (Preprocessor::macro_iterator M = PP.macro_begin(),
676  MEnd = PP.macro_end();
677  M != MEnd; ++M) {
678  Location Loc(SM, M->second.getLatest()->getLocation());
679  if (!Loc)
680  continue;
681 
682  Entities.add(M->first->getName().str(), Entry::EK_Macro, Loc);
683  }
684 
685  // Merge header contents.
686  Entities.mergeCurHeaderContents();
687  }
688 
689 private:
690  EntityMap &Entities;
692  Preprocessor &PP;
693  int &HadErrors;
694 };
695 
697 public:
699  PreprocessorTracker &preprocessorTracker,
700  int &HadErrors)
701  : Entities(Entities), PPTracker(preprocessorTracker),
702  HadErrors(HadErrors) {}
703 
704 protected:
705  std::unique_ptr<clang::ASTConsumer>
706  CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
707  return llvm::make_unique<CollectEntitiesConsumer>(
708  Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
709  }
710 
711 private:
712  EntityMap &Entities;
714  int &HadErrors;
715 };
716 
718 public:
720  PreprocessorTracker &preprocessorTracker,
721  int &HadErrors)
722  : Entities(Entities), PPTracker(preprocessorTracker),
723  HadErrors(HadErrors) {}
724 
726  return new CollectEntitiesAction(Entities, PPTracker, HadErrors);
727  }
728 
729 private:
730  EntityMap &Entities;
732  int &HadErrors;
733 };
734 
736  : public RecursiveASTVisitor<CompileCheckVisitor> {
737 public:
739 
740  bool TraverseStmt(Stmt *S) { return true; }
741  bool TraverseType(QualType T) { return true; }
742  bool TraverseTypeLoc(TypeLoc TL) { return true; }
743  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
744  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
745  return true;
746  }
747  bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
748  return true;
749  }
750  bool TraverseTemplateName(TemplateName Template) { return true; }
751  bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
752  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
753  return true;
754  }
755  bool TraverseTemplateArguments(const TemplateArgument *Args,
756  unsigned NumArgs) {
757  return true;
758  }
759  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
760  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
761  Expr *Init) {
762  return true;
763  }
764 
765  // Check 'extern "*" {}' block for #include directives.
766  bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
767  return true;
768  }
769 
770  // Check 'namespace (name) {}' block for #include directives.
771  bool VisitNamespaceDecl(const NamespaceDecl *D) {
772  return true;
773  }
774 
775  // Collect definition entities.
776  bool VisitNamedDecl(NamedDecl *ND) {
777  return true;
778  }
779 };
780 
782 public:
784 
785  void HandleTranslationUnit(ASTContext &Ctx) override {
786  CompileCheckVisitor().TraverseDecl(Ctx.getTranslationUnitDecl());
787  }
788 };
789 
791 public:
793 
794 protected:
795  std::unique_ptr<clang::ASTConsumer>
796  CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
797  return llvm::make_unique<CompileCheckConsumer>();
798  }
799 };
800 
802 public:
804 
806  return new CompileCheckAction();
807  }
808 };
809 
810 int main(int Argc, const char **Argv) {
811 
812  // Save program name for error messages.
813  Argv0 = Argv[0];
814 
815  // Save program arguments for use in module.modulemap comment.
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]);
820  }
821 
822  // This causes options to be parsed.
823  cl::ParseCommandLineOptions(Argc, Argv, "modularize.\n");
824 
825  // No go if we have no header list file.
826  if (ListFileNames.size() == 0) {
827  cl::PrintHelpMessage();
828  return 1;
829  }
830 
831  std::unique_ptr<ModularizeUtilities> ModUtil;
832  int HadErrors = 0;
833 
834  ModUtil.reset(
835  ModularizeUtilities::createModularizeUtilities(
837 
838  // Get header file names and dependencies.
839  if (ModUtil->loadAllHeaderListsAndDependencies())
840  HadErrors = 1;
841 
842  // If we are in assistant mode, output the module map and quit.
843  if (ModuleMapPath.length() != 0) {
844  if (!createModuleMap(ModuleMapPath, ModUtil->HeaderFileNames,
845  ModUtil->ProblemFileNames,
846  ModUtil->Dependencies, HeaderPrefix, RootModule))
847  return 1; // Failed.
848  return 0; // Success - Skip checks in assistant mode.
849  }
850 
851  // If we're doing module maps.
852  if (!NoCoverageCheck && ModUtil->HasModuleMap) {
853  // Do coverage check.
854  if (ModUtil->doCoverageCheck(IncludePaths, CommandLine))
855  HadErrors = 1;
856  }
857 
858  // Bail early if only doing the coverage check.
859  if (CoverageCheckOnly)
860  return HadErrors;
861 
862  // Create the compilation database.
863  SmallString<256> PathBuf;
864  sys::fs::current_path(PathBuf);
865  std::unique_ptr<CompilationDatabase> Compilations;
866  Compilations.reset(
867  new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
868 
869  // Create preprocessor tracker, to watch for macro and conditional problems.
870  std::unique_ptr<PreprocessorTracker> PPTracker(
871  PreprocessorTracker::create(ModUtil->HeaderFileNames,
873 
874  // Coolect entities here.
875  EntityMap Entities;
876 
877  // Because we can't easily determine which files failed
878  // during the tool run, if we're collecting the file lists
879  // for display, we do a first compile pass on individual
880  // files to find which ones don't compile stand-alone.
881  if (DisplayFileLists) {
882  // First, make a pass to just get compile errors.
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(
888  getModularizeArgumentsAdjuster(ModUtil->Dependencies));
889  int CompileCheckFileErrors = 0;
890  CompileCheckFrontendActionFactory CompileCheckFactory;
891  CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
892  if (CompileCheckFileErrors != 0) {
893  ModUtil->addUniqueProblemFile(CompileCheckFile); // Save problem file.
894  HadErrors |= 1;
895  }
896  else
897  ModUtil->addNoCompileErrorsFile(CompileCheckFile); // Save good file.
898  }
899  }
900 
901  // Then we make another pass on the good files to do the rest of the work.
902  ClangTool Tool(*Compilations,
903  (DisplayFileLists ? ModUtil->GoodFileNames : ModUtil->HeaderFileNames));
904  Tool.appendArgumentsAdjuster(
905  getModularizeArgumentsAdjuster(ModUtil->Dependencies));
906  ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
907  HadErrors |= Tool.run(&Factory);
908 
909  // Create a place to save duplicate entity locations, separate bins per kind.
910  typedef SmallVector<Location, 8> LocationArray;
911  typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray;
912  EntryBinArray EntryBins;
913  int KindIndex;
914  for (KindIndex = 0; KindIndex < Entry::EK_NumberOfKinds; ++KindIndex) {
915  LocationArray Array;
916  EntryBins.push_back(Array);
917  }
918 
919  // Check for the same entity being defined in multiple places.
920  for (EntityMap::iterator E = Entities.begin(), EEnd = Entities.end();
921  E != EEnd; ++E) {
922  // If only one occurrence, exit early.
923  if (E->second.size() == 1)
924  continue;
925  // Clear entity locations.
926  for (EntryBinArray::iterator CI = EntryBins.begin(), CE = EntryBins.end();
927  CI != CE; ++CI) {
928  CI->clear();
929  }
930  // Walk the entities of a single name, collecting the locations,
931  // separated into separate bins.
932  for (unsigned I = 0, N = E->second.size(); I != N; ++I) {
933  EntryBins[E->second[I].Kind].push_back(E->second[I].Loc);
934  }
935  // Report any duplicate entity definition errors.
936  int KindIndex = 0;
937  for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end();
938  DI != DE; ++DI, ++KindIndex) {
939  int ECount = DI->size();
940  // If only 1 occurrence of this entity, skip it, we only report duplicates.
941  if (ECount <= 1)
942  continue;
943  LocationArray::iterator FI = DI->begin();
944  StringRef kindName = Entry::getKindName((Entry::EntryKind)KindIndex);
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());
951  }
952  HadErrors = 1;
953  }
954  }
955 
956  // Complain about macro instance in header files that differ based on how
957  // they are included.
958  if (PPTracker->reportInconsistentMacros(errs()))
959  HadErrors = 1;
960 
961  // Complain about preprocessor conditional directives in header files that
962  // differ based on how they are included.
963  if (PPTracker->reportInconsistentConditionals(errs()))
964  HadErrors = 1;
965 
966  // Complain about any headers that have contents that differ based on how
967  // they are included.
968  // FIXME: Could we provide information about which preprocessor conditionals
969  // are involved?
970  for (DenseMap<const FileEntry *, HeaderContents>::iterator
971  H = Entities.HeaderContentMismatches.begin(),
972  HEnd = Entities.HeaderContentMismatches.end();
973  H != HEnd; ++H) {
974  if (H->second.empty()) {
975  errs() << "internal error: phantom header content mismatch\n";
976  continue;
977  }
978 
979  HadErrors = 1;
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";
988  }
989  }
990 
991  if (DisplayFileLists) {
992  ModUtil->displayProblemFiles();
993  ModUtil->displayGoodFiles();
994  ModUtil->displayCombinedFiles();
995  }
996 
997  return HadErrors;
998 }
SourceLocation Loc
'#' location in the include directive
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
Definition: Modularize.cpp:567
friend bool operator>(const Location &X, const Location &Y)
Definition: Modularize.cpp:421
void HandleTranslationUnit(ASTContext &Ctx) override
Definition: Modularize.cpp:667
void HandleTranslationUnit(ASTContext &Ctx) override
Definition: Modularize.cpp:785
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."))
DenseMap< const FileEntry *, HeaderContents > HeaderContentMismatches
Definition: Modularize.cpp:488
unsigned Column
Definition: Modularize.cpp:386
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Definition: Modularize.cpp:706
Location Loc
Definition: Modularize.cpp:462
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)
Definition: Modularize.cpp:410
static cl::opt< bool > CoverageCheckOnly("coverage-check-only", cl::init(false), cl::desc("Only do the coverage check."))
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Definition: Modularize.cpp:571
friend bool operator<=(const Location &X, const Location &Y)
Definition: Modularize.cpp:422
StringHandle Name
llvm::SmallVector< std::string, 4 > DependentsVector
Definition: Modularize.h:32
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
Definition: Modularize.cpp:559
static clang::FrontendPluginRegistry::Add< clang::tidy::ClangTidyPluginAction > X("clang-tidy","clang-tidy")
const char * Argv0
Definition: Modularize.cpp:334
StringRef getKindName()
Definition: Modularize.cpp:441
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
Definition: Modularize.cpp:755
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
Definition: Modularize.cpp:752
bool TraverseTemplateName(TemplateName Template)
Definition: Modularize.cpp:750
HeaderHandle File
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 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)
Definition: Modularize.cpp:698
bool VisitNamedDecl(NamedDecl *ND)
Definition: Modularize.cpp:776
int Column
static ArgumentsAdjuster getModularizeArgumentsAdjuster(DependencyMap &Dependencies)
Definition: Modularize.cpp:356
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)
Definition: Modularize.cpp:572
ModularizeFrontendActionFactory(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
Definition: Modularize.cpp:719
friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:473
ModularizeUtilities class definition.
friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:479
void mergeCurHeaderContents()
Definition: Modularize.cpp:507
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Definition: Modularize.cpp:744
const FileEntry * File
Definition: Modularize.cpp:385
BindArgumentKind Kind
SourceManager & SM
static std::string findInputFile(const CommandLineArguments &CLArgs)
Definition: Modularize.cpp:339
Location Loc
Definition: Modularize.cpp:439
friend bool operator<(const Location &X, const Location &Y)
Definition: Modularize.cpp:414
void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc)
Definition: Modularize.cpp:490
bool VisitNamespaceDecl(const NamespaceDecl *D)
Definition: Modularize.cpp:771
bool TraverseStmt(Stmt *S)
Definition: Modularize.cpp:552
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
Definition: Modularize.cpp:747
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Definition: Modularize.cpp:759
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 VisitNamespaceDecl(const NamespaceDecl *D)
Definition: Modularize.cpp:599
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Definition: Modularize.cpp:796
friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:464
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.
PreprocessorTrackerImpl & PPTracker
friend bool operator<(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:470
bool TraverseStmt(Stmt *S)
Definition: Modularize.cpp:740
int main(int Argc, const char **Argv)
Definition: Modularize.cpp:810
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
Definition: Modularize.cpp:766
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Definition: Modularize.cpp:555
~CollectEntitiesConsumer() override
Definition: Modularize.cpp:665
std::string CommandLine
Definition: Modularize.cpp:336
Preprocessor * PP
CompileCheckAction * create() override
Definition: Modularize.cpp:805
bool TraverseTypeLoc(TypeLoc TL)
Definition: Modularize.cpp:554
llvm::StringMap< DependentsVector > DependencyMap
Definition: Modularize.h:33
static cl::opt< bool > NoCoverageCheck("no-coverage-check", cl::init(false), cl::desc("Don't do the coverage check."))
CollectEntitiesAction * create() override
Definition: Modularize.cpp:725
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)
Definition: Modularize.cpp:760
friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:467
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.
std::string Name
Definition: Modularize.cpp:461
friend bool operator>=(const Location &X, const Location &Y)
Definition: Modularize.cpp:425
friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:476
friend bool operator==(const Location &X, const Location &Y)
Definition: Modularize.cpp:406
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
Definition: Modularize.cpp:578
bool TraverseTemplateName(TemplateName Template)
Definition: Modularize.cpp:562
Location(SourceManager &SM, SourceLocation Loc)
Definition: Modularize.cpp:390
unsigned Line
Definition: Modularize.cpp:386
bool TraverseType(QualType T)
Definition: Modularize.cpp:741
std::vector< HeaderEntry > HeaderContents
Definition: Modularize.cpp:484
bool VisitNamedDecl(NamedDecl *ND)
Definition: Modularize.cpp:611
CollectEntitiesConsumer(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, Preprocessor &PP, StringRef InFile, int &HadErrors)
Definition: Modularize.cpp:657
Preprocessor tracker for modularize.
bool TraverseTypeLoc(TypeLoc TL)
Definition: Modularize.cpp:742
bool TraverseType(QualType T)
Definition: Modularize.cpp:553
bool TraverseTemplateArgument(const TemplateArgument &Arg)
Definition: Modularize.cpp:751
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 '#'."))
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Definition: Modularize.cpp:556
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
Definition: Modularize.cpp:564
CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities, Preprocessor &PP, PreprocessorTracker &PPTracker, int &HadErrors)
Definition: Modularize.cpp:546
bool TraverseTemplateArgument(const TemplateArgument &Arg)
Definition: Modularize.cpp:563
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Definition: Modularize.cpp:743