clang  8.0.0svn
PlistDiagnostics.cpp
Go to the documentation of this file.
1 //===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===//
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 defines the PlistDiagnostics object.
11 //
12 //===----------------------------------------------------------------------===//
13 
17 #include "clang/Basic/Version.h"
18 #include "clang/Lex/Preprocessor.h"
24 #include "llvm/ADT/Statistic.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/Support/Casting.h"
27 using namespace clang;
28 using namespace ento;
29 using namespace markup;
30 
31 namespace {
32  class PlistDiagnostics : public PathDiagnosticConsumer {
33  const std::string OutputFile;
34  const Preprocessor &PP;
35  AnalyzerOptions &AnOpts;
36  const bool SupportsCrossFileDiagnostics;
37  public:
38  PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
39  const std::string& prefix,
40  const Preprocessor &PP,
41  bool supportsMultipleFiles);
42 
43  ~PlistDiagnostics() override {}
44 
45  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
46  FilesMade *filesMade) override;
47 
48  StringRef getName() const override {
49  return "PlistDiagnostics";
50  }
51 
52  PathGenerationScheme getGenerationScheme() const override {
53  return Extensive;
54  }
55  bool supportsLogicalOpControlFlow() const override { return true; }
56  bool supportsCrossFileDiagnostics() const override {
57  return SupportsCrossFileDiagnostics;
58  }
59  };
60 } // end anonymous namespace
61 
62 PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
63  const std::string& output,
64  const Preprocessor &PP,
65  bool supportsMultipleFiles)
66  : OutputFile(output), PP(PP), AnOpts(AnalyzerOpts),
67  SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
68 
69 void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
71  const std::string& s,
72  const Preprocessor &PP) {
73  C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
74  /*supportsMultipleFiles*/ false));
75 }
76 
77 void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
79  const std::string &s,
80  const Preprocessor &PP) {
81  C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
82  /*supportsMultipleFiles*/ true));
83 }
84 
85 static void EmitRanges(raw_ostream &o,
86  const ArrayRef<SourceRange> Ranges,
87  const FIDMap& FM,
88  const Preprocessor &PP,
89  unsigned indent) {
90 
91  if (Ranges.empty())
92  return;
93 
94  Indent(o, indent) << "<key>ranges</key>\n";
95  Indent(o, indent) << "<array>\n";
96  ++indent;
97 
98  const SourceManager &SM = PP.getSourceManager();
99  const LangOptions &LangOpts = PP.getLangOpts();
100 
101  for (auto &R : Ranges)
102  EmitRange(o, SM,
103  Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts),
104  FM, indent + 1);
105  --indent;
106  Indent(o, indent) << "</array>\n";
107 }
108 
109 static void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent) {
110  // Output the text.
111  assert(!Message.empty());
112  Indent(o, indent) << "<key>extended_message</key>\n";
113  Indent(o, indent);
114  EmitString(o, Message) << '\n';
115 
116  // Output the short text.
117  // FIXME: Really use a short string.
118  Indent(o, indent) << "<key>message</key>\n";
119  Indent(o, indent);
120  EmitString(o, Message) << '\n';
121 }
122 
123 static void ReportControlFlow(raw_ostream &o,
124  const PathDiagnosticControlFlowPiece& P,
125  const FIDMap& FM,
126  const Preprocessor &PP,
127  unsigned indent) {
128 
129  const SourceManager &SM = PP.getSourceManager();
130  const LangOptions &LangOpts = PP.getLangOpts();
131 
132  Indent(o, indent) << "<dict>\n";
133  ++indent;
134 
135  Indent(o, indent) << "<key>kind</key><string>control</string>\n";
136 
137  // Emit edges.
138  Indent(o, indent) << "<key>edges</key>\n";
139  ++indent;
140  Indent(o, indent) << "<array>\n";
141  ++indent;
142  for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
143  I!=E; ++I) {
144  Indent(o, indent) << "<dict>\n";
145  ++indent;
146 
147  // Make the ranges of the start and end point self-consistent with adjacent edges
148  // by forcing to use only the beginning of the range. This simplifies the layout
149  // logic for clients.
150  Indent(o, indent) << "<key>start</key>\n";
151  SourceRange StartEdge(
152  SM.getExpansionLoc(I->getStart().asRange().getBegin()));
153  EmitRange(o, SM, Lexer::getAsCharRange(StartEdge, SM, LangOpts), FM,
154  indent + 1);
155 
156  Indent(o, indent) << "<key>end</key>\n";
157  SourceRange EndEdge(SM.getExpansionLoc(I->getEnd().asRange().getBegin()));
158  EmitRange(o, SM, Lexer::getAsCharRange(EndEdge, SM, LangOpts), FM,
159  indent + 1);
160 
161  --indent;
162  Indent(o, indent) << "</dict>\n";
163  }
164  --indent;
165  Indent(o, indent) << "</array>\n";
166  --indent;
167 
168  // Output any helper text.
169  const auto &s = P.getString();
170  if (!s.empty()) {
171  Indent(o, indent) << "<key>alternate</key>";
172  EmitString(o, s) << '\n';
173  }
174 
175  --indent;
176  Indent(o, indent) << "</dict>\n";
177 }
178 
179 static void ReportEvent(raw_ostream &o,
180  const PathDiagnosticEventPiece& P,
181  const FIDMap& FM,
182  const Preprocessor &PP,
183  unsigned indent,
184  unsigned depth,
185  bool isKeyEvent = false) {
186 
187  const SourceManager &SM = PP.getSourceManager();
188 
189  Indent(o, indent) << "<dict>\n";
190  ++indent;
191 
192  Indent(o, indent) << "<key>kind</key><string>event</string>\n";
193 
194  if (isKeyEvent) {
195  Indent(o, indent) << "<key>key_event</key><true/>\n";
196  }
197 
198  // Output the location.
199  FullSourceLoc L = P.getLocation().asLocation();
200 
201  Indent(o, indent) << "<key>location</key>\n";
202  EmitLocation(o, SM, L, FM, indent);
203 
204  // Output the ranges (if any).
205  ArrayRef<SourceRange> Ranges = P.getRanges();
206  EmitRanges(o, Ranges, FM, PP, indent);
207 
208  // Output the call depth.
209  Indent(o, indent) << "<key>depth</key>";
210  EmitInteger(o, depth) << '\n';
211 
212  // Output the text.
213  EmitMessage(o, P.getString(), indent);
214 
215  // Finish up.
216  --indent;
217  Indent(o, indent); o << "</dict>\n";
218 }
219 
220 static void ReportPiece(raw_ostream &o,
221  const PathDiagnosticPiece &P,
222  const FIDMap& FM,
223  const Preprocessor &PP,
224  AnalyzerOptions &AnOpts,
225  unsigned indent,
226  unsigned depth,
227  bool includeControlFlow,
228  bool isKeyEvent = false);
229 
230 static void ReportCall(raw_ostream &o,
231  const PathDiagnosticCallPiece &P,
232  const FIDMap& FM,
233  const Preprocessor &PP,
234  AnalyzerOptions &AnOpts,
235  unsigned indent,
236  unsigned depth) {
237 
238  if (auto callEnter = P.getCallEnterEvent())
239  ReportPiece(o, *callEnter, FM, PP, AnOpts, indent, depth,
240  /*includeControlFlow*/ true, P.isLastInMainSourceFile());
241 
242 
243  ++depth;
244 
245  if (auto callEnterWithinCaller = P.getCallEnterWithinCallerEvent())
246  ReportPiece(o, *callEnterWithinCaller, FM, PP, AnOpts, indent, depth,
247  /*includeControlFlow*/ true);
248 
249  for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
250  ReportPiece(o, **I, FM, PP, AnOpts, indent, depth,
251  /*includeControlFlow*/ true);
252 
253  --depth;
254 
255  if (auto callExit = P.getCallExitEvent())
256  ReportPiece(o, *callExit, FM, PP, AnOpts, indent, depth,
257  /*includeControlFlow*/ true);
258 }
259 
260 static void ReportMacro(raw_ostream &o,
261  const PathDiagnosticMacroPiece& P,
262  const FIDMap& FM,
263  const Preprocessor &PP,
264  AnalyzerOptions &AnOpts,
265  unsigned indent,
266  unsigned depth) {
267 
268  for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
269  I!=E; ++I) {
270  ReportPiece(o, **I, FM, PP, AnOpts, indent, depth,
271  /*includeControlFlow*/ false);
272  }
273 }
274 
275 static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P,
276  const FIDMap& FM,
277  const Preprocessor &PP,
278  unsigned indent) {
279 
280  const SourceManager &SM = PP.getSourceManager();
281 
282  Indent(o, indent) << "<dict>\n";
283  ++indent;
284 
285  // Output the location.
286  FullSourceLoc L = P.getLocation().asLocation();
287 
288  Indent(o, indent) << "<key>location</key>\n";
289  EmitLocation(o, SM, L, FM, indent);
290 
291  // Output the ranges (if any).
292  ArrayRef<SourceRange> Ranges = P.getRanges();
293  EmitRanges(o, Ranges, FM, PP, indent);
294 
295  // Output the text.
296  EmitMessage(o, P.getString(), indent);
297 
298  // Finish up.
299  --indent;
300  Indent(o, indent); o << "</dict>\n";
301 }
302 
303 static void ReportDiag(raw_ostream &o,
304  const PathDiagnosticPiece& P,
305  const FIDMap& FM,
306  const Preprocessor &PP,
307  AnalyzerOptions &AnOpts) {
308  ReportPiece(o, P, FM, PP, AnOpts, /*indent*/ 4, /*depth*/ 0,
309  /*includeControlFlow*/ true);
310 }
311 
312 static void ReportPiece(raw_ostream &o,
313  const PathDiagnosticPiece &P,
314  const FIDMap& FM,
315  const Preprocessor &PP,
316  AnalyzerOptions &AnOpts,
317  unsigned indent,
318  unsigned depth,
319  bool includeControlFlow,
320  bool isKeyEvent) {
321  switch (P.getKind()) {
323  if (includeControlFlow)
324  ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, PP,
325  indent);
326  break;
328  ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, PP, AnOpts, indent,
329  depth);
330  break;
332  ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, PP, indent, depth,
333  isKeyEvent);
334  break;
336  ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, PP, AnOpts, indent,
337  depth);
338  break;
340  ReportNote(o, cast<PathDiagnosticNotePiece>(P), FM, PP, indent);
341  break;
342  }
343 }
344 
345 /// Print coverage information to output stream {@code o}.
346 /// May modify the used list of files {@code Fids} by inserting new ones.
347 static void printCoverage(const PathDiagnostic *D,
348  unsigned InputIndentLevel,
350  FIDMap &FM,
351  llvm::raw_fd_ostream &o) {
352  unsigned IndentLevel = InputIndentLevel;
353 
354  Indent(o, IndentLevel) << "<key>ExecutedLines</key>\n";
355  Indent(o, IndentLevel) << "<dict>\n";
356  IndentLevel++;
357 
358  // Mapping from file IDs to executed lines.
359  const FilesToLineNumsMap &ExecutedLines = D->getExecutedLines();
360  for (auto I = ExecutedLines.begin(), E = ExecutedLines.end(); I != E; ++I) {
361  unsigned FileKey = AddFID(FM, Fids, I->first);
362  Indent(o, IndentLevel) << "<key>" << FileKey << "</key>\n";
363  Indent(o, IndentLevel) << "<array>\n";
364  IndentLevel++;
365  for (unsigned LineNo : I->second) {
366  Indent(o, IndentLevel);
367  EmitInteger(o, LineNo) << "\n";
368  }
369  IndentLevel--;
370  Indent(o, IndentLevel) << "</array>\n";
371  }
372  IndentLevel--;
373  Indent(o, IndentLevel) << "</dict>\n";
374 
375  assert(IndentLevel == InputIndentLevel);
376 }
377 
378 void PlistDiagnostics::FlushDiagnosticsImpl(
379  std::vector<const PathDiagnostic *> &Diags,
380  FilesMade *filesMade) {
381  // Build up a set of FIDs that we use by scanning the locations and
382  // ranges of the diagnostics.
383  FIDMap FM;
385  const SourceManager& SM = PP.getSourceManager();
386  const LangOptions &LangOpts = PP.getLangOpts();
387 
388  auto AddPieceFID = [&FM, &Fids, &SM](const PathDiagnosticPiece &Piece) {
389  AddFID(FM, Fids, SM, Piece.getLocation().asLocation());
390  ArrayRef<SourceRange> Ranges = Piece.getRanges();
391  for (const SourceRange &Range : Ranges) {
392  AddFID(FM, Fids, SM, Range.getBegin());
393  AddFID(FM, Fids, SM, Range.getEnd());
394  }
395  };
396 
397  for (const PathDiagnostic *D : Diags) {
398 
400  WorkList.push_back(&D->path);
401 
402  while (!WorkList.empty()) {
403  const PathPieces &Path = *WorkList.pop_back_val();
404 
405  for (const auto &Iter : Path) {
406  const PathDiagnosticPiece &Piece = *Iter;
407  AddPieceFID(Piece);
408 
409  if (const PathDiagnosticCallPiece *Call =
410  dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
411  if (auto CallEnterWithin = Call->getCallEnterWithinCallerEvent())
412  AddPieceFID(*CallEnterWithin);
413 
414  if (auto CallEnterEvent = Call->getCallEnterEvent())
415  AddPieceFID(*CallEnterEvent);
416 
417  WorkList.push_back(&Call->path);
418  } else if (const PathDiagnosticMacroPiece *Macro =
419  dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
420  WorkList.push_back(&Macro->subPieces);
421  }
422  }
423  }
424  }
425 
426  // Open the file.
427  std::error_code EC;
428  llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
429  if (EC) {
430  llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
431  return;
432  }
433 
434  EmitPlistHeader(o);
435 
436  // Write the root object: a <dict> containing...
437  // - "clang_version", the string representation of clang version
438  // - "files", an <array> mapping from FIDs to file names
439  // - "diagnostics", an <array> containing the path diagnostics
440  o << "<dict>\n" <<
441  " <key>clang_version</key>\n";
442  EmitString(o, getClangFullVersion()) << '\n';
443  o << " <key>diagnostics</key>\n"
444  " <array>\n";
445 
446  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
447  DE = Diags.end(); DI!=DE; ++DI) {
448 
449  o << " <dict>\n";
450 
451  const PathDiagnostic *D = *DI;
452  const PathPieces &Path = D->path;
453 
454  assert(std::is_partitioned(
455  Path.begin(), Path.end(),
456  [](const std::shared_ptr<PathDiagnosticPiece> &E)
457  { return E->getKind() == PathDiagnosticPiece::Note; }) &&
458  "PathDiagnostic is not partitioned so that notes precede the rest");
459 
460  PathPieces::const_iterator FirstNonNote = std::partition_point(
461  Path.begin(), Path.end(),
462  [](const std::shared_ptr<PathDiagnosticPiece> &E)
463  { return E->getKind() == PathDiagnosticPiece::Note; });
464 
465  PathPieces::const_iterator I = Path.begin();
466 
467  if (FirstNonNote != Path.begin()) {
468  o << " <key>notes</key>\n"
469  " <array>\n";
470 
471  for (; I != FirstNonNote; ++I)
472  ReportDiag(o, **I, FM, PP, AnOpts);
473 
474  o << " </array>\n";
475  }
476 
477  o << " <key>path</key>\n";
478 
479  o << " <array>\n";
480 
481  for (PathPieces::const_iterator E = Path.end(); I != E; ++I)
482  ReportDiag(o, **I, FM, PP, AnOpts);
483 
484  o << " </array>\n";
485 
486  // Output the bug type and bug category.
487  o << " <key>description</key>";
488  EmitString(o, D->getShortDescription()) << '\n';
489  o << " <key>category</key>";
490  EmitString(o, D->getCategory()) << '\n';
491  o << " <key>type</key>";
492  EmitString(o, D->getBugType()) << '\n';
493  o << " <key>check_name</key>";
494  EmitString(o, D->getCheckName()) << '\n';
495 
496  o << " <!-- This hash is experimental and going to change! -->\n";
497  o << " <key>issue_hash_content_of_line_in_context</key>";
498  PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
499  FullSourceLoc L(SM.getExpansionLoc(UPDLoc.isValid()
500  ? UPDLoc.asLocation()
501  : D->getLocation().asLocation()),
502  SM);
503  const Decl *DeclWithIssue = D->getDeclWithIssue();
504  EmitString(o, GetIssueHash(SM, L, D->getCheckName(), D->getBugType(),
505  DeclWithIssue, LangOpts))
506  << '\n';
507 
508  // Output information about the semantic context where
509  // the issue occurred.
510  if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
511  // FIXME: handle blocks, which have no name.
512  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
513  StringRef declKind;
514  switch (ND->getKind()) {
515  case Decl::CXXRecord:
516  declKind = "C++ class";
517  break;
518  case Decl::CXXMethod:
519  declKind = "C++ method";
520  break;
521  case Decl::ObjCMethod:
522  declKind = "Objective-C method";
523  break;
524  case Decl::Function:
525  declKind = "function";
526  break;
527  default:
528  break;
529  }
530  if (!declKind.empty()) {
531  const std::string &declName = ND->getDeclName().getAsString();
532  o << " <key>issue_context_kind</key>";
533  EmitString(o, declKind) << '\n';
534  o << " <key>issue_context</key>";
535  EmitString(o, declName) << '\n';
536  }
537 
538  // Output the bug hash for issue unique-ing. Currently, it's just an
539  // offset from the beginning of the function.
540  if (const Stmt *Body = DeclWithIssue->getBody()) {
541 
542  // If the bug uniqueing location exists, use it for the hash.
543  // For example, this ensures that two leaks reported on the same line
544  // will have different issue_hashes and that the hash will identify
545  // the leak location even after code is added between the allocation
546  // site and the end of scope (leak report location).
547  if (UPDLoc.isValid()) {
548  FullSourceLoc UFunL(
549  SM.getExpansionLoc(
550  D->getUniqueingDecl()->getBody()->getBeginLoc()),
551  SM);
552  o << " <key>issue_hash_function_offset</key><string>"
554  << "</string>\n";
555 
556  // Otherwise, use the location on which the bug is reported.
557  } else {
558  FullSourceLoc FunL(SM.getExpansionLoc(Body->getBeginLoc()), SM);
559  o << " <key>issue_hash_function_offset</key><string>"
561  << "</string>\n";
562  }
563 
564  }
565  }
566  }
567 
568  // Output the location of the bug.
569  o << " <key>location</key>\n";
570  EmitLocation(o, SM, D->getLocation().asLocation(), FM, 2);
571 
572  // Output the diagnostic to the sub-diagnostic client, if any.
573  if (!filesMade->empty()) {
574  StringRef lastName;
575  PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
576  if (files) {
577  for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
578  CE = files->end(); CI != CE; ++CI) {
579  StringRef newName = CI->first;
580  if (newName != lastName) {
581  if (!lastName.empty()) {
582  o << " </array>\n";
583  }
584  lastName = newName;
585  o << " <key>" << lastName << "_files</key>\n";
586  o << " <array>\n";
587  }
588  o << " <string>" << CI->second << "</string>\n";
589  }
590  o << " </array>\n";
591  }
592  }
593 
594  printCoverage(D, /*IndentLevel=*/2, Fids, FM, o);
595 
596  // Close up the entry.
597  o << " </dict>\n";
598  }
599 
600  o << " </array>\n";
601 
602  o << " <key>files</key>\n"
603  " <array>\n";
604  for (FileID FID : Fids)
605  EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
606  o << " </array>\n";
607 
608  if (llvm::AreStatisticsEnabled() && AnOpts.shouldSerializeStats()) {
609  o << " <key>statistics</key>\n";
610  std::string stats;
611  llvm::raw_string_ostream os(stats);
612  llvm::PrintStatisticsJSON(os);
613  os.flush();
614  EmitString(o, html::EscapeText(stats)) << '\n';
615  }
616 
617  // Finish.
618  o << "</dict>\n</plist>";
619 }
void EmitLocation(raw_ostream &o, const SourceManager &SM, SourceLocation L, const FIDMap &FM, unsigned indent)
Definition: PlistSupport.h:108
Defines the clang::FileManager interface and associated types.
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number...
Definition: Version.cpp:118
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:979
Stmt - This represents one statement.
Definition: Stmt.h:66
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:87
StringRef P
llvm::SmallString< 32 > GetIssueHash(const SourceManager &SM, FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef BugType, const Decl *D, const LangOptions &LangOpts)
Get an MD5 hash to help identify bugs.
static void EmitRanges(raw_ostream &o, const ArrayRef< SourceRange > Ranges, const FIDMap &FM, const Preprocessor &PP, unsigned indent)
constexpr XRayInstrMask Function
Definition: XRayInstr.h:39
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
Definition: PlistSupport.h:72
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
unsigned AddFID(FIDMap &FIDs, SmallVectorImpl< FileID > &V, FileID FID)
Definition: PlistSupport.h:28
static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece &P, const FIDMap &FM, const Preprocessor &PP, unsigned indent)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:50
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:827
static void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, const FIDMap &FM, const Preprocessor &PP, AnalyzerOptions &AnOpts, unsigned indent, unsigned depth)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece &P, const FIDMap &FM, const Preprocessor &PP, unsigned indent)
static void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece &P, const FIDMap &FM, const Preprocessor &PP, unsigned indent, unsigned depth, bool isKeyEvent=false)
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Defines version macros and version-related utility functions for Clang.
Defines the clang::Preprocessor interface.
SourceLocation getEnd() const
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
llvm::DenseMap< FileID, unsigned > FIDMap
Definition: PlistSupport.h:26
SourceManager & getSourceManager() const
Definition: Preprocessor.h:831
StringRef getName() const
Definition: FileManager.h:85
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
void EscapeText(Rewriter &R, FileID FID, bool EscapeSpaces=false, bool ReplaceTabs=false)
EscapeText - HTMLize a specified file so that special characters are are translated so that they are ...
raw_ostream & EmitPlistHeader(raw_ostream &o)
Definition: PlistSupport.h:63
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Dataflow Directional Tag Classes.
PathDiagnosticLocation()=default
Create an invalid location.
void EmitRange(raw_ostream &o, const SourceManager &SM, CharSourceRange R, const FIDMap &FM, unsigned indent)
Definition: PlistSupport.h:124
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
Definition: Lexer.h:380
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
raw_ostream & EmitString(raw_ostream &o, StringRef s)
Definition: PlistSupport.h:79
static void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece &P, const FIDMap &FM, const Preprocessor &PP, AnalyzerOptions &AnOpts, unsigned indent, unsigned depth)
static void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent)
static void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const Preprocessor &PP, AnalyzerOptions &AnOpts, unsigned indent, unsigned depth, bool includeControlFlow, bool isKeyEvent=false)
A SourceLocation and its associated SourceManager.
A trivial tuple used to represent a source range.
static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap &FM, const Preprocessor &PP, AnalyzerOptions &AnOpts)
This represents a decl that may have a name.
Definition: Decl.h:248
SourceLocation getBegin() const
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:127