brintos

brintos / llvm-project-archived public Read only

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