1//===---- tools/extra/ToolTemplate.cpp - Template for refactoring tool ----===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements an empty refactoring tool using the clang tooling.
10// The goal is to lower the "barrier to entry" for writing refactoring tools.
11//
12// Usage:
13// tool-template <cmake-output-dir> <file1> <file2> ...
14//
15// Where <cmake-output-dir> is a CMake build directory in which a file named
16// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
17// CMake to get this output).
18//
19// <file1> ... specify the paths of files in the CMake source tree. This path
20// is looked up in the compile command database. If the path of a file is
21// absolute, it needs to point into CMake's source tree. If the path is
22// relative, the current working directory needs to be in the CMake source
23// tree and the file must be in a subdirectory of the current working
24// directory. "./" prefixes in the relative files will be automatically
25// removed, but the rest of a relative path must be a suffix of a path in
26// the compile command line database.
27//
28// For example, to use tool-template on all files in a subtree of the
29// source tree, use:
30//
31// /path/in/subtree $ find . -name '*.cpp'|
32// xargs tool-template /path/to/build
33//
34//===----------------------------------------------------------------------===//
35
36#include "clang/ASTMatchers/ASTMatchFinder.h"
37#include "clang/ASTMatchers/ASTMatchers.h"
38#include "clang/Basic/SourceManager.h"
39#include "clang/Frontend/FrontendActions.h"
40#include "clang/Lex/Lexer.h"
41#include "clang/Tooling/CommonOptionsParser.h"
42#include "clang/Tooling/Execution.h"
43#include "clang/Tooling/Refactoring.h"
44#include "clang/Tooling/Refactoring/AtomicChange.h"
45#include "clang/Tooling/Tooling.h"
46#include "llvm/Support/CommandLine.h"
47#include "llvm/Support/MemoryBuffer.h"
48#include "llvm/Support/Signals.h"
49
50using namespace clang;
51using namespace clang::ast_matchers;
52using namespace clang::tooling;
53using namespace llvm;
54
55namespace {
56class ToolTemplateCallback : public MatchFinder::MatchCallback {
57public:
58 ToolTemplateCallback(ExecutionContext &Context) : Context(Context) {}
59
60 void run(const MatchFinder::MatchResult &Result) override {
61 // TODO: This routine will get called for each thing that the matchers
62 // find.
63 // At this point, you can examine the match, and do whatever you want,
64 // including replacing the matched text with other text
65 auto *D = Result.Nodes.getNodeAs<NamedDecl>(ID: "decl");
66 assert(D);
67 // Use AtomicChange to get a key.
68 if (D->getBeginLoc().isValid()) {
69 AtomicChange Change(*Result.SourceManager, D->getBeginLoc());
70 Context.reportResult(Key: Change.getKey(), Value: D->getQualifiedNameAsString());
71 }
72 }
73
74 void onStartOfTranslationUnit() override {
75 Context.reportResult(Key: "START", Value: "Start of TU.");
76 }
77 void onEndOfTranslationUnit() override {
78 Context.reportResult(Key: "END", Value: "End of TU.");
79 }
80
81private:
82 ExecutionContext &Context;
83};
84} // end anonymous namespace
85
86// Set up the command line options
87static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
88static cl::OptionCategory ToolTemplateCategory("tool-template options");
89
90int main(int argc, const char **argv) {
91 llvm::sys::PrintStackTraceOnErrorSignal(Argv0: argv[0]);
92
93 auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
94 argc, argv, Category&: ToolTemplateCategory);
95
96 if (!Executor) {
97 llvm::errs() << llvm::toString(E: Executor.takeError()) << "\n";
98 return 1;
99 }
100
101 ast_matchers::MatchFinder Finder;
102 ToolTemplateCallback Callback(*Executor->get()->getExecutionContext());
103
104 // TODO: Put your matchers here.
105 // Use Finder.addMatcher(...) to define the patterns in the AST that you
106 // want to match against. You are not limited to just one matcher!
107 //
108 // This is a sample matcher:
109 Finder.addMatcher(
110 NodeMatch: namedDecl(cxxRecordDecl(), isExpansionInMainFile()).bind(ID: "decl"),
111 Action: &Callback);
112
113 auto Err = Executor->get()->execute(Action: newFrontendActionFactory(ConsumerFactory: &Finder));
114 if (Err) {
115 llvm::errs() << llvm::toString(E: std::move(Err)) << "\n";
116 }
117 Executor->get()->getToolResults()->forEachResult(
118 Callback: [](llvm::StringRef key, llvm::StringRef value) {
119 llvm::errs() << "----" << key.str() << "\n" << value.str() << "\n";
120 });
121}
122

source code of clang-tools-extra/tool-template/ToolTemplate.cpp