1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a clang-check tool that runs clang based on the info
// stored in a compilation database.
//
// This tool uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp MoreHelp(
"\tFor example, to run clang-check on all files in a subtree of the\n"
"\tsource tree, use:\n"
"\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
"\n"
"\tor using a specific build path:\n"
"\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
"\n"
"\tNote, that path/in/subtree and current directory should follow the\n"
"\trules described above.\n"
"\n"
);
static cl::OptionCategory ClangCheckCategory("clang-check options");
static std::unique_ptr<opt::OptTable> Options(createDriverOptTable());
static cl::opt<bool>
ASTDump("ast-dump", cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTList("ast-list", cl::desc(Options->getOptionHelpText(options::OPT_ast_list)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTPrint("ast-print",
cl::desc(Options->getOptionHelpText(options::OPT_ast_print)),
cl::cat(ClangCheckCategory));
static cl::opt<std::string> ASTDumpFilter(
"ast-dump-filter",
cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
Analyze("analyze", cl::desc(Options->getOptionHelpText(options::OPT_analyze)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
Fixit("fixit", cl::desc(Options->getOptionHelpText(options::OPT_fixit)),
cl::cat(ClangCheckCategory));
static cl::opt<bool> FixWhatYouCan(
"fix-what-you-can",
cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
cl::cat(ClangCheckCategory));
static cl::list<std::string> ArgsAfter(
"extra-arg",
cl::desc("Additional argument to append to the compiler command line"),
cl::cat(ClangCheckCategory));
static cl::list<std::string> ArgsBefore(
"extra-arg-before",
cl::desc("Additional argument to prepend to the compiler command line"),
cl::cat(ClangCheckCategory));
namespace {
// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
// into a header file and reuse that.
class FixItOptions : public clang::FixItOptions {
public:
FixItOptions() {
FixWhatYouCan = ::FixWhatYouCan;
}
std::string RewriteFilename(const std::string& filename, int &fd) override {
assert(llvm::sys::path::is_absolute(filename) &&
"clang-fixit expects absolute paths only.");
// We don't need to do permission checking here since clang will diagnose
// any I/O errors itself.
fd = -1; // No file descriptor for file.
return filename;
}
};
/// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
/// in the final error counts.
///
/// This has the side-effect that clang-check -fixit exits with code 0 on
/// successfully fixing all errors.
class FixItRewriter : public clang::FixItRewriter {
public:
FixItRewriter(clang::DiagnosticsEngine& Diags,
clang::SourceManager& SourceMgr,
const clang::LangOptions& LangOpts,
clang::FixItOptions* FixItOpts)
: clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
}
bool IncludeInDiagnosticCounts() const override { return false; }
};
/// \brief Subclasses \c clang::FixItAction so that we can install the custom
/// \c FixItRewriter.
class FixItAction : public clang::FixItAction {
public:
bool BeginSourceFileAction(clang::CompilerInstance& CI,
StringRef Filename) override {
FixItOpts.reset(new FixItOptions);
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get()));
return true;
}
};
class InsertAdjuster: public clang::tooling::ArgumentsAdjuster {
public:
enum Position { BEGIN, END };
InsertAdjuster(const CommandLineArguments &Extra, Position Pos)
: Extra(Extra), Pos(Pos) {
}
InsertAdjuster(const char *Extra, Position Pos)
: Extra(1, std::string(Extra)), Pos(Pos) {
}
virtual CommandLineArguments
Adjust(const CommandLineArguments &Args) override {
CommandLineArguments Return(Args);
CommandLineArguments::iterator I;
if (Pos == END) {
I = Return.end();
} else {
I = Return.begin();
++I; // To leave the program name in place
}
Return.insert(I, Extra.begin(), Extra.end());
return Return;
}
private:
const CommandLineArguments Extra;
const Position Pos;
};
} // namespace
// Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6.
// "Non-global symbol: ... can't be a weak_definition"
namespace clang_check {
class ClangCheckActionFactory {
public:
clang::ASTConsumer *newASTConsumer() {
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
return clang::CreateASTDumper(ASTDumpFilter);
if (ASTPrint)
return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
return new clang::ASTConsumer();
}
};
}
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
// Clear adjusters because -fsyntax-only is inserted by the default chain.
Tool.clearArgumentsAdjusters();
Tool.appendArgumentsAdjuster(new ClangStripOutputAdjuster());
if (ArgsAfter.size() > 0) {
Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsAfter,
InsertAdjuster::END));
}
if (ArgsBefore.size() > 0) {
Tool.appendArgumentsAdjuster(new InsertAdjuster(ArgsBefore,
InsertAdjuster::BEGIN));
}
// Running the analyzer requires --analyze. Other modes can work with the
// -fsyntax-only option.
Tool.appendArgumentsAdjuster(new InsertAdjuster(
Analyze ? "--analyze" : "-fsyntax-only", InsertAdjuster::BEGIN));
clang_check::ClangCheckActionFactory CheckFactory;
std::unique_ptr<FrontendActionFactory> FrontendFactory;
// Choose the correct factory based on the selected mode.
if (Analyze)
FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
else if (Fixit)
FrontendFactory = newFrontendActionFactory<FixItAction>();
else
FrontendFactory = newFrontendActionFactory(&CheckFactory);
return Tool.run(FrontendFactory.get());
}
|