aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt1
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Tooling/ASTMatchers.cpp564
-rw-r--r--lib/Tooling/CMakeLists.txt7
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.cpp214
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.h107
-rw-r--r--lib/Tooling/Makefile15
-rw-r--r--lib/Tooling/Tooling.cpp403
8 files changed, 1 insertions, 1312 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 0943e2b1c7..b4574344bc 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -13,4 +13,3 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
-add_subdirectory(Tooling)
diff --git a/lib/Makefile b/lib/Makefile
index eda7017bb8..924819c818 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@ CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
- Index Driver Tooling
+ Index Driver
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Tooling/ASTMatchers.cpp b/lib/Tooling/ASTMatchers.cpp
deleted file mode 100644
index f03580ea34..0000000000
--- a/lib/Tooling/ASTMatchers.cpp
+++ /dev/null
@@ -1,564 +0,0 @@
-//===--- ASTMatchers.cpp - Structural query framework ---------------------===//
-//
-// 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 framework of AST matchers that can be used to express
-// structural queries on C++ code.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/ASTMatchers.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/DenseMap.h"
-#include <assert.h>
-#include <stddef.h>
-#include <set>
-#include <utility>
-
-namespace clang {
-namespace tooling {
-
-// Returns the value that 'a_map' maps 'key' to, or NULL if 'key' is
-// not in 'a_map'.
-template <typename Map>
-static const typename Map::mapped_type *Find(
- const Map &AMap, const typename Map::key_type &Key) {
- typename Map::const_iterator It = AMap.find(Key);
- return It == AMap.end() ? NULL : &It->second;
-}
-
-// We use memoization to avoid running the same matcher on the same
-// AST node twice. This pair is the key for looking up match
-// result. It consists of an ID of the MatcherInterface (for
-// identifying the matcher) and a pointer to the AST node.
-typedef std::pair<uint64_t, const void*> UntypedMatchInput;
-
-// Used to store the result of a match and possibly bound nodes.
-struct MemoizedMatchResult {
- bool ResultOfMatch;
- BoundNodes Nodes;
-};
-
-// A RecursiveASTVisitor that traverses all children or all descendants of
-// a node.
-class MatchChildASTVisitor
- : public clang::RecursiveASTVisitor<MatchChildASTVisitor> {
- public:
- typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
-
- // Creates an AST visitor that matches 'matcher' on all children or
- // descendants of a traversed node. max_depth is the maximum depth
- // to traverse: use 1 for matching the children and INT_MAX for
- // matching the descendants.
- MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
- ASTMatchFinder *Finder,
- BoundNodesBuilder *Builder,
- int MaxDepth,
- ASTMatchFinder::TraversalMethod Traversal)
- : BaseMatcher(BaseMatcher),
- Finder(Finder),
- Builder(Builder),
- CurrentDepth(-1),
- MaxDepth(MaxDepth),
- Traversal(Traversal),
- Matches(false) {}
-
- // Returns true if a match is found in the subtree rooted at the
- // given AST node. This is done via a set of mutually recursive
- // functions. Here's how the recursion is done (the *wildcard can
- // actually be Decl, Stmt, or Type):
- //
- // - Traverse(node) calls BaseTraverse(node) when it needs
- // to visit the descendants of node.
- // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
- // Traverse*(c) for each child c of 'node'.
- // - Traverse*(c) in turn calls Traverse(c), completing the
- // recursion.
- template <typename T>
- bool FindMatch(const T &Node) {
- Reset();
- Traverse(Node);
- return Matches;
- }
-
- // The following are overriding methods from the base visitor class.
- // They are public only to allow CRTP to work. They are *not *part
- // of the public API of this class.
- bool TraverseDecl(clang::Decl *DeclNode) {
- return (DeclNode == NULL) || Traverse(*DeclNode);
- }
- bool TraverseStmt(clang::Stmt *StmtNode) {
- const clang::Stmt *StmtToTraverse = StmtNode;
- if (Traversal ==
- ASTMatchFinder::kIgnoreImplicitCastsAndParentheses) {
- const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode);
- if (ExprNode != NULL) {
- StmtToTraverse = ExprNode->IgnoreParenImpCasts();
- }
- }
- return (StmtToTraverse == NULL) || Traverse(*StmtToTraverse);
- }
- bool TraverseType(clang::QualType TypeNode) {
- return Traverse(TypeNode);
- }
-
- bool shouldVisitTemplateInstantiations() const { return true; }
-
- private:
- // Resets the state of this object.
- void Reset() {
- Matches = false;
- CurrentDepth = -1;
- }
-
- // Forwards the call to the corresponding Traverse*() method in the
- // base visitor class.
- bool BaseTraverse(const clang::Decl &DeclNode) {
- return VisitorBase::TraverseDecl(const_cast<clang::Decl*>(&DeclNode));
- }
- bool BaseTraverse(const clang::Stmt &StmtNode) {
- return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode));
- }
- bool BaseTraverse(clang::QualType TypeNode) {
- return VisitorBase::TraverseType(TypeNode);
- }
-
- // Traverses the subtree rooted at 'node'; returns true if the
- // traversal should continue after this function returns; also sets
- // matched_ to true if a match is found during the traversal.
- template <typename T>
- bool Traverse(const T &Node) {
- COMPILE_ASSERT(IsBaseType<T>::value,
- traverse_can_only_be_instantiated_with_base_type);
- ++CurrentDepth;
- bool ShouldContinue;
- if (CurrentDepth == 0) {
- // We don't want to match the root node, so just recurse.
- ShouldContinue = BaseTraverse(Node);
- } else if (BaseMatcher->Matches(Node, Finder, Builder)) {
- Matches = true;
- ShouldContinue = false; // Abort as soon as a match is found.
- } else if (CurrentDepth < MaxDepth) {
- // The current node doesn't match, and we haven't reached the
- // maximum depth yet, so recurse.
- ShouldContinue = BaseTraverse(Node);
- } else {
- // The current node doesn't match, and we have reached the
- // maximum depth, so don't recurse (but continue the traversal
- // such that other nodes at the current level can be visited).
- ShouldContinue = true;
- }
- --CurrentDepth;
- return ShouldContinue;
- }
-
- const UntypedBaseMatcher *const BaseMatcher;
- ASTMatchFinder *const Finder;
- BoundNodesBuilder *const Builder;
- int CurrentDepth;
- const int MaxDepth;
- const ASTMatchFinder::TraversalMethod Traversal;
- bool Matches;
-};
-
-// Controls the outermost traversal of the AST and allows to match multiple
-// matchers.
-class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>,
- public ASTMatchFinder {
- public:
- MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers,
- clang::SourceManager *VisitorSourceManager,
- clang::LangOptions *LanguageOptions)
- : Triggers(Triggers),
- VisitorSourceManager(VisitorSourceManager),
- LanguageOptions(LanguageOptions),
- ActiveASTContext(NULL) {
- assert(VisitorSourceManager != NULL);
- assert(LanguageOptions != NULL);
- // FIXME: add rewriter_(*source_manager, *language_options)
- }
-
- void set_active_ast_context(clang::ASTContext *NewActiveASTContext) {
- ActiveASTContext = NewActiveASTContext;
- }
-
- // The following Visit*() and Traverse*() functions "override"
- // methods in RecursiveASTVisitor.
-
- bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) {
- // When we see 'typedef A B', we add name 'B' to the set of names
- // A's canonical type maps to. This is necessary for implementing
- // IsDerivedFrom(x) properly, where x can be the name of the base
- // class or any of its aliases.
- //
- // In general, the is-alias-of (as defined by typedefs) relation
- // is tree-shaped, as you can typedef a type more than once. For
- // example,
- //
- // typedef A B;
- // typedef A C;
- // typedef C D;
- // typedef C E;
- //
- // gives you
- //
- // A
- // |- B
- // `- C
- // |- D
- // `- E
- //
- // It is wrong to assume that the relation is a chain. A correct
- // implementation of IsDerivedFrom() needs to recognize that B and
- // E are aliases, even though neither is a typedef of the other.
- // Therefore, we cannot simply walk through one typedef chain to
- // find out whether the type name matches.
- const clang::Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
- const clang::Type *CanonicalType = // root of the typedef tree
- ActiveASTContext->getCanonicalType(TypeNode);
- TypeToUnqualifiedAliases[CanonicalType].insert(
- DeclNode->getName().str());
- return true;
- }
-
- bool TraverseDecl(clang::Decl *DeclNode);
- bool TraverseStmt(clang::Stmt *StmtNode);
- bool TraverseType(clang::QualType TypeNode);
- bool TraverseTypeLoc(clang::TypeLoc TypeNode);
-
- // Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool MemoizedMatchesRecursively(
- const T &Node, const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder, int MaxDepth,
- TraversalMethod Traversal) {
- COMPILE_ASSERT((llvm::is_same<T, clang::Decl>::value) ||
- (llvm::is_same<T, clang::Stmt>::value),
- type_does_not_support_memoization);
- const UntypedMatchInput input(BaseMatcher.GetID(), &Node);
- std::pair <MemoizationMap::iterator, bool>
- InsertResult = ResultCache.insert(
- std::make_pair(input, MemoizedMatchResult()));
- if (InsertResult.second) {
- BoundNodesBuilder DescendantBoundNodesBuilder;
- InsertResult.first->second.ResultOfMatch =
- MatchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder,
- MaxDepth, Traversal);
- InsertResult.first->second.Nodes =
- DescendantBoundNodesBuilder.Build();
- }
- InsertResult.first->second.Nodes.CopyTo(Builder);
- return InsertResult.first->second.ResultOfMatch;
- }
-
- // Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool MatchesRecursively(
- const T &Node, const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder, int MaxDepth,
- TraversalMethod Traversal) {
- MatchChildASTVisitor Visitor(
- &BaseMatcher, this, Builder, MaxDepth, Traversal);
- return Visitor.FindMatch(Node);
- }
-
- virtual bool ClassIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
- const std::string &BaseName) const;
-
- // Implements ASTMatchFinder::MatchesChildOf.
- virtual bool MatchesChildOf(const clang::Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder,
- TraversalMethod Traversal) {
- return MatchesRecursively(
- DeclNode, BaseMatcher, Builder, 1, Traversal);
- }
- virtual bool MatchesChildOf(const clang::Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder,
- TraversalMethod Traversal) {
- return MatchesRecursively(
- StmtNode, BaseMatcher, Builder, 1, Traversal);
- }
-
- // Implements ASTMatchFinder::MatchesDescendantOf.
- virtual bool MatchesDescendantOf(const clang::Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder) {
- return MemoizedMatchesRecursively(
- DeclNode, BaseMatcher, Builder, INT_MAX, kAsIs);
- }
- virtual bool MatchesDescendantOf(const clang::Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesBuilder *Builder) {
- return MemoizedMatchesRecursively(
- StmtNode, BaseMatcher, Builder, INT_MAX, kAsIs);
- }
-
- bool shouldVisitTemplateInstantiations() const { return true; }
-
- private:
- // Returns true if 'TypeNode' is also known by the name 'Name'. In other
- // words, there is a type (including typedef) with the name 'Name'
- // that is equal to 'TypeNode'.
- bool TypeHasAlias(
- const clang::Type *TypeNode, const std::string &Name) const {
- const clang::Type *const CanonicalType =
- ActiveASTContext->getCanonicalType(TypeNode);
- const std::set<std::string> *UnqualifiedAlias =
- Find(TypeToUnqualifiedAliases, CanonicalType);
- return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0;
- }
-
- // Matches all registered matchers on the given node and calls the
- // result callback for every node that matches.
- template <typename T>
- void Match(const T &node) {
- for (std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers->begin(), End = Triggers->end();
- It != End; ++It) {
- BoundNodesBuilder Builder;
- if (It->first->Matches(node, this, &Builder)) {
- MatchFinder::MatchResult Result;
- Result.Nodes = Builder.Build();
- Result.Context = ActiveASTContext;
- Result.SourceManager = VisitorSourceManager;
- It->second->Run(Result);
- }
- }
- }
-
- std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *const Triggers;
- clang::SourceManager *const VisitorSourceManager;
- clang::LangOptions *const LanguageOptions;
- clang::ASTContext *ActiveASTContext;
-
- // Maps a canonical type to the names of its typedefs.
- llvm::DenseMap<const clang::Type*, std::set<std::string> >
- TypeToUnqualifiedAliases;
-
- // Maps (matcher, node) -> the match result for memoization.
- typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
- MemoizationMap ResultCache;
-};
-
-// Returns true if the given class is directly or indirectly derived
-// from a base type with the given name. A class is considered to be
-// also derived from itself.
-bool MatchASTVisitor::ClassIsDerivedFrom(
- const clang::CXXRecordDecl *Declaration,
- const std::string &BaseName) const {
- if (std::string(Declaration->getName()) == BaseName) {
- return true;
- }
- if (!Declaration->hasDefinition()) {
- return false;
- }
- typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator;
- for (BaseIterator It = Declaration->bases_begin(),
- End = Declaration->bases_end(); It != End; ++It) {
- const clang::Type *TypeNode = It->getType().getTypePtr();
-
- if (TypeHasAlias(TypeNode, BaseName))
- return true;
-
- // clang::Type::getAs<...>() drills through typedefs.
- if (TypeNode->getAs<clang::DependentNameType>() != NULL ||
- TypeNode->getAs<clang::TemplateTypeParmType>() != NULL) {
- // Dependent names and template TypeNode parameters will be matched when
- // the template is instantiated.
- continue;
- }
- clang::CXXRecordDecl *ClassDecl = NULL;
- clang::TemplateSpecializationType const *TemplateType =
- TypeNode->getAs<clang::TemplateSpecializationType>();
- if (TemplateType != NULL) {
- if (TemplateType->getTemplateName().isDependent()) {
- // Dependent template specializations will be matched when the
- // template is instantiated.
- continue;
- }
- // For template specialization types which are specializing a template
- // declaration which is an explicit or partial specialization of another
- // template declaration, getAsCXXRecordDecl() returns the corresponding
- // ClassTemplateSpecializationDecl.
- //
- // For template specialization types which are specializing a template
- // declaration which is neither an explicit nor partial specialization of
- // another template declaration, getAsCXXRecordDecl() returns NULL and
- // we get the CXXRecordDecl of the templated declaration.
- clang::CXXRecordDecl *SpecializationDecl =
- TemplateType->getAsCXXRecordDecl();
- if (SpecializationDecl != NULL) {
- ClassDecl = SpecializationDecl;
- } else {
- ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>(
- TemplateType->getTemplateName()
- .getAsTemplateDecl()->getTemplatedDecl());
- }
- } else {
- ClassDecl = TypeNode->getAsCXXRecordDecl();
- }
- assert(ClassDecl != NULL);
- assert(ClassDecl != Declaration);
- if (ClassIsDerivedFrom(ClassDecl, BaseName)) {
- return true;
- }
- }
- return false;
-}
-
-bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) {
- if (DeclNode == NULL) {
- return true;
- }
- Match(*DeclNode);
- return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
-}
-
-bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) {
- if (StmtNode == NULL) {
- return true;
- }
- Match(*StmtNode);
- return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
-}
-
-bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) {
- Match(TypeNode);
- return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
-}
-
-bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) {
- return clang::RecursiveASTVisitor<MatchASTVisitor>::
- TraverseType(TypeLoc.getType());
-}
-
-class MatchASTConsumer : public clang::ASTConsumer {
- public:
- MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers,
- MatchFinder::ParsingDoneTestCallback *ParsingDone,
- clang::SourceManager *ConsumerSourceManager,
- clang::LangOptions *LanaguageOptions)
- : Visitor(Triggers, ConsumerSourceManager, LanaguageOptions),
- ParsingDone(ParsingDone) {}
-
- private:
- virtual void HandleTranslationUnit(
- clang::ASTContext &Context) { // NOLINT: external API uses refs
- if (ParsingDone != NULL) {
- ParsingDone->Run();
- }
- Visitor.set_active_ast_context(&Context);
- Visitor.TraverseDecl(Context.getTranslationUnitDecl());
- Visitor.set_active_ast_context(NULL);
- }
-
- MatchASTVisitor Visitor;
- MatchFinder::ParsingDoneTestCallback *ParsingDone;
-};
-
-class MatchASTAction : public clang::ASTFrontendAction {
- public:
- explicit MatchASTAction(
- std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers,
- MatchFinder::ParsingDoneTestCallback *ParsingDone)
- : Triggers(Triggers),
- ParsingDone(ParsingDone) {}
-
- private:
- clang::ASTConsumer *CreateASTConsumer(
- clang::CompilerInstance &Compiler,
- llvm::StringRef) {
- return new MatchASTConsumer(Triggers,
- ParsingDone,
- &Compiler.getSourceManager(),
- &Compiler.getLangOpts());
- }
-
- std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *const Triggers;
- MatchFinder::ParsingDoneTestCallback *ParsingDone;
-};
-
-MatchFinder::MatchCallback::~MatchCallback() {}
-MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
-
-MatchFinder::MatchFinder() : ParsingDone(NULL) {}
-
-MatchFinder::~MatchFinder() {
- for (std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers.begin(), End = Triggers.end();
- It != End; ++It) {
- delete It->first;
- delete It->second;
- }
-}
-
-void MatchFinder::AddMatcher(const Matcher<clang::Decl> &NodeMatch,
- MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new TypedBaseMatcher<clang::Decl>(NodeMatch), Action));
-}
-
-void MatchFinder::AddMatcher(const Matcher<clang::QualType> &NodeMatch,
- MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new TypedBaseMatcher<clang::QualType>(NodeMatch), Action));
-}
-
-void MatchFinder::AddMatcher(const Matcher<clang::Stmt> &NodeMatch,
- MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new TypedBaseMatcher<clang::Stmt>(NodeMatch), Action));
-}
-
-bool MatchFinder::FindAll(const std::string &Code) {
- return RunSyntaxOnlyToolOnCode(
- new MatchASTAction(&Triggers, ParsingDone), Code);
-}
-
-clang::FrontendAction *MatchFinder::NewVisitorAction() {
- return new MatchASTAction(&Triggers, ParsingDone);
-}
-
-class MatchFinderFrontendActionFactory : public FrontendActionFactory {
- public:
- explicit MatchFinderFrontendActionFactory(MatchFinder *Finder)
- : Finder(Finder) {}
-
- virtual clang::FrontendAction *New() {
- return Finder->NewVisitorAction();
- }
-
- private:
- MatchFinder *const Finder;
-};
-
-FrontendActionFactory *MatchFinder::NewFrontendActionFactory() {
- return new MatchFinderFrontendActionFactory(this);
-}
-
-void MatchFinder::RegisterTestCallbackAfterParsing(
- MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
- ParsingDone = NewParsingDone;
-}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
deleted file mode 100644
index 0a0020a555..0000000000
--- a/lib/Tooling/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
-
-add_clang_library(clangTooling
- ASTMatchers.cpp
- JsonCompileCommandLineDatabase.cpp
- Tooling.cpp
- )
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
deleted file mode 100644
index 7f027cfbea..0000000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements reading a compile command line database, as written
-// out for example by CMake.
-//
-//===----------------------------------------------------------------------===//
-
-#include "JsonCompileCommandLineDatabase.h"
-#include "llvm/ADT/Twine.h"
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// A parser for JSON escaped strings of command line arguments with \-escaping
-// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)).
-class CommandLineArgumentParser {
- public:
- CommandLineArgumentParser(llvm::StringRef CommandLine)
- : Input(CommandLine), Position(Input.begin()-1) {}
-
- std::vector<std::string> Parse() {
- bool HasMoreInput = true;
- while (HasMoreInput && NextNonWhitespace()) {
- std::string Argument;
- HasMoreInput = ParseStringInto(Argument);
- CommandLine.push_back(Argument);
- }
- return CommandLine;
- }
-
- private:
- // All private methods return true if there is more input available.
-
- bool ParseStringInto(std::string &String) {
- do {
- if (*Position == '"') {
- if (!ParseQuotedStringInto(String)) return false;
- } else {
- if (!ParseFreeStringInto(String)) return false;
- }
- } while (*Position != ' ');
- return true;
- }
-
- bool ParseQuotedStringInto(std::string &String) {
- if (!Next()) return false;
- while (*Position != '"') {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- }
- return Next();
- }
-
- bool ParseFreeStringInto(std::string &String) {
- do {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- } while (*Position != ' ' && *Position != '"');
- return true;
- }
-
- bool SkipEscapeCharacter() {
- if (*Position == '\\') {
- return Next();
- }
- return true;
- }
-
- bool NextNonWhitespace() {
- do {
- if (!Next()) return false;
- } while (*Position == ' ');
- return true;
- }
-
- bool Next() {
- ++Position;
- if (Position == Input.end()) return false;
- // Remove the JSON escaping first. This is done unconditionally.
- if (*Position == '\\') ++Position;
- return Position != Input.end();
- }
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::vector<std::string> CommandLine;
-};
-
-} // end namespace
-
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine) {
- CommandLineArgumentParser parser(JsonEscapedCommandLine);
- return parser.Parse();
-}
-
-JsonCompileCommandLineParser::JsonCompileCommandLineParser(
- const llvm::StringRef Input, CompileCommandHandler *CommandHandler)
- : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {}
-
-bool JsonCompileCommandLineParser::Parse() {
- NextNonWhitespace();
- return ParseTranslationUnits();
-}
-
-std::string JsonCompileCommandLineParser::GetErrorMessage() const {
- return ErrorMessage;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnits() {
- if (!ConsumeOrError('[', "at start of compile command file")) return false;
- if (!ParseTranslationUnit(/*First=*/true)) return false;
- while (Consume(',')) {
- if (!ParseTranslationUnit(/*First=*/false)) return false;
- }
- if (!ConsumeOrError(']', "at end of array")) return false;
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnits();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) {
- if (First) {
- if (!Consume('{')) return true;
- } else {
- if (!ConsumeOrError('{', "at start of object")) return false;
- }
- if (!Consume('}')) {
- if (!ParseObjectKeyValuePairs()) return false;
- if (!ConsumeOrError('}', "at end of object")) return false;
- }
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnit();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() {
- do {
- llvm::StringRef Key;
- if (!ParseString(Key)) return false;
- if (!ConsumeOrError(':', "between name and value")) return false;
- llvm::StringRef Value;
- if (!ParseString(Value)) return false;
- if (CommandHandler != NULL) {
- CommandHandler->HandleKeyValue(Key, Value);
- }
- } while (Consume(','));
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) {
- if (!ConsumeOrError('"', "at start of string")) return false;
- llvm::StringRef::iterator First = Position;
- llvm::StringRef::iterator Last = Position;
- while (!Consume('"')) {
- Consume('\\');
- ++Position;
- // We need to store Position, as Consume will change Last before leaving
- // the loop.
- Last = Position;
- }
- String = llvm::StringRef(First, Last - First);
- return true;
-}
-
-bool JsonCompileCommandLineParser::Consume(char C) {
- if (Position == Input.end()) return false;
- if (*Position != C) return false;
- NextNonWhitespace();
- return true;
-}
-
-bool JsonCompileCommandLineParser::ConsumeOrError(
- char C, llvm::StringRef Message) {
- if (!Consume(C)) {
- SetExpectError(C, Message);
- return false;
- }
- return true;
-}
-
-void JsonCompileCommandLineParser::SetExpectError(
- char C, llvm::StringRef Message) {
- ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) +
- "' expected " + Message + ".").str();
-}
-
-void JsonCompileCommandLineParser::NextNonWhitespace() {
- do {
- ++Position;
- } while (IsWhitespace());
-}
-
-bool JsonCompileCommandLineParser::IsWhitespace() {
- if (Position == Input.end()) return false;
- return (*Position == ' ' || *Position == '\t' ||
- *Position == '\n' || *Position == '\r');
-}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.h b/lib/Tooling/JsonCompileCommandLineDatabase.h
deleted file mode 100644
index ea7cf0e6e1..0000000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- 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 reading a compile command line database, as written
-// out for example by CMake. It only supports the subset of the JSON standard
-// that is needed to parse the CMake output.
-// See http://www.json.org/ for the full standard.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-
-#include "llvm/ADT/StringRef.h"
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace tooling {
-
-/// \brief Converts a JSON escaped command line to a vector of arguments.
-///
-/// \param JsonEscapedCommandLine The escaped command line as a string. This
-/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped).
-/// In addition, any arguments containing spaces are assumed to be \-escaped
-///
-/// For example, the input (|| denoting non C-escaped strings):
-/// |./call a \"b \\\" c \\\\ \" d|
-/// would yield:
-/// [ |./call|, |a|, |b " c \ |, |d| ].
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine);
-
-/// \brief Interface for users of the JsonCompileCommandLineParser.
-class CompileCommandHandler {
- public:
- virtual ~CompileCommandHandler() {}
-
- /// \brief Called after all translation units are parsed.
- virtual void EndTranslationUnits() {}
-
- /// \brief Called at the end of a single translation unit.
- virtual void EndTranslationUnit() {}
-
- /// \brief Called for every (Key, Value) pair in a translation unit
- /// description.
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {}
-};
-
-/// \brief A JSON parser that supports the subset of JSON needed to parse
-/// JSON compile command line databases as written out by CMake.
-///
-/// The supported subset describes a list of compile command lines for
-/// each processed translation unit. The translation units are stored in a
-/// JSON array, where each translation unit is described by a JSON object
-/// containing (Key, Value) pairs for the working directory the compile command
-/// line was executed from, the main C/C++ input file of the translation unit
-/// and the actual compile command line, for example:
-/// [
-/// {
-/// "file":"/file.cpp",
-/// "directory":"/",
-/// "command":"/cc /file.cpp"
-/// }
-/// ]
-class JsonCompileCommandLineParser {
- public:
- /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the
- /// parsed constructs. 'CommandHandler' may be NULL in order to just check
- /// the validity of 'Input'.
- JsonCompileCommandLineParser(const llvm::StringRef Input,
- CompileCommandHandler *CommandHandler);
-
- /// \brief Parses the specified input. Returns true if no parsing errors were
- /// found.
- bool Parse();
-
- /// \brief Returns an error message if Parse() returned false previously.
- std::string GetErrorMessage() const;
-
- private:
- bool ParseTranslationUnits();
- bool ParseTranslationUnit(bool First);
- bool ParseObjectKeyValuePairs();
- bool ParseString(llvm::StringRef &String);
- bool Consume(char C);
- bool ConsumeOrError(char C, llvm::StringRef Message);
- void NextNonWhitespace();
- bool IsWhitespace();
- void SetExpectError(char C, llvm::StringRef Message);
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::string ErrorMessage;
- CompileCommandHandler * const CommandHandler;
-};
-
-} // end namespace tooling
-} // end namespace clang
-
-#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
deleted file mode 100644
index 501a00c3f4..0000000000
--- a/lib/Tooling/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- clang/lib/Tooling/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 := ../..
-LIBRARYNAME := clangTooling
-
-include $(CLANG_LEVEL)/Makefile
-
-
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
deleted file mode 100644
index 97a9463852..0000000000
--- a/lib/Tooling/Tooling.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-//===--- Tooling.cpp - Running clang standalone tools ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements functions to run clang tools standalone instead
-// of running them as a plugin.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
-#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "JsonCompileCommandLineDatabase.h"
-#include <map>
-#include <cstdio>
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// Checks that the input conforms to the argv[] convention as in
-// main(). Namely:
-// - it must contain at least a program path,
-// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
-// - argv[argc] must be NULL.
-void ValidateArgv(int argc, char *argv[]) {
- if (argc < 1) {
- fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc);
- abort();
- }
-
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == NULL) {
- fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
- abort();
- }
- }
-
- if (argv[argc] != NULL) {
- fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
- abort();
- }
-}
-
-} // end namespace
-
-// FIXME: This file contains structural duplication with other parts of the
-// code that sets up a compiler to run tools on it, and we should refactor
-// it to be based on the same framework.
-
-static clang::Diagnostic *NewTextDiagnostics() {
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
- new clang::DiagnosticIDs());
- clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
- llvm::errs(), clang::DiagnosticOptions());
- return new clang::Diagnostic(DiagIDs, DiagClient);
-}
-
-// Exists solely for the purpose of lookup of the main executable.
-static int StaticSymbol;
-
-/// \brief Builds a clang driver initialized for running clang tools.
-static clang::driver::Driver *NewDriver(clang::Diagnostic *Diagnostics,
- const char *BinaryName) {
- // This just needs to be some symbol in the binary.
- void *const SymbolAddr = &StaticSymbol;
- const llvm::sys::Path ExePath =
- llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
-
- const std::string DefaultOutputName = "a.out";
- clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
- ExePath.str(), llvm::sys::getHostTriple(),
- DefaultOutputName, false, false, *Diagnostics);
- CompilerDriver->setTitle("clang_based_tool");
- return CompilerDriver;
-}
-
-/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
-/// Returns NULL on error.
-static const clang::driver::ArgStringList *GetCC1Arguments(
- clang::Diagnostic *Diagnostics, clang::driver::Compilation *Compilation) {
- // We expect to get back exactly one Command job, if we didn't something
- // failed. Extract that job from the Compilation.
- const clang::driver::JobList &Jobs = Compilation->getJobs();
- if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
- llvm::raw_svector_ostream error_stream(error_msg);
- Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
- Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
- << error_stream.str();
- return NULL;
- }
-
- // The one job we find should be to invoke clang again.
- const clang::driver::Command *Cmd =
- cast<clang::driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
- return NULL;
- }
-
- return &Cmd->getArguments();
-}
-
-/// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation *NewInvocation(
- clang::Diagnostic *Diagnostics,
- const clang::driver::ArgStringList &CC1Args) {
- clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
- clang::CompilerInvocation::CreateFromArgs(
- *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
- *Diagnostics);
- Invocation->getFrontendOpts().DisableFree = false;
- return Invocation;
-}
-
-/// \brief Runs the specified clang tool action and returns whether it executed
-/// successfully.
-static bool RunInvocation(const char *BinaryName,
- clang::driver::Compilation *Compilation,
- clang::CompilerInvocation *Invocation,
- const clang::driver::ArgStringList &CC1Args,
- clang::FrontendAction *ToolAction) {
- llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
- // Show the invocation, with -v.
- if (Invocation->getHeaderSearchOpts().Verbose) {
- llvm::errs() << "clang Invocation:\n";
- Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
- llvm::errs() << "\n";
- }
-
- // Create a compiler instance to handle the actual work.
- clang::CompilerInstance Compiler;
- Compiler.setInvocation(Invocation);
-
- // Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
- if (!Compiler.hasDiagnostics())
- return false;
-
- // Infer the builtin include path if unspecified.
- if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
- Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
- // This just needs to be some symbol in the binary.
- void *const SymbolAddr = &StaticSymbol;
- Compiler.getHeaderSearchOpts().ResourceDir =
- clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
- }
-
- const bool Success = Compiler.ExecuteAction(*ToolAction);
- return Success;
-}
-
-/// \brief Converts a string vector representing a Command line into a C
-/// string vector representing the Argv (including the trailing NULL).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command) {
- std::vector<char*> Result(Command->size() + 1);
- for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
- Result[I] = const_cast<char*>((*Command)[I].c_str());
- }
- Result[Command->size()] = NULL;
- return Result;
-}
-
-bool RunToolWithFlags(
- clang::FrontendAction *ToolAction, int Args, char *Argv[]) {
- ValidateArgv(Args, Argv);
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), Argv[0]));
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
- const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
- return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
- *CC1Args, ToolAction);
-}
-
-/// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
-///
-/// \param FileContents A mapping from file name to source code. For each
-/// entry a virtual file mapping will be created when running the tool.
-bool RunToolWithFlagsOnCode(
- const std::vector<std::string> &CommandLine,
- const std::map<std::string, std::string> &FileContents,
- clang::FrontendAction *ToolAction) {
- const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
- const char *const BinaryName = Argv[0];
-
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), BinaryName));
-
- // Since the Input is only virtual, don't check whether it exists.
- Driver->setCheckInputsExist(false);
-
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
- Argv.size() - 1)));
- const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
-
- for (std::map<std::string, std::string>::const_iterator
- It = FileContents.begin(), End = FileContents.end();
- It != End; ++It) {
- // Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer *Input =
- llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
- Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
- }
-
- return RunInvocation(BinaryName, Compilation.get(),
- Invocation.take(), *CC1Args, ToolAction);
-}
-
-bool RunSyntaxOnlyToolOnCode(
- clang::FrontendAction *ToolAction, llvm::StringRef Code) {
- const char *const FileName = "input.cc";
- const char *const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileName
- };
- std::map<std::string, std::string> FileContents;
- FileContents[FileName] = Code;
- return RunToolWithFlagsOnCode(
- std::vector<std::string>(
- CommandLine,
- CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])),
- FileContents, ToolAction);
-}
-
-namespace {
-
-// A CompileCommandHandler implementation that finds compile commands for a
-// specific input file.
-//
-// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
-class FindHandler : public clang::tooling::CompileCommandHandler {
- public:
- explicit FindHandler(llvm::StringRef File)
- : FileToMatch(File), FoundMatchingCommand(false) {}
-
- virtual void EndTranslationUnits() {
- if (!FoundMatchingCommand && ErrorMessage.empty()) {
- ErrorMessage = "ERROR: No matching command found.";
- }
- }
-
- virtual void EndTranslationUnit() {
- if (File == FileToMatch) {
- FoundMatchingCommand = true;
- MatchingCommand.Directory = Directory;
- MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
- }
- }
-
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
- if (Key == "directory") { Directory = Value; }
- else if (Key == "file") { File = Value; }
- else if (Key == "command") { Command = Value; }
- else {
- ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
- }
- }
-
- const llvm::StringRef FileToMatch;
- bool FoundMatchingCommand;
- CompileCommand MatchingCommand;
- std::string ErrorMessage;
-
- llvm::StringRef Directory;
- llvm::StringRef File;
- llvm::StringRef Command;
-};
-
-} // end namespace
-
-CompileCommand FindCompileArgsInJsonDatabase(
- llvm::StringRef FileName, llvm::StringRef JsonDatabase,
- std::string &ErrorMessage) {
- FindHandler find_handler(FileName);
- JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
- if (!parser.Parse()) {
- ErrorMessage = parser.GetErrorMessage();
- return CompileCommand();
- }
- return find_handler.MatchingCommand;
-}
-
-/// \brief Returns the absolute path of 'File', by prepending it with
-/// 'BaseDirectory' if 'File' is not absolute. Otherwise returns 'File'.
-/// If 'File' starts with "./", the returned path will not contain the "./".
-/// Otherwise, the returned path will contain the literal path-concatenation of
-/// 'BaseDirectory' and 'File'.
-///
-/// \param File Either an absolute or relative path.
-/// \param BaseDirectory An absolute path.
-static std::string GetAbsolutePath(
- llvm::StringRef File, llvm::StringRef BaseDirectory) {
- assert(llvm::sys::path::is_absolute(BaseDirectory));
- if (llvm::sys::path::is_absolute(File)) {
- return File;
- }
- llvm::StringRef RelativePath(File);
- if (RelativePath.startswith("./")) {
- RelativePath = RelativePath.substr(strlen("./"));
- }
- llvm::SmallString<1024> AbsolutePath(BaseDirectory);
- llvm::sys::path::append(AbsolutePath, RelativePath);
- return AbsolutePath.str();
-}
-
-FrontendActionFactory::~FrontendActionFactory() {}
-
-ClangTool::ClangTool(int argc, char **argv) {
- if (argc < 3) {
- llvm::outs() << "Usage: " << argv[0] << " <cmake-output-dir> "
- << "<file1> <file2> ...\n";
- exit(1);
- }
- llvm::SmallString<1024> JsonDatabasePath(argv[1]);
- llvm::sys::path::append(JsonDatabasePath, "compile_commands.json");
- llvm::error_code Result =
- llvm::MemoryBuffer::getFile(JsonDatabasePath, JsonDatabase);
- if (Result != 0) {
- llvm::outs() << "Error while opening JSON database: " << Result.message()
- << "\n";
- exit(1);
- }
- Files = std::vector<std::string>(argv + 2, argv + argc);
-}
-
-int ClangTool::Run(FrontendActionFactory *ActionFactory) {
- llvm::StringRef BaseDirectory(::getenv("PWD"));
- bool ProcessingFailed = false;
- for (unsigned I = 0; I < Files.size(); ++I) {
- llvm::SmallString<1024> File(GetAbsolutePath(Files[I], BaseDirectory));
- llvm::outs() << "Processing " << File << ".\n";
- std::string ErrorMessage;
- clang::tooling::CompileCommand LookupResult =
- clang::tooling::FindCompileArgsInJsonDatabase(
- File.str(), JsonDatabase->getBuffer(), ErrorMessage);
- if (!LookupResult.CommandLine.empty()) {
- if (!LookupResult.Directory.empty()) {
- // FIXME: What should happen if CommandLine includes -working-directory
- // as well?
- LookupResult.CommandLine.push_back(
- "-working-directory=" + LookupResult.Directory);
- }
- if (!clang::tooling::RunToolWithFlags(
- ActionFactory->New(),
- LookupResult.CommandLine.size(),
- &clang::tooling::CommandLineToArgv(
- &LookupResult.CommandLine)[0])) {
- llvm::outs() << "Error while processing " << File << ".\n";
- ProcessingFailed = true;
- }
- } else {
- // FIXME: There are two use cases here: doing a fuzzy
- // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
- // about the .cc files that were not found, and the use case where I
- // specify all files I want to run over explicitly, where this should
- // be an error. We'll want to add an option for this.
- llvm::outs() << "Skipping " << File << ". Command line not found.\n";
- }
- }
- return ProcessingFailed ? 1 : 0;
-}
-
-} // end namespace tooling
-} // end namespace clang
-