1 //===--- PPCallbacksTracker.cpp - Preprocessor tracker -*--*---------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// Implementations for preprocessor tracking.
12 /// See the header for details.
14 //===----------------------------------------------------------------------===//
16 #include "PPCallbacksTracker.h"
17 #include "clang/Basic/FileManager.h"
18 #include "clang/Lex/MacroArgs.h"
19 #include "llvm/Support/raw_ostream.h"
24 // Get a "file:line:column" source location string.
25 static std::string
getSourceLocationString(Preprocessor
&PP
,
28 return std::string("(none)");
31 PresumedLoc PLoc
= PP
.getSourceManager().getPresumedLoc(Loc
);
33 if (PLoc
.isInvalid()) {
34 return std::string("(invalid)");
38 llvm::raw_string_ostream
SS(Str
);
40 // The macro expansion and spelling pos is identical for file locs.
41 SS
<< "\"" << PLoc
.getFilename() << ':' << PLoc
.getLine() << ':'
42 << PLoc
.getColumn() << "\"";
44 std::string Result
= SS
.str();
46 // YAML treats backslash as escape, so use forward slashes.
47 std::replace(Result
.begin(), Result
.end(), '\\', '/');
52 return std::string("(nonfile)");
55 // Enum string tables.
57 // FileChangeReason strings.
58 static const char *const FileChangeReasonStrings
[] = {
59 "EnterFile", "ExitFile", "SystemHeaderPragma", "RenameFile"
62 // CharacteristicKind strings.
63 static const char *const CharacteristicKindStrings
[] = { "C_User", "C_System",
66 // MacroDirective::Kind strings.
67 static const char *const MacroDirectiveKindStrings
[] = {
68 "MD_Define","MD_Undefine", "MD_Visibility"
71 // PragmaIntroducerKind strings.
72 static const char *const PragmaIntroducerKindStrings
[] = { "PIK_HashPragma",
76 // PragmaMessageKind strings.
77 static const char *const PragmaMessageKindStrings
[] = {
78 "PMK_Message", "PMK_Warning", "PMK_Error"
81 // PragmaWarningSpecifier strings.
82 static const char *const PragmaWarningSpecifierStrings
[] = {
83 "PWS_Default", "PWS_Disable", "PWS_Error", "PWS_Once", "PWS_Suppress",
84 "PWS_Level1", "PWS_Level2", "PWS_Level3", "PWS_Level4",
87 // ConditionValueKind strings.
88 static const char *const ConditionValueKindStrings
[] = {
89 "CVK_NotEvaluated", "CVK_False", "CVK_True"
93 static const char *const MappingStrings
[] = { "0", "MAP_IGNORE",
94 "MAP_REMARK", "MAP_WARNING",
95 "MAP_ERROR", "MAP_FATAL" };
97 // PPCallbacksTracker functions.
99 PPCallbacksTracker::PPCallbacksTracker(const FilterType
&Filters
,
100 std::vector
<CallbackCall
> &CallbackCalls
,
102 : CallbackCalls(CallbackCalls
), Filters(Filters
), PP(PP
) {}
104 PPCallbacksTracker::~PPCallbacksTracker() {}
106 // Callback functions.
108 // Callback invoked whenever a source file is entered or exited.
109 void PPCallbacksTracker::FileChanged(SourceLocation Loc
,
110 PPCallbacks::FileChangeReason Reason
,
111 SrcMgr::CharacteristicKind FileType
,
113 beginCallback("FileChanged");
114 appendArgument("Loc", Loc
);
115 appendArgument("Reason", Reason
, FileChangeReasonStrings
);
116 appendArgument("FileType", FileType
, CharacteristicKindStrings
);
117 appendArgument("PrevFID", PrevFID
);
120 // Callback invoked whenever a source file is skipped as the result
121 // of header guard optimization.
122 void 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
);
131 // Callback invoked whenever an inclusion directive of
132 // any kind (#include, #import, etc.) has been processed, regardless
133 // of whether the inclusion will actually result in an inclusion.
134 void 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
);
153 // Callback invoked whenever there was an explicit module-import
155 void PPCallbacksTracker::moduleImport(SourceLocation ImportLoc
,
157 const Module
*Imported
) {
158 beginCallback("moduleImport");
159 appendArgument("ImportLoc", ImportLoc
);
160 appendArgument("Path", Path
);
161 appendArgument("Imported", Imported
);
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"); }
168 // Callback invoked when a #ident or #sccs directive is read.
169 void PPCallbacksTracker::Ident(SourceLocation Loc
, llvm::StringRef Str
) {
170 beginCallback("Ident");
171 appendArgument("Loc", Loc
);
172 appendArgument("Str", Str
);
175 // Callback invoked when start reading any pragma directive.
176 void PPCallbacksTracker::PragmaDirective(SourceLocation Loc
,
177 PragmaIntroducerKind Introducer
) {
178 beginCallback("PragmaDirective");
179 appendArgument("Loc", Loc
);
180 appendArgument("Introducer", Introducer
, PragmaIntroducerKindStrings
);
183 // Callback invoked when a #pragma comment directive is read.
184 void 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
);
193 // Callback invoked when a #pragma detect_mismatch directive is
195 void 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
);
204 // Callback invoked when a #pragma clang __debug directive is read.
205 void PPCallbacksTracker::PragmaDebug(SourceLocation Loc
,
206 llvm::StringRef DebugType
) {
207 beginCallback("PragmaDebug");
208 appendArgument("Loc", Loc
);
209 appendArgument("DebugType", DebugType
);
212 // Callback invoked when a #pragma message directive is read.
213 void 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
);
224 // Callback invoked when a #pragma gcc diagnostic push directive
226 void PPCallbacksTracker::PragmaDiagnosticPush(SourceLocation Loc
,
227 llvm::StringRef Namespace
) {
228 beginCallback("PragmaDiagnosticPush");
229 appendArgument("Loc", Loc
);
230 appendArgument("Namespace", Namespace
);
233 // Callback invoked when a #pragma gcc diagnostic pop directive
235 void PPCallbacksTracker::PragmaDiagnosticPop(SourceLocation Loc
,
236 llvm::StringRef Namespace
) {
237 beginCallback("PragmaDiagnosticPop");
238 appendArgument("Loc", Loc
);
239 appendArgument("Namespace", Namespace
);
242 // Callback invoked when a #pragma gcc diagnostic directive is read.
243 void 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
);
254 // Called when an OpenCL extension is either disabled or
255 // enabled with a pragma.
256 void PPCallbacksTracker::PragmaOpenCLExtension(SourceLocation NameLoc
,
257 const IdentifierInfo
*Name
,
258 SourceLocation StateLoc
,
260 beginCallback("PragmaOpenCLExtension");
261 appendArgument("NameLoc", NameLoc
);
262 appendArgument("Name", Name
);
263 appendArgument("StateLoc", StateLoc
);
264 appendArgument("State", (int)State
);
267 // Callback invoked when a #pragma warning directive is read.
268 void PPCallbacksTracker::PragmaWarning(SourceLocation Loc
,
269 PragmaWarningSpecifier WarningSpec
,
270 llvm::ArrayRef
<int> Ids
) {
271 beginCallback("PragmaWarning");
272 appendArgument("Loc", Loc
);
273 appendArgument("WarningSpec", WarningSpec
, PragmaWarningSpecifierStrings
);
276 llvm::raw_string_ostream
SS(Str
);
278 for (int i
= 0, e
= Ids
.size(); i
!= e
; ++i
) {
284 appendArgument("Ids", SS
.str());
287 // Callback invoked when a #pragma warning(push) directive is read.
288 void PPCallbacksTracker::PragmaWarningPush(SourceLocation Loc
, int Level
) {
289 beginCallback("PragmaWarningPush");
290 appendArgument("Loc", Loc
);
291 appendArgument("Level", Level
);
294 // Callback invoked when a #pragma warning(pop) directive is read.
295 void PPCallbacksTracker::PragmaWarningPop(SourceLocation Loc
) {
296 beginCallback("PragmaWarningPop");
297 appendArgument("Loc", Loc
);
300 // Callback invoked when a #pragma execution_character_set(push) directive
302 void PPCallbacksTracker::PragmaExecCharsetPush(SourceLocation Loc
,
304 beginCallback("PragmaExecCharsetPush");
305 appendArgument("Loc", Loc
);
306 appendArgument("Charset", Str
);
309 // Callback invoked when a #pragma execution_character_set(pop) directive
311 void PPCallbacksTracker::PragmaExecCharsetPop(SourceLocation Loc
) {
312 beginCallback("PragmaExecCharsetPop");
313 appendArgument("Loc", Loc
);
316 // Called by Preprocessor::HandleMacroExpandedIdentifier when a
317 // macro invocation is found.
318 void PPCallbacksTracker::MacroExpands(const Token
&MacroNameTok
,
319 const MacroDefinition
&MacroDefinition
,
321 const MacroArgs
*Args
) {
322 beginCallback("MacroExpands");
323 appendArgument("MacroNameTok", MacroNameTok
);
324 appendArgument("MacroDefinition", MacroDefinition
);
325 appendArgument("Range", Range
);
326 appendArgument("Args", Args
);
329 // Hook called whenever a macro definition is seen.
330 void PPCallbacksTracker::MacroDefined(const Token
&MacroNameTok
,
331 const MacroDirective
*MacroDirective
) {
332 beginCallback("MacroDefined");
333 appendArgument("MacroNameTok", MacroNameTok
);
334 appendArgument("MacroDirective", MacroDirective
);
337 // Hook called whenever a macro #undef is seen.
338 void PPCallbacksTracker::MacroUndefined(const Token
&MacroNameTok
,
339 const MacroDefinition
&MacroDefinition
,
340 const MacroDirective
*Undef
) {
341 beginCallback("MacroUndefined");
342 appendArgument("MacroNameTok", MacroNameTok
);
343 appendArgument("MacroDefinition", MacroDefinition
);
346 // Hook called whenever the 'defined' operator is seen.
347 void PPCallbacksTracker::Defined(const Token
&MacroNameTok
,
348 const MacroDefinition
&MacroDefinition
,
350 beginCallback("Defined");
351 appendArgument("MacroNameTok", MacroNameTok
);
352 appendArgument("MacroDefinition", MacroDefinition
);
353 appendArgument("Range", Range
);
356 // Hook called when a source range is skipped.
357 void PPCallbacksTracker::SourceRangeSkipped(SourceRange Range
,
358 SourceLocation EndifLoc
) {
359 beginCallback("SourceRangeSkipped");
360 appendArgument("Range", SourceRange(Range
.getBegin(), EndifLoc
));
363 // Hook called whenever an #if is seen.
364 void PPCallbacksTracker::If(SourceLocation Loc
, SourceRange ConditionRange
,
365 ConditionValueKind ConditionValue
) {
367 appendArgument("Loc", Loc
);
368 appendArgument("ConditionRange", ConditionRange
);
369 appendArgument("ConditionValue", ConditionValue
, ConditionValueKindStrings
);
372 // Hook called whenever an #elif is seen.
373 void 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
);
383 // Hook called whenever an #ifdef is seen.
384 void 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
);
392 // Hook called whenever an #ifndef is seen.
393 void 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
);
401 // Hook called whenever an #else is seen.
402 void PPCallbacksTracker::Else(SourceLocation Loc
, SourceLocation IfLoc
) {
403 beginCallback("Else");
404 appendArgument("Loc", Loc
);
405 appendArgument("IfLoc", IfLoc
);
408 // Hook called whenever an #endif is seen.
409 void PPCallbacksTracker::Endif(SourceLocation Loc
, SourceLocation IfLoc
) {
410 beginCallback("Endif");
411 appendArgument("Loc", Loc
);
412 appendArgument("IfLoc", IfLoc
);
417 // Start a new callback.
418 void PPCallbacksTracker::beginCallback(const char *Name
) {
419 auto R
= CallbackIsEnabled
.try_emplace(Name
, false);
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
;
426 DisableTrace
= !R
.first
->second
;
429 CallbackCalls
.push_back(CallbackCall(Name
));
432 // Append a bool argument to the top trace item.
433 void PPCallbacksTracker::appendArgument(const char *Name
, bool Value
) {
434 appendArgument(Name
, (Value
? "true" : "false"));
437 // Append an int argument to the top trace item.
438 void PPCallbacksTracker::appendArgument(const char *Name
, int Value
) {
440 llvm::raw_string_ostream
SS(Str
);
442 appendArgument(Name
, SS
.str());
445 // Append a string argument to the top trace item.
446 void PPCallbacksTracker::appendArgument(const char *Name
, const char *Value
) {
449 CallbackCalls
.back().Arguments
.push_back(Argument
{Name
, Value
});
452 // Append a string object argument to the top trace item.
453 void PPCallbacksTracker::appendArgument(const char *Name
,
454 llvm::StringRef Value
) {
455 appendArgument(Name
, Value
.str());
458 // Append a string object argument to the top trace item.
459 void PPCallbacksTracker::appendArgument(const char *Name
,
460 const std::string
&Value
) {
461 appendArgument(Name
, Value
.c_str());
464 // Append a token argument to the top trace item.
465 void PPCallbacksTracker::appendArgument(const char *Name
, const Token
&Value
) {
466 appendArgument(Name
, PP
.getSpelling(Value
));
469 // Append an enum argument to the top trace item.
470 void PPCallbacksTracker::appendArgument(const char *Name
, int Value
,
471 const char *const Strings
[]) {
472 appendArgument(Name
, Strings
[Value
]);
475 // Append a FileID argument to the top trace item.
476 void PPCallbacksTracker::appendArgument(const char *Name
, FileID Value
) {
477 if (Value
.isInvalid()) {
478 appendArgument(Name
, "(invalid)");
481 OptionalFileEntryRef FileEntry
=
482 PP
.getSourceManager().getFileEntryRefForID(Value
);
484 appendArgument(Name
, "(getFileEntryForID failed)");
487 appendFilePathArgument(Name
, FileEntry
->getName());
490 // Append a FileEntry argument to the top trace item.
491 void PPCallbacksTracker::appendArgument(const char *Name
,
492 OptionalFileEntryRef Value
) {
494 appendArgument(Name
, "(null)");
497 appendArgument(Name
, *Value
);
500 void PPCallbacksTracker::appendArgument(const char *Name
, FileEntryRef Value
) {
501 appendFilePathArgument(Name
, Value
.getName());
504 // Append a SourceLocation argument to the top trace item.
505 void PPCallbacksTracker::appendArgument(const char *Name
,
506 SourceLocation Value
) {
507 if (Value
.isInvalid()) {
508 appendArgument(Name
, "(invalid)");
511 appendArgument(Name
, getSourceLocationString(PP
, Value
).c_str());
514 // Append a SourceRange argument to the top trace item.
515 void PPCallbacksTracker::appendArgument(const char *Name
, SourceRange Value
) {
518 if (Value
.isInvalid()) {
519 appendArgument(Name
, "(invalid)");
523 llvm::raw_string_ostream
SS(Str
);
524 SS
<< "[" << getSourceLocationString(PP
, Value
.getBegin()) << ", "
525 << getSourceLocationString(PP
, Value
.getEnd()) << "]";
526 appendArgument(Name
, SS
.str());
529 // Append a CharSourceRange argument to the top trace item.
530 void PPCallbacksTracker::appendArgument(const char *Name
,
531 CharSourceRange Value
) {
532 if (Value
.isInvalid()) {
533 appendArgument(Name
, "(invalid)");
536 appendArgument(Name
, getSourceString(Value
).str().c_str());
539 // Append a SourceLocation argument to the top trace item.
540 void PPCallbacksTracker::appendArgument(const char *Name
, ModuleIdPath Value
) {
544 llvm::raw_string_ostream
SS(Str
);
546 for (int I
= 0, E
= Value
.size(); I
!= E
; ++I
) {
550 << "Name: " << Value
[I
].first
->getName() << ", "
551 << "Loc: " << getSourceLocationString(PP
, Value
[I
].second
) << "}";
554 appendArgument(Name
, SS
.str());
557 // Append an IdentifierInfo argument to the top trace item.
558 void PPCallbacksTracker::appendArgument(const char *Name
,
559 const IdentifierInfo
*Value
) {
561 appendArgument(Name
, "(null)");
564 appendArgument(Name
, Value
->getName().str().c_str());
567 // Append a MacroDirective argument to the top trace item.
568 void PPCallbacksTracker::appendArgument(const char *Name
,
569 const MacroDirective
*Value
) {
571 appendArgument(Name
, "(null)");
574 appendArgument(Name
, MacroDirectiveKindStrings
[Value
->getKind()]);
577 // Append a MacroDefinition argument to the top trace item.
578 void PPCallbacksTracker::appendArgument(const char *Name
,
579 const MacroDefinition
&Value
) {
581 llvm::raw_string_ostream
SS(Str
);
584 if (Value
.getLocalDirective()) {
588 for (auto *MM
: Value
.getModuleMacros()) {
590 SS
<< MM
->getOwningModule()->getFullModuleName();
593 appendArgument(Name
, SS
.str());
596 // Append a MacroArgs argument to the top trace item.
597 void PPCallbacksTracker::appendArgument(const char *Name
,
598 const MacroArgs
*Value
) {
600 appendArgument(Name
, "(null)");
604 llvm::raw_string_ostream
SS(Str
);
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
);
614 while (Current
->isNot(tok::eof
)) {
617 // We need to be careful here because the arguments might not be legal in
618 // YAML, so we use the token name for anything but identifiers and
620 if (Current
->isAnyIdentifier() || Current
->is(tok::numeric_constant
)) {
621 SS
<< PP
.getSpelling(*Current
);
623 SS
<< "<" << Current
->getName() << ">";
630 appendArgument(Name
, SS
.str());
633 // Append a Module argument to the top trace item.
634 void PPCallbacksTracker::appendArgument(const char *Name
, const Module
*Value
) {
636 appendArgument(Name
, "(null)");
639 appendArgument(Name
, Value
->Name
.c_str());
642 // Append a double-quoted argument to the top trace item.
643 void PPCallbacksTracker::appendQuotedArgument(const char *Name
,
644 const std::string
&Value
) {
646 llvm::raw_string_ostream
SS(Str
);
647 SS
<< "\"" << Value
<< "\"";
648 appendArgument(Name
, SS
.str());
651 // Append a double-quoted file path argument to the top trace item.
652 void 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 std::replace(Path
.begin(), Path
.end(), '\\', '/');
657 appendQuotedArgument(Name
, Path
);
660 // Get the raw source string of the range.
661 llvm::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
);
667 } // namespace pp_trace