clang  9.0.0svn
PlistDiagnostics.cpp
Go to the documentation of this file.
1 //===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the PlistDiagnostics object.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "clang/Basic/Version.h"
17 #include "clang/Lex/Preprocessor.h"
24 #include "llvm/ADT/Statistic.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/Support/Casting.h"
27 
28 using namespace clang;
29 using namespace ento;
30 using namespace markup;
31 
32 //===----------------------------------------------------------------------===//
33 // Declarations of helper classes and functions for emitting bug reports in
34 // plist format.
35 //===----------------------------------------------------------------------===//
36 
37 namespace {
38  class PlistDiagnostics : public PathDiagnosticConsumer {
39  const std::string OutputFile;
40  const Preprocessor &PP;
41  AnalyzerOptions &AnOpts;
42  const bool SupportsCrossFileDiagnostics;
43  public:
44  PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
45  const std::string& prefix,
46  const Preprocessor &PP,
47  bool supportsMultipleFiles);
48 
49  ~PlistDiagnostics() override {}
50 
51  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
52  FilesMade *filesMade) override;
53 
54  StringRef getName() const override {
55  return "PlistDiagnostics";
56  }
57 
58  PathGenerationScheme getGenerationScheme() const override {
59  return Extensive;
60  }
61  bool supportsLogicalOpControlFlow() const override { return true; }
62  bool supportsCrossFileDiagnostics() const override {
63  return SupportsCrossFileDiagnostics;
64  }
65  };
66 } // end anonymous namespace
67 
68 namespace {
69 
70 /// A helper class for emitting a single report.
71 class PlistPrinter {
72  const FIDMap& FM;
73  AnalyzerOptions &AnOpts;
74  const Preprocessor &PP;
76 
77 public:
78  PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts,
79  const Preprocessor &PP)
80  : FM(FM), AnOpts(AnOpts), PP(PP) {
81  }
82 
83  void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) {
84  ReportPiece(o, P, /*indent*/ 4, /*depth*/ 0, /*includeControlFlow*/ true);
85 
86  // Don't emit a warning about an unused private field.
87  (void)AnOpts;
88  }
89 
90  /// Print the expansions of the collected macro pieces.
91  ///
92  /// Each time ReportDiag is called on a PathDiagnosticMacroPiece (or, if one
93  /// is found through a call piece, etc), it's subpieces are reported, and the
94  /// piece itself is collected. Call this function after the entire bugpath
95  /// was reported.
96  void ReportMacroExpansions(raw_ostream &o, unsigned indent);
97 
98 private:
99  void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P,
100  unsigned indent, unsigned depth, bool includeControlFlow,
101  bool isKeyEvent = false) {
102  switch (P.getKind()) {
104  if (includeControlFlow)
105  ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), indent);
106  break;
108  ReportCall(o, cast<PathDiagnosticCallPiece>(P), indent,
109  depth);
110  break;
112  ReportEvent(o, cast<PathDiagnosticEventPiece>(P), indent, depth,
113  isKeyEvent);
114  break;
116  ReportMacroSubPieces(o, cast<PathDiagnosticMacroPiece>(P), indent,
117  depth);
118  break;
120  ReportNote(o, cast<PathDiagnosticNotePiece>(P), indent);
121  break;
122  }
123  }
124 
125  void EmitRanges(raw_ostream &o, const ArrayRef<SourceRange> Ranges,
126  unsigned indent);
127  void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent);
128 
129  void ReportControlFlow(raw_ostream &o,
130  const PathDiagnosticControlFlowPiece& P,
131  unsigned indent);
132  void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P,
133  unsigned indent, unsigned depth, bool isKeyEvent = false);
134  void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P,
135  unsigned indent, unsigned depth);
136  void ReportMacroSubPieces(raw_ostream &o, const PathDiagnosticMacroPiece& P,
137  unsigned indent, unsigned depth);
138  void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P,
139  unsigned indent);
140 };
141 
142 } // end of anonymous namespace
143 
144 namespace {
145 
146 struct ExpansionInfo {
147  std::string MacroName;
148  std::string Expansion;
149  ExpansionInfo(std::string N, std::string E)
150  : MacroName(std::move(N)), Expansion(std::move(E)) {}
151 };
152 
153 } // end of anonymous namespace
154 
155 static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
156  AnalyzerOptions &AnOpts,
157  const Preprocessor &PP,
158  const PathPieces &Path);
159 
160 /// Print coverage information to output stream {@code o}.
161 /// May modify the used list of files {@code Fids} by inserting new ones.
162 static void printCoverage(const PathDiagnostic *D,
163  unsigned InputIndentLevel,
165  FIDMap &FM,
166  llvm::raw_fd_ostream &o);
167 
168 static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
169  const Preprocessor &PP);
170 
171 //===----------------------------------------------------------------------===//
172 // Methods of PlistPrinter.
173 //===----------------------------------------------------------------------===//
174 
175 void PlistPrinter::EmitRanges(raw_ostream &o,
176  const ArrayRef<SourceRange> Ranges,
177  unsigned indent) {
178 
179  if (Ranges.empty())
180  return;
181 
182  Indent(o, indent) << "<key>ranges</key>\n";
183  Indent(o, indent) << "<array>\n";
184  ++indent;
185 
186  const SourceManager &SM = PP.getSourceManager();
187  const LangOptions &LangOpts = PP.getLangOpts();
188 
189  for (auto &R : Ranges)
190  EmitRange(o, SM,
191  Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts),
192  FM, indent + 1);
193  --indent;
194  Indent(o, indent) << "</array>\n";
195 }
196 
197 void PlistPrinter::EmitMessage(raw_ostream &o, StringRef Message,
198  unsigned indent) {
199  // Output the text.
200  assert(!Message.empty());
201  Indent(o, indent) << "<key>extended_message</key>\n";
202  Indent(o, indent);
203  EmitString(o, Message) << '\n';
204 
205  // Output the short text.
206  // FIXME: Really use a short string.
207  Indent(o, indent) << "<key>message</key>\n";
208  Indent(o, indent);
209  EmitString(o, Message) << '\n';
210 }
211 
212 void PlistPrinter::ReportControlFlow(raw_ostream &o,
213  const PathDiagnosticControlFlowPiece& P,
214  unsigned indent) {
215 
216  const SourceManager &SM = PP.getSourceManager();
217  const LangOptions &LangOpts = PP.getLangOpts();
218 
219  Indent(o, indent) << "<dict>\n";
220  ++indent;
221 
222  Indent(o, indent) << "<key>kind</key><string>control</string>\n";
223 
224  // Emit edges.
225  Indent(o, indent) << "<key>edges</key>\n";
226  ++indent;
227  Indent(o, indent) << "<array>\n";
228  ++indent;
229  for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
230  I!=E; ++I) {
231  Indent(o, indent) << "<dict>\n";
232  ++indent;
233 
234  // Make the ranges of the start and end point self-consistent with adjacent edges
235  // by forcing to use only the beginning of the range. This simplifies the layout
236  // logic for clients.
237  Indent(o, indent) << "<key>start</key>\n";
238  SourceRange StartEdge(
239  SM.getExpansionLoc(I->getStart().asRange().getBegin()));
240  EmitRange(o, SM, Lexer::getAsCharRange(StartEdge, SM, LangOpts), FM,
241  indent + 1);
242 
243  Indent(o, indent) << "<key>end</key>\n";
244  SourceRange EndEdge(SM.getExpansionLoc(I->getEnd().asRange().getBegin()));
245  EmitRange(o, SM, Lexer::getAsCharRange(EndEdge, SM, LangOpts), FM,
246  indent + 1);
247 
248  --indent;
249  Indent(o, indent) << "</dict>\n";
250  }
251  --indent;
252  Indent(o, indent) << "</array>\n";
253  --indent;
254 
255  // Output any helper text.
256  const auto &s = P.getString();
257  if (!s.empty()) {
258  Indent(o, indent) << "<key>alternate</key>";
259  EmitString(o, s) << '\n';
260  }
261 
262  --indent;
263  Indent(o, indent) << "</dict>\n";
264 }
265 
266 void PlistPrinter::ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P,
267  unsigned indent, unsigned depth,
268  bool isKeyEvent) {
269 
270  const SourceManager &SM = PP.getSourceManager();
271 
272  Indent(o, indent) << "<dict>\n";
273  ++indent;
274 
275  Indent(o, indent) << "<key>kind</key><string>event</string>\n";
276 
277  if (isKeyEvent) {
278  Indent(o, indent) << "<key>key_event</key><true/>\n";
279  }
280 
281  // Output the location.
282  FullSourceLoc L = P.getLocation().asLocation();
283 
284  Indent(o, indent) << "<key>location</key>\n";
285  EmitLocation(o, SM, L, FM, indent);
286 
287  // Output the ranges (if any).
288  ArrayRef<SourceRange> Ranges = P.getRanges();
289  EmitRanges(o, Ranges, indent);
290 
291  // Output the call depth.
292  Indent(o, indent) << "<key>depth</key>";
293  EmitInteger(o, depth) << '\n';
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 void PlistPrinter::ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P,
304  unsigned indent,
305  unsigned depth) {
306 
307  if (auto callEnter = P.getCallEnterEvent())
308  ReportPiece(o, *callEnter, indent, depth, /*includeControlFlow*/ true,
309  P.isLastInMainSourceFile());
310 
311 
312  ++depth;
313 
314  if (auto callEnterWithinCaller = P.getCallEnterWithinCallerEvent())
315  ReportPiece(o, *callEnterWithinCaller, indent, depth,
316  /*includeControlFlow*/ true);
317 
318  for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
319  ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ true);
320 
321  --depth;
322 
323  if (auto callExit = P.getCallExitEvent())
324  ReportPiece(o, *callExit, indent, depth, /*includeControlFlow*/ true);
325 }
326 
327 void PlistPrinter::ReportMacroSubPieces(raw_ostream &o,
328  const PathDiagnosticMacroPiece& P,
329  unsigned indent, unsigned depth) {
330  MacroPieces.push_back(&P);
331 
332  for (PathPieces::const_iterator I = P.subPieces.begin(),
333  E = P.subPieces.end();
334  I != E; ++I) {
335  ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false);
336  }
337 }
338 
339 void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {
340 
341  for (const PathDiagnosticMacroPiece *P : MacroPieces) {
342  const SourceManager &SM = PP.getSourceManager();
343  ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP);
344 
345  Indent(o, indent) << "<dict>\n";
346  ++indent;
347 
348  // Output the location.
349  FullSourceLoc L = P->getLocation().asLocation();
350 
351  Indent(o, indent) << "<key>location</key>\n";
352  EmitLocation(o, SM, L, FM, indent);
353 
354  // Output the ranges (if any).
355  ArrayRef<SourceRange> Ranges = P->getRanges();
356  EmitRanges(o, Ranges, indent);
357 
358  // Output the macro name.
359  Indent(o, indent) << "<key>name</key>";
360  EmitString(o, EI.MacroName) << '\n';
361 
362  // Output what it expands into.
363  Indent(o, indent) << "<key>expansion</key>";
364  EmitString(o, EI.Expansion) << '\n';
365 
366  // Finish up.
367  --indent;
368  Indent(o, indent);
369  o << "</dict>\n";
370  }
371 }
372 
373 void PlistPrinter::ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P,
374  unsigned indent) {
375 
376  const SourceManager &SM = PP.getSourceManager();
377 
378  Indent(o, indent) << "<dict>\n";
379  ++indent;
380 
381  // Output the location.
382  FullSourceLoc L = P.getLocation().asLocation();
383 
384  Indent(o, indent) << "<key>location</key>\n";
385  EmitLocation(o, SM, L, FM, indent);
386 
387  // Output the ranges (if any).
388  ArrayRef<SourceRange> Ranges = P.getRanges();
389  EmitRanges(o, Ranges, indent);
390 
391  // Output the text.
392  EmitMessage(o, P.getString(), indent);
393 
394  // Finish up.
395  --indent;
396  Indent(o, indent); o << "</dict>\n";
397 }
398 
399 //===----------------------------------------------------------------------===//
400 // Static function definitions.
401 //===----------------------------------------------------------------------===//
402 
403 /// Print coverage information to output stream {@code o}.
404 /// May modify the used list of files {@code Fids} by inserting new ones.
405 static void printCoverage(const PathDiagnostic *D,
406  unsigned InputIndentLevel,
408  FIDMap &FM,
409  llvm::raw_fd_ostream &o) {
410  unsigned IndentLevel = InputIndentLevel;
411 
412  Indent(o, IndentLevel) << "<key>ExecutedLines</key>\n";
413  Indent(o, IndentLevel) << "<dict>\n";
414  IndentLevel++;
415 
416  // Mapping from file IDs to executed lines.
417  const FilesToLineNumsMap &ExecutedLines = D->getExecutedLines();
418  for (auto I = ExecutedLines.begin(), E = ExecutedLines.end(); I != E; ++I) {
419  unsigned FileKey = AddFID(FM, Fids, I->first);
420  Indent(o, IndentLevel) << "<key>" << FileKey << "</key>\n";
421  Indent(o, IndentLevel) << "<array>\n";
422  IndentLevel++;
423  for (unsigned LineNo : I->second) {
424  Indent(o, IndentLevel);
425  EmitInteger(o, LineNo) << "\n";
426  }
427  IndentLevel--;
428  Indent(o, IndentLevel) << "</array>\n";
429  }
430  IndentLevel--;
431  Indent(o, IndentLevel) << "</dict>\n";
432 
433  assert(IndentLevel == InputIndentLevel);
434 }
435 
436 static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
437  AnalyzerOptions &AnOpts,
438  const Preprocessor &PP,
439  const PathPieces &Path) {
440  PlistPrinter Printer(FM, AnOpts, PP);
441  assert(std::is_partitioned(
442  Path.begin(), Path.end(),
443  [](const std::shared_ptr<PathDiagnosticPiece> &E)
444  { return E->getKind() == PathDiagnosticPiece::Note; }) &&
445  "PathDiagnostic is not partitioned so that notes precede the rest");
446 
447  PathPieces::const_iterator FirstNonNote = std::partition_point(
448  Path.begin(), Path.end(),
449  [](const std::shared_ptr<PathDiagnosticPiece> &E)
450  { return E->getKind() == PathDiagnosticPiece::Note; });
451 
452  PathPieces::const_iterator I = Path.begin();
453 
454  if (FirstNonNote != Path.begin()) {
455  o << " <key>notes</key>\n"
456  " <array>\n";
457 
458  for (; I != FirstNonNote; ++I)
459  Printer.ReportDiag(o, **I);
460 
461  o << " </array>\n";
462  }
463 
464  o << " <key>path</key>\n";
465 
466  o << " <array>\n";
467 
468  for (PathPieces::const_iterator E = Path.end(); I != E; ++I)
469  Printer.ReportDiag(o, **I);
470 
471  o << " </array>\n";
472 
473  if (!AnOpts.ShouldDisplayMacroExpansions)
474  return;
475 
476  o << " <key>macro_expansions</key>\n"
477  " <array>\n";
478  Printer.ReportMacroExpansions(o, /* indent */ 4);
479  o << " </array>\n";
480 }
481 
482 //===----------------------------------------------------------------------===//
483 // Methods of PlistDiagnostics.
484 //===----------------------------------------------------------------------===//
485 
486 PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
487  const std::string& output,
488  const Preprocessor &PP,
489  bool supportsMultipleFiles)
490  : OutputFile(output), PP(PP), AnOpts(AnalyzerOpts),
491  SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
492 
493 void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
495  const std::string& s,
496  const Preprocessor &PP) {
497  C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
498  /*supportsMultipleFiles*/ false));
499 }
500 
501 void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
503  const std::string &s,
504  const Preprocessor &PP) {
505  C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
506  /*supportsMultipleFiles*/ true));
507 }
508 void PlistDiagnostics::FlushDiagnosticsImpl(
509  std::vector<const PathDiagnostic *> &Diags,
510  FilesMade *filesMade) {
511  // Build up a set of FIDs that we use by scanning the locations and
512  // ranges of the diagnostics.
513  FIDMap FM;
515  const SourceManager& SM = PP.getSourceManager();
516  const LangOptions &LangOpts = PP.getLangOpts();
517 
518  auto AddPieceFID = [&FM, &Fids, &SM](const PathDiagnosticPiece &Piece) {
519  AddFID(FM, Fids, SM, Piece.getLocation().asLocation());
520  ArrayRef<SourceRange> Ranges = Piece.getRanges();
521  for (const SourceRange &Range : Ranges) {
522  AddFID(FM, Fids, SM, Range.getBegin());
523  AddFID(FM, Fids, SM, Range.getEnd());
524  }
525  };
526 
527  for (const PathDiagnostic *D : Diags) {
528 
530  WorkList.push_back(&D->path);
531 
532  while (!WorkList.empty()) {
533  const PathPieces &Path = *WorkList.pop_back_val();
534 
535  for (const auto &Iter : Path) {
536  const PathDiagnosticPiece &Piece = *Iter;
537  AddPieceFID(Piece);
538 
539  if (const PathDiagnosticCallPiece *Call =
540  dyn_cast<PathDiagnosticCallPiece>(&Piece)) {
541  if (auto CallEnterWithin = Call->getCallEnterWithinCallerEvent())
542  AddPieceFID(*CallEnterWithin);
543 
544  if (auto CallEnterEvent = Call->getCallEnterEvent())
545  AddPieceFID(*CallEnterEvent);
546 
547  WorkList.push_back(&Call->path);
548  } else if (const PathDiagnosticMacroPiece *Macro =
549  dyn_cast<PathDiagnosticMacroPiece>(&Piece)) {
550  WorkList.push_back(&Macro->subPieces);
551  }
552  }
553  }
554  }
555 
556  // Open the file.
557  std::error_code EC;
558  llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
559  if (EC) {
560  llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
561  return;
562  }
563 
564  EmitPlistHeader(o);
565 
566  // Write the root object: a <dict> containing...
567  // - "clang_version", the string representation of clang version
568  // - "files", an <array> mapping from FIDs to file names
569  // - "diagnostics", an <array> containing the path diagnostics
570  o << "<dict>\n" <<
571  " <key>clang_version</key>\n";
572  EmitString(o, getClangFullVersion()) << '\n';
573  o << " <key>diagnostics</key>\n"
574  " <array>\n";
575 
576  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
577  DE = Diags.end(); DI!=DE; ++DI) {
578 
579  o << " <dict>\n";
580 
581  const PathDiagnostic *D = *DI;
582  printBugPath(o, FM, AnOpts, PP, D->path);
583 
584  // Output the bug type and bug category.
585  o << " <key>description</key>";
586  EmitString(o, D->getShortDescription()) << '\n';
587  o << " <key>category</key>";
588  EmitString(o, D->getCategory()) << '\n';
589  o << " <key>type</key>";
590  EmitString(o, D->getBugType()) << '\n';
591  o << " <key>check_name</key>";
592  EmitString(o, D->getCheckName()) << '\n';
593 
594  o << " <!-- This hash is experimental and going to change! -->\n";
595  o << " <key>issue_hash_content_of_line_in_context</key>";
596  PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
597  FullSourceLoc L(SM.getExpansionLoc(UPDLoc.isValid()
598  ? UPDLoc.asLocation()
599  : D->getLocation().asLocation()),
600  SM);
601  const Decl *DeclWithIssue = D->getDeclWithIssue();
602  EmitString(o, GetIssueHash(SM, L, D->getCheckName(), D->getBugType(),
603  DeclWithIssue, LangOpts))
604  << '\n';
605 
606  // Output information about the semantic context where
607  // the issue occurred.
608  if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
609  // FIXME: handle blocks, which have no name.
610  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
611  StringRef declKind;
612  switch (ND->getKind()) {
613  case Decl::CXXRecord:
614  declKind = "C++ class";
615  break;
616  case Decl::CXXMethod:
617  declKind = "C++ method";
618  break;
619  case Decl::ObjCMethod:
620  declKind = "Objective-C method";
621  break;
622  case Decl::Function:
623  declKind = "function";
624  break;
625  default:
626  break;
627  }
628  if (!declKind.empty()) {
629  const std::string &declName = ND->getDeclName().getAsString();
630  o << " <key>issue_context_kind</key>";
631  EmitString(o, declKind) << '\n';
632  o << " <key>issue_context</key>";
633  EmitString(o, declName) << '\n';
634  }
635 
636  // Output the bug hash for issue unique-ing. Currently, it's just an
637  // offset from the beginning of the function.
638  if (const Stmt *Body = DeclWithIssue->getBody()) {
639 
640  // If the bug uniqueing location exists, use it for the hash.
641  // For example, this ensures that two leaks reported on the same line
642  // will have different issue_hashes and that the hash will identify
643  // the leak location even after code is added between the allocation
644  // site and the end of scope (leak report location).
645  if (UPDLoc.isValid()) {
646  FullSourceLoc UFunL(
647  SM.getExpansionLoc(
648  D->getUniqueingDecl()->getBody()->getBeginLoc()),
649  SM);
650  o << " <key>issue_hash_function_offset</key><string>"
651  << L.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
652  << "</string>\n";
653 
654  // Otherwise, use the location on which the bug is reported.
655  } else {
656  FullSourceLoc FunL(SM.getExpansionLoc(Body->getBeginLoc()), SM);
657  o << " <key>issue_hash_function_offset</key><string>"
658  << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
659  << "</string>\n";
660  }
661 
662  }
663  }
664  }
665 
666  // Output the location of the bug.
667  o << " <key>location</key>\n";
668  EmitLocation(o, SM, D->getLocation().asLocation(), FM, 2);
669 
670  // Output the diagnostic to the sub-diagnostic client, if any.
671  if (!filesMade->empty()) {
672  StringRef lastName;
673  PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
674  if (files) {
675  for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
676  CE = files->end(); CI != CE; ++CI) {
677  StringRef newName = CI->first;
678  if (newName != lastName) {
679  if (!lastName.empty()) {
680  o << " </array>\n";
681  }
682  lastName = newName;
683  o << " <key>" << lastName << "_files</key>\n";
684  o << " <array>\n";
685  }
686  o << " <string>" << CI->second << "</string>\n";
687  }
688  o << " </array>\n";
689  }
690  }
691 
692  printCoverage(D, /*IndentLevel=*/2, Fids, FM, o);
693 
694  // Close up the entry.
695  o << " </dict>\n";
696  }
697 
698  o << " </array>\n";
699 
700  o << " <key>files</key>\n"
701  " <array>\n";
702  for (FileID FID : Fids)
703  EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
704  o << " </array>\n";
705 
706  if (llvm::AreStatisticsEnabled() && AnOpts.ShouldSerializeStats) {
707  o << " <key>statistics</key>\n";
708  std::string stats;
709  llvm::raw_string_ostream os(stats);
710  llvm::PrintStatisticsJSON(os);
711  os.flush();
712  EmitString(o, html::EscapeText(stats)) << '\n';
713  }
714 
715  // Finish.
716  o << "</dict>\n</plist>";
717 }
718 
719 //===----------------------------------------------------------------------===//
720 // Declarations of helper functions and data structures for expanding macros.
721 //===----------------------------------------------------------------------===//
722 
723 namespace {
724 
725 using ExpArgTokens = llvm::SmallVector<Token, 2>;
726 
727 /// Maps unexpanded macro arguments to expanded arguments. A macro argument may
728 /// need to expanded further when it is nested inside another macro.
729 class MacroArgMap : public std::map<const IdentifierInfo *, ExpArgTokens> {
730 public:
731  void expandFromPrevMacro(const MacroArgMap &Super);
732 };
733 
734 struct MacroNameAndArgs {
735  std::string Name;
736  const MacroInfo *MI = nullptr;
737  MacroArgMap Args;
738 
739  MacroNameAndArgs(std::string N, const MacroInfo *MI, MacroArgMap M)
740  : Name(std::move(N)), MI(MI), Args(std::move(M)) {}
741 };
742 
743 class TokenPrinter {
744  llvm::raw_ostream &OS;
745  const Preprocessor &PP;
746 
747  Token PrevTok, PrevPrevTok;
748  TokenConcatenation ConcatInfo;
749 
750 public:
751  TokenPrinter(llvm::raw_ostream &OS, const Preprocessor &PP)
752  : OS(OS), PP(PP), ConcatInfo(PP) {
753  PrevTok.setKind(tok::unknown);
754  PrevPrevTok.setKind(tok::unknown);
755  }
756 
757  void printToken(const Token &Tok);
758 };
759 
760 } // end of anonymous namespace
761 
762 /// The implementation method of getMacroExpansion: It prints the expansion of
763 /// a macro to \p Printer, and returns with the name of the macro.
764 ///
765 /// Since macros can be nested in one another, this function may call itself
766 /// recursively.
767 ///
768 /// Unfortunately, macro arguments have to expanded manually. To understand why,
769 /// observe the following example:
770 ///
771 /// #define PRINT(x) print(x)
772 /// #define DO_SOMETHING(str) PRINT(str)
773 ///
774 /// DO_SOMETHING("Cute panda cubs.");
775 ///
776 /// As we expand the last line, we'll immediately replace PRINT(str) with
777 /// print(x). The information that both 'str' and 'x' refers to the same string
778 /// is an information we have to forward, hence the argument \p PrevArgs.
779 static std::string getMacroNameAndPrintExpansion(TokenPrinter &Printer,
780  SourceLocation MacroLoc,
781  const Preprocessor &PP,
782  const MacroArgMap &PrevArgs);
783 
784 /// Retrieves the name of the macro and what it's arguments expand into
785 /// at \p ExpanLoc.
786 ///
787 /// For example, for the following macro expansion:
788 ///
789 /// #define SET_TO_NULL(x) x = 0
790 /// #define NOT_SUSPICIOUS(a) \
791 /// { \
792 /// int b = 0; \
793 /// } \
794 /// SET_TO_NULL(a)
795 ///
796 /// int *ptr = new int(4);
797 /// NOT_SUSPICIOUS(&ptr);
798 /// *ptr = 5;
799 ///
800 /// When \p ExpanLoc references the last line, the macro name "NOT_SUSPICIOUS"
801 /// and the MacroArgMap map { (a, &ptr) } will be returned.
802 ///
803 /// When \p ExpanLoc references "SET_TO_NULL(a)" within the definition of
804 /// "NOT_SUSPICOUS", the macro name "SET_TO_NULL" and the MacroArgMap map
805 /// { (x, a) } will be returned.
806 static MacroNameAndArgs getMacroNameAndArgs(SourceLocation ExpanLoc,
807  const Preprocessor &PP);
808 
809 /// Retrieves the ')' token that matches '(' \p It points to.
810 static MacroInfo::tokens_iterator getMatchingRParen(
813 
814 /// Retrieves the macro info for \p II refers to at \p Loc. This is important
815 /// because macros can be redefined or undefined.
816 static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP,
817  const SourceManager &SM,
818  const IdentifierInfo *II,
819  SourceLocation Loc);
820 
821 //===----------------------------------------------------------------------===//
822 // Definitions of helper functions and methods for expanding macros.
823 //===----------------------------------------------------------------------===//
824 
825 static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
826  const Preprocessor &PP) {
827 
828  llvm::SmallString<200> ExpansionBuf;
829  llvm::raw_svector_ostream OS(ExpansionBuf);
830  TokenPrinter Printer(OS, PP);
831  std::string MacroName =
832  getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, MacroArgMap{});
833  return { MacroName, OS.str() };
834 }
835 
836 static std::string getMacroNameAndPrintExpansion(TokenPrinter &Printer,
837  SourceLocation MacroLoc,
838  const Preprocessor &PP,
839  const MacroArgMap &PrevArgs) {
840 
841  const SourceManager &SM = PP.getSourceManager();
842 
843  MacroNameAndArgs Info = getMacroNameAndArgs(SM.getExpansionLoc(MacroLoc), PP);
844 
845  // Manually expand its arguments from the previous macro.
846  Info.Args.expandFromPrevMacro(PrevArgs);
847 
848  // Iterate over the macro's tokens and stringify them.
849  for (auto It = Info.MI->tokens_begin(), E = Info.MI->tokens_end(); It != E;
850  ++It) {
851  Token T = *It;
852 
853  // If this token is not an identifier, we only need to print it.
854  if (T.isNot(tok::identifier)) {
855  Printer.printToken(T);
856  continue;
857  }
858 
859  const auto *II = T.getIdentifierInfo();
860  assert(II &&
861  "This token is an identifier but has no IdentifierInfo!");
862 
863  // If this token is a macro that should be expanded inside the current
864  // macro.
865  if (const MacroInfo *MI =
866  getMacroInfoForLocation(PP, SM, II, T.getLocation())) {
867  getMacroNameAndPrintExpansion(Printer, T.getLocation(), PP, Info.Args);
868 
869  // If this is a function-like macro, skip its arguments, as
870  // getExpandedMacro() already printed them. If this is the case, let's
871  // first jump to the '(' token.
872  if (MI->getNumParams() != 0)
873  It = getMatchingRParen(++It, E);
874  continue;
875  }
876 
877  // If this token is the current macro's argument, we should expand it.
878  auto ArgMapIt = Info.Args.find(II);
879  if (ArgMapIt != Info.Args.end()) {
880  for (MacroInfo::tokens_iterator ArgIt = ArgMapIt->second.begin(),
881  ArgEnd = ArgMapIt->second.end();
882  ArgIt != ArgEnd; ++ArgIt) {
883 
884  // These tokens may still be macros, if that is the case, handle it the
885  // same way we did above.
886  const auto *ArgII = ArgIt->getIdentifierInfo();
887  if (!ArgII) {
888  Printer.printToken(*ArgIt);
889  continue;
890  }
891 
892  const auto *MI = PP.getMacroInfo(ArgII);
893  if (!MI) {
894  Printer.printToken(*ArgIt);
895  continue;
896  }
897 
898  getMacroNameAndPrintExpansion(Printer, ArgIt->getLocation(), PP,
899  Info.Args);
900  if (MI->getNumParams() != 0)
901  ArgIt = getMatchingRParen(++ArgIt, ArgEnd);
902  }
903  continue;
904  }
905 
906  // If control reached here, then this token isn't a macro identifier, nor an
907  // unexpanded macro argument that we need to handle, print it.
908  Printer.printToken(T);
909  }
910 
911  return Info.Name;
912 }
913 
914 static MacroNameAndArgs getMacroNameAndArgs(SourceLocation ExpanLoc,
915  const Preprocessor &PP) {
916 
917  const SourceManager &SM = PP.getSourceManager();
918  const LangOptions &LangOpts = PP.getLangOpts();
919 
920  // First, we create a Lexer to lex *at the expansion location* the tokens
921  // referring to the macro's name and its arguments.
922  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ExpanLoc);
923  const llvm::MemoryBuffer *MB = SM.getBuffer(LocInfo.first);
924  const char *MacroNameTokenPos = MB->getBufferStart() + LocInfo.second;
925 
926  Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
927  MB->getBufferStart(), MacroNameTokenPos, MB->getBufferEnd());
928 
929  // Acquire the macro's name.
930  Token TheTok;
931  RawLexer.LexFromRawLexer(TheTok);
932 
933  std::string MacroName = PP.getSpelling(TheTok);
934 
935  const auto *II = PP.getIdentifierInfo(MacroName);
936  assert(II && "Failed to acquire the IndetifierInfo for the macro!");
937 
938  const MacroInfo *MI = getMacroInfoForLocation(PP, SM, II, ExpanLoc);
939  assert(MI && "The macro must've been defined at it's expansion location!");
940 
941  // Acquire the macro's arguments.
942  //
943  // The rough idea here is to lex from the first left parentheses to the last
944  // right parentheses, and map the macro's unexpanded arguments to what they
945  // will be expanded to. An expanded macro argument may contain several tokens
946  // (like '3 + 4'), so we'll lex until we find a tok::comma or tok::r_paren, at
947  // which point we start lexing the next argument or finish.
949  if (MacroArgs.empty())
950  return { MacroName, MI, {} };
951 
952  RawLexer.LexFromRawLexer(TheTok);
953  assert(TheTok.is(tok::l_paren) &&
954  "The token after the macro's identifier token should be '('!");
955 
956  MacroArgMap Args;
957 
958  // When the macro's argument is a function call, like
959  // CALL_FN(someFunctionName(param1, param2))
960  // we will find tok::l_paren, tok::r_paren, and tok::comma that do not divide
961  // actual macro arguments, or do not represent the macro argument's closing
962  // parentheses, so we'll count how many parentheses aren't closed yet.
963  // If ParanthesesDepth
964  // * = 0, then there are no more arguments to lex.
965  // * = 1, then if we find a tok::comma, we can start lexing the next arg.
966  // * > 1, then tok::comma is a part of the current arg.
967  int ParenthesesDepth = 1;
968 
969  // If we encounter __VA_ARGS__, we will lex until the closing tok::r_paren,
970  // even if we lex a tok::comma and ParanthesesDepth == 1.
971  const IdentifierInfo *__VA_ARGS__II = PP.getIdentifierInfo("__VA_ARGS__");
972 
973  for (const IdentifierInfo *UnexpArgII : MacroArgs) {
974  MacroArgMap::mapped_type ExpandedArgTokens;
975 
976  // One could also simply not supply a single argument to __VA_ARGS__ -- this
977  // results in a preprocessor warning, but is not an error:
978  // #define VARIADIC(ptr, ...) \
979  // someVariadicTemplateFunction(__VA_ARGS__)
980  //
981  // int *ptr;
982  // VARIADIC(ptr); // Note that there are no commas, this isn't just an
983  // // empty parameter -- there are no parameters for '...'.
984  // In any other case, ParenthesesDepth mustn't be 0 here.
985  if (ParenthesesDepth != 0) {
986 
987  // Lex the first token of the next macro parameter.
988  RawLexer.LexFromRawLexer(TheTok);
989 
990  while (!(ParenthesesDepth == 1 &&
991  (UnexpArgII == __VA_ARGS__II ? false : TheTok.is(tok::comma)))) {
992  assert(TheTok.isNot(tok::eof) &&
993  "EOF encountered while looking for expanded macro args!");
994 
995  if (TheTok.is(tok::l_paren))
996  ++ParenthesesDepth;
997 
998  if (TheTok.is(tok::r_paren))
999  --ParenthesesDepth;
1000 
1001  if (ParenthesesDepth == 0)
1002  break;
1003 
1004  if (TheTok.is(tok::raw_identifier))
1005  PP.LookUpIdentifierInfo(TheTok);
1006 
1007  ExpandedArgTokens.push_back(TheTok);
1008  RawLexer.LexFromRawLexer(TheTok);
1009  }
1010  } else {
1011  assert(UnexpArgII == __VA_ARGS__II);
1012  }
1013 
1014  Args.emplace(UnexpArgII, std::move(ExpandedArgTokens));
1015  }
1016 
1017  assert(TheTok.is(tok::r_paren) &&
1018  "Expanded macro argument acquisition failed! After the end of the loop"
1019  " this token should be ')'!");
1020 
1021  return { MacroName, MI, Args };
1022 }
1023 
1024 static MacroInfo::tokens_iterator getMatchingRParen(
1027 
1028  assert(It->is(tok::l_paren) && "This token should be '('!");
1029 
1030  // Skip until we find the closing ')'.
1031  int ParenthesesDepth = 1;
1032  while (ParenthesesDepth != 0) {
1033  ++It;
1034 
1035  assert(It->isNot(tok::eof) &&
1036  "Encountered EOF while attempting to skip macro arguments!");
1037  assert(It != End &&
1038  "End of the macro definition reached before finding ')'!");
1039 
1040  if (It->is(tok::l_paren))
1041  ++ParenthesesDepth;
1042 
1043  if (It->is(tok::r_paren))
1044  --ParenthesesDepth;
1045  }
1046  return It;
1047 }
1048 
1049 static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP,
1050  const SourceManager &SM,
1051  const IdentifierInfo *II,
1052  SourceLocation Loc) {
1053 
1054  const MacroDirective *MD = PP.getLocalMacroDirectiveHistory(II);
1055  if (!MD)
1056  return nullptr;
1057 
1058  return MD->findDirectiveAtLoc(Loc, SM).getMacroInfo();
1059 }
1060 
1061 void MacroArgMap::expandFromPrevMacro(const MacroArgMap &Super) {
1062 
1063  for (value_type &Pair : *this) {
1064  ExpArgTokens &CurrExpArgTokens = Pair.second;
1065 
1066  // For each token in the expanded macro argument.
1067  auto It = CurrExpArgTokens.begin();
1068  while (It != CurrExpArgTokens.end()) {
1069  if (It->isNot(tok::identifier)) {
1070  ++It;
1071  continue;
1072  }
1073 
1074  const auto *II = It->getIdentifierInfo();
1075  assert(II);
1076 
1077  // Is this an argument that "Super" expands further?
1078  if (!Super.count(II)) {
1079  ++It;
1080  continue;
1081  }
1082 
1083  const ExpArgTokens &SuperExpArgTokens = Super.at(II);
1084 
1085  It = CurrExpArgTokens.insert(
1086  It, SuperExpArgTokens.begin(), SuperExpArgTokens.end());
1087  std::advance(It, SuperExpArgTokens.size());
1088  It = CurrExpArgTokens.erase(It);
1089  }
1090  }
1091 }
1092 
1093 void TokenPrinter::printToken(const Token &Tok) {
1094  // If this is the first token to be printed, don't print space.
1095  if (PrevTok.isNot(tok::unknown)) {
1096  // If the tokens were already space separated, or if they must be to avoid
1097  // them being implicitly pasted, add a space between them.
1098  if(Tok.hasLeadingSpace() || ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok,
1099  Tok)) {
1100  // AvoidConcat doesn't check for ##, don't print a space around it.
1101  if (PrevTok.isNot(tok::hashhash) && Tok.isNot(tok::hashhash)) {
1102  OS << ' ';
1103  }
1104  }
1105  }
1106 
1107  if (!Tok.isOneOf(tok::hash, tok::hashhash)) {
1108  if (PrevTok.is(tok::hash))
1109  OS << '\"' << PP.getSpelling(Tok) << '\"';
1110  else
1111  OS << PP.getSpelling(Tok);
1112  }
1113 
1114  PrevPrevTok = PrevTok;
1115  PrevTok = Tok;
1116 }
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
Definition: Lexer.h:76
void EmitLocation(raw_ostream &o, const SourceManager &SM, SourceLocation L, const FIDMap &FM, unsigned indent)
Definition: PlistSupport.h:107
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
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:117
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:978
Stmt - This represents one statement.
Definition: Stmt.h:65
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
Definition: Token.h:94
Defines the SourceManager interface.
TokenConcatenation class, which answers the question of "Is it safe to emit two tokens without a whit...
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
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.
constexpr XRayInstrMask Function
Definition: XRayInstr.h:38
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
Definition: PlistSupport.h:71
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
One of these records is kept for each identifier that is lexed.
unsigned AddFID(FIDMap &FIDs, SmallVectorImpl< FileID > &V, FileID FID)
Definition: PlistSupport.h:27
Definition: Format.h:2071
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
void setKind(tok::TokenKind K)
Definition: Token.h:90
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:814
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the &#39;spelling&#39; of the token at the given location; does not go up to the spelling location or ...
const FormatToken & Tok
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
SmallVectorImpl< Token >::const_iterator tokens_iterator
Definition: MacroInfo.h:240
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
SourceLocation End
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition: MacroArgs.h:29
Defines version macros and version-related utility functions for Clang.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
Definition: Token.h:123
Defines the clang::Preprocessor interface.
const MacroInfo * getMacroInfo(const IdentifierInfo *II) const
Definition: Preprocessor.h:980
SourceLocation getEnd() const
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
static void printBugPath(llvm::raw_ostream &o, const FIDMap &FM, AnalyzerOptions &AnOpts, const Preprocessor &PP, const PathPieces &Path)
const SourceManager & SM
Definition: Format.cpp:1489
llvm::DenseMap< FileID, unsigned > FIDMap
Definition: PlistSupport.h:25
SourceManager & getSourceManager() const
Definition: Preprocessor.h:818
const DefInfo findDirectiveAtLoc(SourceLocation L, const SourceManager &SM) const
Find macro definition active in the specified source location.
Definition: MacroInfo.cpp:202
Encapsulates changes to the "macros namespace" (the location where the macro name became active...
Definition: MacroInfo.h:290
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
Encodes a location in the source.
StringRef getName() const
Definition: FileManager.h:85
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
MacroDirective * getLocalMacroDirectiveHistory(const IdentifierInfo *II) const
Given an identifier, return the latest non-imported macro directive for that identifier.
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 ...
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:176
raw_ostream & EmitPlistHeader(raw_ostream &o)
Definition: PlistSupport.h:62
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isNot(tok::TokenKind K) const
Definition: Token.h:95
Dataflow Directional Tag Classes.
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const
Definition: Token.h:96
PathDiagnosticLocation()=default
Create an invalid location.
void EmitRange(raw_ostream &o, const SourceManager &SM, CharSourceRange R, const FIDMap &FM, unsigned indent)
Definition: PlistSupport.h:123
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
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:379
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, const Token &Tok) const
AvoidConcat - If printing PrevTok immediately followed by Tok would cause the two individual tokens t...
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:78
Stores options for the analyzer from the command line.
A SourceLocation and its associated SourceManager.
A trivial tuple used to represent a source range.
This represents a decl that may have a name.
Definition: Decl.h:248
SourceLocation getBegin() const
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
Definition: Token.h:269
This class handles loading and caching of source files into memory.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:124
ArrayRef< const IdentifierInfo * > params() const
Definition: MacroInfo.h:183