1 //===--- ClangTidyOptions.h - clang-tidy ------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
11 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
12 
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/IntrusiveRefCntPtr.h"
17 #include "llvm/Support/ErrorOr.h"
18 #include "clang/Basic/VirtualFileSystem.h"
19 #include <functional>
20 #include <map>
21 #include <string>
22 #include <system_error>
23 #include <utility>
24 #include <vector>
25 
26 namespace clang {
27 namespace tidy {
28 
29 /// \brief Contains a list of line ranges in a single file.
30 struct FileFilter {
31   /// \brief File name.
32   std::string Name;
33 
34   /// \brief LineRange is a pair<start, end> (inclusive).
35   typedef std::pair<unsigned, unsigned> LineRange;
36 
37   /// \brief A list of line ranges in this file, for which we show warnings.
38   std::vector<LineRange> LineRanges;
39 };
40 
41 /// \brief Global options. These options are neither stored nor read from
42 /// configuration files.
43 struct ClangTidyGlobalOptions {
44   /// \brief Output warnings from certain line ranges of certain files only.
45   /// If empty, no warnings will be filtered.
46   std::vector<FileFilter> LineFilter;
47 };
48 
49 /// \brief Contains options for clang-tidy. These options may be read from
50 /// configuration files, and may be different for different translation units.
51 struct ClangTidyOptions {
52   /// \brief These options are used for all settings that haven't been
53   /// overridden by the \c OptionsProvider.
54   ///
55   /// Allow no checks and no headers by default. This method initializes
56   /// check-specific options by calling \c ClangTidyModule::getModuleOptions()
57   /// of each registered \c ClangTidyModule.
58   static ClangTidyOptions getDefaults();
59 
60   /// \brief Creates a new \c ClangTidyOptions instance combined from all fields
61   /// of this instance overridden by the fields of \p Other that have a value.
62   ClangTidyOptions mergeWith(const ClangTidyOptions &Other) const;
63 
64   /// \brief Checks filter.
65   llvm::Optional<std::string> Checks;
66 
67   /// \brief WarningsAsErrors filter.
68   llvm::Optional<std::string> WarningsAsErrors;
69 
70   /// \brief Output warnings from headers matching this filter. Warnings from
71   /// main files will always be displayed.
72   llvm::Optional<std::string> HeaderFilterRegex;
73 
74   /// \brief Output warnings from system headers matching \c HeaderFilterRegex.
75   llvm::Optional<bool> SystemHeaders;
76 
77   /// \brief Format code around applied fixes with clang-format using this
78   /// style.
79   ///
80   /// Can be one of:
81   ///   * 'none' - don't format code around applied fixes;
82   ///   * 'llvm', 'google', 'mozilla' or other predefined clang-format style
83   ///     names;
84   ///   * 'file' - use the .clang-format file in the closest parent directory of
85   ///     each source file;
86   ///   * '{inline-formatting-style-in-yaml-format}'.
87   ///
88   /// See clang-format documentation for more about configuring format style.
89   llvm::Optional<std::string> FormatStyle;
90 
91   /// \brief Specifies the name or e-mail of the user running clang-tidy.
92   ///
93   /// This option is used, for example, to place the correct user name in TODO()
94   /// comments in the relevant check.
95   llvm::Optional<std::string> User;
96 
97   typedef std::pair<std::string, std::string> StringPair;
98   typedef std::map<std::string, std::string> OptionMap;
99 
100   /// \brief Key-value mapping used to store check-specific options.
101   OptionMap CheckOptions;
102 
103   typedef std::vector<std::string> ArgList;
104 
105   /// \brief Add extra compilation arguments to the end of the list.
106   llvm::Optional<ArgList> ExtraArgs;
107 
108   /// \brief Add extra compilation arguments to the start of the list.
109   llvm::Optional<ArgList> ExtraArgsBefore;
110 };
111 
112 /// \brief Abstract interface for retrieving various ClangTidy options.
113 class ClangTidyOptionsProvider {
114 public:
115   static const char OptionsSourceTypeDefaultBinary[];
116   static const char OptionsSourceTypeCheckCommandLineOption[];
117   static const char OptionsSourceTypeConfigCommandLineOption[];
118 
~ClangTidyOptionsProvider()119   virtual ~ClangTidyOptionsProvider() {}
120 
121   /// \brief Returns global options, which are independent of the file.
122   virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
123 
124   /// \brief ClangTidyOptions and its source.
125   //
126   /// clang-tidy has 3 types of the sources in order of increasing priority:
127   ///    * clang-tidy binary.
128   ///    * '-config' commandline option or a specific configuration file. If the
129   ///       commandline option is specified, clang-tidy will ignore the
130   ///       configuration file.
131   ///    * '-checks' commandline option.
132   typedef std::pair<ClangTidyOptions, std::string> OptionsSource;
133 
134   /// \brief Returns an ordered vector of OptionsSources, in order of increasing
135   /// priority.
136   virtual std::vector<OptionsSource>
137   getRawOptions(llvm::StringRef FileName) = 0;
138 
139   /// \brief Returns options applying to a specific translation unit with the
140   /// specified \p FileName.
141   ClangTidyOptions getOptions(llvm::StringRef FileName);
142 };
143 
144 /// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
145 /// returns the same options for all files.
146 class DefaultOptionsProvider : public ClangTidyOptionsProvider {
147 public:
DefaultOptionsProvider(const ClangTidyGlobalOptions & GlobalOptions,const ClangTidyOptions & Options)148   DefaultOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
149                          const ClangTidyOptions &Options)
150       : GlobalOptions(GlobalOptions), DefaultOptions(Options) {}
getGlobalOptions()151   const ClangTidyGlobalOptions &getGlobalOptions() override {
152     return GlobalOptions;
153   }
154   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
155 
156 private:
157   ClangTidyGlobalOptions GlobalOptions;
158   ClangTidyOptions DefaultOptions;
159 };
160 
161 /// \brief Implementation of ClangTidyOptions interface, which is used for
162 /// '-config' command-line option.
163 class ConfigOptionsProvider : public DefaultOptionsProvider {
164 public:
165   ConfigOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
166                         const ClangTidyOptions &DefaultOptions,
167                         const ClangTidyOptions &ConfigOptions,
168                         const ClangTidyOptions &OverrideOptions);
169   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
170 
171 private:
172   ClangTidyOptions ConfigOptions;
173   ClangTidyOptions OverrideOptions;
174 };
175 
176 /// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
177 /// tries to find a configuration file in the closest parent directory of each
178 /// source file.
179 ///
180 /// By default, files named ".clang-tidy" will be considered, and the
181 /// \c clang::tidy::parseConfiguration function will be used for parsing, but a
182 /// custom set of configuration file names and parsing functions can be
183 /// specified using the appropriate constructor.
184 class FileOptionsProvider : public DefaultOptionsProvider {
185 public:
186   // \brief A pair of configuration file base name and a function parsing
187   // configuration from text in the corresponding format.
188   typedef std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions>(
189                                      llvm::StringRef)>>
190       ConfigFileHandler;
191 
192   /// \brief Configuration file handlers listed in the order of priority.
193   ///
194   /// Custom configuration file formats can be supported by constructing the
195   /// list of handlers and passing it to the appropriate \c FileOptionsProvider
196   /// constructor. E.g. initialization of a \c FileOptionsProvider with support
197   /// of a custom configuration file format for files named ".my-tidy-config"
198   /// could look similar to this:
199   /// \code
200   /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers;
201   /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat);
202   /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
203   /// return llvm::make_unique<FileOptionsProvider>(
204   ///     GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers);
205   /// \endcode
206   ///
207   /// With the order of handlers shown above, the ".my-tidy-config" file would
208   /// take precedence over ".clang-tidy" if both reside in the same directory.
209   typedef std::vector<ConfigFileHandler> ConfigFileHandlers;
210 
211   /// \brief Initializes the \c FileOptionsProvider instance.
212   ///
213   /// \param GlobalOptions are just stored and returned to the caller of
214   /// \c getGlobalOptions.
215   ///
216   /// \param DefaultOptions are used for all settings not specified in a
217   /// configuration file.
218   ///
219   /// If any of the \param OverrideOptions fields are set, they will override
220   /// whatever options are read from the configuration file.
221   FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
222                       const ClangTidyOptions &DefaultOptions,
223                       const ClangTidyOptions &OverrideOptions,
224                       llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr);
225 
226   /// \brief Initializes the \c FileOptionsProvider instance with a custom set
227   /// of configuration file handlers.
228   ///
229   /// \param GlobalOptions are just stored and returned to the caller of
230   /// \c getGlobalOptions.
231   ///
232   /// \param DefaultOptions are used for all settings not specified in a
233   /// configuration file.
234   ///
235   /// If any of the \param OverrideOptions fields are set, they will override
236   /// whatever options are read from the configuration file.
237   ///
238   /// \param ConfigHandlers specifies a custom set of configuration file
239   /// handlers. Each handler is a pair of configuration file name and a function
240   /// that can parse configuration from this file type. The configuration files
241   /// in each directory are searched for in the order of appearance in
242   /// \p ConfigHandlers.
243   FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
244                       const ClangTidyOptions &DefaultOptions,
245                       const ClangTidyOptions &OverrideOptions,
246                       const ConfigFileHandlers &ConfigHandlers);
247 
248   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
249 
250 protected:
251   /// \brief Try to read configuration files from \p Directory using registered
252   /// \c ConfigHandlers.
253   llvm::Optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory);
254 
255   llvm::StringMap<OptionsSource> CachedOptions;
256   ClangTidyOptions OverrideOptions;
257   ConfigFileHandlers ConfigHandlers;
258   llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS;
259 };
260 
261 /// \brief Parses LineFilter from JSON and stores it to the \p Options.
262 std::error_code parseLineFilter(llvm::StringRef LineFilter,
263                                 ClangTidyGlobalOptions &Options);
264 
265 /// \brief Parses configuration from JSON and returns \c ClangTidyOptions or an
266 /// error.
267 llvm::ErrorOr<ClangTidyOptions> parseConfiguration(llvm::StringRef Config);
268 
269 /// \brief Serializes configuration to a YAML-encoded string.
270 std::string configurationAsText(const ClangTidyOptions &Options);
271 
272 } // end namespace tidy
273 } // end namespace clang
274 
275 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
276