blob: a9ca7b462ec1ee0d3e8db204ffaca85c91ab9a8c [file] [log] [blame]
//===--- ConfigFragment.h - Unit of user-specified configuration -*- 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
//
//===----------------------------------------------------------------------===//
//
// Various clangd features have configurable behaviour (or can be disabled).
// The configuration system allows users to control this:
// - in a user config file, a project config file, via LSP, or via flags
// - specifying different settings for different files
//
// This file defines the config::Fragment structure which models one piece of
// configuration as obtained from a source like a file.
//
// This is distinct from how the config is interpreted (CompiledFragment),
// combined (Provider) and exposed to the rest of clangd (Config).
//
//===----------------------------------------------------------------------===//
//
// To add a new configuration option, you must:
// - add its syntactic form to Fragment
// - update ConfigYAML.cpp to parse it
// - add its semantic form to Config (in Config.h)
// - update ConfigCompile.cpp to map Fragment -> Config
// - make use of the option inside clangd
// - document the new option (config.md in the llvm/clangd-www repository)
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
#include "ConfigProvider.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
#include <string>
#include <vector>
namespace clang {
namespace clangd {
namespace config {
/// An entity written in config along, with its optional location in the file.
template <typename T> struct Located {
Located(T Value, llvm::SMRange Range = {})
: Range(Range), Value(std::move(Value)) {}
llvm::SMRange Range;
T *operator->() { return &Value; }
const T *operator->() const { return &Value; }
T &operator*() { return Value; }
const T &operator*() const { return Value; }
private:
T Value;
};
/// A chunk of configuration obtained from a config file, LSP, or elsewhere.
struct Fragment {
/// Parses fragments from a YAML file (one from each --- delimited document).
/// Documents that contained fatal errors are omitted from the results.
/// BufferName is used for the SourceMgr and diagnostics.
static std::vector<Fragment> parseYAML(llvm::StringRef YAML,
llvm::StringRef BufferName,
DiagnosticCallback);
/// Analyzes and consumes this fragment, possibly yielding more diagnostics.
/// This always produces a usable result (errors are recovered).
///
/// Typically, providers will compile a Fragment once when it's first loaded,
/// caching the result for reuse.
/// Like a compiled program, this is good for performance and also encourages
/// errors to be reported early and only once.
///
/// The returned function is a cheap-copyable wrapper of refcounted internals.
CompiledFragment compile(DiagnosticCallback) &&;
/// These fields are not part of the user-specified configuration, but
/// instead are populated by the parser to describe the configuration source.
struct SourceInfo {
/// Retains a buffer of the original source this fragment was parsed from.
/// Locations within Located<T> objects point into this SourceMgr.
/// Shared because multiple fragments are often parsed from one (YAML) file.
/// May be null, then all locations should be ignored.
std::shared_ptr<llvm::SourceMgr> Manager;
/// The start of the original source for this fragment.
/// Only valid if SourceManager is set.
llvm::SMLoc Location;
/// Absolute path to directory the fragment is associated with. Relative
/// paths mentioned in the fragment are resolved against this.
std::string Directory;
/// Whether this fragment is allowed to make critical security/privacy
/// decisions.
bool Trusted = false;
};
SourceInfo Source;
/// Conditions in the If block restrict when a Fragment applies.
///
/// Each separate condition must match (combined with AND).
/// When one condition has multiple values, any may match (combined with OR).
/// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory.
///
/// Conditions based on a file's path use the following form:
/// - if the fragment came from a project directory, the path is relative
/// - if the fragment is global (e.g. user config), the path is absolute
/// - paths always use forward-slashes (UNIX-style)
/// If no file is being processed, these conditions will not match.
struct IfBlock {
/// The file being processed must fully match a regular expression.
std::vector<Located<std::string>> PathMatch;
/// The file being processed must *not* fully match a regular expression.
std::vector<Located<std::string>> PathExclude;
/// An unrecognized key was found while parsing the condition.
/// The condition will evaluate to false.
bool HasUnrecognizedCondition = false;
};
IfBlock If;
/// Conditions in the CompileFlags block affect how a file is parsed.
///
/// clangd emulates how clang would interpret a file.
/// By default, it behaves roughly like `clang $FILENAME`, but real projects
/// usually require setting the include path (with the `-I` flag), defining
/// preprocessor symbols, configuring warnings etc.
/// Often, a compilation database specifies these compile commands. clangd
/// searches for compile_commands.json in parents of the source file.
///
/// This section modifies how the compile command is constructed.
struct CompileFlagsBlock {
/// List of flags to append to the compile command.
std::vector<Located<std::string>> Add;
/// List of flags to remove from the compile command.
///
/// - If the value is a recognized clang flag (like "-I") then it will be
/// removed along with any arguments. Synonyms like --include-dir= will
/// also be removed.
/// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument
/// with the prefix will be removed.
/// - Otherwise any argument exactly matching the value is removed.
///
/// In all cases, -Xclang is also removed where needed.
///
/// Example:
/// Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc
/// Remove: [-I, -DFOO=*]
/// Result: clang++ foo.cc
///
/// Flags added by the same CompileFlags entry will not be removed.
std::vector<Located<std::string>> Remove;
/// Directory to search for compilation database (compile_comands.json etc).
/// Valid values are:
/// - A single path to a directory (absolute, or relative to the fragment)
/// - Ancestors: search all parent directories (the default)
/// - None: do not use a compilation database, just default flags.
llvm::Optional<Located<std::string>> CompilationDatabase;
};
CompileFlagsBlock CompileFlags;
/// Controls how clangd understands code outside the current file.
/// clangd's indexes provide information about symbols that isn't available
/// to clang's parser, such as incoming references.
struct IndexBlock {
/// Whether files are built in the background to produce a project index.
/// This is checked for translation units only, not headers they include.
/// Legal values are "Build" or "Skip".
llvm::Optional<Located<std::string>> Background;
/// An external index uses data source outside of clangd itself. This is
/// usually prepared using clangd-indexer.
/// Exactly one source (File/Server) should be configured.
struct ExternalBlock {
/// Whether the block is explicitly set to `None`. Can be used to clear
/// any external index specified before.
Located<bool> IsNone = false;
/// Path to an index file generated by clangd-indexer. Relative paths may
/// be used, if config fragment is associated with a directory.
llvm::Optional<Located<std::string>> File;
/// Address and port number for a clangd-index-server. e.g.
/// `123.1.1.1:13337`.
llvm::Optional<Located<std::string>> Server;
/// Source root governed by this index. Default is the directory
/// associated with the config fragment. Absolute in case of user config
/// and relative otherwise. Should always use forward-slashes.
llvm::Optional<Located<std::string>> MountPoint;
};
llvm::Optional<Located<ExternalBlock>> External;
};
IndexBlock Index;
/// Controls behavior of diagnostics (errors and warnings).
struct DiagnosticsBlock {
/// Diagnostic codes that should be suppressed.
///
/// Valid values are:
/// - *, to disable all diagnostics
/// - diagnostic codes exposed by clangd (e.g unknown_type, -Wunused-result)
/// - clang internal diagnostic codes (e.g. err_unknown_type)
/// - warning categories (e.g. unused-result)
/// - clang-tidy check names (e.g. bugprone-narrowing-conversions)
///
/// This is a simple filter. Diagnostics can be controlled in other ways
/// (e.g. by disabling a clang-tidy check, or the -Wunused compile flag).
/// This often has other advantages, such as skipping some analysis.
std::vector<Located<std::string>> Suppress;
/// Controls how clangd will correct "unnecessary #include directives.
/// clangd can warn if a header is `#include`d but not used, and suggest
/// removing it.
//
/// Strict means a header is unused if it does not *directly* provide any
/// symbol used in the file. Removing it may still break compilation if it
/// transitively includes headers that are used. This should be fixed by
/// including those headers directly.
///
/// Valid values are:
/// - Strict
/// - None
llvm::Optional<Located<std::string>> UnusedIncludes;
/// Controls how clang-tidy will run over the code base.
///
/// The settings are merged with any settings found in .clang-tidy
/// configiration files with these ones taking precedence.
struct ClangTidyBlock {
std::vector<Located<std::string>> Add;
/// List of checks to disable.
/// Takes precedence over Add. To enable all llvm checks except include
/// order:
/// Add: llvm-*
/// Remove: llvm-include-onder
std::vector<Located<std::string>> Remove;
/// A Key-Value pair list of options to pass to clang-tidy checks
/// These take precedence over options specified in clang-tidy
/// configuration files. Example:
/// CheckOptions:
/// readability-braces-around-statements.ShortStatementLines: 2
std::vector<std::pair<Located<std::string>, Located<std::string>>>
CheckOptions;
};
ClangTidyBlock ClangTidy;
};
DiagnosticsBlock Diagnostics;
// Describes the style of the codebase, beyond formatting.
struct StyleBlock {
// Namespaces that should always be fully qualified, meaning no "using"
// declarations, always spell out the whole name (with or without leading
// ::). All nested namespaces are affected as well.
// Affects availability of the AddUsing tweak.
std::vector<Located<std::string>> FullyQualifiedNamespaces;
};
StyleBlock Style;
/// Describes code completion preferences.
struct CompletionBlock {
/// Whether code completion should include suggestions from scopes that are
/// not visible. The required scope prefix will be inserted.
llvm::Optional<Located<bool>> AllScopes;
};
CompletionBlock Completion;
};
} // namespace config
} // namespace clangd
} // namespace clang
#endif