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