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