aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Lira <marcelo.lira@openbossa.org>2010-06-15 15:11:11 -0300
committerMarcelo Lira <marcelo.lira@openbossa.org>2010-06-15 20:15:09 -0300
commitb22d72848c3ce6a8433399a5e9e3d182ff08c13d (patch)
tree0714ae4c4a5df708197d3a161f3577526afcc62f
parent7f433285d4e78a9525d6b72fcaf679a208d45bf3 (diff)
Overload decisor code modified to separate the decision and caller parts.
This makes the generated code more clear and eases future improvements as named argument support. There is room for performance improvements. Reviewed by Luciano Wolf <luciano.wolf@openbossa.org> Reviewed by Renato Araújo <renato.filho@openbossa.org>
-rw-r--r--cppgenerator.cpp260
-rw-r--r--cppgenerator.h31
2 files changed, 214 insertions, 77 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index 3b742e298..4b30a573e 100644
--- a/cppgenerator.cpp
+++ b/cppgenerator.cpp
@@ -675,9 +675,11 @@ void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass
void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
{
OverloadData overloadData(overloads, this);
+
const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
const AbstractMetaClass* metaClass = rfunc->ownerClass();
QString className = cpythonTypeName(metaClass);
+
m_currentErrorCode = -1;
s << "static int" << endl;
@@ -689,17 +691,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
s << (hasCppWrapper ? wrapperName(metaClass) : metaClass->qualifiedCppName());
s << "* cptr = 0;" << endl;
-
- bool hasCodeInjectionsAtEnd = false;
- foreach(AbstractMetaFunction* func, overloads) {
- foreach (CodeSnip cs, func->injectedCodeSnips()) {
- if (cs.position == CodeSnip::End) {
- hasCodeInjectionsAtEnd = true;
- break;
- }
- }
- }
- if (hasCodeInjectionsAtEnd)
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
s << INDENT << "int overloadId = -1;" << endl;
if (overloadData.hasAllowThread())
@@ -745,7 +738,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
writeArgumentsInitializer(s, overloadData);
}
- writeOverloadedMethodDecisor(s, &overloadData);
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, &overloadData);
+
+ writeFunctionCalls(s, overloadData);
s << endl;
s << INDENT << "if (PyErr_Occurred() || !Shiboken::setCppPointer(sbkSelf, Shiboken::SbkType<" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl;
@@ -781,6 +777,15 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
// Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ foreach(AbstractMetaFunction* func, overloads) {
+ foreach (CodeSnip cs, func->injectedCodeSnips()) {
+ if (cs.position == CodeSnip::End) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
if (hasCodeInjectionsAtEnd) {
// FIXME: C++ arguments are not available in code injection on constructor when position = end.
s << INDENT << "switch(overloadId) {" << endl;
@@ -905,7 +910,17 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << ')' << endl << '{' << endl;
if (rfunc->implementingClass() &&
- (!rfunc->implementingClass()->isNamespace() && !rfunc->isStatic())) {
+ (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
+
+ s << INDENT;
+#ifdef AVOID_PROTECTED_HACK
+ QString _wrapperName = wrapperName(rfunc->ownerClass());
+ bool hasProtectedMembers = rfunc->ownerClass()->hasProtectedMembers();
+ s << (hasProtectedMembers ? _wrapperName : rfunc->ownerClass()->qualifiedCppName());
+#else
+ s << rfunc->ownerClass()->qualifiedCppName();
+#endif
+ s << "* " CPP_SELF_VAR " = 0;" << endl;
if (rfunc->isOperatorOverload() && rfunc->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(rfunc->ownerClass()->typeEntry());
@@ -915,16 +930,25 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << INDENT << "std::swap(self, arg);\n\n";
}
+ // Sets the C++ "self" (the "this" for the object) if it has one.
+ QString cppSelfAttribution = CPP_SELF_VAR " = ";
+#ifdef AVOID_PROTECTED_HACK
+ cppSelfAttribution += (hasProtectedMembers ? QString("(%1*)").arg(_wrapperName) : "");
+#endif
+ cppSelfAttribution += cpythonWrapperCPtr(rfunc->ownerClass(), "self");
+
// Checks if the underlying C++ object is valid.
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ if (overloadData.hasStaticFunction()) {
s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
}
s << INDENT << '}' << endl;
} else {
writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
}
s << endl;
}
@@ -933,9 +957,13 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
if (hasReturnValue && !rfunc->isInplaceOperator())
s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
+ s << INDENT << "int overloadId = -1;" << endl;
+
if (overloadData.hasAllowThread())
s << INDENT << "Shiboken::ThreadStateSaver " THREAD_STATE_SAVER_VAR ";" << endl;
- s << endl;
if (minArgs != maxArgs || maxArgs > 1) {
s << INDENT << "int numArgs = ";
@@ -944,6 +972,7 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
else
writeArgumentsInitializer(s, overloadData);
}
+ s << endl;
/*
* Make sure reverse <</>> operators defined in other classes (specially from other modules)
@@ -991,7 +1020,11 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
}
- writeOverloadedMethodDecisor(s, &overloadData);
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData);
+ s << endl;
if (callExtendedReverseOperator)
s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl << endl;
@@ -1218,7 +1251,8 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadDa
void CppGenerator::writeArgumentConversion(QTextStream& s,
const AbstractMetaType* argType,
QString argName, QString pyArgName,
- const AbstractMetaClass* context)
+ const AbstractMetaClass* context,
+ QString defaultValue)
{
const TypeEntry* type = argType->typeEntry();
@@ -1245,25 +1279,47 @@ void CppGenerator::writeArgumentConversion(QTextStream& s,
bool hasImplicitConversions = !implicitConversions(argType).isEmpty();
if (isWrappedCppClass) {
- const TypeEntry* type = (hasImplicitConversions ? argType->typeEntry() : 0);
+ const TypeEntry* type = (hasImplicitConversions ? type : 0);
writeInvalidCppObjectCheck(s, pyArgName, type);
}
- if (hasImplicitConversions) {
- s << INDENT << "std::auto_ptr<" << baseTypeName << " > ";
- s << argName << "_auto_ptr;" << endl;
- }
+ // Auto pointer to dealloc new objects created because to satisfy implicit conversion.
+ if (hasImplicitConversions)
+ s << INDENT << "std::auto_ptr<" << baseTypeName << " > " << argName << "_auto_ptr;" << endl;
+
+ // Value type that has default value.
+ if (argType->isValue() && !defaultValue.isEmpty())
+ s << INDENT << baseTypeName << ' ' << argName << "_tmp = " << defaultValue << ';' << endl;
if (usePySideExtensions() && typeName == "QStringRef") {
- s << INDENT << "QString " << argName << "_qstring = Shiboken::Converter<QString>::toCpp(" << pyArgName << ");" << endl;
+ s << INDENT << "QString " << argName << "_qstring = ";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<QString>::toCpp(" << pyArgName << ')' << endl;
+ if (!defaultValue.isEmpty())
+ s << " : " << defaultValue;
+ s << ';' << endl;
s << INDENT << "QStringRef " << argName << "(&" << argName << "_qstring);" << endl;
} else {
s << INDENT << typeName << ' ' << argName << " = ";
- s << "Shiboken::Converter<" << typeName << " >::toCpp(" << pyArgName << ");" << endl;
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<" << typeName << " >::toCpp(" << pyArgName << ')';
+ if (!defaultValue.isEmpty()) {
+ s << " : ";
+ if (argType->isValue())
+ s << '&' << argName << "_tmp";
+ else
+ s << defaultValue;
+ }
+ s << ';' << endl;
}
if (hasImplicitConversions) {
- s << INDENT << "if (!" << cpythonCheckFunction(argType->typeEntry()) << '(' << pyArgName << "))";
+ s << INDENT << "if (";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " && ";
+ s << '!' << cpythonCheckFunction(type) << '(' << pyArgName << "))";
s << endl;
Indentation indent(INDENT);
s << INDENT << argName << "_auto_ptr = std::auto_ptr<" << baseTypeName;
@@ -1279,7 +1335,21 @@ void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* f
}
}
-void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* parentOverloadData)
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData)
+{
+ s << INDENT << "// Overloaded function decisor" << endl;
+ QList<const AbstractMetaFunction*> functionOverloads = overloadData.overloadsWithoutRepetition();
+ for (int i = 0; i < functionOverloads.count(); i++)
+ s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl;
+ writeOverloadedFunctionDecisor(s, &overloadData);
+ s << endl;
+
+ s << INDENT << "// Function signature not found." << endl;
+ s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData* parentOverloadData)
{
bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction();
@@ -1287,7 +1357,7 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
// If the next argument has not an argument with a default value, it is still possible
// that one of the overloads for the current overload data has its final occurrence here.
// If found, the final occurrence of a method is attributed to the referenceFunction
- // variable to be used further on this method on the conditional that writes default
+ // variable to be used further on this method on the conditional that identifies default
// method calls.
if (!hasDefaultCall) {
foreach (const AbstractMetaFunction* func, parentOverloadData->overloads()) {
@@ -1303,9 +1373,10 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
// Python constructors always receive multiple arguments.
bool manyArgs = maxArgs > 1 || referenceFunction->isConstructor();
- // Functions without arguments are written right away.
+ // Functions without arguments are identified right away.
if (maxArgs == 0) {
- writeMethodCall(s, referenceFunction);
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction);
+ s << "; // " << referenceFunction->minimalSignature() << endl;
return;
// To decide if a method call is possible at this point the current overload
@@ -1316,25 +1387,24 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
bool signatureFound = parentOverloadData->overloads().size() == 1;
// The current overload data describes the last argument of a signature,
- // so the method can be called right now.
+ // so the method can be identified right now.
if (isLastArgument || (signatureFound && !hasDefaultCall)) {
const AbstractMetaFunction* func = parentOverloadData->referenceFunction();
- int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
- writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
- if (!func->isConstructor())
- writeNoneReturn(s, func, parentOverloadData->headOverloadData()->hasNonVoidReturnType());
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
return;
}
}
- s << INDENT;
+ bool isFirst = true;
// If the next argument has a default value the decisor can perform a method call;
// it just need to check if the number of arguments received from Python are equal
// to the number of parameters preceding the argument with the default value.
if (hasDefaultCall) {
+ isFirst = false;
int numArgs = parentOverloadData->argPos() + 1;
- s << "if (numArgs == " << numArgs << ") {" << endl;
+ s << INDENT << "if (numArgs == " << numArgs << ") {" << endl;
{
Indentation indent(INDENT);
const AbstractMetaFunction* func = referenceFunction;
@@ -1345,11 +1415,10 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
break;
}
}
- writeMethodCall(s, func, numArgs);
- if (!func->isConstructor())
- writeNoneReturn(s, func, parentOverloadData->headOverloadData()->hasNonVoidReturnType());
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
}
- s << INDENT << "} else ";
+ s << INDENT << '}';
}
foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
@@ -1359,6 +1428,13 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
+ if (isFirst) {
+ isFirst = false;
+ s << INDENT;
+ } else {
+ s << " else ";
+ }
+
s << "if (";
if (manyArgs && signatureFound) {
AbstractMetaArgumentList args = refFunc->arguments();
@@ -1384,22 +1460,6 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
writeTypeCheck(tck, od, pyArgName);
- const AbstractMetaType* argType = 0;
- if (od->argumentTypeReplaced().isEmpty())
- argType = od->argType();
- else
- argType = buildAbstractMetaTypeFromString(od->argumentTypeReplaced());
-
- Indentation indent(INDENT);
- if (argType) {
- writeArgumentConversion(tcv, argType,
- QString("cpp_arg%1").arg(od->argPos()),
- pyArgName,
- refFunc->implementingClass());
- if (argType != od->argType())
- delete argType;
- }
-
if (od->nextOverloadData().isEmpty()
|| od->nextArgumentHasDefaultValue()
|| od->nextOverloadData().size() != 1
@@ -1418,14 +1478,84 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
{
Indentation indent(INDENT);
- writeOverloadedMethodDecisor(s, overloadData);
+ writeOverloadedFunctionDecisor(s, overloadData);
}
- s << INDENT << "} else ";
+ s << INDENT << "}";
}
+ s << endl;
+}
- if (maxArgs > 0)
- s << "goto " << cpythonFunctionName(referenceFunction) << "_TypeError;" << endl;
+void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overloadData)
+{
+ QList<const AbstractMetaFunction*> overloads = overloadData.overloadsWithoutRepetition();
+
+ s << INDENT << "// Call function/method" << endl;
+ s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloads.count() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.first());
+ } else {
+ for (int i = 0; i < overloads.count(); i++) {
+ const AbstractMetaFunction* func = overloads.at(i);
+ s << INDENT << "case " << i << ": // " << func->minimalSignature() << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeSingleFunctionCall(s, overloadData, func);
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func)
+{
+ const AbstractMetaClass* implementingClass = overloadData.referenceFunction()->implementingClass();
+ bool multipleArguments = overloadData.maxArgs() > 1 || overloadData.referenceFunction()->isConstructor();
+
+ int removedArgs = 0;
+ for (int i = 0; i < func->arguments().count(); i++) {
+ if (func->argumentRemoved(i + 1)) {
+ removedArgs++;
+ continue;
+ }
+
+ if (!func->conversionRule(TypeSystem::NativeCode, i + 1).isEmpty())
+ continue;
+
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ const AbstractMetaType* argType = 0;
+ if (typeReplaced.isEmpty())
+ argType = arg->type();
+ else
+ argType = buildAbstractMetaTypeFromString(typeReplaced);
+
+ if (argType) {
+ QString argName = QString("cpp_arg%1").arg(i - removedArgs);
+ QString pyArgName = multipleArguments ? QString("pyargs[%1]").arg(i - removedArgs) : "arg";
+ QString defaultValue = guessScopeForDefaultValue(func, arg);
+
+ writeArgumentConversion(s, argType, argName, pyArgName, implementingClass, defaultValue);
+
+ // Free a custom type created by buildAbstractMetaTypeFromString.
+ if (argType != arg->type())
+ delete argType;
+ }
+ }
+
+ s << endl;
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+ writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
}
QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
@@ -1477,8 +1607,6 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
s << INDENT << "}\n";
}
- writeCppSelfDefinition(s, func);
-
// Used to provide contextual information to custom code writer function.
const AbstractMetaArgument* lastArg = 0;
@@ -1531,7 +1659,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
if (arg->defaultValueExpression().isEmpty())
badModifications = true;
else
- userArgs << arg->defaultValueExpression();
+ userArgs << guessScopeForDefaultValue(func, arg);
}
} else {
int idx = arg->argumentIndex() - removedArgs;
@@ -1568,7 +1696,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
if (!arg->defaultValueExpression().isEmpty())
- otherArgs.prepend(arg->defaultValueExpression());
+ otherArgs.prepend(guessScopeForDefaultValue(func, arg));
else if (hasConversionRule)
otherArgs.prepend(arg->argumentName() + "_out");
else
@@ -3286,14 +3414,12 @@ bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMeta
void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn)
{
const int numArgs = func->arguments().count();
- s << INDENT << "//CppGenerator::writeParentChildManagement" << endl;
// -1 = return value
// 0 = self
// 1..n = func. args.
- for (int i = -1; i <= numArgs; ++i) {
+ for (int i = -1; i <= numArgs; ++i)
writeParentChildManagement(s, func, i, i == 0 ? useHeuristicForReturn : true);
- }
}
void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self)
diff --git a/cppgenerator.h b/cppgenerator.h
index c6ba546ba..eee5e2e9d 100644
--- a/cppgenerator.h
+++ b/cppgenerator.h
@@ -76,20 +76,22 @@ private:
* code to deallocate a possible new instance is also generated.
* \param s text stream to write
* \param metatype a pointer to the argument type to be converted
- * \param context the current meta class
* \param argName C++ argument name
- * \param argName Python argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
*/
void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType,
QString argName, QString pyArgName,
- const AbstractMetaClass* context = 0);
- /// Convenience method to call writeArgumentConversion with an AbstractMetaArgument
- /// instead of an AbstractMetaType.
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString());
+ /// Convenience method to call writeArgumentConversion with an AbstractMetaArgument instead of an AbstractMetaType.
void writeArgumentConversion(QTextStream& s, const AbstractMetaArgument* arg,
QString argName, QString pyArgName,
- const AbstractMetaClass* context = 0)
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString())
{
- writeArgumentConversion(s, arg->type(), argName, pyArgName, context);
+ writeArgumentConversion(s, arg->type(), argName, pyArgName, context, defaultValue);
}
/**
@@ -104,12 +106,21 @@ private:
void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue);
/**
- * Writes the Python method wrapper overload decisor that selects which C++
+ * Writes the Python function wrapper overload decisor that selects which C++
* method/function to call with the received Python arguments.
* \param s text stream to write
- * \param parentOverloadData a pointer to overload data describing the argument being evaluated
+ * \param overloadData the overload data describing all the possible overloads for the function/method
*/
- void writeOverloadedMethodDecisor(QTextStream& s, OverloadData* parentOverloadData);
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData);
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData* parentOverloadData);
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(QTextStream& s, const OverloadData& overloadData);
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func = 0);
+
/// Returns a string containing the name of an argument for the given function and argument index.
QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass);
void writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs = 0);