77// ===----------------------------------------------------------------------===//
88
99#include " ClangTidyCheck.h"
10+ #include " llvm/ADT/SmallString.h"
11+ #include " llvm/ADT/StringRef.h"
12+ #include " llvm/Support/Error.h"
13+ #include " llvm/Support/raw_ostream.h"
1014
1115namespace clang {
1216namespace tidy {
1317
18+ char MissingOptionError::ID;
19+ char UnparseableEnumOptionError::ID;
20+ char UnparseableIntegerOptionError::ID;
21+
22+ std::string MissingOptionError::message () const {
23+ llvm::SmallString<128 > Buffer;
24+ llvm::raw_svector_ostream Output (Buffer);
25+ Output << " option not found '" << OptionName << ' \' ' ;
26+ return std::string (Buffer);
27+ }
28+
29+ std::string UnparseableEnumOptionError::message () const {
30+ llvm::SmallString<128 > Buffer;
31+ llvm::raw_svector_ostream Output (Buffer);
32+ Output << " invalid configuration value '" << LookupValue << " ' for option '"
33+ << LookupName << ' \' ' ;
34+ if (SuggestedValue)
35+ Output << " ; did you mean '" << *SuggestedValue << " '?" ;
36+ return std::string (Buffer);
37+ }
38+
39+ std::string UnparseableIntegerOptionError::message () const {
40+ llvm::SmallString<128 > Buffer;
41+ llvm::raw_svector_ostream Output (Buffer);
42+ Output << " invalid configuration value '" << LookupValue << " ' for option '"
43+ << LookupName << " '; expected "
44+ << (IsBoolean ? " a bool" : " an integer value" );
45+ return std::string (Buffer);
46+ }
47+
1448ClangTidyCheck::ClangTidyCheck (StringRef CheckName, ClangTidyContext *Context)
1549 : CheckName(CheckName), Context(Context),
1650 Options (CheckName, Context->getOptions ().CheckOptions) {
@@ -34,25 +68,82 @@ ClangTidyCheck::OptionsView::OptionsView(StringRef CheckName,
3468 const ClangTidyOptions::OptionMap &CheckOptions)
3569 : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
3670
37- std::string ClangTidyCheck::OptionsView::get (StringRef LocalName,
38- StringRef Default ) const {
71+ llvm::Expected<std::string>
72+ ClangTidyCheck::OptionsView::get ( StringRef LocalName ) const {
3973 const auto &Iter = CheckOptions.find (NamePrefix + LocalName.str ());
4074 if (Iter != CheckOptions.end ())
4175 return Iter->second ;
42- return std::string (Default );
76+ return llvm::make_error<MissingOptionError>((NamePrefix + LocalName). str () );
4377}
4478
45- std::string
46- ClangTidyCheck::OptionsView::getLocalOrGlobal (StringRef LocalName,
47- StringRef Default) const {
79+ llvm::Expected<std::string>
80+ ClangTidyCheck::OptionsView::getLocalOrGlobal (StringRef LocalName) const {
4881 auto Iter = CheckOptions.find (NamePrefix + LocalName.str ());
4982 if (Iter != CheckOptions.end ())
5083 return Iter->second ;
5184 // Fallback to global setting, if present.
5285 Iter = CheckOptions.find (LocalName.str ());
5386 if (Iter != CheckOptions.end ())
5487 return Iter->second ;
55- return std::string (Default);
88+ return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str ());
89+ }
90+
91+ static llvm::Expected<bool > getAsBool (StringRef Value,
92+ const llvm::Twine &LookupName) {
93+ if (Value == " true" )
94+ return true ;
95+ if (Value == " false" )
96+ return false ;
97+ bool Result;
98+ if (!Value.getAsInteger (10 , Result))
99+ return Result;
100+ return llvm::make_error<UnparseableIntegerOptionError>(LookupName.str (),
101+ Value.str (), true );
102+ }
103+
104+ template <>
105+ llvm::Expected<bool >
106+ ClangTidyCheck::OptionsView::get<bool >(StringRef LocalName) const {
107+ llvm::Expected<std::string> ValueOr = get (LocalName);
108+ if (ValueOr)
109+ return getAsBool (*ValueOr, NamePrefix + LocalName);
110+ return ValueOr.takeError ();
111+ }
112+
113+ template <>
114+ bool ClangTidyCheck::OptionsView::get<bool >(StringRef LocalName,
115+ bool Default) const {
116+ llvm::Expected<bool > ValueOr = get<bool >(LocalName);
117+ if (ValueOr)
118+ return *ValueOr;
119+ logErrToStdErr (ValueOr.takeError ());
120+ return Default;
121+ }
122+
123+ template <>
124+ llvm::Expected<bool >
125+ ClangTidyCheck::OptionsView::getLocalOrGlobal<bool >(StringRef LocalName) const {
126+ llvm::Expected<std::string> ValueOr = get (LocalName);
127+ bool IsGlobal = false ;
128+ if (!ValueOr) {
129+ llvm::consumeError (ValueOr.takeError ());
130+ ValueOr = getLocalOrGlobal (LocalName);
131+ IsGlobal = true ;
132+ }
133+ if (!ValueOr)
134+ return ValueOr.takeError ();
135+ return getAsBool (*ValueOr, IsGlobal ? llvm::Twine (LocalName)
136+ : (NamePrefix + LocalName));
137+ }
138+
139+ template <>
140+ bool ClangTidyCheck::OptionsView::getLocalOrGlobal<bool >(StringRef LocalName,
141+ bool Default) const {
142+ llvm::Expected<bool > ValueOr = getLocalOrGlobal<bool >(LocalName);
143+ if (ValueOr)
144+ return *ValueOr;
145+ logErrToStdErr (ValueOr.takeError ());
146+ return Default;
56147}
57148
58149void ClangTidyCheck::OptionsView::store (ClangTidyOptions::OptionMap &Options,
@@ -67,5 +158,49 @@ void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options,
67158 store (Options, LocalName, llvm::itostr (Value));
68159}
69160
161+ llvm::Expected<int64_t > ClangTidyCheck::OptionsView::getEnumInt (
162+ StringRef LocalName, ArrayRef<std::pair<StringRef, int64_t >> Mapping,
163+ bool CheckGlobal, bool IgnoreCase) {
164+ auto Iter = CheckOptions.find ((NamePrefix + LocalName).str ());
165+ if (CheckGlobal && Iter == CheckOptions.end ())
166+ Iter = CheckOptions.find (LocalName.str ());
167+ if (Iter == CheckOptions.end ())
168+ return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str ());
169+
170+ StringRef Value = Iter->second ;
171+ StringRef Closest;
172+ unsigned EditDistance = -1 ;
173+ for (const auto &NameAndEnum : Mapping) {
174+ if (IgnoreCase) {
175+ if (Value.equals_lower (NameAndEnum.first ))
176+ return NameAndEnum.second ;
177+ } else if (Value.equals (NameAndEnum.first )) {
178+ return NameAndEnum.second ;
179+ } else if (Value.equals_lower (NameAndEnum.first )) {
180+ Closest = NameAndEnum.first ;
181+ EditDistance = 0 ;
182+ continue ;
183+ }
184+ unsigned Distance = Value.edit_distance (NameAndEnum.first );
185+ if (Distance < EditDistance) {
186+ EditDistance = Distance;
187+ Closest = NameAndEnum.first ;
188+ }
189+ }
190+ if (EditDistance < 3 )
191+ return llvm::make_error<UnparseableEnumOptionError>(
192+ Iter->first , Iter->second , std::string (Closest));
193+ return llvm::make_error<UnparseableEnumOptionError>(Iter->first ,
194+ Iter->second );
195+ }
196+
197+ void ClangTidyCheck::OptionsView::logErrToStdErr (llvm::Error &&Err) {
198+ llvm::logAllUnhandledErrors (
199+ llvm::handleErrors (std::move (Err),
200+ [](const MissingOptionError &) -> llvm::Error {
201+ return llvm::Error::success ();
202+ }),
203+ llvm::errs (), " warning: " );
204+ }
70205} // namespace tidy
71206} // namespace clang
0 commit comments