@@ -27,6 +27,13 @@ class CompilerInstance;
2727
2828namespace tidy {
2929
30+ // / This class should be specialized by any enum type that needs to be converted
31+ // / to and from an \ref llvm::StringRef.
32+ template <class T > struct OptionEnumMapping {
33+ // Specializations of this struct must implement this function.
34+ static ArrayRef<std::pair<T, StringRef>> getEnumMapping () = delete;
35+ };
36+
3037template <typename T> class OptionError : public llvm ::ErrorInfo<T> {
3138 std::error_code convertToErrorCode () const override {
3239 return llvm::inconvertibleErrorCode ();
@@ -313,77 +320,80 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
313320 }
314321
315322 // / Read a named option from the ``Context`` and parse it as an
316- // / enum type ``T`` using the \p Mapping provided. If \p IgnoreCase is set,
317- // / it will search the mapping ignoring the case.
323+ // / enum type ``T``.
318324 // /
319325 // / Reads the option with the check-local name \p LocalName from the
320326 // / ``CheckOptions``. If the corresponding key is not present, returns a
321327 // / ``MissingOptionError``. If the key can't be parsed as a ``T`` returns a
322328 // / ``UnparseableEnumOptionError``.
329+ // /
330+ // / \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
331+ // / supply the mapping required to convert between ``T`` and a string.
323332 template <typename T>
324333 std::enable_if_t <std::is_enum<T>::value, llvm::Expected<T>>
325- get (StringRef LocalName, ArrayRef<std::pair<StringRef, T>> Mapping,
326- bool IgnoreCase = false ) {
327- if (llvm::Expected<int64_t > ValueOr = getEnumInt (
328- LocalName, typeEraseMapping (Mapping), false , IgnoreCase))
334+ get (StringRef LocalName, bool IgnoreCase = false ) {
335+ if (llvm::Expected<int64_t > ValueOr =
336+ getEnumInt (LocalName, typeEraseMapping<T>(), false , IgnoreCase))
329337 return static_cast <T>(*ValueOr);
330338 else
331339 return std::move (ValueOr.takeError ());
332340 }
333341
334342 // / Read a named option from the ``Context`` and parse it as an
335- // / enum type ``T`` using the \p Mapping provided. If \p IgnoreCase is set,
336- // / it will search the mapping ignoring the case.
343+ // / enum type ``T``.
337344 // /
338345 // / Reads the option with the check-local name \p LocalName from the
339346 // / ``CheckOptions``. If the corresponding key is not present or it can't be
340347 // / parsed as a ``T``, returns \p Default.
348+ // /
349+ // / \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
350+ // / supply the mapping required to convert between ``T`` and a string.
341351 template <typename T>
342352 std::enable_if_t <std::is_enum<T>::value, T>
343- get (StringRef LocalName, ArrayRef<std::pair<StringRef, T>> Mapping,
344- T Default, bool IgnoreCase = false ) {
345- if (auto ValueOr = get (LocalName, Mapping, IgnoreCase))
353+ get (StringRef LocalName, T Default, bool IgnoreCase = false ) {
354+ if (auto ValueOr = get<T>(LocalName, IgnoreCase))
346355 return *ValueOr;
347356 else
348357 logErrToStdErr (ValueOr.takeError ());
349358 return Default;
350359 }
351360
352361 // / Read a named option from the ``Context`` and parse it as an
353- // / enum type ``T`` using the \p Mapping provided. If \p IgnoreCase is set,
354- // / it will search the mapping ignoring the case.
362+ // / enum type ``T``.
355363 // /
356364 // / Reads the option with the check-local name \p LocalName from local or
357365 // / global ``CheckOptions``. Gets local option first. If local is not
358366 // / present, falls back to get global option. If global option is not
359367 // / present either, returns a ``MissingOptionError``. If the key can't be
360368 // / parsed as a ``T`` returns a ``UnparseableEnumOptionError``.
369+ // /
370+ // / \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
371+ // / supply the mapping required to convert between ``T`` and a string.
361372 template <typename T>
362373 std::enable_if_t <std::is_enum<T>::value, llvm::Expected<T>>
363374 getLocalOrGlobal (StringRef LocalName,
364- ArrayRef<std::pair<StringRef, T>> Mapping,
365375 bool IgnoreCase = false ) {
366- if (llvm::Expected<int64_t > ValueOr = getEnumInt (
367- LocalName, typeEraseMapping (Mapping ), true , IgnoreCase))
376+ if (llvm::Expected<int64_t > ValueOr =
377+ getEnumInt ( LocalName, typeEraseMapping<T>( ), true , IgnoreCase))
368378 return static_cast <T>(*ValueOr);
369379 else
370380 return std::move (ValueOr.takeError ());
371381 }
372382
373383 // / Read a named option from the ``Context`` and parse it as an
374- // / enum type ``T`` using the \p Mapping provided. If \p IgnoreCase is set,
375- // / it will search the mapping ignoring the case.
384+ // / enum type ``T``.
376385 // /
377386 // / Reads the option with the check-local name \p LocalName from local or
378387 // / global ``CheckOptions``. Gets local option first. If local is not
379388 // / present, falls back to get global option. If global option is not
380389 // / present either or it can't be parsed as a ``T``, returns \p Default.
390+ // /
391+ // / \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
392+ // / supply the mapping required to convert between ``T`` and a string.
381393 template <typename T>
382394 std::enable_if_t <std::is_enum<T>::value, T>
383- getLocalOrGlobal (StringRef LocalName,
384- ArrayRef<std::pair<StringRef, T>> Mapping, T Default,
385- bool IgnoreCase = false ) {
386- if (auto ValueOr = getLocalOrGlobal (LocalName, Mapping, IgnoreCase))
395+ getLocalOrGlobal (StringRef LocalName, T Default, bool IgnoreCase = false ) {
396+ if (auto ValueOr = getLocalOrGlobal<T>(LocalName, IgnoreCase))
387397 return *ValueOr;
388398 else
389399 logErrToStdErr (ValueOr.takeError ());
@@ -401,34 +411,40 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
401411 int64_t Value) const ;
402412
403413 // / Stores an option with the check-local name \p LocalName as the string
404- // / representation of the Enum \p Value using the \p Mapping to \p Options.
414+ // / representation of the Enum \p Value to \p Options.
415+ // /
416+ // / \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
417+ // / supply the mapping required to convert between ``T`` and a string.
405418 template <typename T>
406419 std::enable_if_t <std::is_enum<T>::value>
407- store (ClangTidyOptions::OptionMap &Options, StringRef LocalName, T Value,
408- ArrayRef<std::pair<StringRef, T>> Mapping) {
420+ store (ClangTidyOptions::OptionMap &Options, StringRef LocalName, T Value) {
421+ ArrayRef<std::pair<T, StringRef>> Mapping =
422+ OptionEnumMapping<T>::getEnumMapping ();
409423 auto Iter = llvm::find_if (
410- Mapping, [&](const std::pair<StringRef, T > &NameAndEnum) {
411- return NameAndEnum.second == Value;
424+ Mapping, [&](const std::pair<T, StringRef > &NameAndEnum) {
425+ return NameAndEnum.first == Value;
412426 });
413427 assert (Iter != Mapping.end () && " Unknown Case Value" );
414- store (Options, LocalName, Iter->first );
428+ store (Options, LocalName, Iter->second );
415429 }
416430
417431 private:
418- using NameAndValue = std::pair<StringRef, int64_t >;
432+ using NameAndValue = std::pair<int64_t , StringRef >;
419433
420434 llvm::Expected<int64_t > getEnumInt (StringRef LocalName,
421435 ArrayRef<NameAndValue> Mapping,
422436 bool CheckGlobal, bool IgnoreCase);
423437
424438 template <typename T>
425439 std::enable_if_t <std::is_enum<T>::value, std::vector<NameAndValue>>
426- typeEraseMapping (ArrayRef<std::pair<StringRef, T>> Mapping) {
440+ typeEraseMapping () {
441+ ArrayRef<std::pair<T, StringRef>> Mapping =
442+ OptionEnumMapping<T>::getEnumMapping ();
427443 std::vector<NameAndValue> Result;
428444 Result.reserve (Mapping.size ());
429445 for (auto &MappedItem : Mapping) {
430- Result.emplace_back (MappedItem.first ,
431- static_cast < int64_t >( MappedItem.second ) );
446+ Result.emplace_back (static_cast < int64_t >( MappedItem.first ) ,
447+ MappedItem.second );
432448 }
433449 return Result;
434450 }
0 commit comments