blob: 0e4ce638fc72f4c30dd7ed492015797e1c460503 [file] [log] [blame]
Sam McCalle9fb1502020-06-23 17:21:56 +02001//===--- ConfigFragment.h - Unit of user-specified configuration -*- 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// Various clangd features have configurable behaviour (or can be disabled).
10// The configuration system allows users to control this:
11// - in a user config file, a project config file, via LSP, or via flags
12// - specifying different settings for different files
13//
14// This file defines the config::Fragment structure which models one piece of
15// configuration as obtained from a source like a file.
16//
17// This is distinct from how the config is interpreted (CompiledFragment),
18// combined (Provider) and exposed to the rest of clangd (Config).
19//
20//===----------------------------------------------------------------------===//
21//
22// To add a new configuration option, you must:
23// - add its syntactic form to Fragment
24// - update ConfigYAML.cpp to parse it
25// - add its semantic form to Config (in Config.h)
26// - update ConfigCompile.cpp to map Fragment -> Config
27// - make use of the option inside clangd
28// - document the new option (config.md in the llvm/clangd-www repository)
29//
30//===----------------------------------------------------------------------===//
31
32#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
33#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
34
Sam McCallf12cd992020-06-26 01:49:53 +020035#include "ConfigProvider.h"
Sam McCalle9fb1502020-06-23 17:21:56 +020036#include "llvm/ADT/Optional.h"
37#include "llvm/ADT/STLExtras.h"
38#include "llvm/Support/Error.h"
39#include "llvm/Support/SMLoc.h"
40#include "llvm/Support/SourceMgr.h"
41#include <string>
42#include <vector>
43
44namespace clang {
45namespace clangd {
46namespace config {
47
48/// An entity written in config along, with its optional location in the file.
49template <typename T> struct Located {
50 Located(T Value, llvm::SMRange Range = {})
51 : Range(Range), Value(std::move(Value)) {}
52
53 llvm::SMRange Range;
Nathan Jamescb9d0e82020-11-04 01:36:13 +000054 T *operator->() { return &Value; }
55 const T *operator->() const { return &Value; }
Sam McCalle9fb1502020-06-23 17:21:56 +020056 T &operator*() { return Value; }
57 const T &operator*() const { return Value; }
58
59private:
60 T Value;
61};
62
Sam McCalle9fb1502020-06-23 17:21:56 +020063/// A chunk of configuration obtained from a config file, LSP, or elsewhere.
64struct Fragment {
65 /// Parses fragments from a YAML file (one from each --- delimited document).
66 /// Documents that contained fatal errors are omitted from the results.
67 /// BufferName is used for the SourceMgr and diagnostics.
68 static std::vector<Fragment> parseYAML(llvm::StringRef YAML,
69 llvm::StringRef BufferName,
70 DiagnosticCallback);
71
Sam McCallf12cd992020-06-26 01:49:53 +020072 /// Analyzes and consumes this fragment, possibly yielding more diagnostics.
73 /// This always produces a usable result (errors are recovered).
74 ///
75 /// Typically, providers will compile a Fragment once when it's first loaded,
76 /// caching the result for reuse.
77 /// Like a compiled program, this is good for performance and also encourages
78 /// errors to be reported early and only once.
79 ///
80 /// The returned function is a cheap-copyable wrapper of refcounted internals.
81 CompiledFragment compile(DiagnosticCallback) &&;
82
Sam McCalle9fb1502020-06-23 17:21:56 +020083 /// These fields are not part of the user-specified configuration, but
84 /// instead are populated by the parser to describe the configuration source.
85 struct SourceInfo {
86 /// Retains a buffer of the original source this fragment was parsed from.
87 /// Locations within Located<T> objects point into this SourceMgr.
88 /// Shared because multiple fragments are often parsed from one (YAML) file.
89 /// May be null, then all locations should be ignored.
90 std::shared_ptr<llvm::SourceMgr> Manager;
91 /// The start of the original source for this fragment.
92 /// Only valid if SourceManager is set.
93 llvm::SMLoc Location;
Kadir Cetinkaya7f059a22020-10-27 23:03:41 +010094 /// Absolute path to directory the fragment is associated with. Relative
95 /// paths mentioned in the fragment are resolved against this.
96 std::string Directory;
Sam McCalle9fb1502020-06-23 17:21:56 +020097 };
98 SourceInfo Source;
99
Sam McCallf12cd992020-06-26 01:49:53 +0200100 /// Conditions in the If block restrict when a Fragment applies.
Sam McCalle9fb1502020-06-23 17:21:56 +0200101 ///
102 /// Each separate condition must match (combined with AND).
103 /// When one condition has multiple values, any may match (combined with OR).
Sam McCallf12cd992020-06-26 01:49:53 +0200104 /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory.
Sam McCalle9fb1502020-06-23 17:21:56 +0200105 ///
106 /// Conditions based on a file's path use the following form:
107 /// - if the fragment came from a project directory, the path is relative
108 /// - if the fragment is global (e.g. user config), the path is absolute
109 /// - paths always use forward-slashes (UNIX-style)
110 /// If no file is being processed, these conditions will not match.
Sam McCallf12cd992020-06-26 01:49:53 +0200111 struct IfBlock {
Sam McCalle9fb1502020-06-23 17:21:56 +0200112 /// The file being processed must fully match a regular expression.
113 std::vector<Located<std::string>> PathMatch;
Sam McCall86f13132020-07-09 23:33:46 +0200114 /// The file being processed must *not* fully match a regular expression.
115 std::vector<Located<std::string>> PathExclude;
116
Sam McCalle9fb1502020-06-23 17:21:56 +0200117 /// An unrecognized key was found while parsing the condition.
118 /// The condition will evaluate to false.
119 bool HasUnrecognizedCondition = false;
120 };
Sam McCallf12cd992020-06-26 01:49:53 +0200121 IfBlock If;
Sam McCalle9fb1502020-06-23 17:21:56 +0200122
Sam McCall6c16fbd2020-07-13 20:37:54 +0200123 /// Conditions in the CompileFlags block affect how a file is parsed.
124 ///
125 /// clangd emulates how clang would interpret a file.
126 /// By default, it behaves roughly like `clang $FILENAME`, but real projects
127 /// usually require setting the include path (with the `-I` flag), defining
128 /// preprocessor symbols, configuring warnings etc.
129 /// Often, a compilation database specifies these compile commands. clangd
130 /// searches for compile_commands.json in parents of the source file.
131 ///
132 /// This section modifies how the compile command is constructed.
Sam McCalle9fb1502020-06-23 17:21:56 +0200133 struct CompileFlagsBlock {
Sam McCall6c16fbd2020-07-13 20:37:54 +0200134 /// List of flags to append to the compile command.
Sam McCalle9fb1502020-06-23 17:21:56 +0200135 std::vector<Located<std::string>> Add;
Sam McCall6c16fbd2020-07-13 20:37:54 +0200136 /// List of flags to remove from the compile command.
137 ///
138 /// - If the value is a recognized clang flag (like "-I") then it will be
139 /// removed along with any arguments. Synonyms like --include-dir= will
140 /// also be removed.
141 /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument
142 /// with the prefix will be removed.
143 /// - Otherwise any argument exactly matching the value is removed.
144 ///
145 /// In all cases, -Xclang is also removed where needed.
146 ///
147 /// Example:
148 /// Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc
149 /// Remove: [-I, -DFOO=*]
150 /// Result: clang++ foo.cc
151 ///
152 /// Flags added by the same CompileFlags entry will not be removed.
153 std::vector<Located<std::string>> Remove;
154 };
155 CompileFlagsBlock CompileFlags;
Sam McCalldbf486c2020-07-14 15:17:16 +0200156
157 /// Controls how clangd understands code outside the current file.
158 /// clangd's indexes provide information about symbols that isn't available
159 /// to clang's parser, such as incoming references.
160 struct IndexBlock {
161 /// Whether files are built in the background to produce a project index.
162 /// This is checked for translation units only, not headers they include.
163 /// Legal values are "Build" or "Skip".
164 llvm::Optional<Located<std::string>> Background;
Kadir Cetinkaya359e2f92020-10-01 12:29:55 +0100165 /// An external index uses data source outside of clangd itself. This is
166 /// usually prepared using clangd-indexer.
167 /// Exactly one source (File/Server) should be configured.
168 struct ExternalBlock {
169 /// Path to an index file generated by clangd-indexer. Relative paths may
170 /// be used, if config fragment is associated with a directory.
171 llvm::Optional<Located<std::string>> File;
172 /// Address and port number for a clangd-index-server. e.g.
173 /// `123.1.1.1:13337`.
174 llvm::Optional<Located<std::string>> Server;
175 /// Source root governed by this index. Default is the directory
176 /// associated with the config fragment. Absolute in case of user config
177 /// and relative otherwise. Should always use forward-slashes.
178 llvm::Optional<Located<std::string>> MountPoint;
179 };
180 llvm::Optional<Located<ExternalBlock>> External;
Sam McCalldbf486c2020-07-14 15:17:16 +0200181 };
182 IndexBlock Index;
Adam Czachorowskic894bfd2020-09-15 19:47:50 +0200183
184 // Describes the style of the codebase, beyond formatting.
185 struct StyleBlock {
186 // Namespaces that should always be fully qualified, meaning no "using"
187 // declarations, always spell out the whole name (with or without leading
188 // ::). All nested namespaces are affected as well.
189 // Affects availability of the AddUsing tweak.
190 std::vector<Located<std::string>> FullyQualifiedNamespaces;
191 };
192 StyleBlock Style;
Nathan James20b69af2020-11-22 10:04:00 +0000193
194 /// Controls how clang-tidy will run over the code base.
195 ///
196 /// The settings are merged with any settings found in .clang-tidy
197 /// configiration files with these ones taking precedence.
198 struct ClangTidyBlock {
199 std::vector<Located<std::string>> Add;
200 /// List of checks to disable.
201 /// Takes precedence over Add. To enable all llvm checks except include
202 /// order:
203 /// Add: llvm-*
204 /// Remove: llvm-include-onder
205 std::vector<Located<std::string>> Remove;
206
207 /// A Key-Value pair list of options to pass to clang-tidy checks
208 /// These take precedence over options specified in clang-tidy configuration
209 /// files. Example:
210 /// CheckOptions:
211 /// readability-braces-around-statements.ShortStatementLines: 2
212 std::vector<std::pair<Located<std::string>, Located<std::string>>>
213 CheckOptions;
214 };
215 ClangTidyBlock ClangTidy;
Sam McCalle9fb1502020-06-23 17:21:56 +0200216};
217
218} // namespace config
219} // namespace clangd
220} // namespace clang
221
222#endif