diff options
Diffstat (limited to 'include/clang/Tooling')
-rw-r--r-- | include/clang/Tooling/ArgumentsAdjusters.h | 59 | ||||
-rw-r--r-- | include/clang/Tooling/CommandLineClangTool.h | 80 | ||||
-rw-r--r-- | include/clang/Tooling/CompilationDatabase.h | 28 | ||||
-rw-r--r-- | include/clang/Tooling/Refactoring.h | 151 | ||||
-rw-r--r-- | include/clang/Tooling/RefactoringCallbacks.h | 90 | ||||
-rw-r--r-- | include/clang/Tooling/Tooling.h | 85 |
6 files changed, 471 insertions, 22 deletions
diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h new file mode 100644 index 0000000000000..492ddd2b0078b --- /dev/null +++ b/include/clang/Tooling/ArgumentsAdjusters.h @@ -0,0 +1,59 @@ +//===--- ArgumentsAdjusters.h - Command line arguments adjuster -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares base abstract class ArgumentsAdjuster and its descendants. +// These classes are intended to modify command line arguments obtained from +// a compilation database before they are used to run a frontend action. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H +#define LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H + +#include <string> +#include <vector> + +namespace clang { + +namespace tooling { + +/// \brief A sequence of command line arguments. +typedef std::vector<std::string> CommandLineArguments; + +/// \brief Abstract interface for a command line adjusters. +/// +/// This abstract interface describes a command line argument adjuster, +/// which is responsible for command line arguments modification before +/// the arguments are used to run a frontend action. +class ArgumentsAdjuster { + virtual void anchor(); +public: + /// \brief Returns adjusted command line arguments. + /// + /// \param Args Input sequence of command line arguments. + /// + /// \returns Modified sequence of command line arguments. + virtual CommandLineArguments Adjust(const CommandLineArguments &Args) = 0; + virtual ~ArgumentsAdjuster() { + } +}; + +/// \brief Syntax check only command line adjuster. +/// +/// This class implements ArgumentsAdjuster interface and converts input +/// command line arguments to the "syntax check only" variant. +class ClangSyntaxOnlyAdjuster : public ArgumentsAdjuster { + virtual CommandLineArguments Adjust(const CommandLineArguments &Args); +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_ARGUMENTSADJUSTERS_H + diff --git a/include/clang/Tooling/CommandLineClangTool.h b/include/clang/Tooling/CommandLineClangTool.h new file mode 100644 index 0000000000000..c29c30236416d --- /dev/null +++ b/include/clang/Tooling/CommandLineClangTool.h @@ -0,0 +1,80 @@ +//===- CommandLineClangTool.h - command-line clang tools driver -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CommandLineClangTool class used to run clang +// tools as separate command-line applications with a consistent common +// interface for handling compilation database and input files. +// +// It provides a common subset of command-line options, common algorithm +// for locating a compilation database and source files, and help messages +// for the basic command-line interface. +// +// It creates a CompilationDatabase, initializes a ClangTool and runs a +// user-specified FrontendAction over all TUs in which the given files are +// compiled. +// +// This class uses the Clang Tooling infrastructure, see +// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +// for details on setting it up with LLVM source tree. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H +#define LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H + +#include "llvm/Support/CommandLine.h" +#include "clang/Tooling/CompilationDatabase.h" + +namespace clang { + +namespace tooling { + +class CompilationDatabase; +class FrontendActionFactory; + +/// \brief A common driver for command-line Clang tools. +/// +/// Parses a common subset of command-line arguments, locates and loads a +/// compilation commands database, runs a tool with user-specified action. It +/// also contains a help message for the common command-line options. +/// An example of usage: +/// @code +/// int main(int argc, const char **argv) { +/// CommandLineClangTool Tool; +/// cl::extrahelp MoreHelp("\nMore help text..."); +/// Tool.initialize(argc, argv); +/// return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>()); +/// } +/// @endcode +/// +class CommandLineClangTool { +public: + /// Sets up command-line options and help messages. + /// Add your own help messages after constructing this tool. + CommandLineClangTool(); + + /// Parses command-line, initializes a compilation database. + /// This method exits program in case of error. + void initialize(int argc, const char **argv); + + /// Runs a clang tool with an action created by \c ActionFactory. + int run(FrontendActionFactory *ActionFactory); + +private: + llvm::OwningPtr<CompilationDatabase> Compilations; + llvm::cl::opt<std::string> BuildPath; + llvm::cl::list<std::string> SourcePaths; + llvm::cl::extrahelp MoreHelp; +}; + +} // namespace tooling + +} // namespace clang + +#endif // LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h index 625c8eced4b8f..f78ffaed284ce 100644 --- a/include/clang/Tooling/CompilationDatabase.h +++ b/include/clang/Tooling/CompilationDatabase.h @@ -81,6 +81,20 @@ public: static CompilationDatabase *loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage); + /// \brief Tries to detect a compilation database location and load it. + /// + /// Looks for a compilation database in all parent paths of file 'SourceFile' + /// by calling loadFromDirectory. + static CompilationDatabase *autoDetectFromSource(StringRef SourceFile, + std::string &ErrorMessage); + + /// \brief Tries to detect a compilation database location and load it. + /// + /// Looks for a compilation database in directory 'SourceDir' and all + /// its parent paths by calling loadFromDirectory. + static CompilationDatabase *autoDetectFromDirectory(StringRef SourceDir, + std::string &ErrorMessage); + /// \brief Returns all compile commands in which the specified file was /// compiled. /// @@ -92,6 +106,9 @@ public: /// lines for a.cc and b.cc and only the first command line for t.cc. virtual std::vector<CompileCommand> getCompileCommands( StringRef FilePath) const = 0; + + /// \brief Returns the list of all files available in the compilation database. + virtual std::vector<std::string> getAllFiles() const = 0; }; /// \brief A compilation database that returns a single compile command line. @@ -141,6 +158,11 @@ public: virtual std::vector<CompileCommand> getCompileCommands( StringRef FilePath) const; + /// \brief Returns the list of all files available in the compilation database. + /// + /// Note: This is always an empty list for the fixed compilation database. + virtual std::vector<std::string> getAllFiles() const; + private: /// This is built up to contain a single entry vector to be returned from /// getCompileCommands after adding the positional argument. @@ -187,6 +209,11 @@ public: virtual std::vector<CompileCommand> getCompileCommands( StringRef FilePath) const; + /// \brief Returns the list of all files available in the compilation database. + /// + /// These are the 'file' entries of the JSON objects. + virtual std::vector<std::string> getAllFiles() const; + private: /// \brief Constructs a JSON compilation database on a memory buffer. JSONCompilationDatabase(llvm::MemoryBuffer *Database) @@ -215,4 +242,3 @@ private: } // end namespace clang #endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H - diff --git a/include/clang/Tooling/Refactoring.h b/include/clang/Tooling/Refactoring.h new file mode 100644 index 0000000000000..0e42a0ec64fc4 --- /dev/null +++ b/include/clang/Tooling/Refactoring.h @@ -0,0 +1,151 @@ +//===--- Refactoring.h - Framework for clang refactoring tools --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interfaces supporting refactorings that span multiple translation units. +// While single translation unit refactorings are supported via the Rewriter, +// when refactoring multiple translation units changes must be stored in a +// SourceManager independent form, duplicate changes need to be removed, and +// all changes must be applied at once at the end of the refactoring so that +// the code is always parseable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORING_H +#define LLVM_CLANG_TOOLING_REFACTORING_H + +#include "llvm/ADT/StringRef.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Tooling/Tooling.h" +#include <set> +#include <string> + +namespace clang { + +class Rewriter; +class SourceLocation; + +namespace tooling { + +/// \brief A text replacement. +/// +/// Represents a SourceManager independent replacement of a range of text in a +/// specific file. +class Replacement { +public: + /// \brief Creates an invalid (not applicable) replacement. + Replacement(); + + /// \brief Creates a replacement of the range [Offset, Offset+Length) in + /// FilePath with ReplacementText. + /// + /// \param FilePath A source file accessible via a SourceManager. + /// \param Offset The byte offset of the start of the range in the file. + /// \param Length The length of the range in bytes. + Replacement(llvm::StringRef FilePath, unsigned Offset, + unsigned Length, llvm::StringRef ReplacementText); + + /// \brief Creates a Replacement of the range [Start, Start+Length) with + /// ReplacementText. + Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length, + llvm::StringRef ReplacementText); + + /// \brief Creates a Replacement of the given range with ReplacementText. + Replacement(SourceManager &Sources, const CharSourceRange &Range, + llvm::StringRef ReplacementText); + + /// \brief Creates a Replacement of the node with ReplacementText. + template <typename Node> + Replacement(SourceManager &Sources, const Node &NodeToReplace, + llvm::StringRef ReplacementText); + + /// \brief Returns whether this replacement can be applied to a file. + /// + /// Only replacements that are in a valid file can be applied. + bool isApplicable() const; + + /// \brief Accessors. + /// @{ + StringRef getFilePath() const { return FilePath; } + unsigned getOffset() const { return Offset; } + unsigned getLength() const { return Length; } + /// @} + + /// \brief Applies the replacement on the Rewriter. + bool apply(Rewriter &Rewrite) const; + + /// \brief Returns a human readable string representation. + std::string toString() const; + + /// \brief Comparator to be able to use Replacement in std::set for uniquing. + class Less { + public: + bool operator()(const Replacement &R1, const Replacement &R2) const; + }; + + private: + void setFromSourceLocation(SourceManager &Sources, SourceLocation Start, + unsigned Length, llvm::StringRef ReplacementText); + void setFromSourceRange(SourceManager &Sources, const CharSourceRange &Range, + llvm::StringRef ReplacementText); + + std::string FilePath; + unsigned Offset; + unsigned Length; + std::string ReplacementText; +}; + +/// \brief A set of Replacements. +/// FIXME: Change to a vector and deduplicate in the RefactoringTool. +typedef std::set<Replacement, Replacement::Less> Replacements; + +/// \brief Apply all replacements on the Rewriter. +/// +/// If at least one Apply returns false, ApplyAll returns false. Every +/// Apply will be executed independently of the result of other +/// Apply operations. +bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite); + +/// \brief A tool to run refactorings. +/// +/// This is a refactoring specific version of \see ClangTool. +/// All text replacements added to getReplacements() during the run of the +/// tool will be applied and saved after all translation units have been +/// processed. +class RefactoringTool { +public: + /// \see ClangTool::ClangTool. + RefactoringTool(const CompilationDatabase &Compilations, + ArrayRef<std::string> SourcePaths); + + /// \brief Returns a set of replacements. All replacements added during the + /// run of the tool will be applied after all translation units have been + /// processed. + Replacements &getReplacements(); + + /// \see ClangTool::run. + int run(FrontendActionFactory *ActionFactory); + +private: + ClangTool Tool; + Replacements Replace; +}; + +template <typename Node> +Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace, + llvm::StringRef ReplacementText) { + const CharSourceRange Range = + CharSourceRange::getTokenRange(NodeToReplace->getSourceRange()); + setFromSourceRange(Sources, Range, ReplacementText); +} + +} // end namespace tooling +} // end namespace clang + +#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H + diff --git a/include/clang/Tooling/RefactoringCallbacks.h b/include/clang/Tooling/RefactoringCallbacks.h new file mode 100644 index 0000000000000..c500f356a4d27 --- /dev/null +++ b/include/clang/Tooling/RefactoringCallbacks.h @@ -0,0 +1,90 @@ +//===--- RefactoringCallbacks.h - Structural query framework ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides callbacks to make common kinds of refactorings easy. +// +// The general idea is to construct a matcher expression that describes a +// subtree match on the AST and then replace the corresponding source code +// either by some specific text or some other AST node. +// +// Example: +// int main(int argc, char **argv) { +// ClangTool Tool(argc, argv); +// MatchFinder Finder; +// ReplaceStmtWithText Callback("integer", "42"); +// Finder.AddMatcher(id("integer", expression(integerLiteral())), Callback); +// return Tool.run(newFrontendActionFactory(&Finder)); +// } +// +// This will replace all integer literals with "42". +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H +#define LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Refactoring.h" + +namespace clang { +namespace tooling { + +/// \brief Base class for RefactoringCallbacks. +/// +/// Collects \c tooling::Replacements while running. +class RefactoringCallback : public ast_matchers::MatchFinder::MatchCallback { +public: + RefactoringCallback(); + Replacements &getReplacements(); + +protected: + Replacements Replace; +}; + +/// \brief Replace the text of the statement bound to \c FromId with the text in +/// \c ToText. +class ReplaceStmtWithText : public RefactoringCallback { +public: + ReplaceStmtWithText(StringRef FromId, StringRef ToText); + virtual void run(const ast_matchers::MatchFinder::MatchResult &Result); + +private: + std::string FromId; + std::string ToText; +}; + +/// \brief Replace the text of the statement bound to \c FromId with the text of +/// the statement bound to \c ToId. +class ReplaceStmtWithStmt : public RefactoringCallback { +public: + ReplaceStmtWithStmt(StringRef FromId, StringRef ToId); + virtual void run(const ast_matchers::MatchFinder::MatchResult &Result); + +private: + std::string FromId; + std::string ToId; +}; + +/// \brief Replace an if-statement bound to \c Id with the outdented text of its +/// body, choosing the consequent or the alternative based on whether +/// \c PickTrueBranch is true. +class ReplaceIfStmtWithItsBody : public RefactoringCallback { +public: + ReplaceIfStmtWithItsBody(StringRef Id, bool PickTrueBranch); + virtual void run(const ast_matchers::MatchFinder::MatchResult &Result); + +private: + std::string Id; + const bool PickTrueBranch; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTORING_CALLBACKS_H diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index 868eae306899e..e06705f0279bd 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -15,7 +15,7 @@ // all TUs in which the given files are compiled. // // It is also possible to run a FrontendAction over a snippet of code by -// calling runSyntaxOnlyToolOnCode, which is useful for unit testing. +// calling runToolOnCode, which is useful for unit testing. // // Applications that need more fine grained control over how to run // multiple FrontendActions over code can use ToolInvocation. @@ -35,6 +35,9 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Util.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Tooling/CompilationDatabase.h" #include <string> #include <vector> @@ -50,8 +53,6 @@ class FrontendAction; namespace tooling { -class CompilationDatabase; - /// \brief Interface to generate clang::FrontendActions. class FrontendActionFactory { public: @@ -74,18 +75,19 @@ template <typename T> FrontendActionFactory *newFrontendActionFactory(); /// \brief Returns a new FrontendActionFactory for any type that provides an -/// implementation of newFrontendAction(). +/// implementation of newASTConsumer(). /// -/// FactoryT must implement: FrontendAction *newFrontendAction(). +/// FactoryT must implement: ASTConsumer *newASTConsumer(). /// /// Example: -/// struct ProvidesFrontendActions { -/// FrontendAction *newFrontendAction(); +/// struct ProvidesASTConsumers { +/// clang::ASTConsumer *newASTConsumer(); /// } Factory; /// FrontendActionFactory *FactoryAdapter = /// newFrontendActionFactory(&Factory); template <typename FactoryT> -FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory); +inline FrontendActionFactory *newFrontendActionFactory( + FactoryT *ConsumerFactory); /// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag. /// @@ -102,7 +104,10 @@ class ToolInvocation { public: /// \brief Create a tool invocation. /// - /// \param CommandLine The command line arguments to clang. + /// \param CommandLine The command line arguments to clang. Note that clang + /// uses its binary name (CommandLine[0]) to locate its builtin headers. + /// Callers have to ensure that they are installed in a compatible location + /// (see clang driver implementation) or mapped in via mapVirtualFile. /// \param ToolAction The action to be executed. Class takes ownership. /// \param Files The FileManager used for the execution. Class does not take /// ownership. @@ -126,8 +131,7 @@ class ToolInvocation { bool runInvocation(const char *BinaryName, clang::driver::Compilation *Compilation, clang::CompilerInvocation *Invocation, - const clang::driver::ArgStringList &CC1Args, - clang::FrontendAction *ToolAction); + const clang::driver::ArgStringList &CC1Args); std::vector<std::string> CommandLine; llvm::OwningPtr<FrontendAction> ToolAction; @@ -139,6 +143,10 @@ class ToolInvocation { /// \brief Utility to run a FrontendAction over a set of files. /// /// This class is written to be usable for command line utilities. +/// By default the class uses ClangSyntaxOnlyAdjuster to modify +/// command line arguments before the arguments are used to run +/// a frontend action. One could install another command line +/// arguments adjuster by call setArgumentsAdjuster() method. class ClangTool { public: /// \brief Constructs a clang tool to run over a list of files. @@ -156,6 +164,11 @@ class ClangTool { /// \param Content A null terminated buffer of the file's content. void mapVirtualFile(StringRef FilePath, StringRef Content); + /// \brief Install command line arguments adjuster. + /// + /// \param Adjuster Command line arguments adjuster. + void setArgumentsAdjuster(ArgumentsAdjuster *Adjuster); + /// Runs a frontend action over all files specified in the command line. /// /// \param ActionFactory Factory generating the frontend actions. The function @@ -169,13 +182,14 @@ class ClangTool { FileManager &getFiles() { return Files; } private: - // We store command lines as pair (file name, command line). - typedef std::pair< std::string, std::vector<std::string> > CommandLine; - std::vector<CommandLine> CommandLines; + // We store compile commands as pair (file name, compile command). + std::vector< std::pair<std::string, CompileCommand> > CompileCommands; FileManager Files; // Contains a list of pairs (<file name>, <file content>). std::vector< std::pair<StringRef, StringRef> > MappedFileContents; + + llvm::OwningPtr<ArgumentsAdjuster> ArgsAdjuster; }; template <typename T> @@ -189,25 +203,54 @@ FrontendActionFactory *newFrontendActionFactory() { } template <typename FactoryT> -FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory) { +inline FrontendActionFactory *newFrontendActionFactory( + FactoryT *ConsumerFactory) { class FrontendActionFactoryAdapter : public FrontendActionFactory { public: - explicit FrontendActionFactoryAdapter(FactoryT *ActionFactory) - : ActionFactory(ActionFactory) {} + explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory) + : ConsumerFactory(ConsumerFactory) {} virtual clang::FrontendAction *create() { - return ActionFactory->newFrontendAction(); + return new ConsumerFactoryAdaptor(ConsumerFactory); } private: - FactoryT *ActionFactory; + class ConsumerFactoryAdaptor : public clang::ASTFrontendAction { + public: + ConsumerFactoryAdaptor(FactoryT *ConsumerFactory) + : ConsumerFactory(ConsumerFactory) {} + + clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &, + llvm::StringRef) { + return ConsumerFactory->newASTConsumer(); + } + + private: + FactoryT *ConsumerFactory; + }; + FactoryT *ConsumerFactory; }; - return new FrontendActionFactoryAdapter(ActionFactory); + return new FrontendActionFactoryAdapter(ConsumerFactory); } +/// \brief Returns the absolute path of \c File, by prepending it with +/// the current directory if \c File is not absolute. +/// +/// Otherwise returns \c File. +/// If 'File' starts with "./", the returned path will not contain the "./". +/// Otherwise, the returned path will contain the literal path-concatenation of +/// the current directory and \c File. +/// +/// The difference to llvm::sys::fs::make_absolute is that we prefer +/// ::getenv("PWD") if available. +/// FIXME: Make this functionality available from llvm::sys::fs and delete +/// this function. +/// +/// \param File Either an absolute or relative path. +std::string getAbsolutePath(StringRef File); + } // end namespace tooling } // end namespace clang #endif // LLVM_CLANG_TOOLING_TOOLING_H - |