147c245a5SManuel Klimek //===--- CompilationDatabase.cpp - ----------------------------------------===//
247c245a5SManuel Klimek //
347c245a5SManuel Klimek //                     The LLVM Compiler Infrastructure
447c245a5SManuel Klimek //
547c245a5SManuel Klimek // This file is distributed under the University of Illinois Open Source
647c245a5SManuel Klimek // License. See LICENSE.TXT for details.
747c245a5SManuel Klimek //
847c245a5SManuel Klimek //===----------------------------------------------------------------------===//
947c245a5SManuel Klimek //
106ed1f85cSDaniel Jasper //  This file contains implementations of the CompilationDatabase base class
116ed1f85cSDaniel Jasper //  and the FixedCompilationDatabase.
1247c245a5SManuel Klimek //
1347c245a5SManuel Klimek //===----------------------------------------------------------------------===//
1447c245a5SManuel Klimek 
1547c245a5SManuel Klimek #include "clang/Tooling/CompilationDatabase.h"
166ed1f85cSDaniel Jasper #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
1765fd0e1fSManuel Klimek #include "clang/Tooling/Tooling.h"
1847c245a5SManuel Klimek #include "llvm/ADT/SmallString.h"
1947c245a5SManuel Klimek #include "llvm/Support/Path.h"
2047c245a5SManuel Klimek #include "llvm/Support/system_error.h"
213a02247dSChandler Carruth #include <sstream>
2247c245a5SManuel Klimek 
23eb56f4feSEdwin Vane #include "clang/Basic/Diagnostic.h"
24eb56f4feSEdwin Vane #include "clang/Driver/Action.h"
25eb56f4feSEdwin Vane #include "clang/Driver/Driver.h"
26eb56f4feSEdwin Vane #include "clang/Driver/DriverDiagnostic.h"
27eb56f4feSEdwin Vane #include "clang/Driver/Job.h"
28eb56f4feSEdwin Vane #include "clang/Driver/Compilation.h"
29eb56f4feSEdwin Vane #include "clang/Frontend/TextDiagnosticPrinter.h"
30eb56f4feSEdwin Vane #include "llvm/Support/Host.h"
31eb56f4feSEdwin Vane #include "llvm/Option/Arg.h"
32eb56f4feSEdwin Vane 
3347c245a5SManuel Klimek namespace clang {
3447c245a5SManuel Klimek namespace tooling {
3547c245a5SManuel Klimek 
3647c245a5SManuel Klimek CompilationDatabase::~CompilationDatabase() {}
3747c245a5SManuel Klimek 
3847c245a5SManuel Klimek CompilationDatabase *
3947c245a5SManuel Klimek CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
4047c245a5SManuel Klimek                                        std::string &ErrorMessage) {
416ed1f85cSDaniel Jasper   std::stringstream ErrorStream;
426ed1f85cSDaniel Jasper   for (CompilationDatabasePluginRegistry::iterator
436ed1f85cSDaniel Jasper        It = CompilationDatabasePluginRegistry::begin(),
446ed1f85cSDaniel Jasper        Ie = CompilationDatabasePluginRegistry::end();
456ed1f85cSDaniel Jasper        It != Ie; ++It) {
466ed1f85cSDaniel Jasper     std::string DatabaseErrorMessage;
476ed1f85cSDaniel Jasper     OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
486ed1f85cSDaniel Jasper     if (CompilationDatabase *DB =
496ed1f85cSDaniel Jasper         Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
506ed1f85cSDaniel Jasper       return DB;
516ed1f85cSDaniel Jasper     else
526ed1f85cSDaniel Jasper       ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
5347c245a5SManuel Klimek   }
546ed1f85cSDaniel Jasper   ErrorMessage = ErrorStream.str();
556ed1f85cSDaniel Jasper   return NULL;
5647c245a5SManuel Klimek }
5747c245a5SManuel Klimek 
58617f5269SArnaud A. de Grandmaison static CompilationDatabase *
596ed1f85cSDaniel Jasper findCompilationDatabaseFromDirectory(StringRef Directory,
606ed1f85cSDaniel Jasper                                      std::string &ErrorMessage) {
616ed1f85cSDaniel Jasper   std::stringstream ErrorStream;
6274351ff4SDaniel Jasper   bool HasErrorMessage = false;
63617f5269SArnaud A. de Grandmaison   while (!Directory.empty()) {
64617f5269SArnaud A. de Grandmaison     std::string LoadErrorMessage;
65617f5269SArnaud A. de Grandmaison 
66617f5269SArnaud A. de Grandmaison     if (CompilationDatabase *DB =
67617f5269SArnaud A. de Grandmaison            CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
68617f5269SArnaud A. de Grandmaison       return DB;
6974351ff4SDaniel Jasper 
7074351ff4SDaniel Jasper     if (!HasErrorMessage) {
716ed1f85cSDaniel Jasper       ErrorStream << "No compilation database found in " << Directory.str()
7274351ff4SDaniel Jasper                   << " or any parent directory\n" << LoadErrorMessage;
7374351ff4SDaniel Jasper       HasErrorMessage = true;
7474351ff4SDaniel Jasper     }
75617f5269SArnaud A. de Grandmaison 
76617f5269SArnaud A. de Grandmaison     Directory = llvm::sys::path::parent_path(Directory);
77617f5269SArnaud A. de Grandmaison   }
786ed1f85cSDaniel Jasper   ErrorMessage = ErrorStream.str();
79617f5269SArnaud A. de Grandmaison   return NULL;
80617f5269SArnaud A. de Grandmaison }
81617f5269SArnaud A. de Grandmaison 
8265fd0e1fSManuel Klimek CompilationDatabase *
8365fd0e1fSManuel Klimek CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
8465fd0e1fSManuel Klimek                                           std::string &ErrorMessage) {
85f857950dSDmitri Gribenko   SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
8665fd0e1fSManuel Klimek   StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
87617f5269SArnaud A. de Grandmaison 
886ed1f85cSDaniel Jasper   CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
896ed1f85cSDaniel Jasper                                                                  ErrorMessage);
90617f5269SArnaud A. de Grandmaison 
91617f5269SArnaud A. de Grandmaison   if (!DB)
9265fd0e1fSManuel Klimek     ErrorMessage = ("Could not auto-detect compilation database for file \"" +
936ed1f85cSDaniel Jasper                    SourceFile + "\"\n" + ErrorMessage).str();
94617f5269SArnaud A. de Grandmaison   return DB;
95617f5269SArnaud A. de Grandmaison }
96617f5269SArnaud A. de Grandmaison 
97617f5269SArnaud A. de Grandmaison CompilationDatabase *
98617f5269SArnaud A. de Grandmaison CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
99617f5269SArnaud A. de Grandmaison                                              std::string &ErrorMessage) {
100f857950dSDmitri Gribenko   SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
101617f5269SArnaud A. de Grandmaison 
1026ed1f85cSDaniel Jasper   CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
1036ed1f85cSDaniel Jasper                                                                  ErrorMessage);
104617f5269SArnaud A. de Grandmaison 
105617f5269SArnaud A. de Grandmaison   if (!DB)
106617f5269SArnaud A. de Grandmaison     ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
1076ed1f85cSDaniel Jasper                    SourceDir + "\"\n" + ErrorMessage).str();
108617f5269SArnaud A. de Grandmaison   return DB;
10965fd0e1fSManuel Klimek }
11065fd0e1fSManuel Klimek 
1116ed1f85cSDaniel Jasper CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
1126ed1f85cSDaniel Jasper 
113eb56f4feSEdwin Vane // Helper for recursively searching through a chain of actions and collecting
114eb56f4feSEdwin Vane // all inputs, direct and indirect, of compile jobs.
115eb56f4feSEdwin Vane struct CompileJobAnalyzer {
116eb56f4feSEdwin Vane   void run(const driver::Action *A) {
117eb56f4feSEdwin Vane     runImpl(A, false);
118eb56f4feSEdwin Vane   }
119eb56f4feSEdwin Vane 
120eb56f4feSEdwin Vane   SmallVector<std::string, 2> Inputs;
121eb56f4feSEdwin Vane 
122eb56f4feSEdwin Vane private:
123eb56f4feSEdwin Vane 
124eb56f4feSEdwin Vane   void runImpl(const driver::Action *A, bool Collect) {
125eb56f4feSEdwin Vane     bool CollectChildren = Collect;
126eb56f4feSEdwin Vane     switch (A->getKind()) {
127eb56f4feSEdwin Vane     case driver::Action::CompileJobClass:
128eb56f4feSEdwin Vane       CollectChildren = true;
129eb56f4feSEdwin Vane       break;
130eb56f4feSEdwin Vane 
131eb56f4feSEdwin Vane     case driver::Action::InputClass: {
132eb56f4feSEdwin Vane       if (Collect) {
133eb56f4feSEdwin Vane         const driver::InputAction *IA = cast<driver::InputAction>(A);
134eb56f4feSEdwin Vane         Inputs.push_back(IA->getInputArg().getSpelling());
135eb56f4feSEdwin Vane       }
136eb56f4feSEdwin Vane     } break;
137eb56f4feSEdwin Vane 
138eb56f4feSEdwin Vane     default:
139eb56f4feSEdwin Vane       // Don't care about others
140eb56f4feSEdwin Vane       ;
141eb56f4feSEdwin Vane     }
142eb56f4feSEdwin Vane 
143eb56f4feSEdwin Vane     for (driver::ActionList::const_iterator I = A->begin(), E = A->end();
144eb56f4feSEdwin Vane          I != E; ++I)
145eb56f4feSEdwin Vane       runImpl(*I, CollectChildren);
146eb56f4feSEdwin Vane   }
147eb56f4feSEdwin Vane };
148eb56f4feSEdwin Vane 
149eb56f4feSEdwin Vane // Special DiagnosticConsumer that looks for warn_drv_input_file_unused
150eb56f4feSEdwin Vane // diagnostics from the driver and collects the option strings for those unused
151eb56f4feSEdwin Vane // options.
152eb56f4feSEdwin Vane class UnusedInputDiagConsumer : public DiagnosticConsumer {
153eb56f4feSEdwin Vane public:
154eb56f4feSEdwin Vane   UnusedInputDiagConsumer() : Other(0) {}
155eb56f4feSEdwin Vane 
156eb56f4feSEdwin Vane   // Useful for debugging, chain diagnostics to another consumer after
157eb56f4feSEdwin Vane   // recording for our own purposes.
158eb56f4feSEdwin Vane   UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
159eb56f4feSEdwin Vane 
160eb56f4feSEdwin Vane   virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
161eb56f4feSEdwin Vane                                 const Diagnostic &Info) LLVM_OVERRIDE {
162eb56f4feSEdwin Vane     if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
163eb56f4feSEdwin Vane       // Arg 1 for this diagnostic is the option that didn't get used.
164eb56f4feSEdwin Vane       UnusedInputs.push_back(Info.getArgStdStr(0));
165eb56f4feSEdwin Vane     }
166eb56f4feSEdwin Vane     if (Other)
167eb56f4feSEdwin Vane       Other->HandleDiagnostic(DiagLevel, Info);
168eb56f4feSEdwin Vane   }
169eb56f4feSEdwin Vane 
170eb56f4feSEdwin Vane   DiagnosticConsumer *Other;
171eb56f4feSEdwin Vane   SmallVector<std::string, 2> UnusedInputs;
172eb56f4feSEdwin Vane };
173eb56f4feSEdwin Vane 
174eb56f4feSEdwin Vane // Unary functor for asking "Given a StringRef S1, does there exist a string
175eb56f4feSEdwin Vane // S2 in Arr where S1 == S2?"
176eb56f4feSEdwin Vane struct MatchesAny {
177eb56f4feSEdwin Vane   MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
178eb56f4feSEdwin Vane   bool operator() (StringRef S) {
179eb56f4feSEdwin Vane     for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
180eb56f4feSEdwin Vane       if (*I == S)
181eb56f4feSEdwin Vane         return true;
182eb56f4feSEdwin Vane     return false;
183eb56f4feSEdwin Vane   }
184eb56f4feSEdwin Vane private:
185eb56f4feSEdwin Vane   ArrayRef<std::string> Arr;
186eb56f4feSEdwin Vane };
187eb56f4feSEdwin Vane 
188eb56f4feSEdwin Vane /// \brief Strips any positional args and possible argv[0] from a command-line
189eb56f4feSEdwin Vane /// provided by the user to construct a FixedCompilationDatabase.
190eb56f4feSEdwin Vane ///
191eb56f4feSEdwin Vane /// FixedCompilationDatabase requires a command line to be in this format as it
192eb56f4feSEdwin Vane /// constructs the command line for each file by appending the name of the file
193eb56f4feSEdwin Vane /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
194eb56f4feSEdwin Vane /// start of the command line although its value is not important as it's just
195eb56f4feSEdwin Vane /// ignored by the Driver invoked by the ClangTool using the
196eb56f4feSEdwin Vane /// FixedCompilationDatabase.
197eb56f4feSEdwin Vane ///
198eb56f4feSEdwin Vane /// FIXME: This functionality should probably be made available by
199eb56f4feSEdwin Vane /// clang::driver::Driver although what the interface should look like is not
200eb56f4feSEdwin Vane /// clear.
201eb56f4feSEdwin Vane ///
202eb56f4feSEdwin Vane /// \param[in] Args Args as provided by the user.
2035335cf33SNAKAMURA Takumi /// \return Resulting stripped command line.
2045335cf33SNAKAMURA Takumi ///          \li true if successful.
205eb56f4feSEdwin Vane ///          \li false if \c Args cannot be used for compilation jobs (e.g.
206eb56f4feSEdwin Vane ///          contains an option like -E or -version).
207eb56f4feSEdwin Vane bool stripPositionalArgs(std::vector<const char *> Args,
208eb56f4feSEdwin Vane                          std::vector<std::string> &Result) {
209eb56f4feSEdwin Vane   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
210eb56f4feSEdwin Vane   UnusedInputDiagConsumer DiagClient;
211eb56f4feSEdwin Vane   DiagnosticsEngine Diagnostics(
212eb56f4feSEdwin Vane       IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
213eb56f4feSEdwin Vane       &*DiagOpts, &DiagClient, false);
214eb56f4feSEdwin Vane 
215eb56f4feSEdwin Vane   // Neither clang executable nor default image name are required since the
216eb56f4feSEdwin Vane   // jobs the driver builds will not be executed.
217eb56f4feSEdwin Vane   OwningPtr<driver::Driver> NewDriver(new driver::Driver(
218eb56f4feSEdwin Vane       /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
219eb56f4feSEdwin Vane       /* DefaultImageName= */ "", Diagnostics));
220eb56f4feSEdwin Vane   NewDriver->setCheckInputsExist(false);
221eb56f4feSEdwin Vane 
222eb56f4feSEdwin Vane   // This becomes the new argv[0]. The value is actually not important as it
223eb56f4feSEdwin Vane   // isn't used for invoking Tools.
224eb56f4feSEdwin Vane   Args.insert(Args.begin(), "clang-tool");
225eb56f4feSEdwin Vane 
226eb56f4feSEdwin Vane   // By adding -c, we force the driver to treat compilation as the last phase.
227eb56f4feSEdwin Vane   // It will then issue warnings via Diagnostics about un-used options that
228eb56f4feSEdwin Vane   // would have been used for linking. If the user provided a compiler name as
229eb56f4feSEdwin Vane   // the original argv[0], this will be treated as a linker input thanks to
230eb56f4feSEdwin Vane   // insertng a new argv[0] above. All un-used options get collected by
231eb56f4feSEdwin Vane   // UnusedInputdiagConsumer and get stripped out later.
232eb56f4feSEdwin Vane   Args.push_back("-c");
233eb56f4feSEdwin Vane 
234eb56f4feSEdwin Vane   // Put a dummy C++ file on to ensure there's at least one compile job for the
235eb56f4feSEdwin Vane   // driver to construct. If the user specified some other argument that
236eb56f4feSEdwin Vane   // prevents compilation, e.g. -E or something like -version, we may still end
237eb56f4feSEdwin Vane   // up with no jobs but then this is the user's fault.
238eb56f4feSEdwin Vane   Args.push_back("placeholder.cpp");
239eb56f4feSEdwin Vane 
240eb56f4feSEdwin Vane   const OwningPtr<driver::Compilation> Compilation(
241eb56f4feSEdwin Vane       NewDriver->BuildCompilation(Args));
242eb56f4feSEdwin Vane 
243eb56f4feSEdwin Vane   const driver::JobList &Jobs = Compilation->getJobs();
244eb56f4feSEdwin Vane 
245eb56f4feSEdwin Vane   CompileJobAnalyzer CompileAnalyzer;
246eb56f4feSEdwin Vane 
247eb56f4feSEdwin Vane   for (driver::JobList::const_iterator I = Jobs.begin(), E = Jobs.end(); I != E;
248eb56f4feSEdwin Vane        ++I) {
249eb56f4feSEdwin Vane     if ((*I)->getKind() == driver::Job::CommandClass) {
250eb56f4feSEdwin Vane       const driver::Command *Cmd = cast<driver::Command>(*I);
251eb56f4feSEdwin Vane       // Collect only for Assemble jobs. If we do all jobs we get duplicates
252eb56f4feSEdwin Vane       // since Link jobs point to Assemble jobs as inputs.
253eb56f4feSEdwin Vane       if (Cmd->getSource().getKind() == driver::Action::AssembleJobClass)
254eb56f4feSEdwin Vane         CompileAnalyzer.run(&Cmd->getSource());
255eb56f4feSEdwin Vane     }
256eb56f4feSEdwin Vane   }
257eb56f4feSEdwin Vane 
258eb56f4feSEdwin Vane   if (CompileAnalyzer.Inputs.empty()) {
259eb56f4feSEdwin Vane     // No compile jobs found.
260eb56f4feSEdwin Vane     // FIXME: Emit a warning of some kind?
261eb56f4feSEdwin Vane     return false;
262eb56f4feSEdwin Vane   }
263eb56f4feSEdwin Vane 
264eb56f4feSEdwin Vane   // Remove all compilation input files from the command line. This is
265eb56f4feSEdwin Vane   // necessary so that getCompileCommands() can construct a command line for
266eb56f4feSEdwin Vane   // each file.
267eb56f4feSEdwin Vane   std::vector<const char *>::iterator End = std::remove_if(
268eb56f4feSEdwin Vane       Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
269eb56f4feSEdwin Vane 
270eb56f4feSEdwin Vane   // Remove all inputs deemed unused for compilation.
271eb56f4feSEdwin Vane   End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
272eb56f4feSEdwin Vane 
273eb56f4feSEdwin Vane   // Remove the -c add above as well. It will be at the end right now.
274*e99bb4b2SRichard Trieu   assert(strcmp(*(End - 1), "-c") == 0);
275eb56f4feSEdwin Vane   --End;
276eb56f4feSEdwin Vane 
277eb56f4feSEdwin Vane   Result = std::vector<std::string>(Args.begin() + 1, End);
278eb56f4feSEdwin Vane   return true;
279eb56f4feSEdwin Vane }
280eb56f4feSEdwin Vane 
281ff26efceSManuel Klimek FixedCompilationDatabase *
282ff26efceSManuel Klimek FixedCompilationDatabase::loadFromCommandLine(int &Argc,
283ff26efceSManuel Klimek                                               const char **Argv,
284ff26efceSManuel Klimek                                               Twine Directory) {
285ff26efceSManuel Klimek   const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
286ff26efceSManuel Klimek   if (DoubleDash == Argv + Argc)
287ff26efceSManuel Klimek     return NULL;
288eb56f4feSEdwin Vane   std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
289ff26efceSManuel Klimek   Argc = DoubleDash - Argv;
290eb56f4feSEdwin Vane 
291eb56f4feSEdwin Vane   std::vector<std::string> StrippedArgs;
292eb56f4feSEdwin Vane   if (!stripPositionalArgs(CommandLine, StrippedArgs))
293eb56f4feSEdwin Vane     return 0;
294eb56f4feSEdwin Vane   return new FixedCompilationDatabase(Directory, StrippedArgs);
295ff26efceSManuel Klimek }
296ff26efceSManuel Klimek 
297ff26efceSManuel Klimek FixedCompilationDatabase::
298ff26efceSManuel Klimek FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
299ff26efceSManuel Klimek   std::vector<std::string> ToolCommandLine(1, "clang-tool");
300ff26efceSManuel Klimek   ToolCommandLine.insert(ToolCommandLine.end(),
301ff26efceSManuel Klimek                          CommandLine.begin(), CommandLine.end());
302ff26efceSManuel Klimek   CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine));
303ff26efceSManuel Klimek }
304ff26efceSManuel Klimek 
305ff26efceSManuel Klimek std::vector<CompileCommand>
306ff26efceSManuel Klimek FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
307ff26efceSManuel Klimek   std::vector<CompileCommand> Result(CompileCommands);
308ff26efceSManuel Klimek   Result[0].CommandLine.push_back(FilePath);
309ff26efceSManuel Klimek   return Result;
310ff26efceSManuel Klimek }
311ff26efceSManuel Klimek 
31260b80161SManuel Klimek std::vector<std::string>
31360b80161SManuel Klimek FixedCompilationDatabase::getAllFiles() const {
31460b80161SManuel Klimek   return std::vector<std::string>();
31560b80161SManuel Klimek }
31660b80161SManuel Klimek 
317251ad5e0SArgyrios Kyrtzidis std::vector<CompileCommand>
318251ad5e0SArgyrios Kyrtzidis FixedCompilationDatabase::getAllCompileCommands() const {
319251ad5e0SArgyrios Kyrtzidis   return std::vector<CompileCommand>();
320251ad5e0SArgyrios Kyrtzidis }
321251ad5e0SArgyrios Kyrtzidis 
3226ed1f85cSDaniel Jasper // This anchor is used to force the linker to link in the generated object file
3236ed1f85cSDaniel Jasper // and thus register the JSONCompilationDatabasePlugin.
3246ed1f85cSDaniel Jasper extern volatile int JSONAnchorSource;
3256ed1f85cSDaniel Jasper static int JSONAnchorDest = JSONAnchorSource;
32647c245a5SManuel Klimek 
32747c245a5SManuel Klimek } // end namespace tooling
32847c245a5SManuel Klimek } // end namespace clang
329