@@ -36,37 +36,78 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
3636 eNotImplemented,
3737 eNotAllocated,
3838 eNotCallable,
39+ eUnknownArgumentCount,
40+ eInvalidArgumentCount,
3941 eValid
4042 };
4143
42- llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
44+ struct AbstrackMethodCheckerPayload {
45+
46+ struct InvalidArgumentCountPayload {
47+ InvalidArgumentCountPayload (size_t required, size_t actual)
48+ : required_argument_count(required), actual_argument_count(actual) {}
49+
50+ size_t required_argument_count;
51+ size_t actual_argument_count;
52+ };
53+
54+ AbstractMethodCheckerCases checker_case;
55+ std::variant<std::monostate, InvalidArgumentCountPayload> payload;
56+ };
57+
58+ llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>>
4359 CheckAbstractMethodImplementation (
4460 const python::PythonDictionary &class_dict) const {
4561
4662 using namespace python ;
4763
48- std::map<llvm::StringLiteral, AbstractMethodCheckerCases > checker;
49- #define SET_ERROR_AND_CONTINUE (method_name, error ) \
64+ std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload > checker;
65+ #define SET_CASE_AND_CONTINUE (method_name, case ) \
5066 { \
51- checker[method_name] = error; \
67+ checker[method_name] = { case , {}}; \
5268 continue ; \
5369 }
5470
55- for (const llvm::StringLiteral &method_name : GetAbstractMethods ()) {
71+ for (const AbstractMethodRequirement &requirement :
72+ GetAbstractMethodRequirements ()) {
73+ llvm::StringLiteral method_name = requirement.name ;
5674 if (!class_dict.HasKey (method_name))
57- SET_ERROR_AND_CONTINUE (method_name,
58- AbstractMethodCheckerCases::eNotImplemented)
75+ SET_CASE_AND_CONTINUE (method_name,
76+ AbstractMethodCheckerCases::eNotImplemented)
5977 auto callable_or_err = class_dict.GetItem (method_name);
60- if (!callable_or_err)
61- SET_ERROR_AND_CONTINUE (method_name,
62- AbstractMethodCheckerCases::eNotAllocated)
63- if (!PythonCallable::Check (callable_or_err.get ().get ()))
64- SET_ERROR_AND_CONTINUE (method_name,
65- AbstractMethodCheckerCases::eNotCallable)
66- checker[method_name] = AbstractMethodCheckerCases::eValid;
78+ if (!callable_or_err) {
79+ llvm::consumeError (callable_or_err.takeError ());
80+ SET_CASE_AND_CONTINUE (method_name,
81+ AbstractMethodCheckerCases::eNotAllocated)
82+ }
83+
84+ PythonCallable callable = callable_or_err->AsType <PythonCallable>();
85+ if (!callable)
86+ SET_CASE_AND_CONTINUE (method_name,
87+ AbstractMethodCheckerCases::eNotCallable)
88+
89+ if (!requirement.min_arg_count )
90+ SET_CASE_AND_CONTINUE (method_name, AbstractMethodCheckerCases::eValid)
91+
92+ auto arg_info_or_err = callable.GetArgInfo ();
93+ if (!arg_info_or_err) {
94+ llvm::consumeError (arg_info_or_err.takeError ());
95+ SET_CASE_AND_CONTINUE (method_name,
96+ AbstractMethodCheckerCases::eUnknownArgumentCount)
97+ }
98+
99+ PythonCallable::ArgInfo arg_info = *arg_info_or_err;
100+ if (requirement.min_arg_count <= arg_info.max_positional_args ) {
101+ SET_CASE_AND_CONTINUE (method_name, AbstractMethodCheckerCases::eValid)
102+ } else {
103+ checker[method_name] = {
104+ AbstractMethodCheckerCases::eInvalidArgumentCount,
105+ AbstrackMethodCheckerPayload::InvalidArgumentCountPayload (
106+ requirement.min_arg_count , arg_info.max_positional_args )};
107+ }
67108 }
68109
69- #undef HANDLE_ERROR
110+ #undef SET_CASE_AND_CONTINUE
70111
71112 return checker;
72113 }
@@ -78,8 +119,11 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
78119 using namespace python ;
79120 using Locker = ScriptInterpreterPythonImpl::Locker;
80121
81- auto create_error = [](std::string message) {
82- return llvm::createStringError (llvm::inconvertibleErrorCode (), message);
122+ Log *log = GetLog (LLDBLog::Script);
123+ auto create_error = [](llvm::StringLiteral format, auto &&...ts ) {
124+ return llvm::createStringError (
125+ llvm::formatv (format.data (), std::forward<decltype (ts)>(ts)...)
126+ .str ());
83127 };
84128
85129 bool has_class_name = !class_name.empty ();
@@ -107,16 +151,15 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
107151 PythonModule::MainModule ().ResolveName <python::PythonDictionary>(
108152 m_interpreter.GetDictionaryName ());
109153 if (!dict.IsAllocated ())
110- return create_error (
111- llvm::formatv (" Could not find interpreter dictionary: %s" ,
112- m_interpreter.GetDictionaryName ()));
154+ return create_error (" Could not find interpreter dictionary: {0}" ,
155+ m_interpreter.GetDictionaryName ());
113156
114157 auto init =
115158 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
116159 class_name, dict);
117160 if (!init.IsAllocated ())
118- return create_error (llvm::formatv ( " Could not find script class: {0}" ,
119- class_name.data () ));
161+ return create_error (" Could not find script class: {0}" ,
162+ class_name.data ());
120163
121164 std::tuple<Args...> original_args = std::forward_as_tuple (args...);
122165 auto transformed_args = TransformArgs (original_args);
@@ -186,36 +229,73 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
186229 if (!checker_or_err)
187230 return checker_or_err.takeError ();
188231
232+ llvm::Error abstract_method_errors = llvm::Error::success ();
189233 for (const auto &method_checker : *checker_or_err)
190- switch (method_checker.second ) {
234+ switch (method_checker.second . checker_case ) {
191235 case AbstractMethodCheckerCases::eNotImplemented:
192- LLDB_LOG (GetLog (LLDBLog::Script),
193- " Abstract method {0}.{1} not implemented." ,
194- obj_class_name.GetString (), method_checker.first );
236+ abstract_method_errors = llvm::joinErrors (
237+ std::move (abstract_method_errors),
238+ std::move (create_error (" Abstract method {0}.{1} not implemented." ,
239+ obj_class_name.GetString (),
240+ method_checker.first )));
195241 break ;
196242 case AbstractMethodCheckerCases::eNotAllocated:
197- LLDB_LOG (GetLog (LLDBLog::Script),
198- " Abstract method {0}.{1} not allocated." ,
199- obj_class_name.GetString (), method_checker.first );
243+ abstract_method_errors = llvm::joinErrors (
244+ std::move (abstract_method_errors),
245+ std::move (create_error (" Abstract method {0}.{1} not allocated." ,
246+ obj_class_name.GetString (),
247+ method_checker.first )));
200248 break ;
201249 case AbstractMethodCheckerCases::eNotCallable:
202- LLDB_LOG (GetLog (LLDBLog::Script),
203- " Abstract method {0}.{1} not callable." ,
204- obj_class_name.GetString (), method_checker.first );
250+ abstract_method_errors = llvm::joinErrors (
251+ std::move (abstract_method_errors),
252+ std::move (create_error (" Abstract method {0}.{1} not callable." ,
253+ obj_class_name.GetString (),
254+ method_checker.first )));
255+ break ;
256+ case AbstractMethodCheckerCases::eUnknownArgumentCount:
257+ abstract_method_errors = llvm::joinErrors (
258+ std::move (abstract_method_errors),
259+ std::move (create_error (
260+ " Abstract method {0}.{1} has unknown argument count." ,
261+ obj_class_name.GetString (), method_checker.first )));
205262 break ;
263+ case AbstractMethodCheckerCases::eInvalidArgumentCount: {
264+ auto &payload_variant = method_checker.second .payload ;
265+ if (!std::holds_alternative<
266+ AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
267+ payload_variant)) {
268+ abstract_method_errors = llvm::joinErrors (
269+ std::move (abstract_method_errors),
270+ std::move (create_error (
271+ " Abstract method {0}.{1} has unexpected argument count." ,
272+ obj_class_name.GetString (), method_checker.first )));
273+ } else {
274+ auto payload = std::get<
275+ AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
276+ payload_variant);
277+ abstract_method_errors = llvm::joinErrors (
278+ std::move (abstract_method_errors),
279+ std::move (
280+ create_error (" Abstract method {0}.{1} has unexpected "
281+ " argument count (expected {2} but has {3})." ,
282+ obj_class_name.GetString (), method_checker.first ,
283+ payload.required_argument_count ,
284+ payload.actual_argument_count )));
285+ }
286+ } break ;
206287 case AbstractMethodCheckerCases::eValid:
207- LLDB_LOG (GetLog (LLDBLog::Script),
208- " Abstract method {0}.{1} implemented & valid." ,
288+ LLDB_LOG (log, " Abstract method {0}.{1} implemented & valid." ,
209289 obj_class_name.GetString (), method_checker.first );
210290 break ;
211291 }
212292
213- for ( const auto &method_checker : *checker_or_err)
214- if (method_checker. second != AbstractMethodCheckerCases::eValid)
215- return create_error (
216- llvm::formatv ( " Abstract method {0}.{1} missing. Enable lldb "
217- " script log for more details. " ,
218- obj_class_name. GetString (), method_checker. first ));
293+ if (abstract_method_errors) {
294+ Status error = Status::FromError ( std::move (abstract_method_errors));
295+ LLDB_LOG (log, " Abstract method error in {0}: \n {1} " , class_name,
296+ error. AsCString ());
297+ return error. ToError ();
298+ }
219299
220300 m_object_instance_sp = StructuredData::GenericSP (
221301 new StructuredPythonObject (std::move (result)));
0 commit comments