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