7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#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"
10
14
11
15
namespace clang {
12
16
namespace tidy {
13
17
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
+
14
48
ClangTidyCheck::ClangTidyCheck (StringRef CheckName, ClangTidyContext *Context)
15
49
: CheckName(CheckName), Context(Context),
16
50
Options (CheckName, Context->getOptions ().CheckOptions) {
@@ -34,25 +68,82 @@ ClangTidyCheck::OptionsView::OptionsView(StringRef CheckName,
34
68
const ClangTidyOptions::OptionMap &CheckOptions)
35
69
: NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
36
70
37
- std::string ClangTidyCheck::OptionsView::get (StringRef LocalName,
38
- StringRef Default ) const {
71
+ llvm::Expected<std::string>
72
+ ClangTidyCheck::OptionsView::get ( StringRef LocalName ) const {
39
73
const auto &Iter = CheckOptions.find (NamePrefix + LocalName.str ());
40
74
if (Iter != CheckOptions.end ())
41
75
return Iter->second ;
42
- return std::string (Default );
76
+ return llvm::make_error<MissingOptionError>((NamePrefix + LocalName). str () );
43
77
}
44
78
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 {
48
81
auto Iter = CheckOptions.find (NamePrefix + LocalName.str ());
49
82
if (Iter != CheckOptions.end ())
50
83
return Iter->second ;
51
84
// Fallback to global setting, if present.
52
85
Iter = CheckOptions.find (LocalName.str ());
53
86
if (Iter != CheckOptions.end ())
54
87
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;
56
147
}
57
148
58
149
void ClangTidyCheck::OptionsView::store (ClangTidyOptions::OptionMap &Options,
@@ -67,5 +158,49 @@ void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options,
67
158
store (Options, LocalName, llvm::itostr (Value));
68
159
}
69
160
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
+ }
70
205
} // namespace tidy
71
206
} // namespace clang
0 commit comments