clang-tools 8.0.0

PPTrace.cpp
Go to the documentation of this file.
1 //===--- tools/pp-trace/PPTrace.cpp - Clang preprocessor tracer -----------===//
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 // This file implements pp-trace, a tool for displaying a textual trace
11 // of the Clang preprocessor activity. It's based on a derivation of the
12 // PPCallbacks class, that once registerd with Clang, receives callback calls
13 // to its virtual members, and outputs the information passed to the callbacks
14 // in a high-level YAML format.
15 //
16 // The pp-trace tool also serves as the basis for a test of the PPCallbacks
17 // mechanism.
18 //
19 // The pp-trace tool supports the following general command line format:
20 //
21 // pp-trace [pp-trace options] (source file) [compiler options]
22 //
23 // Basically you put the pp-trace options first, then the source file or files,
24 // and then any options you want to pass to the compiler.
25 //
26 // These are the pp-trace options:
27 //
28 // -ignore (callback list) Don't display output for a comma-separated
29 // list of callbacks, i.e.:
30 // -ignore "FileChanged,InclusionDirective"
31 //
32 // -output (file) Output trace to the given file in a YAML
33 // format, e.g.:
34 //
35 // ---
36 // - Callback: Name
37 // Argument1: Value1
38 // Argument2: Value2
39 // (etc.)
40 // ...
41 //
42 // Future Directions:
43 //
44 // 1. Add option opposite to "-ignore" that specifys a comma-separated option
45 // list of callbacs. Perhaps "-only" or "-exclusive".
46 //
47 //===----------------------------------------------------------------------===//
48
49 #include "PPCallbacksTracker.h"
50 #include "clang/AST/ASTConsumer.h"
51 #include "clang/AST/ASTContext.h"
52 #include "clang/AST/RecursiveASTVisitor.h"
53 #include "clang/Basic/SourceManager.h"
54 #include "clang/Driver/Options.h"
55 #include "clang/Frontend/CompilerInstance.h"
56 #include "clang/Frontend/FrontendActions.h"
57 #include "clang/Lex/Preprocessor.h"
58 #include "clang/Tooling/CompilationDatabase.h"
59 #include "clang/Tooling/Tooling.h"
60 #include "llvm/Option/Arg.h"
61 #include "llvm/Option/ArgList.h"
62 #include "llvm/Option/OptTable.h"
63 #include "llvm/Option/Option.h"
64 #include "llvm/Support/CommandLine.h"
65 #include "llvm/Support/FileSystem.h"
66 #include "llvm/Support/MemoryBuffer.h"
67 #include "llvm/Support/Path.h"
68 #include "llvm/Support/ToolOutputFile.h"
69 #include <algorithm>
70 #include <fstream>
71 #include <iterator>
72 #include <string>
73 #include <vector>
74
75 using namespace clang;
76 using namespace clang::tooling;
77 using namespace llvm;
78
79 // Options:
80
81 // Collect the source files.
82 static cl::list<std::string> SourcePaths(cl::Positional,
83 cl::desc("<source0> [... <sourceN>]"),
84 cl::OneOrMore);
85
86 // Option to specify a list or one or more callback names to ignore.
87 static cl::opt<std::string> IgnoreCallbacks(
88 "ignore", cl::init(""),
89 cl::desc("Ignore callbacks, i.e. \"Callback1, Callback2...\"."));
90
91 // Option to specify the trace output file name.
92 static cl::opt<std::string> OutputFileName(
93 "output", cl::init(""),
94 cl::desc("Output trace to the given file name or '-' for stdout."));
95
96 // Collect all other arguments, which will be passed to the front end.
97 static cl::list<std::string>
98 CC1Arguments(cl::ConsumeAfter,
99 cl::desc("<arguments to be passed to front end>..."));
100
101 // Frontend action stuff:
102
103 namespace {
104 // Consumer is responsible for setting up the callbacks.
105 class PPTraceConsumer : public ASTConsumer {
106 public:
107 PPTraceConsumer(SmallSet<std::string, 4> &Ignore,
108 std::vector<CallbackCall> &CallbackCalls, Preprocessor &PP) {
109 // PP takes ownership.
110 PP.addPPCallbacks(llvm::make_unique<PPCallbacksTracker>(Ignore,
111 CallbackCalls, PP));
112 }
113 };
114
115 class PPTraceAction : public SyntaxOnlyAction {
116 public:
117 PPTraceAction(SmallSet<std::string, 4> &Ignore,
118 std::vector<CallbackCall> &CallbackCalls)
119 : Ignore(Ignore), CallbackCalls(CallbackCalls) {}
120
121 protected:
122 std::unique_ptr<clang::ASTConsumer>
123 CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
124 return llvm::make_unique<PPTraceConsumer>(Ignore, CallbackCalls,
125 CI.getPreprocessor());
126 }
127
128 private:
129 SmallSet<std::string, 4> &Ignore;
130 std::vector<CallbackCall> &CallbackCalls;
131 };
132
133 class PPTraceFrontendActionFactory : public FrontendActionFactory {
134 public:
135 PPTraceFrontendActionFactory(SmallSet<std::string, 4> &Ignore,
136 std::vector<CallbackCall> &CallbackCalls)
137 : Ignore(Ignore), CallbackCalls(CallbackCalls) {}
138
139 PPTraceAction *create() override {
140 return new PPTraceAction(Ignore, CallbackCalls);
141 }
142
143 private:
144 SmallSet<std::string, 4> &Ignore;
145 std::vector<CallbackCall> &CallbackCalls;
146 };
147 } // namespace
148
149 // Output the trace given its data structure and a stream.
150 static int outputPPTrace(std::vector<CallbackCall> &CallbackCalls,
151 llvm::raw_ostream &OS) {
152 // Mark start of document.
153 OS << "---\n";
154
155 for (std::vector<CallbackCall>::const_iterator I = CallbackCalls.begin(),
156 E = CallbackCalls.end();
157 I != E; ++I) {
158 const CallbackCall &Callback = *I;
159 OS << "- Callback: " << Callback.Name << "\n";
160
161 for (auto AI = Callback.Arguments.begin(), AE = Callback.Arguments.end();
162 AI != AE; ++AI) {
163 const Argument &Arg = *AI;
164 OS << " " << Arg.Name << ": " << Arg.Value << "\n";
165 }
166 }
167
168 // Mark end of document.
169 OS << "...\n";
170
171 return 0;
172 }
173
174 // Program entry point.
175 int main(int Argc, const char **Argv) {
176
177 // Parse command line.
178 cl::ParseCommandLineOptions(Argc, Argv, "pp-trace.\n");
179
180 // Parse the IgnoreCallbacks list into strings.
181 SmallVector<StringRef, 32> IgnoreCallbacksStrings;
182 StringRef(IgnoreCallbacks).split(IgnoreCallbacksStrings, ",",
183 /*MaxSplit=*/ -1, /*KeepEmpty=*/false);
184 SmallSet<std::string, 4> Ignore;
185 for (SmallVector<StringRef, 32>::iterator I = IgnoreCallbacksStrings.begin(),
186 E = IgnoreCallbacksStrings.end();
187 I != E; ++I)
188 Ignore.insert(*I);
189
190 // Create the compilation database.
191 SmallString<256> PathBuf;
192 sys::fs::current_path(PathBuf);
193 std::unique_ptr<CompilationDatabase> Compilations;
194 Compilations.reset(
195 new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
196
197 // Store the callback trace information here.
198 std::vector<CallbackCall> CallbackCalls;
199
200 // Create the tool and run the compilation.
201 ClangTool Tool(*Compilations, SourcePaths);
202 PPTraceFrontendActionFactory Factory(Ignore, CallbackCalls);
203 int HadErrors = Tool.run(&Factory);
204
205 // If we had errors, exit early.
206 if (HadErrors)
207 return HadErrors;
208
209 // Do the output.
210 if (!OutputFileName.size()) {
211 HadErrors = outputPPTrace(CallbackCalls, llvm::outs());
212 } else {
213 // Set up output file.
214 std::error_code EC;
215 llvm::ToolOutputFile Out(OutputFileName, EC, llvm::sys::fs::F_Text);
216 if (EC) {
217 llvm::errs() << "pp-trace: error creating " << OutputFileName << ":"
218 << EC.message() << "\n";
219 return 1;
220 }
221
222 HadErrors = outputPPTrace(CallbackCalls, Out.os());
223
224 // Tell ToolOutputFile that we want to keep the file.
225 if (HadErrors == 0)
226 Out.keep();
227 }
228
229 return HadErrors;
230 }
Argument
This class represents one callback function argument by name and value.
Definition: PPCallbacksTracker.h:36
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
CallbackCall::Arguments
std::vector< Argument > Arguments
Definition: PPCallbacksTracker.h:54
clang::tooling
Definition: ClangTidy.h:28
SourcePaths
static cl::list< std::string > SourcePaths(cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore)
CC1Arguments
static cl::list< std::string > CC1Arguments(cl::ConsumeAfter, cl::desc("<arguments to be passed to front end>..."))
CallbackCall::Name
std::string Name
Definition: PPCallbacksTracker.h:53
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
OutputFileName
static cl::opt< std::string > OutputFileName("output", cl::init(""), cl::desc("Output trace to the given file name or '-' for stdout."))
ASTConsumer
IgnoreCallbacks
static cl::opt< std::string > IgnoreCallbacks("ignore", cl::init(""), cl::desc("Ignore callbacks, i.e. \allback1, Callback2...\"))
PPCallbacksTracker.h
Classes and definitions for preprocessor tracking.
CallbackCall
This class represents one callback call by name and an array of arguments.
Definition: PPCallbacksTracker.h:48
SyntaxOnlyAction
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
Argument::Value
std::string Value
Definition: PPCallbacksTracker.h:43
outputPPTrace
static int outputPPTrace(std::vector< CallbackCall > &CallbackCalls, llvm::raw_ostream &OS)
Definition: PPTrace.cpp:150
Argument::Name
std::string Name
Definition: PPCallbacksTracker.h:42
main
int main(int Argc, const char **Argv)
Definition: PPTrace.cpp:175