The new clang-ast-dump tool for selective AST dumping. Moved common command-line tool stuff to CommandLineClangTool

llvm-svn: 160265
This commit is contained in:
Alexander Kornienko 2012-07-16 12:46:48 +00:00
parent b45e7e9191
commit f2f82550fd
11 changed files with 377 additions and 59 deletions

View File

@ -0,0 +1,80 @@
//===- CommandLineClangTool.h - command-line clang tools driver -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CommandLineClangTool class used to run clang
// tools as separate command-line applications with a consistent common
// interface for handling compilation database and input files.
//
// It provides a common subset of command-line options, common algorithm
// for locating a compilation database and source files, and help messages
// for the basic command-line interface.
//
// It creates a CompilationDatabase, initializes a ClangTool and runs a
// user-specified FrontendAction over all TUs in which the given files are
// compiled.
//
// This class uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H
#define LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H
#include "llvm/Support/CommandLine.h"
#include "clang/Tooling/CompilationDatabase.h"
namespace clang {
namespace tooling {
class CompilationDatabase;
class FrontendActionFactory;
/// \brief A common driver for command-line Clang tools.
///
/// Parses a common subset of command-line arguments, locates and loads a
/// compilation commands database, runs a tool with user-specified action. It
/// also contains a help message for the common command-line options.
/// An example of usage:
/// @code
/// int main(int argc, const char **argv) {
/// CommandLineClangTool Tool;
/// cl::extrahelp MoreHelp("\nMore help text...");
/// Tool.initialize(argc, argv);
/// return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
/// }
/// @endcode
///
class CommandLineClangTool {
public:
/// Sets up command-line options and help messages.
/// Add your own help messages after constructing this tool.
CommandLineClangTool();
/// Parses command-line, initializes a compilation database.
/// This method exits program in case of error.
void initialize(int argc, const char **argv);
/// Runs a clang tool with an action created by \c ActionFactory.
int run(FrontendActionFactory *ActionFactory);
private:
llvm::OwningPtr<CompilationDatabase> Compilations;
llvm::cl::opt<std::string> BuildPath;
llvm::cl::list<std::string> SourcePaths;
llvm::cl::extrahelp MoreHelp;
};
} // namespace tooling
} // namespace clang
#endif // LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H

View File

@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTooling
CommandLineClangTool.cpp
CompilationDatabase.cpp
Refactoring.cpp
Tooling.cpp

View File

@ -0,0 +1,80 @@
//===--- CommandLineClangTool.cpp - command-line clang tools driver -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CommandLineClangTool class used to run clang
// tools as separate command-line applications with a consistent common
// interface for handling compilation database and input files.
//
// It provides a common subset of command-line options, common algorithm
// for locating a compilation database and source files, and help messages
// for the basic command-line interface.
//
// It creates a CompilationDatabase, initializes a ClangTool and runs a
// user-specified FrontendAction over all TUs in which the given files are
// compiled.
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommandLineClangTool.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
static const char *MoreHelpText =
"\n"
"-p <build-path> is used to read a compile command database.\n"
"\n"
"\tFor example, it can be a CMake build directory in which a file named\n"
"\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
"\tCMake option to get this output). When no build path is specified,\n"
"\tclang-check will attempt to locate it automatically using all parent\n"
"\tpaths of the first input file. See:\n"
"\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
"\texample of setting up Clang Tooling on a source tree.\n"
"\n"
"<source0> ... specify the paths of source files. These paths are looked\n"
"\tup in the compile command database. If the path of a file is absolute,\n"
"\tit needs to point into CMake's source tree. If the path is relative,\n"
"\tthe current working directory needs to be in the CMake source tree and\n"
"\tthe file must be in a subdirectory of the current working directory.\n"
"\t\"./\" prefixes in the relative files will be automatically removed,\n"
"\tbut the rest of a relative path must be a suffix of a path in the\n"
"\tcompile command database.\n"
"\n";
CommandLineClangTool::CommandLineClangTool() :
BuildPath("p", cl::desc("Build path"), cl::Optional),
SourcePaths(cl::Positional, cl::desc("<source0> [... <sourceN>]"),
cl::OneOrMore),
MoreHelp(MoreHelpText) {
}
void CommandLineClangTool::initialize(int argc, const char **argv) {
Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
std::string ErrorMessage;
if (!BuildPath.empty()) {
Compilations.reset(CompilationDatabase::autoDetectFromDirectory(
BuildPath, ErrorMessage));
} else {
Compilations.reset(CompilationDatabase::autoDetectFromSource(
SourcePaths[0], ErrorMessage));
}
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
}
int CommandLineClangTool::run(FrontendActionFactory *ActionFactory) {
ClangTool Tool(*Compilations, SourcePaths);
return Tool.run(ActionFactory);
}

View File

@ -31,7 +31,7 @@ if( NOT CLANG_BUILT_STANDALONE )
set(CLANG_TEST_DEPS
clang clang-headers
c-index-test diagtool arcmt-test c-arcmt-test
clang-check
clang-check clang-ast-dump
llvm-dis llc opt FileCheck count not
)
set(CLANG_TEST_PARAMS
@ -80,7 +80,7 @@ else()
COMMENT "Running Clang regression tests"
DEPENDS clang clang-headers
c-index-test diagtool arcmt-test c-arcmt-test
clang-check
clang-check clang-ast-dump
)
set_target_properties(check-clang PROPERTIES FOLDER "Clang tests")
endif()

View File

@ -0,0 +1,22 @@
// RUN: clang-ast-dump "%t/test.cpp" -f test_namespace::TheClass::theMethod -- -c 2>&1|FileCheck %s
// FIXME: Make the above easier.
// CHECK: <CXXMethod ptr="0x{{[0-9a-f]+}}" name="theMethod" prototype="true">
// CHECK: <ParmVar ptr="0x{{[0-9a-f]+}}" name="x" initstyle="c">
// CHECK: (CompoundStmt
// CHECK-NEXT: (ReturnStmt
// CHECK-NEXT: (BinaryOperator
namespace test_namespace {
class TheClass {
public:
int theMethod(int x) {
return x + x;
}
};
}
// FIXME: This is incompatible to -fms-compatibility.
// XFAIL: win32

View File

@ -5,3 +5,4 @@ add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
add_subdirectory(clang-check)
add_subdirectory(clang-ast-dump)

View File

@ -9,7 +9,7 @@
CLANG_LEVEL := ..
DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
clang-check
clang-check clang-ast-dump
include $(CLANG_LEVEL)/../../Makefile.config

View File

@ -0,0 +1,8 @@
add_clang_executable(clang-ast-dump
ClangASTDump.cpp
)
target_link_libraries(clang-ast-dump
clangTooling
clangBasic
)

View File

@ -0,0 +1,141 @@
//===- tools/clang-ast-dump/ClangASTDump.cpp - Clang AST Dump 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-ast-dump tool that dumps specified parts
// of an AST of a number of translation units.
//
// Run with '-help' for details.
//
// 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 "llvm/Support/CommandLine.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommandLineClangTool.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
cl::opt<std::string> FilterString(
"f",
cl::desc("Filter string"),
cl::Optional);
cl::opt<bool> ListAll(
"l",
cl::desc("List all filterable nodes"),
cl::init(false),
cl::Optional);
static const char *MoreHelpText =
"-f <filter-string> can be used to dump only AST declaration nodes having\n"
"\ta certain substring in a qualified name.\n"
"\n"
"-l \tlists qualified names of all filterable declaration nodes.\n"
"\n";
namespace {
using namespace clang;
class SelectiveDumpVisitor :
public RecursiveASTVisitor<SelectiveDumpVisitor> {
typedef RecursiveASTVisitor<SelectiveDumpVisitor> base;
public:
SelectiveDumpVisitor(const std::string &FilterString, bool ListAll)
: FilterString(FilterString), ListAll(ListAll) {}
ASTConsumer* newASTConsumer() {
return new DumpConsumer(this);
}
bool shouldWalkTypesOfTypeLocs() const { return false; }
void Run(TranslationUnitDecl *D) {
if (ListAll) {
llvm::outs().changeColor(llvm::raw_ostream::BLUE) <<
"Listing all filterable nodes:\n";
llvm::outs().resetColor();
TraverseDecl(D);
return;
}
if (FilterString.empty()) {
llvm::outs().changeColor(llvm::raw_ostream::BLUE) <<
"Dumping translation unit:\n";
llvm::outs().resetColor();
D->dumpXML(llvm::outs());
return;
}
TraverseDecl(D);
}
bool TraverseDecl(Decl *D) {
if (ListAll) {
std::string Name = getName(D);
if (!Name.empty())
llvm::outs() << Name << "\n";
return base::TraverseDecl(D);
}
if (filterMatches(D)) {
llvm::outs().changeColor(llvm::raw_ostream::BLUE) <<
"Dumping " << getName(D) << ":\n";
llvm::outs().resetColor();
D->dumpXML(llvm::outs());
return true;
}
return base::TraverseDecl(D);
}
private:
std::string getName(Decl *D) {
if (isa<NamedDecl>(D))
return cast<NamedDecl>(D)->getQualifiedNameAsString();
return "";
}
bool filterMatches(Decl *D) {
return getName(D).find(FilterString) != std::string::npos;
}
class DumpConsumer : public ASTConsumer {
public:
DumpConsumer(SelectiveDumpVisitor *Visitor) : Visitor(Visitor) {}
virtual void HandleTranslationUnit(ASTContext &Context) {
Visitor->Context = &Context;
Visitor->Run(Context.getTranslationUnitDecl());
}
private:
SelectiveDumpVisitor *Visitor;
};
ASTContext *Context;
std::string FilterString;
bool ListAll;
};
} // namespace
int main(int argc, const char **argv) {
CommandLineClangTool Tool;
cl::extrahelp MoreHelp(MoreHelpText);
Tool.initialize(argc, argv);
SelectiveDumpVisitor Dumper(FilterString, ListAll);
return Tool.run(newFrontendActionFactory(&Dumper));
}

View File

@ -0,0 +1,23 @@
##===- tools/clang-check/Makefile --------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
TOOLNAME = clang-ast-dump
NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile

View File

@ -1,4 +1,4 @@
//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
//===- tools/clang-check/ClangCheck.cpp - Clang check tool ----------------===//
//
// The LLVM Compiler Infrastructure
//
@ -10,75 +10,37 @@
// This file implements a clang-check tool that runs the
// clang::SyntaxOnlyAction over a number of translation units.
//
// 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 "llvm/Support/CommandLine.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CommandLineClangTool.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
cl::opt<std::string> BuildPath(
"p",
cl::desc("<build-path>"),
cl::Optional);
cl::list<std::string> SourcePaths(
cl::Positional,
cl::desc("<source0> [... <sourceN>]"),
cl::OneOrMore);
static cl::extrahelp MoreHelp(
static const char *MoreHelpText =
"\tFor example, to run clang-check on all files in a subtree of the\n"
"\tsource tree, use:\n"
"\n"
"<build-path> is used to read a compile command database.\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
"\n"
"For example, it can be a CMake build directory in which a file named\n"
"compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
"CMake option to get this output). When no build path is specified,\n"
"clang-check will attempt to locate it automatically using all parent\n"
"paths of the first input file.\n"
"\tor using a specific build path:\n"
"\n"
"<source0> ... specify the paths of source files. These paths are looked\n"
"up in the compile command database. If the path of a file is absolute,\n"
"it needs to point into CMake's source tree. If the path is relative,\n"
"the current working directory needs to be in the CMake source tree and\n"
"the file must be in a subdirectory of the current working directory.\n"
"\"./\" prefixes in the relative files will be automatically removed,\n"
"but the rest of a relative path must be a suffix of a path in the\n"
"compile command database.\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
"\n"
"For example, to use clang-check on all files in a subtree of the source\n"
"tree, use:\n"
"\n"
" find path/in/subtree -name '*.cpp'|xargs clang-check\n"
"\n"
"or using a specific build path:\n"
"\n"
" find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
"\n"
"Note, that path/in/subtree and current directory should follow the\n"
"rules described above.\n"
"\n"
);
"\tNote, that path/in/subtree and current directory should follow the\n"
"\trules described above.\n"
"\n";
int main(int argc, const char **argv) {
llvm::OwningPtr<CompilationDatabase> Compilations(
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
std::string ErrorMessage;
if (!BuildPath.empty()) {
Compilations.reset(
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage));
} else {
Compilations.reset(CompilationDatabase::autoDetectFromSource(
SourcePaths[0], ErrorMessage));
}
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
ClangTool Tool(*Compilations, SourcePaths);
CommandLineClangTool Tool;
cl::extrahelp MoreHelp(MoreHelpText);
Tool.initialize(argc, argv);
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
}