1 //===--- tools/pp-trace/PPTrace.cpp - Clang preprocessor tracer -----------===//
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 //===----------------------------------------------------------------------===//
9 // This file implements pp-trace, a tool for displaying a textual trace
10 // of the Clang preprocessor activity. It's based on a derivation of the
11 // PPCallbacks class, that once registerd with Clang, receives callback calls
12 // to its virtual members, and outputs the information passed to the callbacks
13 // in a high-level YAML format.
15 // The pp-trace tool also serves as the basis for a test of the PPCallbacks
18 // The pp-trace tool supports the following general command line format:
20 // pp-trace [options] file... [-- compiler options]
22 // Basically you put the pp-trace options first, then the source file or files,
23 // and then -- followed by any options you want to pass to the compiler.
25 //===----------------------------------------------------------------------===//
27 #include "PPCallbacksTracker.h"
28 #include "clang/AST/ASTConsumer.h"
29 #include "clang/AST/ASTContext.h"
30 #include "clang/Basic/SourceManager.h"
31 #include "clang/Driver/Options.h"
32 #include "clang/Frontend/CompilerInstance.h"
33 #include "clang/Frontend/FrontendAction.h"
34 #include "clang/Frontend/FrontendActions.h"
35 #include "clang/Lex/Preprocessor.h"
36 #include "clang/Tooling/Execution.h"
37 #include "clang/Tooling/Tooling.h"
38 #include "llvm/Option/Arg.h"
39 #include "llvm/Option/ArgList.h"
40 #include "llvm/Option/OptTable.h"
41 #include "llvm/Option/Option.h"
42 #include "llvm/Support/CommandLine.h"
43 #include "llvm/Support/FileSystem.h"
44 #include "llvm/Support/GlobPattern.h"
45 #include "llvm/Support/InitLLVM.h"
46 #include "llvm/Support/Path.h"
47 #include "llvm/Support/ToolOutputFile.h"
48 #include "llvm/Support/WithColor.h"
57 static cl::OptionCategory
Cat("pp-trace options");
59 static cl::opt
<std::string
> Callbacks(
60 "callbacks", cl::init("*"),
61 cl::desc("Comma-separated list of globs describing the list of callbacks "
62 "to output. Globs are processed in order of appearance. Globs "
63 "with the '-' prefix remove callbacks from the set. e.g. "
67 static cl::opt
<std::string
> OutputFileName(
68 "output", cl::init("-"),
69 cl::desc("Output trace to the given file name or '-' for stdout."),
72 [[noreturn
]] static void error(Twine Message
) {
73 WithColor::error() << Message
<< '\n';
79 class PPTraceAction
: public ASTFrontendAction
{
81 PPTraceAction(const FilterType
&Filters
, raw_ostream
&OS
)
82 : Filters(Filters
), OS(OS
) {}
85 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
86 StringRef InFile
) override
{
87 Preprocessor
&PP
= CI
.getPreprocessor();
89 std::make_unique
<PPCallbacksTracker
>(Filters
, CallbackCalls
, PP
));
90 return std::make_unique
<ASTConsumer
>();
93 void EndSourceFileAction() override
{
95 for (const CallbackCall
&Callback
: CallbackCalls
) {
96 OS
<< "- Callback: " << Callback
.Name
<< "\n";
97 for (const Argument
&Arg
: Callback
.Arguments
)
98 OS
<< " " << Arg
.Name
<< ": " << Arg
.Value
<< "\n";
102 CallbackCalls
.clear();
106 const FilterType
&Filters
;
108 std::vector
<CallbackCall
> CallbackCalls
;
111 class PPTraceFrontendActionFactory
: public tooling::FrontendActionFactory
{
113 PPTraceFrontendActionFactory(const FilterType
&Filters
, raw_ostream
&OS
)
114 : Filters(Filters
), OS(OS
) {}
116 std::unique_ptr
<FrontendAction
> create() override
{
117 return std::make_unique
<PPTraceAction
>(Filters
, OS
);
121 const FilterType
&Filters
;
125 } // namespace pp_trace
128 int main(int argc
, const char **argv
) {
129 using namespace clang::pp_trace
;
130 InitLLVM
X(argc
, argv
);
131 auto OptionsParser
= clang::tooling::CommonOptionsParser::create(
132 argc
, argv
, Cat
, llvm::cl::ZeroOrMore
);
134 error(toString(OptionsParser
.takeError()));
135 // Parse the IgnoreCallbacks list into strings.
136 SmallVector
<StringRef
, 32> Patterns
;
138 StringRef(Callbacks
).split(Patterns
, ",",
139 /*MaxSplit=*/-1, /*KeepEmpty=*/false);
140 for (StringRef Pattern
: Patterns
) {
141 Pattern
= Pattern
.trim();
142 bool Enabled
= !Pattern
.consume_front("-");
143 Expected
<GlobPattern
> Pat
= GlobPattern::create(Pattern
);
145 Filters
.emplace_back(std::move(*Pat
), Enabled
);
147 error(toString(Pat
.takeError()));
150 // Create the tool and run the compilation.
151 clang::tooling::ClangTool
Tool(OptionsParser
->getCompilations(),
152 OptionsParser
->getSourcePathList());
155 llvm::ToolOutputFile
Out(OutputFileName
, EC
, llvm::sys::fs::OF_TextWithCRLF
);
158 PPTraceFrontendActionFactory
Factory(Filters
, Out
.os());
159 int HadErrors
= Tool
.run(&Factory
);
161 // If we had errors, exit early.