clang-tools  3.9.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 (CommandLineArguments::const_iterator I = CLArgs.begin(),
345  E = CLArgs.end();
346  I != E; ++I)
347  Argv.push_back(I->c_str());
348  InputArgList Args = Opts->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
349  IncludedFlagsBitmask);
350  std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
351  return ModularizeUtilities::getCanonicalPath(Inputs.back());
352 }
353 
354 // This arguments adjuster inserts "-include (file)" arguments for header
355 // dependencies. It also inserts a "-w" option and a "-x c++",
356 // if no other "-x" option is present.
357 static ArgumentsAdjuster
359  return [&Dependencies](const CommandLineArguments &Args,
360  StringRef /*unused*/) {
361  std::string InputFile = findInputFile(Args);
362  DependentsVector &FileDependents = Dependencies[InputFile];
363  CommandLineArguments NewArgs(Args);
364  if (int Count = FileDependents.size()) {
365  for (int Index = 0; Index < Count; ++Index) {
366  NewArgs.push_back("-include");
367  std::string File(std::string("\"") + FileDependents[Index] +
368  std::string("\""));
369  NewArgs.push_back(FileDependents[Index]);
370  }
371  }
372  // Ignore warnings. (Insert after "clang_tool" at beginning.)
373  NewArgs.insert(NewArgs.begin() + 1, "-w");
374  // Since we are compiling .h files, assume C++ unless given a -x option.
375  if (std::find(NewArgs.begin(), NewArgs.end(), "-x") == NewArgs.end()) {
376  NewArgs.insert(NewArgs.begin() + 2, "-x");
377  NewArgs.insert(NewArgs.begin() + 3, "c++");
378  }
379  return NewArgs;
380  };
381 }
382 
383 // FIXME: The Location class seems to be something that we might
384 // want to design to be applicable to a wider range of tools, and stick it
385 // somewhere into Tooling/ in mainline
386 struct Location {
387  const FileEntry *File;
388  unsigned Line, Column;
389 
390  Location() : File(), Line(), Column() {}
391 
392  Location(SourceManager &SM, SourceLocation Loc) : File(), Line(), Column() {
393  Loc = SM.getExpansionLoc(Loc);
394  if (Loc.isInvalid())
395  return;
396 
397  std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc);
398  File = SM.getFileEntryForID(Decomposed.first);
399  if (!File)
400  return;
401 
402  Line = SM.getLineNumber(Decomposed.first, Decomposed.second);
403  Column = SM.getColumnNumber(Decomposed.first, Decomposed.second);
404  }
405 
406  operator bool() const { return File != nullptr; }
407 
408  friend bool operator==(const Location &X, const Location &Y) {
409  return X.File == Y.File && X.Line == Y.Line && X.Column == Y.Column;
410  }
411 
412  friend bool operator!=(const Location &X, const Location &Y) {
413  return !(X == Y);
414  }
415 
416  friend bool operator<(const Location &X, const Location &Y) {
417  if (X.File != Y.File)
418  return X.File < Y.File;
419  if (X.Line != Y.Line)
420  return X.Line < Y.Line;
421  return X.Column < Y.Column;
422  }
423  friend bool operator>(const Location &X, const Location &Y) { return Y < X; }
424  friend bool operator<=(const Location &X, const Location &Y) {
425  return !(Y < X);
426  }
427  friend bool operator>=(const Location &X, const Location &Y) {
428  return !(X < Y);
429  }
430 };
431 
432 struct Entry {
433  enum EntryKind {
437 
438  EK_NumberOfKinds
439  } Kind;
440 
442 
443  StringRef getKindName() { return getKindName(Kind); }
444  static StringRef getKindName(EntryKind kind);
445 };
446 
447 // Return a string representing the given kind.
449  switch (kind) {
450  case EK_Tag:
451  return "tag";
452  case EK_Value:
453  return "value";
454  case EK_Macro:
455  return "macro";
456  case EK_NumberOfKinds:
457  break;
458  }
459  llvm_unreachable("invalid Entry kind");
460 }
461 
462 struct HeaderEntry {
463  std::string Name;
465 
466  friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y) {
467  return X.Loc == Y.Loc && X.Name == Y.Name;
468  }
469  friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y) {
470  return !(X == Y);
471  }
472  friend bool operator<(const HeaderEntry &X, const HeaderEntry &Y) {
473  return X.Loc < Y.Loc || (X.Loc == Y.Loc && X.Name < Y.Name);
474  }
475  friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y) {
476  return Y < X;
477  }
478  friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y) {
479  return !(Y < X);
480  }
481  friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y) {
482  return !(X < Y);
483  }
484 };
485 
486 typedef std::vector<HeaderEntry> HeaderContents;
487 
488 class EntityMap : public StringMap<SmallVector<Entry, 2> > {
489 public:
490  DenseMap<const FileEntry *, HeaderContents> HeaderContentMismatches;
491 
492  void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc) {
493  // Record this entity in its header.
494  HeaderEntry HE = { Name, Loc };
495  CurHeaderContents[Loc.File].push_back(HE);
496 
497  // Check whether we've seen this entry before.
498  SmallVector<Entry, 2> &Entries = (*this)[Name];
499  for (unsigned I = 0, N = Entries.size(); I != N; ++I) {
500  if (Entries[I].Kind == Kind && Entries[I].Loc == Loc)
501  return;
502  }
503 
504  // We have not seen this entry before; record it.
505  Entry E = { Kind, Loc };
506  Entries.push_back(E);
507  }
508 
510  for (DenseMap<const FileEntry *, HeaderContents>::iterator
511  H = CurHeaderContents.begin(),
512  HEnd = CurHeaderContents.end();
513  H != HEnd; ++H) {
514  // Sort contents.
515  std::sort(H->second.begin(), H->second.end());
516 
517  // Check whether we've seen this header before.
518  DenseMap<const FileEntry *, HeaderContents>::iterator KnownH =
519  AllHeaderContents.find(H->first);
520  if (KnownH == AllHeaderContents.end()) {
521  // We haven't seen this header before; record its contents.
522  AllHeaderContents.insert(*H);
523  continue;
524  }
525 
526  // If the header contents are the same, we're done.
527  if (H->second == KnownH->second)
528  continue;
529 
530  // Determine what changed.
531  std::set_symmetric_difference(
532  H->second.begin(), H->second.end(), KnownH->second.begin(),
533  KnownH->second.end(),
534  std::back_inserter(HeaderContentMismatches[H->first]));
535  }
536 
537  CurHeaderContents.clear();
538  }
539 
540 private:
541  DenseMap<const FileEntry *, HeaderContents> CurHeaderContents;
542  DenseMap<const FileEntry *, HeaderContents> AllHeaderContents;
543 };
544 
546  : public RecursiveASTVisitor<CollectEntitiesVisitor> {
547 public:
548  CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities,
549  Preprocessor &PP, PreprocessorTracker &PPTracker,
550  int &HadErrors)
551  : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
552  HadErrors(HadErrors) {}
553 
554  bool TraverseStmt(Stmt *S) { return true; }
555  bool TraverseType(QualType T) { return true; }
556  bool TraverseTypeLoc(TypeLoc TL) { return true; }
557  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
558  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
559  return true;
560  }
561  bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
562  return true;
563  }
564  bool TraverseTemplateName(TemplateName Template) { return true; }
565  bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
566  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
567  return true;
568  }
569  bool TraverseTemplateArguments(const TemplateArgument *Args,
570  unsigned NumArgs) {
571  return true;
572  }
573  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
574  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
575 
576  // Check 'extern "*" {}' block for #include directives.
577  bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
578  // Bail if not a block.
579  if (!D->hasBraces())
580  return true;
581  SourceRange BlockRange = D->getSourceRange();
582  const char *LinkageLabel;
583  switch (D->getLanguage()) {
584  case LinkageSpecDecl::lang_c:
585  LinkageLabel = "extern \"C\" {}";
586  break;
587  case LinkageSpecDecl::lang_cxx:
588  LinkageLabel = "extern \"C++\" {}";
589  break;
590  }
591  if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel,
592  errs()))
593  HadErrors = 1;
594  return true;
595  }
596 
597  // Check 'namespace (name) {}' block for #include directives.
598  bool VisitNamespaceDecl(const NamespaceDecl *D) {
599  SourceRange BlockRange = D->getSourceRange();
600  std::string Label("namespace ");
601  Label += D->getName();
602  Label += " {}";
603  if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(),
604  errs()))
605  HadErrors = 1;
606  return true;
607  }
608 
609  // Collect definition entities.
610  bool VisitNamedDecl(NamedDecl *ND) {
611  // We only care about file-context variables.
612  if (!ND->getDeclContext()->isFileContext())
613  return true;
614 
615  // Skip declarations that tend to be properly multiply-declared.
616  if (isa<NamespaceDecl>(ND) || isa<UsingDirectiveDecl>(ND) ||
617  isa<NamespaceAliasDecl>(ND) ||
618  isa<ClassTemplateSpecializationDecl>(ND) || isa<UsingDecl>(ND) ||
619  isa<ClassTemplateDecl>(ND) || isa<TemplateTypeParmDecl>(ND) ||
620  isa<TypeAliasTemplateDecl>(ND) || isa<UsingShadowDecl>(ND) ||
621  isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
622  (isa<TagDecl>(ND) &&
623  !cast<TagDecl>(ND)->isThisDeclarationADefinition()))
624  return true;
625 
626  // Skip anonymous declarations.
627  if (!ND->getDeclName())
628  return true;
629 
630  // Get the qualified name.
631  std::string Name;
632  llvm::raw_string_ostream OS(Name);
633  ND->printQualifiedName(OS);
634  OS.flush();
635  if (Name.empty())
636  return true;
637 
638  Location Loc(SM, ND->getLocation());
639  if (!Loc)
640  return true;
641 
642  Entities.add(Name, isa<TagDecl>(ND) ? Entry::EK_Tag : Entry::EK_Value, Loc);
643  return true;
644  }
645 
646 private:
647  SourceManager &SM;
648  EntityMap &Entities;
649  Preprocessor &PP;
651  int &HadErrors;
652 };
653 
655 public:
657  PreprocessorTracker &preprocessorTracker,
658  Preprocessor &PP, StringRef InFile, int &HadErrors)
659  : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
660  HadErrors(HadErrors) {
661  PPTracker.handlePreprocessorEntry(PP, InFile);
662  }
663 
664  ~CollectEntitiesConsumer() override { PPTracker.handlePreprocessorExit(); }
665 
666  void HandleTranslationUnit(ASTContext &Ctx) override {
667  SourceManager &SM = Ctx.getSourceManager();
668 
669  // Collect declared entities.
670  CollectEntitiesVisitor(SM, Entities, PP, PPTracker, HadErrors)
671  .TraverseDecl(Ctx.getTranslationUnitDecl());
672 
673  // Collect macro definitions.
674  for (Preprocessor::macro_iterator M = PP.macro_begin(),
675  MEnd = PP.macro_end();
676  M != MEnd; ++M) {
677  Location Loc(SM, M->second.getLatest()->getLocation());
678  if (!Loc)
679  continue;
680 
681  Entities.add(M->first->getName().str(), Entry::EK_Macro, Loc);
682  }
683 
684  // Merge header contents.
685  Entities.mergeCurHeaderContents();
686  }
687 
688 private:
689  EntityMap &Entities;
691  Preprocessor &PP;
692  int &HadErrors;
693 };
694 
696 public:
698  PreprocessorTracker &preprocessorTracker,
699  int &HadErrors)
700  : Entities(Entities), PPTracker(preprocessorTracker),
701  HadErrors(HadErrors) {}
702 
703 protected:
704  std::unique_ptr<clang::ASTConsumer>
705  CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
706  return llvm::make_unique<CollectEntitiesConsumer>(
707  Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
708  }
709 
710 private:
711  EntityMap &Entities;
713  int &HadErrors;
714 };
715 
717 public:
719  PreprocessorTracker &preprocessorTracker,
720  int &HadErrors)
721  : Entities(Entities), PPTracker(preprocessorTracker),
722  HadErrors(HadErrors) {}
723 
725  return new CollectEntitiesAction(Entities, PPTracker, HadErrors);
726  }
727 
728 private:
729  EntityMap &Entities;
731  int &HadErrors;
732 };
733 
735  : public RecursiveASTVisitor<CompileCheckVisitor> {
736 public:
738 
739  bool TraverseStmt(Stmt *S) { return true; }
740  bool TraverseType(QualType T) { return true; }
741  bool TraverseTypeLoc(TypeLoc TL) { return true; }
742  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
743  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
744  return true;
745  }
746  bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
747  return true;
748  }
749  bool TraverseTemplateName(TemplateName Template) { return true; }
750  bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
751  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
752  return true;
753  }
754  bool TraverseTemplateArguments(const TemplateArgument *Args,
755  unsigned NumArgs) {
756  return true;
757  }
758  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
759  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
760 
761  // Check 'extern "*" {}' block for #include directives.
762  bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
763  return true;
764  }
765 
766  // Check 'namespace (name) {}' block for #include directives.
767  bool VisitNamespaceDecl(const NamespaceDecl *D) {
768  return true;
769  }
770 
771  // Collect definition entities.
772  bool VisitNamedDecl(NamedDecl *ND) {
773  return true;
774  }
775 };
776 
778 public:
780 
781  void HandleTranslationUnit(ASTContext &Ctx) override {
782  CompileCheckVisitor().TraverseDecl(Ctx.getTranslationUnitDecl());
783  }
784 };
785 
787 public:
789 
790 protected:
791  std::unique_ptr<clang::ASTConsumer>
792  CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
793  return llvm::make_unique<CompileCheckConsumer>();
794  }
795 };
796 
798 public:
800 
802  return new CompileCheckAction();
803  }
804 };
805 
806 int main(int Argc, const char **Argv) {
807 
808  // Save program name for error messages.
809  Argv0 = Argv[0];
810 
811  // Save program arguments for use in module.modulemap comment.
812  CommandLine = sys::path::stem(sys::path::filename(Argv0));
813  for (int ArgIndex = 1; ArgIndex < Argc; ArgIndex++) {
814  CommandLine.append(" ");
815  CommandLine.append(Argv[ArgIndex]);
816  }
817 
818  // This causes options to be parsed.
819  cl::ParseCommandLineOptions(Argc, Argv, "modularize.\n");
820 
821  // No go if we have no header list file.
822  if (ListFileNames.size() == 0) {
823  cl::PrintHelpMessage();
824  return 1;
825  }
826 
827  std::unique_ptr<ModularizeUtilities> ModUtil;
828  int HadErrors = 0;
829 
830  ModUtil.reset(
831  ModularizeUtilities::createModularizeUtilities(
833 
834  // Get header file names and dependencies.
835  if (ModUtil->loadAllHeaderListsAndDependencies())
836  HadErrors = 1;
837 
838  // If we are in assistant mode, output the module map and quit.
839  if (ModuleMapPath.length() != 0) {
840  if (!createModuleMap(ModuleMapPath, ModUtil->HeaderFileNames,
841  ModUtil->ProblemFileNames,
842  ModUtil->Dependencies, HeaderPrefix, RootModule))
843  return 1; // Failed.
844  return 0; // Success - Skip checks in assistant mode.
845  }
846 
847  // If we're doing module maps.
848  if (!NoCoverageCheck && ModUtil->HasModuleMap) {
849  // Do coverage check.
850  if (ModUtil->doCoverageCheck(IncludePaths, CommandLine))
851  HadErrors = 1;
852  }
853 
854  // Bail early if only doing the coverage check.
855  if (CoverageCheckOnly)
856  return HadErrors;
857 
858  // Create the compilation database.
859  SmallString<256> PathBuf;
860  sys::fs::current_path(PathBuf);
861  std::unique_ptr<CompilationDatabase> Compilations;
862  Compilations.reset(
863  new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
864 
865  // Create preprocessor tracker, to watch for macro and conditional problems.
866  std::unique_ptr<PreprocessorTracker> PPTracker(
867  PreprocessorTracker::create(ModUtil->HeaderFileNames,
869 
870  // Coolect entities here.
871  EntityMap Entities;
872 
873  // Because we can't easily determine which files failed
874  // during the tool run, if we're collecting the file lists
875  // for display, we do a first compile pass on individual
876  // files to find which ones don't compile stand-alone.
877  if (DisplayFileLists) {
878  // First, make a pass to just get compile errors.
879  for (auto &CompileCheckFile : ModUtil->HeaderFileNames) {
880  llvm::SmallVector<std::string, 32> CompileCheckFileArray;
881  CompileCheckFileArray.push_back(CompileCheckFile);
882  ClangTool CompileCheckTool(*Compilations, CompileCheckFileArray);
883  CompileCheckTool.appendArgumentsAdjuster(
884  getModularizeArgumentsAdjuster(ModUtil->Dependencies));
885  int CompileCheckFileErrors = 0;
886  CompileCheckFrontendActionFactory CompileCheckFactory;
887  CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
888  if (CompileCheckFileErrors != 0) {
889  ModUtil->addUniqueProblemFile(CompileCheckFile); // Save problem file.
890  HadErrors |= 1;
891  }
892  else
893  ModUtil->addNoCompileErrorsFile(CompileCheckFile); // Save good file.
894  }
895  }
896 
897  // Then we make another pass on the good files to do the rest of the work.
898  ClangTool Tool(*Compilations,
899  (DisplayFileLists ? ModUtil->GoodFileNames : ModUtil->HeaderFileNames));
900  Tool.appendArgumentsAdjuster(
901  getModularizeArgumentsAdjuster(ModUtil->Dependencies));
902  ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
903  HadErrors |= Tool.run(&Factory);
904 
905  // Create a place to save duplicate entity locations, separate bins per kind.
906  typedef SmallVector<Location, 8> LocationArray;
907  typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray;
908  EntryBinArray EntryBins;
909  int KindIndex;
910  for (KindIndex = 0; KindIndex < Entry::EK_NumberOfKinds; ++KindIndex) {
911  LocationArray Array;
912  EntryBins.push_back(Array);
913  }
914 
915  // Check for the same entity being defined in multiple places.
916  for (EntityMap::iterator E = Entities.begin(), EEnd = Entities.end();
917  E != EEnd; ++E) {
918  // If only one occurrence, exit early.
919  if (E->second.size() == 1)
920  continue;
921  // Clear entity locations.
922  for (EntryBinArray::iterator CI = EntryBins.begin(), CE = EntryBins.end();
923  CI != CE; ++CI) {
924  CI->clear();
925  }
926  // Walk the entities of a single name, collecting the locations,
927  // separated into separate bins.
928  for (unsigned I = 0, N = E->second.size(); I != N; ++I) {
929  EntryBins[E->second[I].Kind].push_back(E->second[I].Loc);
930  }
931  // Report any duplicate entity definition errors.
932  int KindIndex = 0;
933  for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end();
934  DI != DE; ++DI, ++KindIndex) {
935  int ECount = DI->size();
936  // If only 1 occurrence of this entity, skip it, we only report duplicates.
937  if (ECount <= 1)
938  continue;
939  LocationArray::iterator FI = DI->begin();
940  StringRef kindName = Entry::getKindName((Entry::EntryKind)KindIndex);
941  errs() << "error: " << kindName << " '" << E->first()
942  << "' defined at multiple locations:\n";
943  for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) {
944  errs() << " " << FI->File->getName() << ":" << FI->Line << ":"
945  << FI->Column << "\n";
946  ModUtil->addUniqueProblemFile(FI->File->getName());
947  }
948  HadErrors = 1;
949  }
950  }
951 
952  // Complain about macro instance in header files that differ based on how
953  // they are included.
954  if (PPTracker->reportInconsistentMacros(errs()))
955  HadErrors = 1;
956 
957  // Complain about preprocessor conditional directives in header files that
958  // differ based on how they are included.
959  if (PPTracker->reportInconsistentConditionals(errs()))
960  HadErrors = 1;
961 
962  // Complain about any headers that have contents that differ based on how
963  // they are included.
964  // FIXME: Could we provide information about which preprocessor conditionals
965  // are involved?
966  for (DenseMap<const FileEntry *, HeaderContents>::iterator
967  H = Entities.HeaderContentMismatches.begin(),
968  HEnd = Entities.HeaderContentMismatches.end();
969  H != HEnd; ++H) {
970  if (H->second.empty()) {
971  errs() << "internal error: phantom header content mismatch\n";
972  continue;
973  }
974 
975  HadErrors = 1;
976  ModUtil->addUniqueProblemFile(H->first->getName());
977  errs() << "error: header '" << H->first->getName()
978  << "' has different contents depending on how it was included.\n";
979  for (unsigned I = 0, N = H->second.size(); I != N; ++I) {
980  errs() << "note: '" << H->second[I].Name << "' in "
981  << H->second[I].Loc.File->getName() << " at "
982  << H->second[I].Loc.Line << ":" << H->second[I].Loc.Column
983  << " not always provided\n";
984  }
985  }
986 
987  if (DisplayFileLists) {
988  ModUtil->displayProblemFiles();
989  ModUtil->displayGoodFiles();
990  ModUtil->displayCombinedFiles();
991  }
992 
993  return HadErrors;
994 }
SourceLocation Loc
'#' location in the include directive
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
Definition: Modularize.cpp:569
friend bool operator>(const Location &X, const Location &Y)
Definition: Modularize.cpp:423
void HandleTranslationUnit(ASTContext &Ctx) override
Definition: Modularize.cpp:666
void HandleTranslationUnit(ASTContext &Ctx) override
Definition: Modularize.cpp:781
const std::string Name
Definition: USRFinder.cpp:140
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:490
unsigned Column
Definition: Modularize.cpp:388
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Definition: Modularize.cpp:705
Location Loc
Definition: Modularize.cpp:464
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:412
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:573
friend bool operator<=(const Location &X, const Location &Y)
Definition: Modularize.cpp:424
llvm::SmallVector< std::string, 4 > DependentsVector
Definition: Modularize.h:32
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
Definition: Modularize.cpp:561
static clang::FrontendPluginRegistry::Add< clang::tidy::ClangTidyPluginAction > X("clang-tidy","clang-tidy")
const char * Argv0
Definition: Modularize.cpp:334
StringRef getKindName()
Definition: Modularize.cpp:443
bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs)
Definition: Modularize.cpp:754
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
Definition: Modularize.cpp:751
bool TraverseTemplateName(TemplateName Template)
Definition: Modularize.cpp:749
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:697
bool VisitNamedDecl(NamedDecl *ND)
Definition: Modularize.cpp:772
int Column
static ArgumentsAdjuster getModularizeArgumentsAdjuster(DependencyMap &Dependencies)
Definition: Modularize.cpp:358
static cl::list< std::string > ListFileNames(cl::Positional, cl::value_desc("list"), cl::desc("<list of one or more header list files>"), cl::CommaSeparated)
ModularizeFrontendActionFactory(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, int &HadErrors)
Definition: Modularize.cpp:718
friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:475
ModularizeUtilities class definition.
friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:481
void mergeCurHeaderContents()
Definition: Modularize.cpp:509
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Definition: Modularize.cpp:743
const FileEntry * File
Definition: Modularize.cpp:387
BindArgumentKind Kind
SourceManager & SM
static std::string findInputFile(const CommandLineArguments &CLArgs)
Definition: Modularize.cpp:339
Location Loc
Definition: Modularize.cpp:441
friend bool operator<(const Location &X, const Location &Y)
Definition: Modularize.cpp:416
void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc)
Definition: Modularize.cpp:492
bool VisitNamespaceDecl(const NamespaceDecl *D)
Definition: Modularize.cpp:767
bool TraverseStmt(Stmt *S)
Definition: Modularize.cpp:554
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo)
Definition: Modularize.cpp:746
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Definition: Modularize.cpp:758
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:598
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Definition: Modularize.cpp:792
friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:466
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:472
bool TraverseStmt(Stmt *S)
Definition: Modularize.cpp:739
int main(int Argc, const char **Argv)
Definition: Modularize.cpp:806
bool TraverseLambdaCapture(LambdaCapture C)
Definition: Modularize.cpp:759
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
Definition: Modularize.cpp:762
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Definition: Modularize.cpp:557
~CollectEntitiesConsumer() override
Definition: Modularize.cpp:664
std::string CommandLine
Definition: Modularize.cpp:336
Preprocessor * PP
CompileCheckAction * create() override
Definition: Modularize.cpp:801
bool TraverseTypeLoc(TypeLoc TL)
Definition: Modularize.cpp:556
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:724
static cl::list< std::string > IncludePaths("I", cl::desc("Include path for coverage check."), cl::ZeroOrMore, cl::value_desc("path"))
friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:469
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:463
friend bool operator>=(const Location &X, const Location &Y)
Definition: Modularize.cpp:427
friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y)
Definition: Modularize.cpp:478
friend bool operator==(const Location &X, const Location &Y)
Definition: Modularize.cpp:408
bool VisitLinkageSpecDecl(LinkageSpecDecl *D)
Definition: Modularize.cpp:577
bool TraverseTemplateName(TemplateName Template)
Definition: Modularize.cpp:564
Location(SourceManager &SM, SourceLocation Loc)
Definition: Modularize.cpp:392
unsigned Line
Definition: Modularize.cpp:388
bool TraverseType(QualType T)
Definition: Modularize.cpp:740
std::vector< HeaderEntry > HeaderContents
Definition: Modularize.cpp:486
bool VisitNamedDecl(NamedDecl *ND)
Definition: Modularize.cpp:610
CollectEntitiesConsumer(EntityMap &Entities, PreprocessorTracker &preprocessorTracker, Preprocessor &PP, StringRef InFile, int &HadErrors)
Definition: Modularize.cpp:656
Preprocessor tracker for modularize.
bool TraverseTypeLoc(TypeLoc TL)
Definition: Modularize.cpp:741
bool TraverseType(QualType T)
Definition: Modularize.cpp:555
bool TraverseTemplateArgument(const TemplateArgument &Arg)
Definition: Modularize.cpp:750
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:558
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
Definition: Modularize.cpp:566
CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities, Preprocessor &PP, PreprocessorTracker &PPTracker, int &HadErrors)
Definition: Modularize.cpp:548
bool TraverseTemplateArgument(const TemplateArgument &Arg)
Definition: Modularize.cpp:565
bool TraverseLambdaCapture(LambdaCapture C)
Definition: Modularize.cpp:574
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Definition: Modularize.cpp:742