@@ -36,37 +36,78 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
36
36
eNotImplemented,
37
37
eNotAllocated,
38
38
eNotCallable,
39
+ eUnknownArgumentCount,
40
+ eInvalidArgumentCount,
39
41
eValid
40
42
};
41
43
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>>
43
59
CheckAbstractMethodImplementation (
44
60
const python::PythonDictionary &class_dict) const {
45
61
46
62
using namespace python ;
47
63
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 ) \
50
66
{ \
51
- checker[method_name] = error; \
67
+ checker[method_name] = { case , {}}; \
52
68
continue ; \
53
69
}
54
70
55
- for (const llvm::StringLiteral &method_name : GetAbstractMethods ()) {
71
+ for (const AbstractMethodRequirement &requirement :
72
+ GetAbstractMethodRequirements ()) {
73
+ llvm::StringLiteral method_name = requirement.name ;
56
74
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)
59
77
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
+ }
67
108
}
68
109
69
- #undef HANDLE_ERROR
110
+ #undef SET_CASE_AND_CONTINUE
70
111
71
112
return checker;
72
113
}
@@ -78,8 +119,11 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
78
119
using namespace python ;
79
120
using Locker = ScriptInterpreterPythonImpl::Locker;
80
121
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 ());
83
127
};
84
128
85
129
bool has_class_name = !class_name.empty ();
@@ -107,16 +151,15 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
107
151
PythonModule::MainModule ().ResolveName <python::PythonDictionary>(
108
152
m_interpreter.GetDictionaryName ());
109
153
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 ());
113
156
114
157
auto init =
115
158
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
116
159
class_name, dict);
117
160
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 ());
120
163
121
164
std::tuple<Args...> original_args = std::forward_as_tuple (args...);
122
165
auto transformed_args = TransformArgs (original_args);
@@ -186,36 +229,73 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
186
229
if (!checker_or_err)
187
230
return checker_or_err.takeError ();
188
231
232
+ llvm::Error abstract_method_errors = llvm::Error::success ();
189
233
for (const auto &method_checker : *checker_or_err)
190
- switch (method_checker.second ) {
234
+ switch (method_checker.second . checker_case ) {
191
235
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 )));
195
241
break ;
196
242
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 )));
200
248
break ;
201
249
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 )));
205
262
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 ;
206
287
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." ,
209
289
obj_class_name.GetString (), method_checker.first );
210
290
break ;
211
291
}
212
292
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
+ }
219
299
220
300
m_object_instance_sp = StructuredData::GenericSP (
221
301
new StructuredPythonObject (std::move (result)));
0 commit comments