1 //===- CompilationDatabase.h ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file provides an interface and multiple implementations for
10 //  CompilationDatabases.
11 //
12 //  While C++ refactoring and analysis tools are not compilers, and thus
13 //  don't run as part of the build system, they need the exact information
14 //  of a build in order to be able to correctly understand the C++ code of
15 //  the project. This information is provided via the CompilationDatabase
16 //  interface.
17 //
18 //  To create a CompilationDatabase from a build directory one can call
19 //  CompilationDatabase::loadFromDirectory(), which deduces the correct
20 //  compilation database from the root of the build tree.
21 //
22 //  See the concrete subclasses of CompilationDatabase for currently supported
23 //  formats.
24 //
25 //===----------------------------------------------------------------------===//
26 
27 #ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
28 #define LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
29 
30 #include "clang/Basic/LLVM.h"
31 #include "llvm/ADT/ArrayRef.h"
32 #include "llvm/ADT/StringRef.h"
33 #include "llvm/ADT/Twine.h"
34 #include <memory>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 namespace clang {
40 namespace tooling {
41 
42 /// Specifies the working directory and command of a compilation.
43 struct CompileCommand {
44   CompileCommand() = default;
45   CompileCommand(Twine Directory, Twine Filename,
46                  std::vector<std::string> CommandLine, Twine Output)
47       : Directory(Directory.str()), Filename(Filename.str()),
48         CommandLine(std::move(CommandLine)), Output(Output.str()){}
49 
50   /// The working directory the command was executed from.
51   std::string Directory;
52 
53   /// The source file associated with the command.
54   std::string Filename;
55 
56   /// The command line that was executed.
57   std::vector<std::string> CommandLine;
58 
59   /// The output file associated with the command.
60   std::string Output;
61 
62   friend bool operator==(const CompileCommand &LHS, const CompileCommand &RHS) {
63     return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
64            LHS.CommandLine == RHS.CommandLine && LHS.Output == RHS.Output;
65   }
66 
67   friend bool operator!=(const CompileCommand &LHS, const CompileCommand &RHS) {
68     return !(LHS == RHS);
69   }
70 };
71 
72 /// Interface for compilation databases.
73 ///
74 /// A compilation database allows the user to retrieve compile command lines
75 /// for the files in a project.
76 ///
77 /// Many implementations are enumerable, allowing all command lines to be
78 /// retrieved. These can be used to run clang tools over a subset of the files
79 /// in a project.
80 class CompilationDatabase {
81 public:
82   virtual ~CompilationDatabase();
83 
84   /// Loads a compilation database from a build directory.
85   ///
86   /// Looks at the specified 'BuildDirectory' and creates a compilation database
87   /// that allows to query compile commands for source files in the
88   /// corresponding source tree.
89   ///
90   /// Returns NULL and sets ErrorMessage if we were not able to build up a
91   /// compilation database for the build directory.
92   ///
93   /// FIXME: Currently only supports JSON compilation databases, which
94   /// are named 'compile_commands.json' in the given directory. Extend this
95   /// for other build types (like ninja build files).
96   static std::unique_ptr<CompilationDatabase>
97   loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage);
98 
99   /// Tries to detect a compilation database location and load it.
100   ///
101   /// Looks for a compilation database in all parent paths of file 'SourceFile'
102   /// by calling loadFromDirectory.
103   static std::unique_ptr<CompilationDatabase>
104   autoDetectFromSource(StringRef SourceFile, std::string &ErrorMessage);
105 
106   /// Tries to detect a compilation database location and load it.
107   ///
108   /// Looks for a compilation database in directory 'SourceDir' and all
109   /// its parent paths by calling loadFromDirectory.
110   static std::unique_ptr<CompilationDatabase>
111   autoDetectFromDirectory(StringRef SourceDir, std::string &ErrorMessage);
112 
113   /// Returns all compile commands in which the specified file was
114   /// compiled.
115   ///
116   /// This includes compile commands that span multiple source files.
117   /// For example, consider a project with the following compilations:
118   /// $ clang++ -o test a.cc b.cc t.cc
119   /// $ clang++ -o production a.cc b.cc -DPRODUCTION
120   /// A compilation database representing the project would return both command
121   /// lines for a.cc and b.cc and only the first command line for t.cc.
122   virtual std::vector<CompileCommand> getCompileCommands(
123       StringRef FilePath) const = 0;
124 
125   /// Returns the list of all files available in the compilation database.
126   ///
127   /// By default, returns nothing. Implementations should override this if they
128   /// can enumerate their source files.
129   virtual std::vector<std::string> getAllFiles() const { return {}; }
130 
131   /// Returns all compile commands for all the files in the compilation
132   /// database.
133   ///
134   /// FIXME: Add a layer in Tooling that provides an interface to run a tool
135   /// over all files in a compilation database. Not all build systems have the
136   /// ability to provide a feasible implementation for \c getAllCompileCommands.
137   ///
138   /// By default, this is implemented in terms of getAllFiles() and
139   /// getCompileCommands(). Subclasses may override this for efficiency.
140   virtual std::vector<CompileCommand> getAllCompileCommands() const;
141 };
142 
143 /// A compilation database that returns a single compile command line.
144 ///
145 /// Useful when we want a tool to behave more like a compiler invocation.
146 /// This compilation database is not enumerable: getAllFiles() returns {}.
147 class FixedCompilationDatabase : public CompilationDatabase {
148 public:
149   /// Creates a FixedCompilationDatabase from the arguments after "--".
150   ///
151   /// Parses the given command line for "--". If "--" is found, the rest of
152   /// the arguments will make up the command line in the returned
153   /// FixedCompilationDatabase.
154   /// The arguments after "--" must not include positional parameters or the
155   /// argv[0] of the tool. Those will be added by the FixedCompilationDatabase
156   /// when a CompileCommand is requested. The argv[0] of the returned command
157   /// line will be "clang-tool".
158   ///
159   /// Returns NULL in case "--" is not found.
160   ///
161   /// The argument list is meant to be compatible with normal llvm command line
162   /// parsing in main methods.
163   /// int main(int argc, char **argv) {
164   ///   std::unique_ptr<FixedCompilationDatabase> Compilations(
165   ///     FixedCompilationDatabase::loadFromCommandLine(argc, argv));
166   ///   cl::ParseCommandLineOptions(argc, argv);
167   ///   ...
168   /// }
169   ///
170   /// \param Argc The number of command line arguments - will be changed to
171   /// the number of arguments before "--", if "--" was found in the argument
172   /// list.
173   /// \param Argv Points to the command line arguments.
174   /// \param ErrorMsg Contains error text if the function returns null pointer.
175   /// \param Directory The base directory used in the FixedCompilationDatabase.
176   static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine(
177       int &Argc, const char *const *Argv, std::string &ErrorMsg,
178       Twine Directory = ".");
179 
180   /// Reads flags from the given file, one-per line.
181   /// Returns nullptr and sets ErrorMessage if we can't read the file.
182   static std::unique_ptr<FixedCompilationDatabase>
183   loadFromFile(StringRef Path, std::string &ErrorMsg);
184 
185   /// Constructs a compilation data base from a specified directory
186   /// and command line.
187   FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine);
188 
189   /// Returns the given compile command.
190   ///
191   /// Will always return a vector with one entry that contains the directory
192   /// and command line specified at construction with "clang-tool" as argv[0]
193   /// and 'FilePath' as positional argument.
194   std::vector<CompileCommand>
195   getCompileCommands(StringRef FilePath) const override;
196 
197 private:
198   /// This is built up to contain a single entry vector to be returned from
199   /// getCompileCommands after adding the positional argument.
200   std::vector<CompileCommand> CompileCommands;
201 };
202 
203 /// Returns a wrapped CompilationDatabase that defers to the provided one,
204 /// but getCompileCommands() will infer commands for unknown files.
205 /// The return value of getAllFiles() or getAllCompileCommands() is unchanged.
206 /// See InterpolatingCompilationDatabase.cpp for details on heuristics.
207 std::unique_ptr<CompilationDatabase>
208     inferMissingCompileCommands(std::unique_ptr<CompilationDatabase>);
209 
210 } // namespace tooling
211 } // namespace clang
212 
213 #endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
214