diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rwxr-xr-x | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/Tooling/ASTMatchers.cpp | 564 | ||||
-rw-r--r-- | lib/Tooling/CMakeLists.txt | 7 | ||||
-rw-r--r-- | lib/Tooling/JsonCompileCommandLineDatabase.cpp | 214 | ||||
-rw-r--r-- | lib/Tooling/JsonCompileCommandLineDatabase.h | 107 | ||||
-rw-r--r-- | lib/Tooling/Makefile | 15 | ||||
-rw-r--r-- | lib/Tooling/Tooling.cpp | 403 |
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 - |