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