• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- 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 
35 #include "ConfigProvider.h"
36 #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 
44 namespace clang {
45 namespace clangd {
46 namespace config {
47 
48 /// An entity written in config along, with its optional location in the file.
49 template <typename T> struct Located {
50   Located(T Value, llvm::SMRange Range = {})
RangeLocated51       : Range(Range), Value(std::move(Value)) {}
52 
53   llvm::SMRange Range;
54   T *operator->() { return &Value; }
55   const T *operator->() const { return &Value; }
56   T &operator*() { return Value; }
57   const T &operator*() const { return Value; }
58 
59 private:
60   T Value;
61 };
62 
63 /// A chunk of configuration obtained from a config file, LSP, or elsewhere.
64 struct 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 
72   /// 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 
83   /// 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;
94     /// Absolute path to directory the fragment is associated with. Relative
95     /// paths mentioned in the fragment are resolved against this.
96     std::string Directory;
97   };
98   SourceInfo Source;
99 
100   /// Conditions in the If block restrict when a Fragment applies.
101   ///
102   /// Each separate condition must match (combined with AND).
103   /// When one condition has multiple values, any may match (combined with OR).
104   /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory.
105   ///
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.
111   struct IfBlock {
112     /// The file being processed must fully match a regular expression.
113     std::vector<Located<std::string>> PathMatch;
114     /// The file being processed must *not* fully match a regular expression.
115     std::vector<Located<std::string>> PathExclude;
116 
117     /// An unrecognized key was found while parsing the condition.
118     /// The condition will evaluate to false.
119     bool HasUnrecognizedCondition = false;
120   };
121   IfBlock If;
122 
123   /// 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.
133   struct CompileFlagsBlock {
134     /// List of flags to append to the compile command.
135     std::vector<Located<std::string>> Add;
136     /// 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;
156 
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;
165     /// 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;
181   };
182   IndexBlock Index;
183 
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;
193 
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;
216 };
217 
218 } // namespace config
219 } // namespace clangd
220 } // namespace clang
221 
222 #endif
223