llvm-capstone/clang-tools-extra/pp-trace/PPCallbacksTracker.cpp
Reid Kleckner e08464fb45 Avoid including FileManager.h from SourceManager.h
Most clients of SourceManager.h need to do things like turning source
locations into file & line number pairs, but this doesn't require
bringing in FileManager.h and LLVM's FS headers.

The main code change here is to sink SM::createFileID into the cpp file.
I reason that this is not performance critical because it doesn't happen
on the diagnostic path, it happens along the paths of macro expansion
(could be hot) and new includes (less hot).

Saves some includes:
    309 -    /usr/local/google/home/rnk/llvm-project/clang/include/clang/Basic/FileManager.h
    272 -    /usr/local/google/home/rnk/llvm-project/clang/include/clang/Basic/FileSystemOptions.h
    271 -    /usr/local/google/home/rnk/llvm-project/llvm/include/llvm/Support/VirtualFileSystem.h
    267 -    /usr/local/google/home/rnk/llvm-project/llvm/include/llvm/Support/FileSystem.h
    266 -    /usr/local/google/home/rnk/llvm-project/llvm/include/llvm/Support/Chrono.h

Differential Revision: https://reviews.llvm.org/D75406
2020-03-11 13:53:12 -07:00

665 lines
23 KiB
C++

//===--- PPCallbacksTracker.cpp - Preprocessor tracker -*--*---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implementations for preprocessor tracking.
///
/// See the header for details.
///
//===----------------------------------------------------------------------===//
#include "PPCallbacksTracker.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/MacroArgs.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace pp_trace {
// Get a "file:line:column" source location string.
static std::string getSourceLocationString(Preprocessor &PP,
SourceLocation Loc) {
if (Loc.isInvalid())
return std::string("(none)");
if (Loc.isFileID()) {
PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
if (PLoc.isInvalid()) {
return std::string("(invalid)");
}
std::string Str;
llvm::raw_string_ostream SS(Str);
// The macro expansion and spelling pos is identical for file locs.
SS << "\"" << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
<< PLoc.getColumn() << "\"";
std::string Result = SS.str();
// YAML treats backslash as escape, so use forward slashes.
std::replace(Result.begin(), Result.end(), '\\', '/');
return Result;
}
return std::string("(nonfile)");
}
// Enum string tables.
// FileChangeReason strings.
static const char *const FileChangeReasonStrings[] = {
"EnterFile", "ExitFile", "SystemHeaderPragma", "RenameFile"
};
// CharacteristicKind strings.
static const char *const CharacteristicKindStrings[] = { "C_User", "C_System",
"C_ExternCSystem" };
// MacroDirective::Kind strings.
static const char *const MacroDirectiveKindStrings[] = {
"MD_Define","MD_Undefine", "MD_Visibility"
};
// PragmaIntroducerKind strings.
static const char *const PragmaIntroducerKindStrings[] = { "PIK_HashPragma",
"PIK__Pragma",
"PIK___pragma" };
// PragmaMessageKind strings.
static const char *const PragmaMessageKindStrings[] = {
"PMK_Message", "PMK_Warning", "PMK_Error"
};
// ConditionValueKind strings.
static const char *const ConditionValueKindStrings[] = {
"CVK_NotEvaluated", "CVK_False", "CVK_True"
};
// Mapping strings.
static const char *const MappingStrings[] = { "0", "MAP_IGNORE",
"MAP_REMARK", "MAP_WARNING",
"MAP_ERROR", "MAP_FATAL" };
// PPCallbacksTracker functions.
PPCallbacksTracker::PPCallbacksTracker(const FilterType &Filters,
std::vector<CallbackCall> &CallbackCalls,
Preprocessor &PP)
: CallbackCalls(CallbackCalls), Filters(Filters), PP(PP) {}
PPCallbacksTracker::~PPCallbacksTracker() {}
// Callback functions.
// Callback invoked whenever a source file is entered or exited.
void PPCallbacksTracker::FileChanged(SourceLocation Loc,
PPCallbacks::FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) {
beginCallback("FileChanged");
appendArgument("Loc", Loc);
appendArgument("Reason", Reason, FileChangeReasonStrings);
appendArgument("FileType", FileType, CharacteristicKindStrings);
appendArgument("PrevFID", PrevFID);
}
// Callback invoked whenever a source file is skipped as the result
// of header guard optimization.
void PPCallbacksTracker::FileSkipped(const FileEntryRef &SkippedFile,
const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) {
beginCallback("FileSkipped");
appendArgument("ParentFile", &SkippedFile.getFileEntry());
appendArgument("FilenameTok", FilenameTok);
appendArgument("FileType", FileType, CharacteristicKindStrings);
}
// Callback invoked whenever an inclusion directive results in a
// file-not-found error.
bool
PPCallbacksTracker::FileNotFound(llvm::StringRef FileName,
llvm::SmallVectorImpl<char> &RecoveryPath) {
beginCallback("FileNotFound");
appendFilePathArgument("FileName", FileName);
return false;
}
// Callback invoked whenever an inclusion directive of
// any kind (#include, #import, etc.) has been processed, regardless
// of whether the inclusion will actually result in an inclusion.
void PPCallbacksTracker::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, llvm::StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
llvm::StringRef SearchPath, llvm::StringRef RelativePath,
const Module *Imported, SrcMgr::CharacteristicKind FileType) {
beginCallback("InclusionDirective");
appendArgument("IncludeTok", IncludeTok);
appendFilePathArgument("FileName", FileName);
appendArgument("IsAngled", IsAngled);
appendArgument("FilenameRange", FilenameRange);
appendArgument("File", File);
appendFilePathArgument("SearchPath", SearchPath);
appendFilePathArgument("RelativePath", RelativePath);
appendArgument("Imported", Imported);
}
// Callback invoked whenever there was an explicit module-import
// syntax.
void PPCallbacksTracker::moduleImport(SourceLocation ImportLoc,
ModuleIdPath Path,
const Module *Imported) {
beginCallback("moduleImport");
appendArgument("ImportLoc", ImportLoc);
appendArgument("Path", Path);
appendArgument("Imported", Imported);
}
// Callback invoked when the end of the main file is reached.
// No subsequent callbacks will be made.
void PPCallbacksTracker::EndOfMainFile() { beginCallback("EndOfMainFile"); }
// Callback invoked when a #ident or #sccs directive is read.
void PPCallbacksTracker::Ident(SourceLocation Loc, llvm::StringRef Str) {
beginCallback("Ident");
appendArgument("Loc", Loc);
appendArgument("Str", Str);
}
// Callback invoked when start reading any pragma directive.
void PPCallbacksTracker::PragmaDirective(SourceLocation Loc,
PragmaIntroducerKind Introducer) {
beginCallback("PragmaDirective");
appendArgument("Loc", Loc);
appendArgument("Introducer", Introducer, PragmaIntroducerKindStrings);
}
// Callback invoked when a #pragma comment directive is read.
void PPCallbacksTracker::PragmaComment(SourceLocation Loc,
const IdentifierInfo *Kind,
llvm::StringRef Str) {
beginCallback("PragmaComment");
appendArgument("Loc", Loc);
appendArgument("Kind", Kind);
appendArgument("Str", Str);
}
// Callback invoked when a #pragma detect_mismatch directive is
// read.
void PPCallbacksTracker::PragmaDetectMismatch(SourceLocation Loc,
llvm::StringRef Name,
llvm::StringRef Value) {
beginCallback("PragmaDetectMismatch");
appendArgument("Loc", Loc);
appendArgument("Name", Name);
appendArgument("Value", Value);
}
// Callback invoked when a #pragma clang __debug directive is read.
void PPCallbacksTracker::PragmaDebug(SourceLocation Loc,
llvm::StringRef DebugType) {
beginCallback("PragmaDebug");
appendArgument("Loc", Loc);
appendArgument("DebugType", DebugType);
}
// Callback invoked when a #pragma message directive is read.
void PPCallbacksTracker::PragmaMessage(SourceLocation Loc,
llvm::StringRef Namespace,
PPCallbacks::PragmaMessageKind Kind,
llvm::StringRef Str) {
beginCallback("PragmaMessage");
appendArgument("Loc", Loc);
appendArgument("Namespace", Namespace);
appendArgument("Kind", Kind, PragmaMessageKindStrings);
appendArgument("Str", Str);
}
// Callback invoked when a #pragma gcc diagnostic push directive
// is read.
void PPCallbacksTracker::PragmaDiagnosticPush(SourceLocation Loc,
llvm::StringRef Namespace) {
beginCallback("PragmaDiagnosticPush");
appendArgument("Loc", Loc);
appendArgument("Namespace", Namespace);
}
// Callback invoked when a #pragma gcc diagnostic pop directive
// is read.
void PPCallbacksTracker::PragmaDiagnosticPop(SourceLocation Loc,
llvm::StringRef Namespace) {
beginCallback("PragmaDiagnosticPop");
appendArgument("Loc", Loc);
appendArgument("Namespace", Namespace);
}
// Callback invoked when a #pragma gcc diagnostic directive is read.
void PPCallbacksTracker::PragmaDiagnostic(SourceLocation Loc,
llvm::StringRef Namespace,
diag::Severity Mapping,
llvm::StringRef Str) {
beginCallback("PragmaDiagnostic");
appendArgument("Loc", Loc);
appendArgument("Namespace", Namespace);
appendArgument("Mapping", (unsigned)Mapping, MappingStrings);
appendArgument("Str", Str);
}
// Called when an OpenCL extension is either disabled or
// enabled with a pragma.
void PPCallbacksTracker::PragmaOpenCLExtension(SourceLocation NameLoc,
const IdentifierInfo *Name,
SourceLocation StateLoc,
unsigned State) {
beginCallback("PragmaOpenCLExtension");
appendArgument("NameLoc", NameLoc);
appendArgument("Name", Name);
appendArgument("StateLoc", StateLoc);
appendArgument("State", (int)State);
}
// Callback invoked when a #pragma warning directive is read.
void PPCallbacksTracker::PragmaWarning(SourceLocation Loc,
llvm::StringRef WarningSpec,
llvm::ArrayRef<int> Ids) {
beginCallback("PragmaWarning");
appendArgument("Loc", Loc);
appendArgument("WarningSpec", WarningSpec);
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "[";
for (int i = 0, e = Ids.size(); i != e; ++i) {
if (i)
SS << ", ";
SS << Ids[i];
}
SS << "]";
appendArgument("Ids", SS.str());
}
// Callback invoked when a #pragma warning(push) directive is read.
void PPCallbacksTracker::PragmaWarningPush(SourceLocation Loc, int Level) {
beginCallback("PragmaWarningPush");
appendArgument("Loc", Loc);
appendArgument("Level", Level);
}
// Callback invoked when a #pragma warning(pop) directive is read.
void PPCallbacksTracker::PragmaWarningPop(SourceLocation Loc) {
beginCallback("PragmaWarningPop");
appendArgument("Loc", Loc);
}
// Callback invoked when a #pragma execution_character_set(push) directive
// is read.
void PPCallbacksTracker::PragmaExecCharsetPush(SourceLocation Loc,
StringRef Str) {
beginCallback("PragmaExecCharsetPush");
appendArgument("Loc", Loc);
appendArgument("Charset", Str);
}
// Callback invoked when a #pragma execution_character_set(pop) directive
// is read.
void PPCallbacksTracker::PragmaExecCharsetPop(SourceLocation Loc) {
beginCallback("PragmaExecCharsetPop");
appendArgument("Loc", Loc);
}
// Called by Preprocessor::HandleMacroExpandedIdentifier when a
// macro invocation is found.
void PPCallbacksTracker::MacroExpands(const Token &MacroNameTok,
const MacroDefinition &MacroDefinition,
SourceRange Range,
const MacroArgs *Args) {
beginCallback("MacroExpands");
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDefinition", MacroDefinition);
appendArgument("Range", Range);
appendArgument("Args", Args);
}
// Hook called whenever a macro definition is seen.
void PPCallbacksTracker::MacroDefined(const Token &MacroNameTok,
const MacroDirective *MacroDirective) {
beginCallback("MacroDefined");
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDirective", MacroDirective);
}
// Hook called whenever a macro #undef is seen.
void PPCallbacksTracker::MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MacroDefinition,
const MacroDirective *Undef) {
beginCallback("MacroUndefined");
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDefinition", MacroDefinition);
}
// Hook called whenever the 'defined' operator is seen.
void PPCallbacksTracker::Defined(const Token &MacroNameTok,
const MacroDefinition &MacroDefinition,
SourceRange Range) {
beginCallback("Defined");
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDefinition", MacroDefinition);
appendArgument("Range", Range);
}
// Hook called when a source range is skipped.
void PPCallbacksTracker::SourceRangeSkipped(SourceRange Range,
SourceLocation EndifLoc) {
beginCallback("SourceRangeSkipped");
appendArgument("Range", SourceRange(Range.getBegin(), EndifLoc));
}
// Hook called whenever an #if is seen.
void PPCallbacksTracker::If(SourceLocation Loc, SourceRange ConditionRange,
ConditionValueKind ConditionValue) {
beginCallback("If");
appendArgument("Loc", Loc);
appendArgument("ConditionRange", ConditionRange);
appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
}
// Hook called whenever an #elif is seen.
void PPCallbacksTracker::Elif(SourceLocation Loc, SourceRange ConditionRange,
ConditionValueKind ConditionValue,
SourceLocation IfLoc) {
beginCallback("Elif");
appendArgument("Loc", Loc);
appendArgument("ConditionRange", ConditionRange);
appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
appendArgument("IfLoc", IfLoc);
}
// Hook called whenever an #ifdef is seen.
void PPCallbacksTracker::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
const MacroDefinition &MacroDefinition) {
beginCallback("Ifdef");
appendArgument("Loc", Loc);
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDefinition", MacroDefinition);
}
// Hook called whenever an #ifndef is seen.
void PPCallbacksTracker::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
const MacroDefinition &MacroDefinition) {
beginCallback("Ifndef");
appendArgument("Loc", Loc);
appendArgument("MacroNameTok", MacroNameTok);
appendArgument("MacroDefinition", MacroDefinition);
}
// Hook called whenever an #else is seen.
void PPCallbacksTracker::Else(SourceLocation Loc, SourceLocation IfLoc) {
beginCallback("Else");
appendArgument("Loc", Loc);
appendArgument("IfLoc", IfLoc);
}
// Hook called whenever an #endif is seen.
void PPCallbacksTracker::Endif(SourceLocation Loc, SourceLocation IfLoc) {
beginCallback("Endif");
appendArgument("Loc", Loc);
appendArgument("IfLoc", IfLoc);
}
// Helper functions.
// Start a new callback.
void PPCallbacksTracker::beginCallback(const char *Name) {
auto R = CallbackIsEnabled.try_emplace(Name, false);
if (R.second) {
llvm::StringRef N(Name);
for (const std::pair<llvm::GlobPattern, bool> &Filter : Filters)
if (Filter.first.match(N))
R.first->second = Filter.second;
}
DisableTrace = !R.first->second;
if (DisableTrace)
return;
CallbackCalls.push_back(CallbackCall(Name));
}
// Append a bool argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, bool Value) {
appendArgument(Name, (Value ? "true" : "false"));
}
// Append an int argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, int Value) {
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << Value;
appendArgument(Name, SS.str());
}
// Append a string argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, const char *Value) {
if (DisableTrace)
return;
CallbackCalls.back().Arguments.push_back(Argument{Name, Value});
}
// Append a string object argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
llvm::StringRef Value) {
appendArgument(Name, Value.str());
}
// Append a string object argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const std::string &Value) {
appendArgument(Name, Value.c_str());
}
// Append a token argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, const Token &Value) {
appendArgument(Name, PP.getSpelling(Value));
}
// Append an enum argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, int Value,
const char *const Strings[]) {
appendArgument(Name, Strings[Value]);
}
// Append a FileID argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, FileID Value) {
if (Value.isInvalid()) {
appendArgument(Name, "(invalid)");
return;
}
const FileEntry *FileEntry = PP.getSourceManager().getFileEntryForID(Value);
if (!FileEntry) {
appendArgument(Name, "(getFileEntryForID failed)");
return;
}
appendFilePathArgument(Name, FileEntry->getName());
}
// Append a FileEntry argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const FileEntry *Value) {
if (!Value) {
appendArgument(Name, "(null)");
return;
}
appendFilePathArgument(Name, Value->getName());
}
// Append a SourceLocation argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
SourceLocation Value) {
if (Value.isInvalid()) {
appendArgument(Name, "(invalid)");
return;
}
appendArgument(Name, getSourceLocationString(PP, Value).c_str());
}
// Append a SourceRange argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, SourceRange Value) {
if (DisableTrace)
return;
if (Value.isInvalid()) {
appendArgument(Name, "(invalid)");
return;
}
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "[" << getSourceLocationString(PP, Value.getBegin()) << ", "
<< getSourceLocationString(PP, Value.getEnd()) << "]";
appendArgument(Name, SS.str());
}
// Append a CharSourceRange argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
CharSourceRange Value) {
if (Value.isInvalid()) {
appendArgument(Name, "(invalid)");
return;
}
appendArgument(Name, getSourceString(Value).str().c_str());
}
// Append a SourceLocation argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, ModuleIdPath Value) {
if (DisableTrace)
return;
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "[";
for (int I = 0, E = Value.size(); I != E; ++I) {
if (I)
SS << ", ";
SS << "{"
<< "Name: " << Value[I].first->getName() << ", "
<< "Loc: " << getSourceLocationString(PP, Value[I].second) << "}";
}
SS << "]";
appendArgument(Name, SS.str());
}
// Append an IdentifierInfo argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const IdentifierInfo *Value) {
if (!Value) {
appendArgument(Name, "(null)");
return;
}
appendArgument(Name, Value->getName().str().c_str());
}
// Append a MacroDirective argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const MacroDirective *Value) {
if (!Value) {
appendArgument(Name, "(null)");
return;
}
appendArgument(Name, MacroDirectiveKindStrings[Value->getKind()]);
}
// Append a MacroDefinition argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const MacroDefinition &Value) {
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "[";
bool Any = false;
if (Value.getLocalDirective()) {
SS << "(local)";
Any = true;
}
for (auto *MM : Value.getModuleMacros()) {
if (Any) SS << ", ";
SS << MM->getOwningModule()->getFullModuleName();
}
SS << "]";
appendArgument(Name, SS.str());
}
// Append a MacroArgs argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name,
const MacroArgs *Value) {
if (!Value) {
appendArgument(Name, "(null)");
return;
}
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "[";
// Each argument is is a series of contiguous Tokens, terminated by a eof.
// Go through each argument printing tokens until we reach eof.
for (unsigned I = 0; I < Value->getNumMacroArguments(); ++I) {
const Token *Current = Value->getUnexpArgument(I);
if (I)
SS << ", ";
bool First = true;
while (Current->isNot(tok::eof)) {
if (!First)
SS << " ";
// We need to be careful here because the arguments might not be legal in
// YAML, so we use the token name for anything but identifiers and
// numeric literals.
if (Current->isAnyIdentifier() || Current->is(tok::numeric_constant)) {
SS << PP.getSpelling(*Current);
} else {
SS << "<" << Current->getName() << ">";
}
++Current;
First = false;
}
}
SS << "]";
appendArgument(Name, SS.str());
}
// Append a Module argument to the top trace item.
void PPCallbacksTracker::appendArgument(const char *Name, const Module *Value) {
if (!Value) {
appendArgument(Name, "(null)");
return;
}
appendArgument(Name, Value->Name.c_str());
}
// Append a double-quoted argument to the top trace item.
void PPCallbacksTracker::appendQuotedArgument(const char *Name,
const std::string &Value) {
std::string Str;
llvm::raw_string_ostream SS(Str);
SS << "\"" << Value << "\"";
appendArgument(Name, SS.str());
}
// Append a double-quoted file path argument to the top trace item.
void PPCallbacksTracker::appendFilePathArgument(const char *Name,
llvm::StringRef Value) {
std::string Path(Value);
// YAML treats backslash as escape, so use forward slashes.
std::replace(Path.begin(), Path.end(), '\\', '/');
appendQuotedArgument(Name, Path);
}
// Get the raw source string of the range.
llvm::StringRef PPCallbacksTracker::getSourceString(CharSourceRange Range) {
const char *B = PP.getSourceManager().getCharacterData(Range.getBegin());
const char *E = PP.getSourceManager().getCharacterData(Range.getEnd());
return llvm::StringRef(B, E - B);
}
} // namespace pp_trace
} // namespace clang