blob: 2cb646757e17d7b9365208d0f683d60ba7195ba8 [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
35#include "llvm/ADT/Optional.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/Support/Error.h"
38#include "llvm/Support/SMLoc.h"
39#include "llvm/Support/SourceMgr.h"
40#include <string>
41#include <vector>
42
43namespace clang {
44namespace clangd {
45namespace config {
46
47/// An entity written in config along, with its optional location in the file.
48template <typename T> struct Located {
49 Located(T Value, llvm::SMRange Range = {})
50 : Range(Range), Value(std::move(Value)) {}
51
52 llvm::SMRange Range;
53 T &operator->() { return Value; }
54 const T &operator->() const { return Value; }
55 T &operator*() { return Value; }
56 const T &operator*() const { return Value; }
57
58private:
59 T Value;
60};
61
62/// Used to report problems in parsing or interpreting a config.
63/// Errors reflect structurally invalid config that should be user-visible.
64/// Warnings reflect e.g. unknown properties that are recoverable.
65using DiagnosticCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>;
66
67/// A chunk of configuration obtained from a config file, LSP, or elsewhere.
68struct Fragment {
69 /// Parses fragments from a YAML file (one from each --- delimited document).
70 /// Documents that contained fatal errors are omitted from the results.
71 /// BufferName is used for the SourceMgr and diagnostics.
72 static std::vector<Fragment> parseYAML(llvm::StringRef YAML,
73 llvm::StringRef BufferName,
74 DiagnosticCallback);
75
76 /// These fields are not part of the user-specified configuration, but
77 /// instead are populated by the parser to describe the configuration source.
78 struct SourceInfo {
79 /// Retains a buffer of the original source this fragment was parsed from.
80 /// Locations within Located<T> objects point into this SourceMgr.
81 /// Shared because multiple fragments are often parsed from one (YAML) file.
82 /// May be null, then all locations should be ignored.
83 std::shared_ptr<llvm::SourceMgr> Manager;
84 /// The start of the original source for this fragment.
85 /// Only valid if SourceManager is set.
86 llvm::SMLoc Location;
87 };
88 SourceInfo Source;
89
90 /// Conditions restrict when a Fragment applies.
91 ///
92 /// Each separate condition must match (combined with AND).
93 /// When one condition has multiple values, any may match (combined with OR).
94 ///
95 /// Conditions based on a file's path use the following form:
96 /// - if the fragment came from a project directory, the path is relative
97 /// - if the fragment is global (e.g. user config), the path is absolute
98 /// - paths always use forward-slashes (UNIX-style)
99 /// If no file is being processed, these conditions will not match.
100 struct ConditionBlock {
101 /// The file being processed must fully match a regular expression.
102 std::vector<Located<std::string>> PathMatch;
103 /// An unrecognized key was found while parsing the condition.
104 /// The condition will evaluate to false.
105 bool HasUnrecognizedCondition = false;
106 };
107 ConditionBlock Condition;
108
109 struct CompileFlagsBlock {
110 std::vector<Located<std::string>> Add;
111 } CompileFlags;
112};
113
114} // namespace config
115} // namespace clangd
116} // namespace clang
117
118#endif