Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame^] | 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 "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 | |
| 43 | namespace clang { |
| 44 | namespace clangd { |
| 45 | namespace config { |
| 46 | |
| 47 | /// An entity written in config along, with its optional location in the file. |
| 48 | template <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 | |
| 58 | private: |
| 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. |
| 65 | using DiagnosticCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>; |
| 66 | |
| 67 | /// A chunk of configuration obtained from a config file, LSP, or elsewhere. |
| 68 | struct 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 |