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