1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_VERIFIER_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 17 #define PANDA_VERIFIER_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 18 19 #include "verification/util/flags.h" 20 #include "verification/util/saturated_enum.h" 21 #include "verifier_messages.h" 22 23 #include <functional> 24 25 namespace panda::verifier { 26 27 struct MethodOption { 28 enum class InfoType { CONTEXT, REG_CHANGES, CFLOW, JOBFILL }; 29 enum class MsgClass { ERROR, WARNING, HIDDEN }; 30 enum class CheckType { CFLOW, RESOLVE_ID, REG_USAGE, TYPING, ABSINT }; 31 using InfoTypeFlag = 32 FlagsForEnum<unsigned, InfoType, InfoType::CONTEXT, InfoType::REG_CHANGES, InfoType::CFLOW, InfoType::JOBFILL>; 33 using MsgClassFlag = FlagsForEnum<unsigned, MsgClass, MsgClass::ERROR, MsgClass::WARNING, MsgClass::HIDDEN>; 34 using CheckEnum = SaturatedEnum<CheckType, CheckType::ABSINT, CheckType::TYPING, CheckType::REG_USAGE, 35 CheckType::RESOLVE_ID, CheckType::CFLOW>; 36 }; 37 38 class MethodOptions { 39 public: ShowContext()40 bool ShowContext() const 41 { 42 return ShowInfo[MethodOption::InfoType::CONTEXT]; 43 } 44 ShowRegChanges()45 bool ShowRegChanges() const 46 { 47 return ShowInfo[MethodOption::InfoType::REG_CHANGES]; 48 } 49 ShowCflow()50 bool ShowCflow() const 51 { 52 return ShowInfo[MethodOption::InfoType::CFLOW]; 53 } 54 ShowJobFill()55 bool ShowJobFill() const 56 { 57 return ShowInfo[MethodOption::InfoType::JOBFILL]; 58 } 59 SetShow(MethodOption::InfoType info)60 void SetShow(MethodOption::InfoType info) 61 { 62 ShowInfo[info] = true; 63 } 64 SetMsgClass(VerifierMessage msg_num,MethodOption::MsgClass klass)65 void SetMsgClass(VerifierMessage msg_num, MethodOption::MsgClass klass) 66 { 67 msg_classes[msg_num][klass] = true; 68 } 69 70 template <typename Validator> SetMsgClass(Validator validator,size_t msg_num,MethodOption::MsgClass klass)71 void SetMsgClass(Validator validator, size_t msg_num, MethodOption::MsgClass klass) 72 { 73 if (validator(static_cast<VerifierMessage>(msg_num))) { 74 msg_classes[static_cast<VerifierMessage>(msg_num)][klass] = true; 75 } 76 } 77 AddUpLevel(const MethodOptions & up)78 void AddUpLevel(const MethodOptions &up) 79 { 80 uplevel.push_back(std::cref(up)); 81 } 82 CanHandleMsg(VerifierMessage msg_num)83 bool CanHandleMsg(VerifierMessage msg_num) const 84 { 85 return msg_classes.count(msg_num) > 0; 86 } 87 IsInMsgClass(VerifierMessage msg_num,MethodOption::MsgClass klass)88 bool IsInMsgClass(VerifierMessage msg_num, MethodOption::MsgClass klass) const 89 { 90 if (msg_classes.count(msg_num) > 0) { 91 return msg_classes.at(msg_num)[klass]; 92 } 93 for (const auto &up : uplevel) { 94 if (up.get().CanHandleMsg(msg_num)) { 95 return up.get().IsInMsgClass(msg_num, klass); 96 } 97 } 98 return false; 99 } 100 101 template <typename Handler> IfInMsgClassThen(VerifierMessage msg_num,MethodOption::MsgClass klass,Handler && handler)102 void IfInMsgClassThen(VerifierMessage msg_num, MethodOption::MsgClass klass, Handler &&handler) const 103 { 104 if (IsInMsgClass(msg_num, klass)) { 105 handler(); 106 } 107 } 108 109 template <typename Handler> IfNotInMsgClassThen(VerifierMessage msg_num,MethodOption::MsgClass klass,Handler && handler)110 void IfNotInMsgClassThen(VerifierMessage msg_num, MethodOption::MsgClass klass, Handler &&handler) const 111 { 112 if (!IsInMsgClass(msg_num, klass)) { 113 handler(); 114 } 115 } 116 117 class Proxy { 118 public: Proxy(VerifierMessage mess_num,const MethodOptions & method_opts)119 Proxy(VerifierMessage mess_num, const MethodOptions &method_opts) : num {mess_num}, opts {method_opts} {} 120 Proxy() = delete; 121 Proxy(const Proxy &) = delete; 122 Proxy(Proxy &&) = delete; 123 ~Proxy() = default; 124 IsError()125 bool IsError() const 126 { 127 return Is(MethodOption::MsgClass::ERROR); 128 } 129 IsNotError()130 bool IsNotError() const 131 { 132 return IsNot(MethodOption::MsgClass::ERROR); 133 } 134 IsWarning()135 bool IsWarning() const 136 { 137 return Is(MethodOption::MsgClass::WARNING); 138 } 139 IsNotWarning()140 bool IsNotWarning() const 141 { 142 return IsNot(MethodOption::MsgClass::WARNING); 143 } 144 145 template <typename Handler> IfError(Handler && handler)146 void IfError(Handler &&handler) const 147 { 148 opts.IfInMsgClassThen(num, MethodOption::MsgClass::ERROR, std::move(handler)); 149 } 150 151 template <typename Handler> IfNotError(Handler && handler)152 void IfNotError(Handler &&handler) const 153 { 154 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::ERROR, std::move(handler)); 155 } 156 157 template <typename Handler> IfWarning(Handler && handler)158 void IfWarning(Handler &&handler) const 159 { 160 opts.IfInMsgClassThen(num, MethodOption::MsgClass::WARNING, std::move(handler)); 161 } 162 163 template <typename Handler> IfNotWarning(Handler && handler)164 void IfNotWarning(Handler &&handler) const 165 { 166 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::WARNING, std::move(handler)); 167 } 168 169 template <typename Handler> IfHidden(Handler && handler)170 void IfHidden(Handler &&handler) const 171 { 172 opts.IfInMsgClassThen(num, MethodOption::MsgClass::HIDDEN, std::move(handler)); 173 } 174 175 template <typename Handler> IfNotHidden(Handler && handler)176 void IfNotHidden(Handler &&handler) const 177 { 178 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::HIDDEN, std::move(handler)); 179 } 180 Is(MethodOption::MsgClass klass)181 bool Is(MethodOption::MsgClass klass) const 182 { 183 return opts.IsInMsgClass(num, klass); 184 } 185 IsNot(MethodOption::MsgClass klass)186 bool IsNot(MethodOption::MsgClass klass) const 187 { 188 return !opts.IsInMsgClass(num, klass); 189 } 190 191 template <typename Handler> If(MethodOption::MsgClass klass,Handler && handler)192 void If(MethodOption::MsgClass klass, Handler &&handler) const 193 { 194 opts.IfInMsgClassThen(num, klass, std::move(handler)); 195 } 196 197 template <typename Handler> IfNot(MethodOption::MsgClass klass,Handler && handler)198 void IfNot(MethodOption::MsgClass klass, Handler &&handler) const 199 { 200 opts.IfNotInMsgClassThen(num, klass, std::move(handler)); 201 } 202 203 private: 204 const VerifierMessage num; 205 const MethodOptions &opts; 206 }; 207 Msg(VerifierMessage num)208 Proxy Msg(VerifierMessage num) const 209 { 210 return {num, *this}; 211 } 212 Image()213 PandaString Image() const 214 { 215 PandaString result {"\n"}; 216 result += " Verifier messages config '" + name + "'\n"; 217 result += " Uplevel configs: "; 218 for (const auto &up : uplevel) { 219 result += "'" + up.get().name + "' "; 220 } 221 result += "\n"; 222 result += " Show: "; 223 ShowInfo.EnumerateFlags([&](auto flag) { 224 switch (flag) { 225 case MethodOption::InfoType::CONTEXT: 226 result += "'context' "; 227 break; 228 case MethodOption::InfoType::REG_CHANGES: 229 result += "'reg-changes' "; 230 break; 231 case MethodOption::InfoType::CFLOW: 232 result += "'cflow' "; 233 break; 234 case MethodOption::InfoType::JOBFILL: 235 result += "'jobfill' "; 236 break; 237 default: 238 result += "<unknown>("; 239 result += static_cast<size_t>(flag); 240 result += ") "; 241 break; 242 } 243 return true; 244 }); 245 result += "\n"; 246 result += " Checks: "; 247 EnabledCheck.EnumerateValues([&](auto flag) { 248 switch (flag) { 249 case MethodOption::CheckType::TYPING: 250 result += "'typing' "; 251 break; 252 case MethodOption::CheckType::ABSINT: 253 result += "'absint' "; 254 break; 255 case MethodOption::CheckType::REG_USAGE: 256 result += "'reg-usage' "; 257 break; 258 case MethodOption::CheckType::CFLOW: 259 result += "'cflow' "; 260 break; 261 case MethodOption::CheckType::RESOLVE_ID: 262 result += "'resolve-id' "; 263 break; 264 default: 265 result += "<unknown>("; 266 result += static_cast<size_t>(flag); 267 result += ") "; 268 break; 269 } 270 return true; 271 }); 272 273 result += "\n"; 274 result += ImageMessages(); 275 return result; 276 } 277 MethodOptions(const PandaString & param_name)278 MethodOptions(const PandaString ¶m_name) : name {param_name} {} 279 GetName()280 const PandaString &GetName() const 281 { 282 return name; 283 } 284 Check()285 MethodOption::CheckEnum &Check() 286 { 287 return EnabledCheck; 288 } 289 Check()290 const MethodOption::CheckEnum &Check() const 291 { 292 return EnabledCheck; 293 } 294 295 private: ImageMessages()296 PandaString ImageMessages() const 297 { 298 PandaString result; 299 result += " Messages:\n"; 300 for (const auto &m : msg_classes) { 301 const auto &msg_num = m.first; 302 const auto &klass = m.second; 303 result += " "; 304 result += VerifierMessageToString(msg_num); 305 result += " : "; 306 klass.EnumerateFlags([&](auto flag) { 307 switch (flag) { 308 case MethodOption::MsgClass::ERROR: 309 result += "E"; 310 break; 311 case MethodOption::MsgClass::WARNING: 312 result += "W"; 313 break; 314 case MethodOption::MsgClass::HIDDEN: 315 result += "H"; 316 break; 317 default: 318 result += "<unknown>("; 319 result += static_cast<size_t>(flag); 320 result += ")"; 321 break; 322 } 323 return true; 324 }); 325 result += "\n"; 326 } 327 return result; 328 } 329 330 const PandaString name; 331 PandaVector<std::reference_wrapper<const MethodOptions>> uplevel; 332 PandaUnorderedMap<VerifierMessage, MethodOption::MsgClassFlag> msg_classes; 333 MethodOption::InfoTypeFlag ShowInfo; 334 MethodOption::CheckEnum EnabledCheck; 335 }; 336 337 } // namespace panda::verifier 338 339 #endif //! PANDA_VERIFIER_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 340