##// END OF EJS Templates
improved wrapper check to avoid crashes on virtual methods while python object gets deleted...
florianlink -
r204:7ce280c51c17
parent child
Show More
@@ -1,332 +1,332
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #include "shellimplgenerator.h"
43 43 #include "reporthandler.h"
44 44 #include "fileout.h"
45 45 #include <iostream>
46 46
47 47 extern void declareFunctionMetaTypes(QTextStream &stream,
48 48 const AbstractMetaFunctionList &functions,
49 49 QSet<QString> &registeredTypeNames);
50 50
51 51 QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
52 52 {
53 53 return QString("PythonQtWrapper_%1.cpp").arg(meta_class->name());
54 54 }
55 55
56 56 static bool include_less_than(const Include &a, const Include &b)
57 57 {
58 58 return a.name < b.name;
59 59 }
60 60
61 61 static void writeHelperCode(QTextStream &s, const AbstractMetaClass *)
62 62 {
63 63 }
64 64
65 65
66 66
67 67 void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
68 68 {
69 69 QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":"";
70 70 QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri";
71 71 priGenerator->addSource(pro_file_name, fileNameForClass(meta_class));
72 72
73 73 s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl;
74 74
75 75 s << "#include <PythonQtSignalReceiver.h>" << endl;
76 76 s << "#include <PythonQtMethodInfo.h>" << endl;
77 77 s << "#include <PythonQtConversion.h>" << endl;
78 78
79 79 //if (!meta_class->generateShellClass())
80 80 // return;
81 81
82 82 IncludeList list = meta_class->typeEntry()->extraIncludes();
83 83 qSort(list.begin(), list.end());
84 84 foreach (const Include &inc, list) {
85 85 ShellGenerator::writeInclude(s, inc);
86 86 }
87 87 s << endl;
88 88
89 89 writeHelperCode(s, meta_class);
90 90
91 91 // find constructors
92 92 AbstractMetaFunctionList ctors;
93 93 ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
94 94 | AbstractMetaClass::WasVisible
95 95 | AbstractMetaClass::NotRemovedFromTargetLang);
96 96 // find member functions
97 97 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
98 98
99 99 // write metatype declarations
100 100 {
101 101 // QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
102 102 // declareFunctionMetaTypes(s, functions, registeredTypeNames);
103 103 // s << endl;
104 104 }
105 105 if (meta_class->qualifiedCppName().contains("Ssl")) {
106 106 s << "#ifndef QT_NO_OPENSSL" << endl;
107 107 }
108 108
109 109 if (meta_class->generateShellClass()) {
110 110
111 111 s << shellClassName(meta_class) << "::~" << shellClassName(meta_class) << "() {" << endl;
112 112 s << " PythonQtPrivate* priv = PythonQt::priv();" << endl;
113 113 s << " if (priv) { priv->shellClassDeleted(this); }" << endl;
114 114 s << "}" << endl;
115 115
116 116 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
117 117 foreach (const AbstractMetaFunction *fun, virtualsForShell) {
118 118 bool hasReturnValue = (fun->type());
119 119 writeFunctionSignature(s, fun, meta_class, QString(),
120 120 Option(OriginalName | ShowStatic | UnderscoreSpaces),
121 121 "PythonQtShell_");
122 122 s << endl << "{" << endl;
123 123
124 124 Option typeOptions = Option(OriginalName | UnderscoreSpaces | SkipName);
125 125 AbstractMetaArgumentList args = fun->arguments();
126 126
127 s << "if (_wrapper) {" << endl;
127 s << "if (_wrapper && (_wrapper->ob_refcnt > 0)) {" << endl;
128 128 s << " static PyObject* name = PyString_FromString(\"" << fun->name() << "\");" << endl;
129 129 s << " PyObject* obj = PyBaseObject_Type.tp_getattro((PyObject*)_wrapper, name);" << endl;
130 130 s << " if (obj) {" << endl;
131 131 s << " static const char* argumentList[] ={\"";
132 132 if (hasReturnValue) {
133 133 // write the arguments, return type first
134 134 writeTypeInfo(s, fun->type(), typeOptions);
135 135 }
136 136 s << "\"";
137 137 for (int i = 0; i < args.size(); ++i) {
138 138 s << " , \"";
139 139 writeTypeInfo(s, args.at(i)->type(), typeOptions);
140 140 s << "\"";
141 141 }
142 142 s << "};" << endl;
143 143 s << " static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(" << QString::number(args.size()+1) << ", argumentList);" << endl;
144 144
145 145 if (hasReturnValue) {
146 146 s << " ";
147 147 writeTypeInfo(s, fun->type(), typeOptions);
148 148 s << " returnValue;" << endl;
149 149 // TODO: POD init to default is missing...
150 150 }
151 151 s << " void* args[" << QString::number(args.size()+1) << "] = {NULL";
152 152 for (int i = 0; i < args.size(); ++i) {
153 153 s << ", (void*)&" << args.at(i)->argumentName();
154 154 }
155 155 s << "};" << endl;
156 156
157 157 s << " PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);" << endl;
158 158 if (hasReturnValue) {
159 159 s << " if (result) {" << endl;
160 160 s << " args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);" << endl;
161 161 s << " if (args[0]!=&returnValue) {" << endl;
162 162 s << " if (args[0]==NULL) {" << endl;
163 163 s << " PythonQt::priv()->handleVirtualOverloadReturnError(\"" << fun->name() << "\", methodInfo, result);" << endl;
164 164 s << " } else {" << endl;
165 165 s << " returnValue = *((";
166 166 writeTypeInfo(s, fun->type(), typeOptions);
167 167 s << "*)args[0]);" << endl;
168 168 s << " }" << endl;
169 169 s << " }" << endl;
170 170 s << " }" << endl;
171 171 }
172 172 s << " if (result) { Py_DECREF(result); } " << endl;
173 173 s << " Py_DECREF(obj);" << endl;
174 174 if (hasReturnValue) {
175 175 s << " return returnValue;" << endl;
176 176 } else {
177 177 s << " return;" << endl;
178 178 }
179 179 s << " } else {" << endl;
180 180 s << " PyErr_Clear();" << endl;
181 181 s << " }" << endl;
182 182 s << "}" << endl;
183 183
184 184 s << " ";
185 185 if (fun->isAbstract()) {
186 186 if (fun->type()) {
187 187 // return empty default object
188 188 s << "return ";
189 189 if (fun->type()->indirections()>0) {
190 190 s << "0;";
191 191 } else {
192 192 writeTypeInfo(s, fun->type(), typeOptions);
193 193 s << "();";
194 194 }
195 195 }
196 196 } else {
197 197 if (fun->type()) {
198 198 s << "return ";
199 199 }
200 200 s << meta_class->qualifiedCppName() << "::";
201 201 s << fun->originalName() << "(";
202 202 for (int i = 0; i < args.size(); ++i) {
203 203 if (i > 0)
204 204 s << ", ";
205 205 s << args.at(i)->argumentName();
206 206 }
207 207 s << ");";
208 208 }
209 209 s << endl << "}" << endl;
210 210 }
211 211 }
212 212
213 213 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
214 214
215 215 // write constructors
216 216 foreach (const AbstractMetaFunction *ctor, ctors) {
217 217 if (!ctor->isPublic() || ctor->isAbstract()) { continue; }
218 218
219 219 s << meta_class->qualifiedCppName() << "* ";
220 220 s << "PythonQtWrapper_" << meta_class->name() << "::";
221 221 writeFunctionSignature(s, ctor, 0, "new_", Option(OriginalName | ShowStatic));
222 222 s << endl;
223 223 s << "{ " << endl;
224 224 s << "return new " << (meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName()) << "(";
225 225 AbstractMetaArgumentList args = ctor->arguments();
226 226 for (int i = 0; i < args.size(); ++i) {
227 227 if (i > 0)
228 228 s << ", ";
229 229 s << args.at(i)->argumentName();
230 230 }
231 231 s << ");" << " }" << endl << endl;
232 232 }
233 233 }
234 234
235 235 QString wrappedObject = " (*theWrappedObject)";
236 236
237 237 // write member functions
238 238 for (int i = 0; i < functions.size(); ++i) {
239 239 AbstractMetaFunction *fun = functions.at(i);
240 240 bool needsWrapping = (!fun->isSlot() || fun->isVirtual());
241 241 if (!needsWrapping) {
242 242 continue;
243 243 }
244 244 writeFunctionSignature(s, fun, meta_class, QString(),
245 245 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | OriginalName | ShowStatic | UnderscoreSpaces),
246 246 "PythonQtWrapper_");
247 247 s << endl << "{" << endl;
248 248 s << " ";
249 249 if (ShellGenerator::isSpecialStreamingOperator(fun)) {
250 250 s << fun->arguments().at(0)->argumentName();
251 251 if (fun->originalName().startsWith("operator>>")) {
252 252 s << " >> ";
253 253 } else {
254 254 s << " << ";
255 255 }
256 256 s << wrappedObject;
257 257 } else {
258 258 QString scriptFunctionName = fun->originalName();
259 259 AbstractMetaArgumentList args = fun->arguments();
260 260 // call the C++ implementation
261 261 if (fun->type()) {
262 262 s << "return ";
263 263 // call the C++ implementation
264 264 if (fun->type()->isReference()) {
265 265 s << "&";
266 266 }
267 267 }
268 268 s << "(";
269 269 if (scriptFunctionName.startsWith("operator>>")) {
270 270 s << wrappedObject << " >>" << args.at(0)->argumentName();
271 271 } else if (scriptFunctionName.startsWith("operator<<")) {
272 272 s << wrappedObject << " <<" << args.at(0)->argumentName();
273 273 } else if (scriptFunctionName.startsWith("operator[]")) {
274 274 s << wrappedObject << "[" << args.at(0)->argumentName() << "]";
275 275 } else if (scriptFunctionName.startsWith("operator") && args.size()==1) {
276 276 QString op = scriptFunctionName.mid(8);
277 277 s << wrappedObject << op << " " << args.at(0)->argumentName();
278 278 } else {
279 279 if (fun->isStatic()) {
280 280 s << meta_class->qualifiedCppName() << "::";
281 281 } else {
282 282 if (!fun->isPublic() || fun->isVirtual()) {
283 283 s << " ((" << promoterClassName(meta_class) << "*)theWrappedObject)->promoted_";
284 284 } else {
285 285 s << " theWrappedObject->";
286 286 }
287 287 }
288 288 s << fun->originalName() << "(";
289 289 for (int i = 0; i < args.size(); ++i) {
290 290 if (i > 0)
291 291 s << ", ";
292 292 s << args.at(i)->argumentName();
293 293 }
294 294 s << ")";
295 295 }
296 296 s << ")";
297 297 }
298 298 s << ";" << endl;
299 299
300 300 s << "}" << endl << endl;
301 301 }
302 302
303 303 if (meta_class->hasDefaultToStringFunction()) {
304 304 s << "QString PythonQtWrapper_" << meta_class->name() << "::py_toString(" << meta_class->qualifiedCppName() << "* obj) { return obj->toString(); }" << endl;
305 305 } else if (meta_class->hasToStringCapability()) {
306 306 FunctionModelItem fun = meta_class->hasToStringCapability();
307 307 int indirections = fun->arguments().at(1)->type().indirections();
308 308 QString deref = QLatin1String(indirections == 0 ? "*" : "");
309 309 s << "QString PythonQtWrapper_" << meta_class->name() << "::py_toString(" << meta_class->qualifiedCppName() << "* obj) {" << endl;
310 310 s << " QString result;" << endl;
311 311 s << " QDebug d(&result);" << endl;
312 312 s << " d << " << deref << "obj;" << endl;
313 313 s << " return result;" << endl;
314 314 s << "}" << endl << endl;
315 315 }
316 316
317 317 writeInjectedCode(s, meta_class);
318 318
319 319 if (meta_class->qualifiedCppName().contains("Ssl")) {
320 320 s << "#endif" << endl;
321 321 }
322 322 }
323 323
324 324 void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
325 325 {
326 326 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
327 327 foreach (const CodeSnip &cs, code_snips) {
328 328 if (cs.language == TypeSystem::PyWrapperCode) {
329 329 s << cs.code() << endl;
330 330 }
331 331 }
332 332 }
General Comments 0
You need to be logged in to leave comments. Login now