reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
//===- CompilationDatabase.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file provides an interface and multiple implementations for
//  CompilationDatabases.
//
//  While C++ refactoring and analysis tools are not compilers, and thus
//  don't run as part of the build system, they need the exact information
//  of a build in order to be able to correctly understand the C++ code of
//  the project. This information is provided via the CompilationDatabase
//  interface.
//
//  To create a CompilationDatabase from a build directory one can call
//  CompilationDatabase::loadFromDirectory(), which deduces the correct
//  compilation database from the root of the build tree.
//
//  See the concrete subclasses of CompilationDatabase for currently supported
//  formats.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H
#define LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H

#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace clang {
namespace tooling {

/// Specifies the working directory and command of a compilation.
struct CompileCommand {
  CompileCommand() = default;
  CompileCommand(Twine Directory, Twine Filename,
                 std::vector<std::string> CommandLine, Twine Output)
      : Directory(Directory.str()), Filename(Filename.str()),
        CommandLine(std::move(CommandLine)), Output(Output.str()){}

  /// The working directory the command was executed from.
  std::string Directory;

  /// The source file associated with the command.
  std::string Filename;

  /// The command line that was executed.
  std::vector<std::string> CommandLine;

  /// The output file associated with the command.
  std::string Output;

  /// If this compile command was guessed rather than read from an authoritative
  /// source, a short human-readable explanation.
  /// e.g. "inferred from foo/bar.h".
  std::string Heuristic;

  friend bool operator==(const CompileCommand &LHS, const CompileCommand &RHS) {
    return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
           LHS.CommandLine == RHS.CommandLine && LHS.Output == RHS.Output &&
           LHS.Heuristic == RHS.Heuristic;
  }

  friend bool operator!=(const CompileCommand &LHS, const CompileCommand &RHS) {
    return !(LHS == RHS);
  }
};

/// Interface for compilation databases.
///
/// A compilation database allows the user to retrieve compile command lines
/// for the files in a project.
///
/// Many implementations are enumerable, allowing all command lines to be
/// retrieved. These can be used to run clang tools over a subset of the files
/// in a project.
class CompilationDatabase {
public:
  virtual ~CompilationDatabase();

  /// Loads a compilation database from a build directory.
  ///
  /// Looks at the specified 'BuildDirectory' and creates a compilation database
  /// that allows to query compile commands for source files in the
  /// corresponding source tree.
  ///
  /// Returns NULL and sets ErrorMessage if we were not able to build up a
  /// compilation database for the build directory.
  ///
  /// FIXME: Currently only supports JSON compilation databases, which
  /// are named 'compile_commands.json' in the given directory. Extend this
  /// for other build types (like ninja build files).
  static std::unique_ptr<CompilationDatabase>
  loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage);

  /// 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 std::unique_ptr<CompilationDatabase>
  autoDetectFromSource(StringRef SourceFile, std::string &ErrorMessage);

  /// 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 std::unique_ptr<CompilationDatabase>
  autoDetectFromDirectory(StringRef SourceDir, std::string &ErrorMessage);

  /// Returns all compile commands in which the specified file was
  /// compiled.
  ///
  /// This includes compile commands that span multiple source files.
  /// For example, consider a project with the following compilations:
  /// $ clang++ -o test a.cc b.cc t.cc
  /// $ clang++ -o production a.cc b.cc -DPRODUCTION
  /// A compilation database representing the project would return both command
  /// 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;

  /// Returns the list of all files available in the compilation database.
  ///
  /// By default, returns nothing. Implementations should override this if they
  /// can enumerate their source files.
  virtual std::vector<std::string> getAllFiles() const { return {}; }

  /// Returns all compile commands for all the files in the compilation
  /// database.
  ///
  /// FIXME: Add a layer in Tooling that provides an interface to run a tool
  /// over all files in a compilation database. Not all build systems have the
  /// ability to provide a feasible implementation for \c getAllCompileCommands.
  ///
  /// By default, this is implemented in terms of getAllFiles() and
  /// getCompileCommands(). Subclasses may override this for efficiency.
  virtual std::vector<CompileCommand> getAllCompileCommands() const;
};

/// A compilation database that returns a single compile command line.
///
/// Useful when we want a tool to behave more like a compiler invocation.
/// This compilation database is not enumerable: getAllFiles() returns {}.
class FixedCompilationDatabase : public CompilationDatabase {
public:
  /// Creates a FixedCompilationDatabase from the arguments after "--".
  ///
  /// Parses the given command line for "--". If "--" is found, the rest of
  /// the arguments will make up the command line in the returned
  /// FixedCompilationDatabase.
  /// The arguments after "--" must not include positional parameters or the
  /// argv[0] of the tool. Those will be added by the FixedCompilationDatabase
  /// when a CompileCommand is requested. The argv[0] of the returned command
  /// line will be "clang-tool".
  ///
  /// Returns NULL in case "--" is not found.
  ///
  /// The argument list is meant to be compatible with normal llvm command line
  /// parsing in main methods.
  /// int main(int argc, char **argv) {
  ///   std::unique_ptr<FixedCompilationDatabase> Compilations(
  ///     FixedCompilationDatabase::loadFromCommandLine(argc, argv));
  ///   cl::ParseCommandLineOptions(argc, argv);
  ///   ...
  /// }
  ///
  /// \param Argc The number of command line arguments - will be changed to
  /// the number of arguments before "--", if "--" was found in the argument
  /// list.
  /// \param Argv Points to the command line arguments.
  /// \param ErrorMsg Contains error text if the function returns null pointer.
  /// \param Directory The base directory used in the FixedCompilationDatabase.
  static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine(
      int &Argc, const char *const *Argv, std::string &ErrorMsg,
      Twine Directory = ".");

  /// Reads flags from the given file, one-per line.
  /// Returns nullptr and sets ErrorMessage if we can't read the file.
  static std::unique_ptr<FixedCompilationDatabase>
  loadFromFile(StringRef Path, std::string &ErrorMsg);

  /// Constructs a compilation data base from a specified directory
  /// and command line.
  FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine);

  /// Returns the given compile command.
  ///
  /// Will always return a vector with one entry that contains the directory
  /// and command line specified at construction with "clang-tool" as argv[0]
  /// and 'FilePath' as positional argument.
  std::vector<CompileCommand>
  getCompileCommands(StringRef FilePath) const override;

private:
  /// This is built up to contain a single entry vector to be returned from
  /// getCompileCommands after adding the positional argument.
  std::vector<CompileCommand> CompileCommands;
};

/// Returns a wrapped CompilationDatabase that defers to the provided one,
/// but getCompileCommands() will infer commands for unknown files.
/// The return value of getAllFiles() or getAllCompileCommands() is unchanged.
/// See InterpolatingCompilationDatabase.cpp for details on heuristics.
std::unique_ptr<CompilationDatabase>
    inferMissingCompileCommands(std::unique_ptr<CompilationDatabase>);

/// Returns a wrapped CompilationDatabase that will add -target and -mode flags
/// to commandline when they can be deduced from argv[0] of commandline returned
/// by underlying database.
std::unique_ptr<CompilationDatabase>
inferTargetAndDriverMode(std::unique_ptr<CompilationDatabase> Base);

} // namespace tooling
} // namespace clang

#endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASE_H