@@ -32,27 +32,66 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
32
32
ScriptedPythonInterface (ScriptInterpreterPythonImpl &interpreter);
33
33
~ScriptedPythonInterface () override = default ;
34
34
35
+ enum class AbstractMethodCheckerCases {
36
+ eNotImplemented,
37
+ eNotAllocated,
38
+ eNotCallable,
39
+ eValid
40
+ };
41
+
42
+ llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>>
43
+ CheckAbstractMethodImplementation (
44
+ const python::PythonDictionary &class_dict) const {
45
+
46
+ using namespace python ;
47
+
48
+ std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker;
49
+ #define SET_ERROR_AND_CONTINUE (method_name, error ) \
50
+ { \
51
+ checker[method_name] = error; \
52
+ continue ; \
53
+ }
54
+
55
+ for (const llvm::StringLiteral &method_name : GetAbstractMethods ()) {
56
+ if (!class_dict.HasKey (method_name))
57
+ SET_ERROR_AND_CONTINUE (method_name,
58
+ AbstractMethodCheckerCases::eNotImplemented)
59
+ 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;
67
+ }
68
+
69
+ #undef HANDLE_ERROR
70
+
71
+ return checker;
72
+ }
73
+
35
74
template <typename ... Args>
36
75
llvm::Expected<StructuredData::GenericSP>
37
76
CreatePluginObject (llvm::StringRef class_name,
38
77
StructuredData::Generic *script_obj, Args... args) {
39
78
using namespace python ;
40
79
using Locker = ScriptInterpreterPythonImpl::Locker;
41
80
81
+ auto create_error = [](std::string message) {
82
+ return llvm::createStringError (llvm::inconvertibleErrorCode (), message);
83
+ };
84
+
42
85
bool has_class_name = !class_name.empty ();
43
86
bool has_interpreter_dict =
44
87
!(llvm::StringRef (m_interpreter.GetDictionaryName ()).empty ());
45
88
if (!has_class_name && !has_interpreter_dict && !script_obj) {
46
89
if (!has_class_name)
47
- return llvm::createStringError (llvm::inconvertibleErrorCode (),
48
- " Missing script class name." );
90
+ return create_error (" Missing script class name." );
49
91
else if (!has_interpreter_dict)
50
- return llvm::createStringError (
51
- llvm::inconvertibleErrorCode (),
52
- " Invalid script interpreter dictionary." );
92
+ return create_error (" Invalid script interpreter dictionary." );
53
93
else
54
- return llvm::createStringError (llvm::inconvertibleErrorCode (),
55
- " Missing scripting object." );
94
+ return create_error (" Missing scripting object." );
56
95
}
57
96
58
97
Locker py_lock (&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
@@ -67,26 +106,23 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
67
106
auto dict =
68
107
PythonModule::MainModule ().ResolveName <python::PythonDictionary>(
69
108
m_interpreter.GetDictionaryName ());
70
- if (!dict.IsAllocated ()) {
71
- return llvm::createStringError (
72
- llvm::inconvertibleErrorCode (),
73
- " Could not find interpreter dictionary: %s" ,
74
- m_interpreter.GetDictionaryName ());
75
- }
109
+ if (!dict.IsAllocated ())
110
+ return create_error (
111
+ llvm::formatv (" Could not find interpreter dictionary: %s" ,
112
+ m_interpreter.GetDictionaryName ()));
76
113
77
- auto method =
114
+ auto init =
78
115
PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
79
116
class_name, dict);
80
- if (!method.IsAllocated ())
81
- return llvm::createStringError (llvm::inconvertibleErrorCode (),
82
- " Could not find script class: %s" ,
83
- class_name.data ());
117
+ if (!init.IsAllocated ())
118
+ return create_error (llvm::formatv (" Could not find script class: %s" ,
119
+ class_name.data ()));
84
120
85
121
std::tuple<Args...> original_args = std::forward_as_tuple (args...);
86
122
auto transformed_args = TransformArgs (original_args);
87
123
88
124
std::string error_string;
89
- llvm::Expected<PythonCallable::ArgInfo> arg_info = method .GetArgInfo ();
125
+ llvm::Expected<PythonCallable::ArgInfo> arg_info = init .GetArgInfo ();
90
126
if (!arg_info) {
91
127
llvm::handleAllErrors (
92
128
arg_info.takeError (),
@@ -99,25 +135,87 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
99
135
}
100
136
101
137
llvm::Expected<PythonObject> expected_return_object =
102
- llvm::createStringError (llvm::inconvertibleErrorCode (),
103
- " Resulting object is not initialized." );
138
+ create_error (" Resulting object is not initialized." );
104
139
105
140
std::apply (
106
- [&method , &expected_return_object](auto &&...args ) {
141
+ [&init , &expected_return_object](auto &&...args ) {
107
142
llvm::consumeError (expected_return_object.takeError ());
108
- expected_return_object = method (args...);
143
+ expected_return_object = init (args...);
109
144
},
110
145
transformed_args);
111
146
112
- if (llvm::Error e = expected_return_object. takeError () )
113
- return std::move (e );
114
- result = std::move ( expected_return_object.get () );
147
+ if (! expected_return_object)
148
+ return expected_return_object. takeError ( );
149
+ result = expected_return_object.get ();
115
150
}
116
151
117
152
if (!result.IsValid ())
118
- return llvm::createStringError (
119
- llvm::inconvertibleErrorCode (),
120
- " Resulting object is not a valid Python Object." );
153
+ return create_error (" Resulting object is not a valid Python Object." );
154
+ if (!result.HasAttribute (" __class__" ))
155
+ return create_error (" Resulting object doesn't have '__class__' member." );
156
+
157
+ PythonObject obj_class = result.GetAttributeValue (" __class__" );
158
+ if (!obj_class.IsValid ())
159
+ return create_error (" Resulting class object is not a valid." );
160
+ if (!obj_class.HasAttribute (" __name__" ))
161
+ return create_error (
162
+ " Resulting object class doesn't have '__name__' member." );
163
+ PythonString obj_class_name =
164
+ obj_class.GetAttributeValue (" __name__" ).AsType <PythonString>();
165
+
166
+ PythonObject object_class_mapping_proxy =
167
+ obj_class.GetAttributeValue (" __dict__" );
168
+ if (!obj_class.HasAttribute (" __dict__" ))
169
+ return create_error (
170
+ " Resulting object class doesn't have '__dict__' member." );
171
+
172
+ PythonCallable dict_converter = PythonModule::BuiltinsModule ()
173
+ .ResolveName (" dict" )
174
+ .AsType <PythonCallable>();
175
+ if (!dict_converter.IsAllocated ())
176
+ return create_error (
177
+ " Python 'builtins' module doesn't have 'dict' class." );
178
+
179
+ PythonDictionary object_class_dict =
180
+ dict_converter (object_class_mapping_proxy).AsType <PythonDictionary>();
181
+ if (!object_class_dict.IsAllocated ())
182
+ return create_error (" Coudn't create dictionary from resulting object "
183
+ " class mapping proxy object." );
184
+
185
+ auto checker_or_err = CheckAbstractMethodImplementation (object_class_dict);
186
+ if (!checker_or_err)
187
+ return checker_or_err.takeError ();
188
+
189
+ for (const auto &method_checker : *checker_or_err)
190
+ switch (method_checker.second ) {
191
+ case AbstractMethodCheckerCases::eNotImplemented:
192
+ LLDB_LOG (GetLog (LLDBLog::Script),
193
+ " Abstract method {0}.{1} not implemented." ,
194
+ obj_class_name.GetString (), method_checker.first );
195
+ break ;
196
+ case AbstractMethodCheckerCases::eNotAllocated:
197
+ LLDB_LOG (GetLog (LLDBLog::Script),
198
+ " Abstract method {0}.{1} not allocated." ,
199
+ obj_class_name.GetString (), method_checker.first );
200
+ break ;
201
+ case AbstractMethodCheckerCases::eNotCallable:
202
+ LLDB_LOG (GetLog (LLDBLog::Script),
203
+ " Abstract method {0}.{1} not callable." ,
204
+ obj_class_name.GetString (), method_checker.first );
205
+ break ;
206
+ case AbstractMethodCheckerCases::eValid:
207
+ LLDB_LOG (GetLog (LLDBLog::Script),
208
+ " Abstract method {0}.{1} implemented & valid." ,
209
+ obj_class_name.GetString (), method_checker.first );
210
+ break ;
211
+ }
212
+
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 ));
121
219
122
220
m_object_instance_sp = StructuredData::GenericSP (
123
221
new StructuredPythonObject (std::move (result)));
0 commit comments