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