1 //===--- PPCallbacksTracker.cpp - Preprocessor tracker -*--*---------------===//
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 /// \file
10 /// Implementations for preprocessor tracking.
11 ///
12 /// See the header for details.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "PPCallbacksTracker.h"
17 #include "clang/Basic/FileManager.h"
18 #include "clang/Lex/MacroArgs.h"
19 #include "llvm/Support/raw_ostream.h"
20 
21 namespace clang {
22 namespace pp_trace {
23 
24 // Get a "file:line:column" source location string.
getSourceLocationString(Preprocessor & PP,SourceLocation Loc)25 static std::string getSourceLocationString(Preprocessor &PP,
26                                            SourceLocation Loc) {
27   if (Loc.isInvalid())
28     return std::string("(none)");
29 
30   if (Loc.isFileID()) {
31     PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
32 
33     if (PLoc.isInvalid()) {
34       return std::string("(invalid)");
35     }
36 
37     std::string Str;
38     llvm::raw_string_ostream SS(Str);
39 
40     // The macro expansion and spelling pos is identical for file locs.
41     SS << "\"" << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
42        << PLoc.getColumn() << "\"";
43 
44     std::string Result = SS.str();
45 
46     // YAML treats backslash as escape, so use forward slashes.
47     std::replace(Result.begin(), Result.end(), '\\', '/');
48 
49     return Result;
50   }
51 
52   return std::string("(nonfile)");
53 }
54 
55 // Enum string tables.
56 
57 // FileChangeReason strings.
58 static const char *const FileChangeReasonStrings[] = {
59   "EnterFile", "ExitFile", "SystemHeaderPragma", "RenameFile"
60 };
61 
62 // CharacteristicKind strings.
63 static const char *const CharacteristicKindStrings[] = { "C_User", "C_System",
64                                                          "C_ExternCSystem" };
65 
66 // MacroDirective::Kind strings.
67 static const char *const MacroDirectiveKindStrings[] = {
68   "MD_Define","MD_Undefine", "MD_Visibility"
69 };
70 
71 // PragmaIntroducerKind strings.
72 static const char *const PragmaIntroducerKindStrings[] = { "PIK_HashPragma",
73                                                            "PIK__Pragma",
74                                                            "PIK___pragma" };
75 
76 // PragmaMessageKind strings.
77 static const char *const PragmaMessageKindStrings[] = {
78   "PMK_Message", "PMK_Warning", "PMK_Error"
79 };
80 
81 // PragmaWarningSpecifier strings.
82 static const char *const PragmaWarningSpecifierStrings[] = {
83     "PWS_Default", "PWS_Disable", "PWS_Error",  "PWS_Once",   "PWS_Suppress",
84     "PWS_Level1",  "PWS_Level2",  "PWS_Level3", "PWS_Level4",
85 };
86 
87 // ConditionValueKind strings.
88 static const char *const ConditionValueKindStrings[] = {
89   "CVK_NotEvaluated", "CVK_False", "CVK_True"
90 };
91 
92 // Mapping strings.
93 static const char *const MappingStrings[] = { "0",          "MAP_IGNORE",
94                                               "MAP_REMARK", "MAP_WARNING",
95                                               "MAP_ERROR",  "MAP_FATAL" };
96 
97 // PPCallbacksTracker functions.
98 
PPCallbacksTracker(const FilterType & Filters,std::vector<CallbackCall> & CallbackCalls,Preprocessor & PP)99 PPCallbacksTracker::PPCallbacksTracker(const FilterType &Filters,
100                                        std::vector<CallbackCall> &CallbackCalls,
101                                        Preprocessor &PP)
102     : CallbackCalls(CallbackCalls), Filters(Filters), PP(PP) {}
103 
~PPCallbacksTracker()104 PPCallbacksTracker::~PPCallbacksTracker() {}
105 
106 // Callback functions.
107 
108 // Callback invoked whenever a source file is entered or exited.
FileChanged(SourceLocation Loc,PPCallbacks::FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)109 void PPCallbacksTracker::FileChanged(SourceLocation Loc,
110                                      PPCallbacks::FileChangeReason Reason,
111                                      SrcMgr::CharacteristicKind FileType,
112                                      FileID PrevFID) {
113   beginCallback("FileChanged");
114   appendArgument("Loc", Loc);
115   appendArgument("Reason", Reason, FileChangeReasonStrings);
116   appendArgument("FileType", FileType, CharacteristicKindStrings);
117   appendArgument("PrevFID", PrevFID);
118 }
119 
120 // Callback invoked whenever a source file is skipped as the result
121 // of header guard optimization.
FileSkipped(const FileEntryRef & SkippedFile,const Token & FilenameTok,SrcMgr::CharacteristicKind FileType)122 void PPCallbacksTracker::FileSkipped(const FileEntryRef &SkippedFile,
123                                      const Token &FilenameTok,
124                                      SrcMgr::CharacteristicKind FileType) {
125   beginCallback("FileSkipped");
126   appendArgument("ParentFile", SkippedFile);
127   appendArgument("FilenameTok", FilenameTok);
128   appendArgument("FileType", FileType, CharacteristicKindStrings);
129 }
130 
131 // Callback invoked whenever an inclusion directive of
132 // any kind (#include, #import, etc.) has been processed, regardless
133 // of whether the inclusion will actually result in an inclusion.
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,llvm::StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,Optional<FileEntryRef> File,llvm::StringRef SearchPath,llvm::StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)134 void PPCallbacksTracker::InclusionDirective(
135     SourceLocation HashLoc, const Token &IncludeTok, llvm::StringRef FileName,
136     bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File,
137     llvm::StringRef SearchPath, llvm::StringRef RelativePath,
138     const Module *Imported, SrcMgr::CharacteristicKind FileType) {
139   beginCallback("InclusionDirective");
140   appendArgument("HashLoc", HashLoc);
141   appendArgument("IncludeTok", IncludeTok);
142   appendFilePathArgument("FileName", FileName);
143   appendArgument("IsAngled", IsAngled);
144   appendArgument("FilenameRange", FilenameRange);
145   appendArgument("File", File);
146   appendFilePathArgument("SearchPath", SearchPath);
147   appendFilePathArgument("RelativePath", RelativePath);
148   appendArgument("Imported", Imported);
149 }
150 
151 // Callback invoked whenever there was an explicit module-import
152 // syntax.
moduleImport(SourceLocation ImportLoc,ModuleIdPath Path,const Module * Imported)153 void PPCallbacksTracker::moduleImport(SourceLocation ImportLoc,
154                                       ModuleIdPath Path,
155                                       const Module *Imported) {
156   beginCallback("moduleImport");
157   appendArgument("ImportLoc", ImportLoc);
158   appendArgument("Path", Path);
159   appendArgument("Imported", Imported);
160 }
161 
162 // Callback invoked when the end of the main file is reached.
163 // No subsequent callbacks will be made.
EndOfMainFile()164 void PPCallbacksTracker::EndOfMainFile() { beginCallback("EndOfMainFile"); }
165 
166 // Callback invoked when a #ident or #sccs directive is read.
Ident(SourceLocation Loc,llvm::StringRef Str)167 void PPCallbacksTracker::Ident(SourceLocation Loc, llvm::StringRef Str) {
168   beginCallback("Ident");
169   appendArgument("Loc", Loc);
170   appendArgument("Str", Str);
171 }
172 
173 // Callback invoked when start reading any pragma directive.
PragmaDirective(SourceLocation Loc,PragmaIntroducerKind Introducer)174 void PPCallbacksTracker::PragmaDirective(SourceLocation Loc,
175                                          PragmaIntroducerKind Introducer) {
176   beginCallback("PragmaDirective");
177   appendArgument("Loc", Loc);
178   appendArgument("Introducer", Introducer, PragmaIntroducerKindStrings);
179 }
180 
181 // Callback invoked when a #pragma comment directive is read.
PragmaComment(SourceLocation Loc,const IdentifierInfo * Kind,llvm::StringRef Str)182 void PPCallbacksTracker::PragmaComment(SourceLocation Loc,
183                                        const IdentifierInfo *Kind,
184                                        llvm::StringRef Str) {
185   beginCallback("PragmaComment");
186   appendArgument("Loc", Loc);
187   appendArgument("Kind", Kind);
188   appendArgument("Str", Str);
189 }
190 
191 // Callback invoked when a #pragma detect_mismatch directive is
192 // read.
PragmaDetectMismatch(SourceLocation Loc,llvm::StringRef Name,llvm::StringRef Value)193 void PPCallbacksTracker::PragmaDetectMismatch(SourceLocation Loc,
194                                               llvm::StringRef Name,
195                                               llvm::StringRef Value) {
196   beginCallback("PragmaDetectMismatch");
197   appendArgument("Loc", Loc);
198   appendArgument("Name", Name);
199   appendArgument("Value", Value);
200 }
201 
202 // Callback invoked when a #pragma clang __debug directive is read.
PragmaDebug(SourceLocation Loc,llvm::StringRef DebugType)203 void PPCallbacksTracker::PragmaDebug(SourceLocation Loc,
204                                      llvm::StringRef DebugType) {
205   beginCallback("PragmaDebug");
206   appendArgument("Loc", Loc);
207   appendArgument("DebugType", DebugType);
208 }
209 
210 // Callback invoked when a #pragma message directive is read.
PragmaMessage(SourceLocation Loc,llvm::StringRef Namespace,PPCallbacks::PragmaMessageKind Kind,llvm::StringRef Str)211 void PPCallbacksTracker::PragmaMessage(SourceLocation Loc,
212                                        llvm::StringRef Namespace,
213                                        PPCallbacks::PragmaMessageKind Kind,
214                                        llvm::StringRef Str) {
215   beginCallback("PragmaMessage");
216   appendArgument("Loc", Loc);
217   appendArgument("Namespace", Namespace);
218   appendArgument("Kind", Kind, PragmaMessageKindStrings);
219   appendArgument("Str", Str);
220 }
221 
222 // Callback invoked when a #pragma gcc diagnostic push directive
223 // is read.
PragmaDiagnosticPush(SourceLocation Loc,llvm::StringRef Namespace)224 void PPCallbacksTracker::PragmaDiagnosticPush(SourceLocation Loc,
225                                               llvm::StringRef Namespace) {
226   beginCallback("PragmaDiagnosticPush");
227   appendArgument("Loc", Loc);
228   appendArgument("Namespace", Namespace);
229 }
230 
231 // Callback invoked when a #pragma gcc diagnostic pop directive
232 // is read.
PragmaDiagnosticPop(SourceLocation Loc,llvm::StringRef Namespace)233 void PPCallbacksTracker::PragmaDiagnosticPop(SourceLocation Loc,
234                                              llvm::StringRef Namespace) {
235   beginCallback("PragmaDiagnosticPop");
236   appendArgument("Loc", Loc);
237   appendArgument("Namespace", Namespace);
238 }
239 
240 // Callback invoked when a #pragma gcc diagnostic directive is read.
PragmaDiagnostic(SourceLocation Loc,llvm::StringRef Namespace,diag::Severity Mapping,llvm::StringRef Str)241 void PPCallbacksTracker::PragmaDiagnostic(SourceLocation Loc,
242                                           llvm::StringRef Namespace,
243                                           diag::Severity Mapping,
244                                           llvm::StringRef Str) {
245   beginCallback("PragmaDiagnostic");
246   appendArgument("Loc", Loc);
247   appendArgument("Namespace", Namespace);
248   appendArgument("Mapping", (unsigned)Mapping, MappingStrings);
249   appendArgument("Str", Str);
250 }
251 
252 // Called when an OpenCL extension is either disabled or
253 // enabled with a pragma.
PragmaOpenCLExtension(SourceLocation NameLoc,const IdentifierInfo * Name,SourceLocation StateLoc,unsigned State)254 void PPCallbacksTracker::PragmaOpenCLExtension(SourceLocation NameLoc,
255                                                const IdentifierInfo *Name,
256                                                SourceLocation StateLoc,
257                                                unsigned State) {
258   beginCallback("PragmaOpenCLExtension");
259   appendArgument("NameLoc", NameLoc);
260   appendArgument("Name", Name);
261   appendArgument("StateLoc", StateLoc);
262   appendArgument("State", (int)State);
263 }
264 
265 // Callback invoked when a #pragma warning directive is read.
PragmaWarning(SourceLocation Loc,PragmaWarningSpecifier WarningSpec,llvm::ArrayRef<int> Ids)266 void PPCallbacksTracker::PragmaWarning(SourceLocation Loc,
267                                        PragmaWarningSpecifier WarningSpec,
268                                        llvm::ArrayRef<int> Ids) {
269   beginCallback("PragmaWarning");
270   appendArgument("Loc", Loc);
271   appendArgument("WarningSpec", WarningSpec, PragmaWarningSpecifierStrings);
272 
273   std::string Str;
274   llvm::raw_string_ostream SS(Str);
275   SS << "[";
276   for (int i = 0, e = Ids.size(); i != e; ++i) {
277     if (i)
278       SS << ", ";
279     SS << Ids[i];
280   }
281   SS << "]";
282   appendArgument("Ids", SS.str());
283 }
284 
285 // Callback invoked when a #pragma warning(push) directive is read.
PragmaWarningPush(SourceLocation Loc,int Level)286 void PPCallbacksTracker::PragmaWarningPush(SourceLocation Loc, int Level) {
287   beginCallback("PragmaWarningPush");
288   appendArgument("Loc", Loc);
289   appendArgument("Level", Level);
290 }
291 
292 // Callback invoked when a #pragma warning(pop) directive is read.
PragmaWarningPop(SourceLocation Loc)293 void PPCallbacksTracker::PragmaWarningPop(SourceLocation Loc) {
294   beginCallback("PragmaWarningPop");
295   appendArgument("Loc", Loc);
296 }
297 
298 // Callback invoked when a #pragma execution_character_set(push) directive
299 // is read.
PragmaExecCharsetPush(SourceLocation Loc,StringRef Str)300 void PPCallbacksTracker::PragmaExecCharsetPush(SourceLocation Loc,
301                                                StringRef Str) {
302   beginCallback("PragmaExecCharsetPush");
303   appendArgument("Loc", Loc);
304   appendArgument("Charset", Str);
305 }
306 
307 // Callback invoked when a #pragma execution_character_set(pop) directive
308 // is read.
PragmaExecCharsetPop(SourceLocation Loc)309 void PPCallbacksTracker::PragmaExecCharsetPop(SourceLocation Loc) {
310   beginCallback("PragmaExecCharsetPop");
311   appendArgument("Loc", Loc);
312 }
313 
314 // Called by Preprocessor::HandleMacroExpandedIdentifier when a
315 // macro invocation is found.
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MacroDefinition,SourceRange Range,const MacroArgs * Args)316 void PPCallbacksTracker::MacroExpands(const Token &MacroNameTok,
317                                       const MacroDefinition &MacroDefinition,
318                                       SourceRange Range,
319                                       const MacroArgs *Args) {
320   beginCallback("MacroExpands");
321   appendArgument("MacroNameTok", MacroNameTok);
322   appendArgument("MacroDefinition", MacroDefinition);
323   appendArgument("Range", Range);
324   appendArgument("Args", Args);
325 }
326 
327 // Hook called whenever a macro definition is seen.
MacroDefined(const Token & MacroNameTok,const MacroDirective * MacroDirective)328 void PPCallbacksTracker::MacroDefined(const Token &MacroNameTok,
329                                       const MacroDirective *MacroDirective) {
330   beginCallback("MacroDefined");
331   appendArgument("MacroNameTok", MacroNameTok);
332   appendArgument("MacroDirective", MacroDirective);
333 }
334 
335 // Hook called whenever a macro #undef is seen.
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MacroDefinition,const MacroDirective * Undef)336 void PPCallbacksTracker::MacroUndefined(const Token &MacroNameTok,
337                                         const MacroDefinition &MacroDefinition,
338                                         const MacroDirective *Undef) {
339   beginCallback("MacroUndefined");
340   appendArgument("MacroNameTok", MacroNameTok);
341   appendArgument("MacroDefinition", MacroDefinition);
342 }
343 
344 // Hook called whenever the 'defined' operator is seen.
Defined(const Token & MacroNameTok,const MacroDefinition & MacroDefinition,SourceRange Range)345 void PPCallbacksTracker::Defined(const Token &MacroNameTok,
346                                  const MacroDefinition &MacroDefinition,
347                                  SourceRange Range) {
348   beginCallback("Defined");
349   appendArgument("MacroNameTok", MacroNameTok);
350   appendArgument("MacroDefinition", MacroDefinition);
351   appendArgument("Range", Range);
352 }
353 
354 // Hook called when a source range is skipped.
SourceRangeSkipped(SourceRange Range,SourceLocation EndifLoc)355 void PPCallbacksTracker::SourceRangeSkipped(SourceRange Range,
356                                             SourceLocation EndifLoc) {
357   beginCallback("SourceRangeSkipped");
358   appendArgument("Range", SourceRange(Range.getBegin(), EndifLoc));
359 }
360 
361 // Hook called whenever an #if is seen.
If(SourceLocation Loc,SourceRange ConditionRange,ConditionValueKind ConditionValue)362 void PPCallbacksTracker::If(SourceLocation Loc, SourceRange ConditionRange,
363                             ConditionValueKind ConditionValue) {
364   beginCallback("If");
365   appendArgument("Loc", Loc);
366   appendArgument("ConditionRange", ConditionRange);
367   appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
368 }
369 
370 // Hook called whenever an #elif is seen.
Elif(SourceLocation Loc,SourceRange ConditionRange,ConditionValueKind ConditionValue,SourceLocation IfLoc)371 void PPCallbacksTracker::Elif(SourceLocation Loc, SourceRange ConditionRange,
372                               ConditionValueKind ConditionValue,
373                               SourceLocation IfLoc) {
374   beginCallback("Elif");
375   appendArgument("Loc", Loc);
376   appendArgument("ConditionRange", ConditionRange);
377   appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
378   appendArgument("IfLoc", IfLoc);
379 }
380 
381 // Hook called whenever an #ifdef is seen.
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MacroDefinition)382 void PPCallbacksTracker::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
383                                const MacroDefinition &MacroDefinition) {
384   beginCallback("Ifdef");
385   appendArgument("Loc", Loc);
386   appendArgument("MacroNameTok", MacroNameTok);
387   appendArgument("MacroDefinition", MacroDefinition);
388 }
389 
390 // Hook called whenever an #ifndef is seen.
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MacroDefinition)391 void PPCallbacksTracker::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
392                                 const MacroDefinition &MacroDefinition) {
393   beginCallback("Ifndef");
394   appendArgument("Loc", Loc);
395   appendArgument("MacroNameTok", MacroNameTok);
396   appendArgument("MacroDefinition", MacroDefinition);
397 }
398 
399 // Hook called whenever an #else is seen.
Else(SourceLocation Loc,SourceLocation IfLoc)400 void PPCallbacksTracker::Else(SourceLocation Loc, SourceLocation IfLoc) {
401   beginCallback("Else");
402   appendArgument("Loc", Loc);
403   appendArgument("IfLoc", IfLoc);
404 }
405 
406 // Hook called whenever an #endif is seen.
Endif(SourceLocation Loc,SourceLocation IfLoc)407 void PPCallbacksTracker::Endif(SourceLocation Loc, SourceLocation IfLoc) {
408   beginCallback("Endif");
409   appendArgument("Loc", Loc);
410   appendArgument("IfLoc", IfLoc);
411 }
412 
413 // Helper functions.
414 
415 // Start a new callback.
beginCallback(const char * Name)416 void PPCallbacksTracker::beginCallback(const char *Name) {
417   auto R = CallbackIsEnabled.try_emplace(Name, false);
418   if (R.second) {
419     llvm::StringRef N(Name);
420     for (const std::pair<llvm::GlobPattern, bool> &Filter : Filters)
421       if (Filter.first.match(N))
422         R.first->second = Filter.second;
423   }
424   DisableTrace = !R.first->second;
425   if (DisableTrace)
426     return;
427   CallbackCalls.push_back(CallbackCall(Name));
428 }
429 
430 // Append a bool argument to the top trace item.
appendArgument(const char * Name,bool Value)431 void PPCallbacksTracker::appendArgument(const char *Name, bool Value) {
432   appendArgument(Name, (Value ? "true" : "false"));
433 }
434 
435 // Append an int argument to the top trace item.
appendArgument(const char * Name,int Value)436 void PPCallbacksTracker::appendArgument(const char *Name, int Value) {
437   std::string Str;
438   llvm::raw_string_ostream SS(Str);
439   SS << Value;
440   appendArgument(Name, SS.str());
441 }
442 
443 // Append a string argument to the top trace item.
appendArgument(const char * Name,const char * Value)444 void PPCallbacksTracker::appendArgument(const char *Name, const char *Value) {
445   if (DisableTrace)
446     return;
447   CallbackCalls.back().Arguments.push_back(Argument{Name, Value});
448 }
449 
450 // Append a string object argument to the top trace item.
appendArgument(const char * Name,llvm::StringRef Value)451 void PPCallbacksTracker::appendArgument(const char *Name,
452                                         llvm::StringRef Value) {
453   appendArgument(Name, Value.str());
454 }
455 
456 // Append a string object argument to the top trace item.
appendArgument(const char * Name,const std::string & Value)457 void PPCallbacksTracker::appendArgument(const char *Name,
458                                         const std::string &Value) {
459   appendArgument(Name, Value.c_str());
460 }
461 
462 // Append a token argument to the top trace item.
appendArgument(const char * Name,const Token & Value)463 void PPCallbacksTracker::appendArgument(const char *Name, const Token &Value) {
464   appendArgument(Name, PP.getSpelling(Value));
465 }
466 
467 // Append an enum argument to the top trace item.
appendArgument(const char * Name,int Value,const char * const Strings[])468 void PPCallbacksTracker::appendArgument(const char *Name, int Value,
469                                         const char *const Strings[]) {
470   appendArgument(Name, Strings[Value]);
471 }
472 
473 // Append a FileID argument to the top trace item.
appendArgument(const char * Name,FileID Value)474 void PPCallbacksTracker::appendArgument(const char *Name, FileID Value) {
475   if (Value.isInvalid()) {
476     appendArgument(Name, "(invalid)");
477     return;
478   }
479   const FileEntry *FileEntry = PP.getSourceManager().getFileEntryForID(Value);
480   if (!FileEntry) {
481     appendArgument(Name, "(getFileEntryForID failed)");
482     return;
483   }
484   appendFilePathArgument(Name, FileEntry->getName());
485 }
486 
487 // Append a FileEntry argument to the top trace item.
appendArgument(const char * Name,Optional<FileEntryRef> Value)488 void PPCallbacksTracker::appendArgument(const char *Name,
489                                         Optional<FileEntryRef> Value) {
490   if (!Value) {
491     appendArgument(Name, "(null)");
492     return;
493   }
494   appendArgument(Name, *Value);
495 }
496 
appendArgument(const char * Name,FileEntryRef Value)497 void PPCallbacksTracker::appendArgument(const char *Name, FileEntryRef Value) {
498   appendFilePathArgument(Name, Value.getName());
499 }
500 
501 // Append a SourceLocation argument to the top trace item.
appendArgument(const char * Name,SourceLocation Value)502 void PPCallbacksTracker::appendArgument(const char *Name,
503                                         SourceLocation Value) {
504   if (Value.isInvalid()) {
505     appendArgument(Name, "(invalid)");
506     return;
507   }
508   appendArgument(Name, getSourceLocationString(PP, Value).c_str());
509 }
510 
511 // Append a SourceRange argument to the top trace item.
appendArgument(const char * Name,SourceRange Value)512 void PPCallbacksTracker::appendArgument(const char *Name, SourceRange Value) {
513   if (DisableTrace)
514     return;
515   if (Value.isInvalid()) {
516     appendArgument(Name, "(invalid)");
517     return;
518   }
519   std::string Str;
520   llvm::raw_string_ostream SS(Str);
521   SS << "[" << getSourceLocationString(PP, Value.getBegin()) << ", "
522      << getSourceLocationString(PP, Value.getEnd()) << "]";
523   appendArgument(Name, SS.str());
524 }
525 
526 // Append a CharSourceRange argument to the top trace item.
appendArgument(const char * Name,CharSourceRange Value)527 void PPCallbacksTracker::appendArgument(const char *Name,
528                                         CharSourceRange Value) {
529   if (Value.isInvalid()) {
530     appendArgument(Name, "(invalid)");
531     return;
532   }
533   appendArgument(Name, getSourceString(Value).str().c_str());
534 }
535 
536 // Append a SourceLocation argument to the top trace item.
appendArgument(const char * Name,ModuleIdPath Value)537 void PPCallbacksTracker::appendArgument(const char *Name, ModuleIdPath Value) {
538   if (DisableTrace)
539     return;
540   std::string Str;
541   llvm::raw_string_ostream SS(Str);
542   SS << "[";
543   for (int I = 0, E = Value.size(); I != E; ++I) {
544     if (I)
545       SS << ", ";
546     SS << "{"
547        << "Name: " << Value[I].first->getName() << ", "
548        << "Loc: " << getSourceLocationString(PP, Value[I].second) << "}";
549   }
550   SS << "]";
551   appendArgument(Name, SS.str());
552 }
553 
554 // Append an IdentifierInfo argument to the top trace item.
appendArgument(const char * Name,const IdentifierInfo * Value)555 void PPCallbacksTracker::appendArgument(const char *Name,
556                                         const IdentifierInfo *Value) {
557   if (!Value) {
558     appendArgument(Name, "(null)");
559     return;
560   }
561   appendArgument(Name, Value->getName().str().c_str());
562 }
563 
564 // Append a MacroDirective argument to the top trace item.
appendArgument(const char * Name,const MacroDirective * Value)565 void PPCallbacksTracker::appendArgument(const char *Name,
566                                         const MacroDirective *Value) {
567   if (!Value) {
568     appendArgument(Name, "(null)");
569     return;
570   }
571   appendArgument(Name, MacroDirectiveKindStrings[Value->getKind()]);
572 }
573 
574 // Append a MacroDefinition argument to the top trace item.
appendArgument(const char * Name,const MacroDefinition & Value)575 void PPCallbacksTracker::appendArgument(const char *Name,
576                                         const MacroDefinition &Value) {
577   std::string Str;
578   llvm::raw_string_ostream SS(Str);
579   SS << "[";
580   bool Any = false;
581   if (Value.getLocalDirective()) {
582     SS << "(local)";
583     Any = true;
584   }
585   for (auto *MM : Value.getModuleMacros()) {
586     if (Any) SS << ", ";
587     SS << MM->getOwningModule()->getFullModuleName();
588   }
589   SS << "]";
590   appendArgument(Name, SS.str());
591 }
592 
593 // Append a MacroArgs argument to the top trace item.
appendArgument(const char * Name,const MacroArgs * Value)594 void PPCallbacksTracker::appendArgument(const char *Name,
595                                         const MacroArgs *Value) {
596   if (!Value) {
597     appendArgument(Name, "(null)");
598     return;
599   }
600   std::string Str;
601   llvm::raw_string_ostream SS(Str);
602   SS << "[";
603 
604   // Each argument is is a series of contiguous Tokens, terminated by a eof.
605   // Go through each argument printing tokens until we reach eof.
606   for (unsigned I = 0; I < Value->getNumMacroArguments(); ++I) {
607     const Token *Current = Value->getUnexpArgument(I);
608     if (I)
609       SS << ", ";
610     bool First = true;
611     while (Current->isNot(tok::eof)) {
612       if (!First)
613         SS << " ";
614       // We need to be careful here because the arguments might not be legal in
615       // YAML, so we use the token name for anything but identifiers and
616       // numeric literals.
617       if (Current->isAnyIdentifier() || Current->is(tok::numeric_constant)) {
618         SS << PP.getSpelling(*Current);
619       } else {
620         SS << "<" << Current->getName() << ">";
621       }
622       ++Current;
623       First = false;
624     }
625   }
626   SS << "]";
627   appendArgument(Name, SS.str());
628 }
629 
630 // Append a Module argument to the top trace item.
appendArgument(const char * Name,const Module * Value)631 void PPCallbacksTracker::appendArgument(const char *Name, const Module *Value) {
632   if (!Value) {
633     appendArgument(Name, "(null)");
634     return;
635   }
636   appendArgument(Name, Value->Name.c_str());
637 }
638 
639 // Append a double-quoted argument to the top trace item.
appendQuotedArgument(const char * Name,const std::string & Value)640 void PPCallbacksTracker::appendQuotedArgument(const char *Name,
641                                               const std::string &Value) {
642   std::string Str;
643   llvm::raw_string_ostream SS(Str);
644   SS << "\"" << Value << "\"";
645   appendArgument(Name, SS.str());
646 }
647 
648 // Append a double-quoted file path argument to the top trace item.
appendFilePathArgument(const char * Name,llvm::StringRef Value)649 void PPCallbacksTracker::appendFilePathArgument(const char *Name,
650                                                 llvm::StringRef Value) {
651   std::string Path(Value);
652   // YAML treats backslash as escape, so use forward slashes.
653   std::replace(Path.begin(), Path.end(), '\\', '/');
654   appendQuotedArgument(Name, Path);
655 }
656 
657 // Get the raw source string of the range.
getSourceString(CharSourceRange Range)658 llvm::StringRef PPCallbacksTracker::getSourceString(CharSourceRange Range) {
659   const char *B = PP.getSourceManager().getCharacterData(Range.getBegin());
660   const char *E = PP.getSourceManager().getCharacterData(Range.getEnd());
661   return llvm::StringRef(B, E - B);
662 }
663 
664 } // namespace pp_trace
665 } // namespace clang
666