1 /* 2 * Copyright (c) 2021 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_VERIFICATION_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 17 #define PANDA_VERIFICATION_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 18 19 #include "verification/util/flags.h" 20 #include "verification/util/saturated_enum.h" 21 22 #include <functional> 23 24 namespace panda::verifier { 25 26 struct MethodOption { 27 enum class InfoType { CONTEXT, REG_CHANGES, CFLOW, JOBFILL }; 28 enum class MsgClass { ERROR, WARNING, HIDDEN }; 29 enum class CheckType { CFLOW, RESOLVE_ID, REG_USAGE, TYPING, ABSINT }; 30 using InfoTypeFlag = 31 FlagsForEnum<unsigned, InfoType, InfoType::CONTEXT, InfoType::REG_CHANGES, InfoType::CFLOW, InfoType::JOBFILL>; 32 using MsgClassFlag = FlagsForEnum<unsigned, MsgClass, MsgClass::ERROR, MsgClass::WARNING, MsgClass::HIDDEN>; 33 using CheckEnum = SaturatedEnum<CheckType, CheckType::ABSINT, CheckType::TYPING, CheckType::REG_USAGE, 34 CheckType::RESOLVE_ID, CheckType::CFLOW>; 35 }; 36 37 template <typename String, typename VerifierMessagesEnum, template <typename...> class UnorderedMap, 38 template <typename...> class Vector> 39 class VerifierMethodOptions { 40 public: 41 using Ref = std::reference_wrapper<const VerifierMethodOptions>; 42 ShowContext()43 bool ShowContext() const 44 { 45 return ShowInfo[MethodOption::InfoType::CONTEXT]; 46 } 47 ShowRegChanges()48 bool ShowRegChanges() const 49 { 50 return ShowInfo[MethodOption::InfoType::REG_CHANGES]; 51 } 52 ShowCflow()53 bool ShowCflow() const 54 { 55 return ShowInfo[MethodOption::InfoType::CFLOW]; 56 } 57 ShowJobFill()58 bool ShowJobFill() const 59 { 60 return ShowInfo[MethodOption::InfoType::JOBFILL]; 61 } 62 SetShow(MethodOption::InfoType info)63 void SetShow(MethodOption::InfoType info) 64 { 65 ShowInfo[info] = true; 66 } 67 SetMsgClass(VerifierMessagesEnum msg_num,MethodOption::MsgClass klass)68 void SetMsgClass(VerifierMessagesEnum msg_num, MethodOption::MsgClass klass) 69 { 70 msg_classes[msg_num][klass] = true; 71 } 72 73 template <typename Validator> SetMsgClass(Validator validator,size_t msg_num,MethodOption::MsgClass klass)74 void SetMsgClass(Validator validator, size_t msg_num, MethodOption::MsgClass klass) 75 { 76 if (validator(static_cast<VerifierMessagesEnum>(msg_num))) { 77 msg_classes[static_cast<VerifierMessagesEnum>(msg_num)][klass] = true; 78 } 79 } 80 AddUpLevel(const VerifierMethodOptions & up)81 void AddUpLevel(const VerifierMethodOptions &up) 82 { 83 uplevel.push_back(std::cref(up)); 84 } 85 CanHandleMsg(VerifierMessagesEnum msg_num)86 bool CanHandleMsg(VerifierMessagesEnum msg_num) const 87 { 88 return msg_classes.count(msg_num) > 0; 89 } 90 IsInMsgClass(VerifierMessagesEnum msg_num,MethodOption::MsgClass klass)91 bool IsInMsgClass(VerifierMessagesEnum msg_num, MethodOption::MsgClass klass) const 92 { 93 if (msg_classes.count(msg_num) > 0) { 94 return msg_classes.at(msg_num)[klass]; 95 } 96 for (const auto &up : uplevel) { 97 if (up.get().CanHandleMsg(msg_num)) { 98 return up.get().IsInMsgClass(msg_num, klass); 99 } 100 } 101 return false; 102 } 103 104 template <typename Handler> IfInMsgClassThen(VerifierMessagesEnum msg_num,MethodOption::MsgClass klass,Handler && handler)105 void IfInMsgClassThen(VerifierMessagesEnum msg_num, MethodOption::MsgClass klass, Handler &&handler) const 106 { 107 if (IsInMsgClass(msg_num, klass)) { 108 handler(); 109 } 110 } 111 112 template <typename Handler> IfNotInMsgClassThen(VerifierMessagesEnum msg_num,MethodOption::MsgClass klass,Handler && handler)113 void IfNotInMsgClassThen(VerifierMessagesEnum msg_num, MethodOption::MsgClass klass, Handler &&handler) const 114 { 115 if (!IsInMsgClass(msg_num, klass)) { 116 handler(); 117 } 118 } 119 120 class Proxy { 121 public: Proxy(VerifierMessagesEnum mess_num,const VerifierMethodOptions & method_opts)122 Proxy(VerifierMessagesEnum mess_num, const VerifierMethodOptions &method_opts) 123 : num {mess_num}, opts {method_opts} 124 { 125 } 126 Proxy() = delete; 127 Proxy(const Proxy &) = delete; 128 Proxy(Proxy &&) = delete; 129 ~Proxy() = default; 130 IsError()131 bool IsError() const 132 { 133 return Is(MethodOption::MsgClass::ERROR); 134 } 135 IsNotError()136 bool IsNotError() const 137 { 138 return IsNot(MethodOption::MsgClass::ERROR); 139 } 140 IsWarning()141 bool IsWarning() const 142 { 143 return Is(MethodOption::MsgClass::WARNING); 144 } 145 IsNotWarning()146 bool IsNotWarning() const 147 { 148 return IsNot(MethodOption::MsgClass::WARNING); 149 } 150 151 template <typename Handler> IfError(Handler && handler)152 void IfError(Handler &&handler) const 153 { 154 opts.IfInMsgClassThen(num, MethodOption::MsgClass::ERROR, std::move(handler)); 155 } 156 157 template <typename Handler> IfNotError(Handler && handler)158 void IfNotError(Handler &&handler) const 159 { 160 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::ERROR, std::move(handler)); 161 } 162 163 template <typename Handler> IfWarning(Handler && handler)164 void IfWarning(Handler &&handler) const 165 { 166 opts.IfInMsgClassThen(num, MethodOption::MsgClass::WARNING, std::move(handler)); 167 } 168 169 template <typename Handler> IfNotWarning(Handler && handler)170 void IfNotWarning(Handler &&handler) const 171 { 172 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::WARNING, std::move(handler)); 173 } 174 175 template <typename Handler> IfHidden(Handler && handler)176 void IfHidden(Handler &&handler) const 177 { 178 opts.IfInMsgClassThen(num, MethodOption::MsgClass::HIDDEN, std::move(handler)); 179 } 180 181 template <typename Handler> IfNotHidden(Handler && handler)182 void IfNotHidden(Handler &&handler) const 183 { 184 opts.IfNotInMsgClassThen(num, MethodOption::MsgClass::HIDDEN, std::move(handler)); 185 } 186 Is(MethodOption::MsgClass klass)187 bool Is(MethodOption::MsgClass klass) const 188 { 189 return opts.IsInMsgClass(num, klass); 190 } 191 IsNot(MethodOption::MsgClass klass)192 bool IsNot(MethodOption::MsgClass klass) const 193 { 194 return !opts.IsInMsgClass(num, klass); 195 } 196 197 template <typename Handler> If(MethodOption::MsgClass klass,Handler && handler)198 void If(MethodOption::MsgClass klass, Handler &&handler) const 199 { 200 opts.IfInMsgClassThen(num, klass, std::move(handler)); 201 } 202 203 template <typename Handler> IfNot(MethodOption::MsgClass klass,Handler && handler)204 void IfNot(MethodOption::MsgClass klass, Handler &&handler) const 205 { 206 opts.IfNotInMsgClassThen(num, klass, std::move(handler)); 207 } 208 209 private: 210 const VerifierMessagesEnum num; 211 const VerifierMethodOptions &opts; 212 }; 213 Msg(VerifierMessagesEnum num)214 Proxy Msg(VerifierMessagesEnum num) const 215 { 216 return {num, *this}; 217 } 218 219 template <typename MsgNumToString> Image(MsgNumToString to_string)220 String Image(MsgNumToString to_string) const 221 { 222 String result {"\n"}; 223 result += " Verifier messages config '" + name + "'\n"; 224 result += " Uplevel configs: "; 225 for (const auto &up : uplevel) { 226 result += "'" + up.get().name + "' "; 227 } 228 result += "\n"; 229 result += " Show: "; 230 ShowInfo.EnumerateFlags([&](auto flag) { 231 switch (flag) { 232 case MethodOption::InfoType::CONTEXT: 233 result += "'context' "; 234 break; 235 case MethodOption::InfoType::REG_CHANGES: 236 result += "'reg-changes' "; 237 break; 238 case MethodOption::InfoType::CFLOW: 239 result += "'cflow' "; 240 break; 241 case MethodOption::InfoType::JOBFILL: 242 result += "'jobfill' "; 243 break; 244 default: 245 result += "<unknown>"; 246 break; 247 }; 248 return true; 249 }); 250 result += "\n"; 251 result += " Checks: "; 252 EnabledCheck.EnumerateValues([&](auto flag) { 253 switch (flag) { 254 case MethodOption::CheckType::ABSINT: 255 result += "'absint' "; 256 break; 257 case MethodOption::CheckType::REG_USAGE: 258 result += "'reg-usage' "; 259 break; 260 case MethodOption::CheckType::CFLOW: 261 result += "'cflow' "; 262 break; 263 default: 264 result += "<unknown>"; 265 break; 266 }; 267 return true; 268 }); 269 270 result += "\n"; 271 result += ImageMessages(to_string); 272 return result; 273 } 274 VerifierMethodOptions(const String & param_name)275 VerifierMethodOptions(const String ¶m_name) : name {param_name} {} 276 ~VerifierMethodOptions() = default; 277 DEFAULT_COPY_SEMANTIC(VerifierMethodOptions); 278 DEFAULT_MOVE_SEMANTIC(VerifierMethodOptions); 279 GetName()280 const String &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: 296 template <typename MsgNumToString> ImageMessages(MsgNumToString to_string)297 String ImageMessages(MsgNumToString to_string) const 298 { 299 String result; 300 result += " Messages:\n"; 301 for (const auto &m : msg_classes) { 302 const auto &msg_num = m.first; 303 const auto &klass = m.second; 304 String msg_name = to_string(msg_num); 305 result += " "; 306 result += msg_name; 307 result += " : "; 308 klass.EnumerateFlags([&](auto flag) { 309 switch (flag) { 310 case MethodOption::MsgClass::ERROR: 311 result += "E"; 312 break; 313 case MethodOption::MsgClass::WARNING: 314 result += "W"; 315 break; 316 case MethodOption::MsgClass::HIDDEN: 317 result += "H"; 318 break; 319 default: 320 result += "<unknown>"; 321 break; 322 }; 323 return true; 324 }); 325 result += "\n"; 326 } 327 return result; 328 } 329 330 const String name; 331 Vector<Ref> uplevel; 332 UnorderedMap<VerifierMessagesEnum, MethodOption::MsgClassFlag> msg_classes; 333 MethodOption::InfoTypeFlag ShowInfo; 334 MethodOption::CheckEnum EnabledCheck; 335 }; 336 337 } // namespace panda::verifier 338 339 #endif // PANDA_VERIFICATION_DEBUG_OPTIONS_METHOD_OPTIONS_H_ 340