@@ -32,27 +32,66 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
3232 ScriptedPythonInterface (ScriptInterpreterPythonImpl &interpreter);
3333 ~ScriptedPythonInterface () override = default ;
3434
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+
3574 template <typename ... Args>
3675 llvm::Expected<StructuredData::GenericSP>
3776 CreatePluginObject (llvm::StringRef class_name,
3877 StructuredData::Generic *script_obj, Args... args) {
3978 using namespace python ;
4079 using Locker = ScriptInterpreterPythonImpl::Locker;
4180
81+ auto create_error = [](std::string message) {
82+ return llvm::createStringError (llvm::inconvertibleErrorCode (), message);
83+ };
84+
4285 bool has_class_name = !class_name.empty ();
4386 bool has_interpreter_dict =
4487 !(llvm::StringRef (m_interpreter.GetDictionaryName ()).empty ());
4588 if (!has_class_name && !has_interpreter_dict && !script_obj) {
4689 if (!has_class_name)
47- return llvm::createStringError (llvm::inconvertibleErrorCode (),
48- " Missing script class name." );
90+ return create_error (" Missing script class name." );
4991 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." );
5393 else
54- return llvm::createStringError (llvm::inconvertibleErrorCode (),
55- " Missing scripting object." );
94+ return create_error (" Missing scripting object." );
5695 }
5796
5897 Locker py_lock (&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
@@ -67,26 +106,23 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
67106 auto dict =
68107 PythonModule::MainModule ().ResolveName <python::PythonDictionary>(
69108 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 ()));
76113
77- auto method =
114+ auto init =
78115 PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
79116 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 ()));
84120
85121 std::tuple<Args...> original_args = std::forward_as_tuple (args...);
86122 auto transformed_args = TransformArgs (original_args);
87123
88124 std::string error_string;
89- llvm::Expected<PythonCallable::ArgInfo> arg_info = method .GetArgInfo ();
125+ llvm::Expected<PythonCallable::ArgInfo> arg_info = init .GetArgInfo ();
90126 if (!arg_info) {
91127 llvm::handleAllErrors (
92128 arg_info.takeError (),
@@ -99,25 +135,87 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
99135 }
100136
101137 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." );
104139
105140 std::apply (
106- [&method , &expected_return_object](auto &&...args ) {
141+ [&init , &expected_return_object](auto &&...args ) {
107142 llvm::consumeError (expected_return_object.takeError ());
108- expected_return_object = method (args...);
143+ expected_return_object = init (args...);
109144 },
110145 transformed_args);
111146
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 ();
115150 }
116151
117152 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 ));
121219
122220 m_object_instance_sp = StructuredData::GenericSP (
123221 new StructuredPythonObject (std::move (result)));
0 commit comments