aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Lira <marcelo.lira@openbossa.org>2011-09-01 18:53:22 -0300
committerHugo Parente Lima <hugo.pl@gmail.com>2012-03-09 19:10:19 -0300
commite7fdca6465740132bd881ffd9d20e61be47472d0 (patch)
tree00b4b44348d9389e4e394d08b99b11478f88d63c
parent2d3a55bd847616a9b666531795d3b99e5c78a56a (diff)
Fixes method's argument types that are templates but the template variable wasn't declared.
An unit test was added. Other unrelated tests had minor improvements. Reviewed by Hugo Parente <hugo.lima@openbossa.org> Reviewed by Luciano Wolf <luciano.wolf@openbossa.org>
-rw-r--r--abstractmetabuilder.cpp229
-rw-r--r--tests/testcontainer.cpp2
-rw-r--r--tests/testenum.cpp4
-rw-r--r--tests/testrefcounttag.cpp4
-rw-r--r--tests/testtemplates.cpp41
-rw-r--r--tests/testtemplates.h1
6 files changed, 203 insertions, 78 deletions
diff --git a/abstractmetabuilder.cpp b/abstractmetabuilder.cpp
index 12c0aebde..9fc1674d8 100644
--- a/abstractmetabuilder.cpp
+++ b/abstractmetabuilder.cpp
@@ -1344,97 +1344,180 @@ void AbstractMetaBuilder::fixReturnTypeOfConversionOperator(AbstractMetaFunction
metaFunction->replaceType(metaType);
}
+static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other)
+{
+ if (!type && !other)
+ return true;
+ if (!type || !other)
+ return false;
+ return type->typeEntry() == other->typeEntry()
+ && type->isConstant() == other->isConstant()
+ && type->isReference() == other->isReference()
+ && type->indirections() == other->indirections();
+}
+
+static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other)
+{
+ if (!func && !other)
+ return true;
+ if (!func || !other)
+ return false;
+ if (func->arguments().count() != other->arguments().count()
+ || func->isConstant() != other->isConstant()
+ || func->isStatic() != other->isStatic()
+ || !_compareAbstractMetaTypes(func->type(), other->type())) {
+ return false;
+ }
+ for (int i = 0; i < func->arguments().count(); ++i) {
+ if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type()))
+ return false;
+ }
+ return true;
+}
+
+static bool _fixFunctionModelItemType(TypeInfo& type, const AbstractMetaClass* metaClass)
+{
+ if (metaClass->templateArguments().isEmpty()
+ || type.qualifiedName().isEmpty()
+ || type.qualifiedName().first() != metaClass->typeEntry()->qualifiedCppName()) {
+ return false;
+ }
+ QStringList templateTypes;
+ foreach (TypeEntry* templateType, metaClass->templateArguments())
+ templateTypes << templateType->qualifiedCppName();
+ QString fixedTypeName = QString("%1<%2 >").arg(metaClass->typeEntry()->qualifiedCppName()).arg(templateTypes.join(", "));
+ type.setQualifiedName(QStringList(fixedTypeName));
+ return true;
+}
+
+static bool _fixFunctionModelItemTypes(FunctionModelItem& function, const AbstractMetaClass* metaClass)
+{
+ TypeInfo functionType = function->type();
+ bool templateTypeFixed = _fixFunctionModelItemType(functionType, metaClass);
+ if (templateTypeFixed)
+ function->setType(functionType);
+
+ ArgumentList arguments = function->arguments();
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ TypeInfo type = arg->type();
+ bool tmpTypeFixed = _fixFunctionModelItemType(type, metaClass);
+ if (tmpTypeFixed)
+ arg->setType(type);
+ templateTypeFixed |= tmpTypeFixed;
+ }
+ return templateTypeFixed;
+}
+
void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass* metaClass)
{
foreach (FunctionModelItem function, scopeItem->functions()) {
+
+ // This fixes method's arguments and return types that are templates
+ // but the template variable wasn't declared in the C++ header.
+ bool templateTypeFixed = _fixFunctionModelItemTypes(function, metaClass);
+
AbstractMetaFunction* metaFunction = traverseFunction(function);
- if (metaFunction) {
- metaFunction->setOriginalAttributes(metaFunction->attributes());
- if (metaClass->isNamespace())
- *metaFunction += AbstractMetaAttributes::Static;
-
- QPropertySpec *read = 0;
- if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) {
- // Property reader must be in the form "<type> name()"
- if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) && (metaFunction->arguments().size() == 0)) {
- *metaFunction += AbstractMetaAttributes::PropertyReader;
- metaFunction->setPropertySpec(read);
- }
- } else if (QPropertySpec* write = metaClass->propertySpecForWrite(metaFunction->name())) {
- // Property setter must be in the form "void name(<type>)"
- // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem
- if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) {
- *metaFunction += AbstractMetaAttributes::PropertyWriter;
- metaFunction->setPropertySpec(write);
- }
- } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
- // Property resetter must be in the form "void name()"
- if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
- *metaFunction += AbstractMetaAttributes::PropertyResetter;
- metaFunction->setPropertySpec(reset);
+ if (!metaFunction)
+ continue;
+
+ if (templateTypeFixed) {
+ foreach (AbstractMetaFunction* func, metaClass->queryFunctionsByName(metaFunction->name())) {
+ if (_compareAbstractMetaFunctions(metaFunction, func)) {
+ delete metaFunction;
+ metaFunction = 0;
+ break;
}
}
+ if (!metaFunction)
+ continue;
+ }
- // Can not use metaFunction->isCopyConstructor() because
- // the function wasn't assigned to its owner class yet.
- bool isCopyCtor = false;
- if (metaFunction->isConstructor() && metaFunction->arguments().size() == 1) {
- const AbstractMetaType* argType = metaFunction->arguments().first()->type();
- isCopyCtor = argType->isConstant()
- && argType->isReference()
- && argType->typeEntry()->name() == metaFunction->name();
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaAttributes::Static;
+
+ QPropertySpec *read = 0;
+ if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) {
+ // Property reader must be in the form "<type> name()"
+ if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyReader;
+ metaFunction->setPropertySpec(read);
}
-
- bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
- bool isInvalidConstructor = metaFunction->isConstructor()
- && ((metaFunction->isPrivate() && !isCopyCtor) || metaFunction->isInvalid());
-
- if ((isInvalidDestructor || isInvalidConstructor)
- && !metaClass->hasNonPrivateConstructor()) {
- *metaClass += AbstractMetaAttributes::Final;
- } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
- *metaClass -= AbstractMetaAttributes::Final;
- metaClass->setHasNonPrivateConstructor(true);
+ } else if (QPropertySpec* write = metaClass->propertySpecForWrite(metaFunction->name())) {
+ // Property setter must be in the form "void name(<type>)"
+ // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) {
+ *metaFunction += AbstractMetaAttributes::PropertyWriter;
+ metaFunction->setPropertySpec(write);
+ }
+ } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
+ // Property resetter must be in the form "void name()"
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyResetter;
+ metaFunction->setPropertySpec(reset);
}
+ }
- // Classes with virtual destructors should always have a shell class
- // (since we aren't registering the destructors, we need this extra check)
- if (metaFunction->isDestructor() && !metaFunction->isFinal())
- metaClass->setForceShellClass(true);
+ // Can not use metaFunction->isCopyConstructor() because
+ // the function wasn't assigned to its owner class yet.
+ bool isCopyCtor = false;
+ if (metaFunction->isConstructor() && metaFunction->arguments().size() == 1) {
+ const AbstractMetaType* argType = metaFunction->arguments().first()->type();
+ isCopyCtor = argType->isConstant()
+ && argType->isReference()
+ && argType->typeEntry()->name() == metaFunction->name();
+ }
- if (!metaFunction->isDestructor()
- && !metaFunction->isInvalid()
- && !(metaFunction->isPrivate() && metaFunction->isConstructor() && !isCopyCtor)) {
+ bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
+ bool isInvalidConstructor = metaFunction->isConstructor()
+ && ((metaFunction->isPrivate() && !isCopyCtor) || metaFunction->isInvalid());
- setupFunctionDefaults(metaFunction, metaClass);
+ if ((isInvalidDestructor || isInvalidConstructor)
+ && !metaClass->hasNonPrivateConstructor()) {
+ *metaClass += AbstractMetaAttributes::Final;
+ } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
+ *metaClass -= AbstractMetaAttributes::Final;
+ metaClass->setHasNonPrivateConstructor(true);
+ }
- if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) {
- QString warn = QString("signal '%1' in class '%2' is overloaded.")
- .arg(metaFunction->name()).arg(metaClass->name());
- ReportHandler::warning(warn);
- }
+ // Classes with virtual destructors should always have a shell class
+ // (since we aren't registering the destructors, we need this extra check)
+ if (metaFunction->isDestructor() && !metaFunction->isFinal())
+ metaClass->setForceShellClass(true);
- if (metaFunction->isSignal() && !metaClass->isQObject()) {
- QString warn = QString("signal '%1' in non-QObject class '%2'")
- .arg(metaFunction->name()).arg(metaClass->name());
- ReportHandler::warning(warn);
- }
+ if (!metaFunction->isDestructor()
+ && !metaFunction->isInvalid()
+ && !(metaFunction->isPrivate() && metaFunction->isConstructor() && !isCopyCtor)) {
- if (metaFunction->isConversionOperator())
- fixReturnTypeOfConversionOperator(metaFunction);
+ setupFunctionDefaults(metaFunction, metaClass);
- metaClass->addFunction(metaFunction);
- applyFunctionModifications(metaFunction);
- } else if (metaFunction->isDestructor()) {
- metaClass->setHasPrivateDestructor(metaFunction->isPrivate());
- metaClass->setHasProtectedDestructor(metaFunction->isProtected());
- metaClass->setHasVirtualDestructor(metaFunction->isVirtual());
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) {
+ QString warn = QString("signal '%1' in class '%2' is overloaded.")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
}
- if (!metaFunction->ownerClass()) {
- delete metaFunction;
- metaFunction = 0;
+
+ if (metaFunction->isSignal() && !metaClass->isQObject()) {
+ QString warn = QString("signal '%1' in non-QObject class '%2'")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
}
+
+ if (metaFunction->isConversionOperator())
+ fixReturnTypeOfConversionOperator(metaFunction);
+
+ metaClass->addFunction(metaFunction);
+ applyFunctionModifications(metaFunction);
+ } else if (metaFunction->isDestructor()) {
+ metaClass->setHasPrivateDestructor(metaFunction->isPrivate());
+ metaClass->setHasProtectedDestructor(metaFunction->isProtected());
+ metaClass->setHasVirtualDestructor(metaFunction->isVirtual());
+ }
+ if (!metaFunction->ownerClass()) {
+ delete metaFunction;
+ metaFunction = 0;
}
}
@@ -1738,7 +1821,6 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem fu
return 0;
}
-
Q_ASSERT(functionItem->functionType() == CodeModel::Normal
|| functionItem->functionType() == CodeModel::Signal
|| functionItem->functionType() == CodeModel::Slot);
@@ -1845,6 +1927,7 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem fu
metaFunction->setInvalid(true);
return metaFunction;
}
+
AbstractMetaArgument* metaArgument = createMetaArgument();
metaArgument->setType(metaType);
diff --git a/tests/testcontainer.cpp b/tests/testcontainer.cpp
index 1f5af51fa..563b75c20 100644
--- a/tests/testcontainer.cpp
+++ b/tests/testcontainer.cpp
@@ -54,8 +54,6 @@ void TestContainer::testContainerType()
QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(classA->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::ListContainer);
}
-
-
QTEST_APPLESS_MAIN(TestContainer)
#include "testcontainer.moc"
diff --git a/tests/testenum.cpp b/tests/testenum.cpp
index 07aa0e8cb..85796a1e9 100644
--- a/tests/testenum.cpp
+++ b/tests/testenum.cpp
@@ -62,7 +62,9 @@ void TestEnum::testEnumCppSignature()
// enum as parameter of a method
AbstractMetaClass* classA = classes.findClass("A");
QCOMPARE(classA->enums().count(), 1);
- AbstractMetaFunction* method = classA->queryFunctionsByName("method").first();
+ AbstractMetaFunctionList funcs = classA->queryFunctionsByName("method");
+ QVERIFY(!funcs.isEmpty());
+ AbstractMetaFunction* method = funcs.first();
QVERIFY(method);
AbstractMetaArgument* arg = method->arguments().first();
QCOMPARE(arg->type()->name(), QString("ClassEnum"));
diff --git a/tests/testrefcounttag.cpp b/tests/testrefcounttag.cpp
index 424055f2c..9e05cee93 100644
--- a/tests/testrefcounttag.cpp
+++ b/tests/testrefcounttag.cpp
@@ -48,7 +48,7 @@ void TestRefCountTag::testReferenceCountTag()
AbstractMetaClassList classes = t.builder()->classes();
AbstractMetaClass* classB = classes.findClass("B");
const AbstractMetaFunction* func = classB->findFunction("keepObject");
-
+ QVERIFY(func);
ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first();
QCOMPARE(refCount.action, ReferenceCount::Add);
}
@@ -80,7 +80,7 @@ void TestRefCountTag::testWithApiVersion()
AbstractMetaClassList classes = t.builder()->classes();
AbstractMetaClass* classB = classes.findClass("B");
const AbstractMetaFunction* func = classB->findFunction("keepObject");
-
+ QVERIFY(func);
ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first();
QCOMPARE(refCount.action, ReferenceCount::Add);
diff --git a/tests/testtemplates.cpp b/tests/testtemplates.cpp
index bfee774d6..c6a65d888 100644
--- a/tests/testtemplates.cpp
+++ b/tests/testtemplates.cpp
@@ -337,6 +337,47 @@ void TestTemplates::testTypedefOfInstantiationOfTemplateClass()
QCOMPARE(inst->cppSignature(), QString("NSpace::TypeOne"));
}
+void TestTemplates::testContainerTypeIncompleteArgument()
+{
+ const char* cppCode ="\
+ template<typename T>\
+ class Vector {\
+ void method(const Vector& vector);\
+ Vector otherMethod();\
+ };\
+ template <typename T>\
+ void Vector<T>::method(const Vector<T>& vector) {}\
+ Vector Vector<T>::otherMethod() { return Vector<T>(); }\
+ typedef Vector<int> IntVector;\
+ ";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\
+ <primitive-type name='int'/>\
+ <container-type name='Vector' type='vector'/>\
+ <value-type name='IntVector'/>\
+ </typesystem>";
+
+ TestUtil t(cppCode, xmlCode, true);
+ AbstractMetaClassList classes = t.builder()->classes();
+ QCOMPARE(classes.count(), 1);
+
+ AbstractMetaClass* vector = classes.findClass("IntVector");
+ QVERIFY(vector);
+ QVERIFY(vector->typeEntry()->baseContainerType());
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(vector->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::VectorContainer);
+ QCOMPARE(vector->functions().count(), 4);
+
+ const AbstractMetaFunction* method = vector->findFunction("method");
+ QVERIFY(method);
+ QCOMPARE(method->signature(), QString("method(const Vector<int > & vector)"));
+
+ const AbstractMetaFunction* otherMethod = vector->findFunction("otherMethod");
+ QVERIFY(otherMethod);
+ QCOMPARE(otherMethod->signature(), QString("otherMethod()"));
+ QVERIFY(otherMethod->type());
+ QCOMPARE(otherMethod->type()->cppSignature(), QString("Vector<int >"));
+}
+
QTEST_APPLESS_MAIN(TestTemplates)
#include "testtemplates.moc"
diff --git a/tests/testtemplates.h b/tests/testtemplates.h
index 1b7267af4..578691169 100644
--- a/tests/testtemplates.h
+++ b/tests/testtemplates.h
@@ -39,6 +39,7 @@ private slots:
void testTemplateInheritanceMixedWithForwardDeclaration();
void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
void testTypedefOfInstantiationOfTemplateClass();
+ void testContainerTypeIncompleteArgument();
};
#endif