diff options
Diffstat (limited to 'pp-trace/PPTrace.cpp')
-rw-r--r-- | pp-trace/PPTrace.cpp | 243 |
1 files changed, 89 insertions, 154 deletions
diff --git a/pp-trace/PPTrace.cpp b/pp-trace/PPTrace.cpp index 08e0f514..5155a8b2 100644 --- a/pp-trace/PPTrace.cpp +++ b/pp-trace/PPTrace.cpp @@ -1,9 +1,8 @@ //===--- tools/pp-trace/PPTrace.cpp - Clang preprocessor tracer -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -18,44 +17,22 @@ // // The pp-trace tool supports the following general command line format: // -// pp-trace [pp-trace options] (source file) [compiler options] +// pp-trace [options] file... [-- compiler options] // // Basically you put the pp-trace options first, then the source file or files, -// and then any options you want to pass to the compiler. -// -// These are the pp-trace options: -// -// -ignore (callback list) Don't display output for a comma-separated -// list of callbacks, i.e.: -// -ignore "FileChanged,InclusionDirective" -// -// -output (file) Output trace to the given file in a YAML -// format, e.g.: -// -// --- -// - Callback: Name -// Argument1: Value1 -// Argument2: Value2 -// (etc.) -// ... -// -// Future Directions: -// -// 1. Add option opposite to "-ignore" that specifys a comma-separated option -// list of callbacs. Perhaps "-only" or "-exclusive". +// and then -- followed by any options you want to pass to the compiler. // //===----------------------------------------------------------------------===// #include "PPCallbacksTracker.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" #include "clang/Driver/Options.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Execution.h" #include "clang/Tooling/Tooling.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -63,168 +40,126 @@ #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/GlobPattern.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/ToolOutputFile.h" -#include <algorithm> -#include <fstream> -#include <iterator> +#include "llvm/Support/WithColor.h" #include <string> #include <vector> -using namespace clang; -using namespace clang::tooling; using namespace llvm; -// Options: +namespace clang { +namespace pp_trace { -// Collect the source files. -static cl::list<std::string> SourcePaths(cl::Positional, - cl::desc("<source0> [... <sourceN>]"), - cl::OneOrMore); +static cl::OptionCategory Cat("pp-trace options"); -// Option to specify a list or one or more callback names to ignore. -static cl::opt<std::string> IgnoreCallbacks( - "ignore", cl::init(""), - cl::desc("Ignore callbacks, i.e. \"Callback1, Callback2...\".")); +static cl::opt<std::string> Callbacks( + "callbacks", cl::init("*"), + cl::desc("Comma-separated list of globs describing the list of callbacks " + "to output. Globs are processed in order of appearance. Globs " + "with the '-' prefix remove callbacks from the set. e.g. " + "'*,-Macro*'."), + cl::cat(Cat)); -// Option to specify the trace output file name. static cl::opt<std::string> OutputFileName( - "output", cl::init(""), - cl::desc("Output trace to the given file name or '-' for stdout.")); + "output", cl::init("-"), + cl::desc("Output trace to the given file name or '-' for stdout."), + cl::cat(Cat)); -// Collect all other arguments, which will be passed to the front end. -static cl::list<std::string> - CC1Arguments(cl::ConsumeAfter, - cl::desc("<arguments to be passed to front end>...")); - -// Frontend action stuff: +LLVM_ATTRIBUTE_NORETURN static void error(Twine Message) { + WithColor::error() << Message << '\n'; + exit(1); +} namespace { -// Consumer is responsible for setting up the callbacks. -class PPTraceConsumer : public ASTConsumer { -public: - PPTraceConsumer(SmallSet<std::string, 4> &Ignore, - std::vector<CallbackCall> &CallbackCalls, Preprocessor &PP) { - // PP takes ownership. - PP.addPPCallbacks(llvm::make_unique<PPCallbacksTracker>(Ignore, - CallbackCalls, PP)); - } -}; -class PPTraceAction : public SyntaxOnlyAction { +class PPTraceAction : public ASTFrontendAction { public: - PPTraceAction(SmallSet<std::string, 4> &Ignore, - std::vector<CallbackCall> &CallbackCalls) - : Ignore(Ignore), CallbackCalls(CallbackCalls) {} + PPTraceAction(const FilterType &Filters, raw_ostream &OS) + : Filters(Filters), OS(OS) {} protected: - std::unique_ptr<clang::ASTConsumer> - CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { - return llvm::make_unique<PPTraceConsumer>(Ignore, CallbackCalls, - CI.getPreprocessor()); + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks( + llvm::make_unique<PPCallbacksTracker>(Filters, CallbackCalls, PP)); + return llvm::make_unique<ASTConsumer>(); + } + + void EndSourceFileAction() override { + OS << "---\n"; + for (const CallbackCall &Callback : CallbackCalls) { + OS << "- Callback: " << Callback.Name << "\n"; + for (const Argument &Arg : Callback.Arguments) + OS << " " << Arg.Name << ": " << Arg.Value << "\n"; + } + OS << "...\n"; + + CallbackCalls.clear(); } private: - SmallSet<std::string, 4> &Ignore; - std::vector<CallbackCall> &CallbackCalls; + const FilterType &Filters; + raw_ostream &OS; + std::vector<CallbackCall> CallbackCalls; }; -class PPTraceFrontendActionFactory : public FrontendActionFactory { +class PPTraceFrontendActionFactory : public tooling::FrontendActionFactory { public: - PPTraceFrontendActionFactory(SmallSet<std::string, 4> &Ignore, - std::vector<CallbackCall> &CallbackCalls) - : Ignore(Ignore), CallbackCalls(CallbackCalls) {} + PPTraceFrontendActionFactory(const FilterType &Filters, raw_ostream &OS) + : Filters(Filters), OS(OS) {} - PPTraceAction *create() override { - return new PPTraceAction(Ignore, CallbackCalls); - } + PPTraceAction *create() override { return new PPTraceAction(Filters, OS); } private: - SmallSet<std::string, 4> &Ignore; - std::vector<CallbackCall> &CallbackCalls; + const FilterType &Filters; + raw_ostream &OS; }; } // namespace - -// Output the trace given its data structure and a stream. -static int outputPPTrace(std::vector<CallbackCall> &CallbackCalls, - llvm::raw_ostream &OS) { - // Mark start of document. - OS << "---\n"; - - for (std::vector<CallbackCall>::const_iterator I = CallbackCalls.begin(), - E = CallbackCalls.end(); - I != E; ++I) { - const CallbackCall &Callback = *I; - OS << "- Callback: " << Callback.Name << "\n"; - - for (auto AI = Callback.Arguments.begin(), AE = Callback.Arguments.end(); - AI != AE; ++AI) { - const Argument &Arg = *AI; - OS << " " << Arg.Name << ": " << Arg.Value << "\n"; - } - } - - // Mark end of document. - OS << "...\n"; - - return 0; -} - -// Program entry point. -int main(int Argc, const char **Argv) { - - // Parse command line. - cl::ParseCommandLineOptions(Argc, Argv, "pp-trace.\n"); - +} // namespace pp_trace +} // namespace clang + +int main(int argc, const char **argv) { + using namespace clang::pp_trace; + InitLLVM X(argc, argv); + auto OptionsParser = clang::tooling::CommonOptionsParser::create( + argc, argv, Cat, llvm::cl::ZeroOrMore); + if (!OptionsParser) + error(toString(OptionsParser.takeError())); // Parse the IgnoreCallbacks list into strings. - SmallVector<StringRef, 32> IgnoreCallbacksStrings; - StringRef(IgnoreCallbacks).split(IgnoreCallbacksStrings, ",", - /*MaxSplit=*/ -1, /*KeepEmpty=*/false); - SmallSet<std::string, 4> Ignore; - for (SmallVector<StringRef, 32>::iterator I = IgnoreCallbacksStrings.begin(), - E = IgnoreCallbacksStrings.end(); - I != E; ++I) - Ignore.insert(*I); - - // Create the compilation database. - SmallString<256> PathBuf; - sys::fs::current_path(PathBuf); - std::unique_ptr<CompilationDatabase> Compilations; - Compilations.reset( - new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments)); - - // Store the callback trace information here. - std::vector<CallbackCall> CallbackCalls; + SmallVector<StringRef, 32> Patterns; + FilterType Filters; + StringRef(Callbacks).split(Patterns, ",", + /*MaxSplit=*/-1, /*KeepEmpty=*/false); + for (StringRef Pattern : Patterns) { + Pattern = Pattern.trim(); + bool Enabled = !Pattern.consume_front("-"); + Expected<GlobPattern> Pat = GlobPattern::create(Pattern); + if (Pat) + Filters.emplace_back(std::move(*Pat), Enabled); + else + error(toString(Pat.takeError())); + } // Create the tool and run the compilation. - ClangTool Tool(*Compilations, SourcePaths); - PPTraceFrontendActionFactory Factory(Ignore, CallbackCalls); + clang::tooling::ClangTool Tool(OptionsParser->getCompilations(), + OptionsParser->getSourcePathList()); + + std::error_code EC; + llvm::ToolOutputFile Out(OutputFileName, EC, llvm::sys::fs::F_Text); + if (EC) + error(EC.message()); + PPTraceFrontendActionFactory Factory(Filters, Out.os()); int HadErrors = Tool.run(&Factory); // If we had errors, exit early. if (HadErrors) return HadErrors; - // Do the output. - if (!OutputFileName.size()) { - HadErrors = outputPPTrace(CallbackCalls, llvm::outs()); - } else { - // Set up output file. - std::error_code EC; - llvm::ToolOutputFile Out(OutputFileName, EC, llvm::sys::fs::F_Text); - if (EC) { - llvm::errs() << "pp-trace: error creating " << OutputFileName << ":" - << EC.message() << "\n"; - return 1; - } - - HadErrors = outputPPTrace(CallbackCalls, Out.os()); - - // Tell ToolOutputFile that we want to keep the file. - if (HadErrors == 0) - Out.keep(); - } + Out.keep(); - return HadErrors; + return 0; } |