summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Lira <marcelo.lira@openbossa.org>2011-12-23 15:10:17 -0300
committerHugo Parente Lima <hugo.pl@gmail.com>2012-03-09 19:10:21 -0300
commit4889efc199243af54cf71accffb3f9554cba933d (patch)
treec08e9b0b65074868454f09807c51455a582a5410
parentab94961a639cc7b364fcb1e3f68531792c312990 (diff)
Added the "<custom-type>" tag, and better requirements for function signatures.sb-0.10.10
Trying to find a non-qualified (without scope information) class, found in a function signature or return type, was a bad idea for it makes the parsing awfully slow when dealing with huge libraries. If the user writes a type in short form in a function signature (e.g. "SomeClass", instead of "Namespace::SomeClass"), APIExtractor will exit with a message indicating the error and the possible candidates for the type. The "<custom-type>" tag is for types of the target language ("PyObject" in Python, for instance) and will be handled by the generator. Reviewed by Hugo Parente <hugo.lima@openbossa.org> Reviewed by Paulo Alcantara <pcacjr@gmail.com>
-rw-r--r--abstractmetabuilder.cpp21
-rw-r--r--doc/typesystem_specifying_types.rst20
-rw-r--r--tests/testaddfunction.cpp24
-rw-r--r--tests/testimplicitconversions.cpp42
-rw-r--r--tests/testnestedtypes.cpp4
-rw-r--r--typedatabase.cpp23
-rw-r--r--typesystem.cpp4
-rw-r--r--typesystem_p.h1
8 files changed, 82 insertions, 57 deletions
diff --git a/abstractmetabuilder.cpp b/abstractmetabuilder.cpp
index abdf5c70..1d01e9ce 100644
--- a/abstractmetabuilder.cpp
+++ b/abstractmetabuilder.cpp
@@ -2018,8 +2018,25 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct
}
if (!type) {
- type = new TypeEntry(typeInfo.name, TypeEntry::CustomType, vr);
- typeDb->addType(type);
+ QStringList candidates;
+ SingleTypeEntryHash entries = typeDb->entries();
+ foreach (QString candidate, entries.keys()) {
+ // Let's try to find the type in different scopes.
+ if (candidate.endsWith("::"+typeName))
+ candidates << candidate;
+ }
+
+ QString msg = QString("Type '%1' wasn't found in the type database.\n").arg(typeName);
+
+ if (candidates.isEmpty())
+ qFatal(qPrintable(QString(msg + "Declare it in the type system using the proper <*-type> tag.")), NULL);
+
+ msg += "Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n";
+ candidates.sort();
+ foreach (const QString& candidate, candidates) {
+ msg += " " + candidate + "\n";
+ }
+ qFatal(qPrintable(msg), NULL);
}
AbstractMetaType* metaType = createMetaType();
diff --git a/doc/typesystem_specifying_types.rst b/doc/typesystem_specifying_types.rst
index d5a4ef2d..0d24a6d5 100644
--- a/doc/typesystem_specifying_types.rst
+++ b/doc/typesystem_specifying_types.rst
@@ -328,6 +328,26 @@ container-type
The *optional* **since** value is used to specify the API version of this container.
+
+.. _custom-type:
+
+custom-type
+^^^^^^^^^^^
+
+ The custom-type node simply makes the parser aware of the existence of a target
+ language type, thus avoiding errors when trying to find a type used in function
+ signatures and other places. The proper handling of the custom type is meant to
+ be done by a generator using the APIExractor.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <custom-type name="..." />
+ </typesystem>
+
+ The **name** attribute is the name of the custom type, e.g., "PyObject".
+
+
.. _function:
function
diff --git a/tests/testaddfunction.cpp b/tests/testaddfunction.cpp
index beb49fa1..c1189c34 100644
--- a/tests/testaddfunction.cpp
+++ b/tests/testaddfunction.cpp
@@ -67,7 +67,7 @@ void TestAddFunction::testAddFunction()
{
const char cppCode[] = "struct B {}; struct A { void a(int); };";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int' />\
<primitive-type name='float' />\
<value-type name='B' />\
@@ -108,7 +108,8 @@ void TestAddFunction::testAddFunctionConstructor()
{
const char cppCode[] = "struct A { A() {} };";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
+ <primitive-type name='int' />\
<value-type name='A'>\
<add-function signature='A(int)' />\
</value-type>\
@@ -130,7 +131,7 @@ void TestAddFunction::testAddFunctionTagDefaultValues()
{
const char cppCode[] = "struct A {};";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<value-type name='A'>\
<add-function signature='func()' />\
</value-type>\
@@ -151,7 +152,7 @@ void TestAddFunction::testAddFunctionCodeSnippets()
{
const char cppCode[] = "struct A {};";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<value-type name='A'>\
<add-function signature='func()'>\
<inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\
@@ -178,7 +179,7 @@ void TestAddFunction::testAddFunctionWithoutParenteses()
const char cppCode[] = "struct A {};";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<value-type name='A'>\
<add-function signature='func'>\
<inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\
@@ -207,7 +208,7 @@ void TestAddFunction::testAddFunctionWithDefaultArgs()
const char cppCode[] = "struct A { };";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int'/> \
<value-type name='A'>\
<add-function signature='func(int, int)'>\
@@ -232,7 +233,7 @@ void TestAddFunction::testAddFunctionAtModuleLevel()
{
const char cppCode[] = "struct A { };";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int'/> \
<value-type name='A'/>\
<add-function signature='func(int, int)'>\
@@ -270,7 +271,7 @@ void TestAddFunction::testAddFunctionWithVarargs()
const char cppCode[] = "struct A {};";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int'/> \
<primitive-type name='char'/> \
<value-type name='A'>\
@@ -293,7 +294,7 @@ void TestAddFunction::testAddStaticFunction()
{
const char cppCode[] = "struct A { };";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int'/> \
<value-type name='A'>\
<add-function signature='func(int, int)' static='yes'>\
@@ -314,7 +315,7 @@ void TestAddFunction::testAddGlobalFunction()
{
const char cppCode[] = "struct A { };struct B {};";
const char xmlCode[] = "\
- <typesystem package=\"Foo\">\
+ <typesystem package='Foo'>\
<primitive-type name='int'/> \
<value-type name='A' />\
<add-function signature='globalFunc(int, int)' static='yes'>\
@@ -385,9 +386,10 @@ void TestAddFunction::testAddFunctionOnTypedef()
const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;";
const char xmlCode[] = "\
<typesystem package='Package'>\
+ <custom-type name='PySequence'/>\
<primitive-type name='int'/>\
<value-type name='FooInt'>\
- <add-function signature='FooInt(PySequence*)'>\
+ <add-function signature='FooInt(PySequence)'>\
<inject-code class='target' position='beginning'>custom_code();</inject-code>\
</add-function>\
<add-function signature='method()'>\
diff --git a/tests/testimplicitconversions.cpp b/tests/testimplicitconversions.cpp
index 86032aca..4bc4d73f 100644
--- a/tests/testimplicitconversions.cpp
+++ b/tests/testimplicitconversions.cpp
@@ -30,22 +30,20 @@ void TestImplicitConversions::testWithPrivateCtors()
const char* cppCode ="\
class B;\
class C;\
- \
class A {\
A(const B&);\
public:\
A(const C&);\
};\
- \
class B {};\
class C {};\
";
const char* xmlCode = "\
- <typesystem package=\"Foo\"> \
- <value-type name=\"A\"/> \
- <value-type name=\"B\"/> \
- <value-type name=\"C\"/> \
- </typesystem>";
+ <typesystem package='Foo'> \
+ <value-type name='A'/> \
+ <value-type name='B'/> \
+ <value-type name='C'/> \
+ </typesystem>";
TestUtil t(cppCode, xmlCode);
AbstractMetaClassList classes = t.builder()->classes();
QCOMPARE(classes.count(), 3);
@@ -65,18 +63,17 @@ void TestImplicitConversions::testWithModifiedVisibility()
public:\
A(const B&);\
};\
- \
class B {};\
";
const char* xmlCode = "\
- <typesystem package=\"Foo\">\
- <value-type name=\"A\">\
+ <typesystem package='Foo'>\
+ <value-type name='A'>\
<modify-function signature='A(const B&amp;)'>\
<access modifier='private' />\
</modify-function>\
</value-type>\
- <value-type name=\"B\"/>\
- </typesystem>";
+ <value-type name='B'/>\
+ </typesystem>";
TestUtil t(cppCode, xmlCode);
AbstractMetaClassList classes = t.builder()->classes();
QCOMPARE(classes.count(), 2);
@@ -96,20 +93,20 @@ void TestImplicitConversions::testWithAddedCtor()
public:\
A(const B&);\
};\
- \
class B {};\
class C {};\
";
const char* xmlCode = "\
- <typesystem package=\"Foo\">\
- <value-type name=\"A\">\
+ <typesystem package='Foo'>\
+ <custom-type name='TARGETLANGTYPE' />\
+ <value-type name='A'>\
<add-function signature='A(const C&amp;)' />\
</value-type>\
- <value-type name=\"B\">\
+ <value-type name='B'>\
<add-function signature='B(TARGETLANGTYPE*)' />\
</value-type>\
- <value-type name=\"C\"/>\
- </typesystem>";
+ <value-type name='C'/>\
+ </typesystem>";
TestUtil t(cppCode, xmlCode);
AbstractMetaClassList classes = t.builder()->classes();
QCOMPARE(classes.count(), 3);
@@ -133,10 +130,10 @@ void TestImplicitConversions::testWithExternalConversionOperator()
};\
";
const char* xmlCode = "\
- <typesystem package=\"Foo\">\
- <value-type name=\"A\"/>\
- <value-type name=\"B\"/>\
- </typesystem>";
+ <typesystem package='Foo'>\
+ <value-type name='A'/>\
+ <value-type name='B'/>\
+ </typesystem>";
TestUtil t(cppCode, xmlCode);
AbstractMetaClassList classes = t.builder()->classes();
QCOMPARE(classes.count(), 2);
@@ -159,4 +156,3 @@ void TestImplicitConversions::testWithExternalConversionOperator()
QTEST_APPLESS_MAIN(TestImplicitConversions)
#include "testimplicitconversions.moc"
-
diff --git a/tests/testnestedtypes.cpp b/tests/testnestedtypes.cpp
index 4e000cb0..83512f7d 100644
--- a/tests/testnestedtypes.cpp
+++ b/tests/testnestedtypes.cpp
@@ -93,7 +93,7 @@ void TestNestedTypes::testDuplicationOfNestedTypes()
<typesystem package='Foo'> \
<namespace-type name='Namespace'>\
<value-type name='SomeClass'>\
- <add-function signature='createSomeClass(SomeClass)'/>\
+ <add-function signature='createSomeClass(Namespace::SomeClass)'/>\
</value-type>\
</namespace-type>\
</typesystem>";
@@ -114,7 +114,7 @@ void TestNestedTypes::testDuplicationOfNestedTypes()
TypeEntry* t1 = TypeDatabase::instance()->findType("Namespace::SomeClass");
QVERIFY(t1);
TypeEntry* t2 = TypeDatabase::instance()->findType("SomeClass");
- QCOMPARE(t1, t2);
+ QVERIFY(!t2);
}
QTEST_APPLESS_MAIN(TestNestedTypes)
diff --git a/typedatabase.cpp b/typedatabase.cpp
index 1247bf7f..d5c1eb6c 100644
--- a/typedatabase.cpp
+++ b/typedatabase.cpp
@@ -141,29 +141,14 @@ PrimitiveTypeEntry* TypeDatabase::findTargetLangPrimitiveType(const QString& tar
TypeEntry* TypeDatabase::findType(const QString& name) const
{
- TypeEntry* typeEntry = 0;
- QList<TypeEntry *> typeEntries = findTypes(name);
-
- if (typeEntries.isEmpty()) {
- SingleTypeEntryHash entriesHash = entries();
- foreach (QString typeName, entriesHash.keys()) {
- // Let's try to find the type in different scopes.
- // We will prefer the ones with the least depth.
- if (typeName.endsWith("::"+name)
- && (!typeEntry || typeEntry->qualifiedCppName().count("::") < typeName.count("::"))) {
- typeEntry = entriesHash[typeName];
- }
- }
- }
-
- foreach (TypeEntry* entry, typeEntries) {
+ QList<TypeEntry *> entries = findTypes(name);
+ foreach (TypeEntry *entry, entries) {
if (entry &&
(!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
- typeEntry = entry;
- break;
+ return entry;
}
}
- return typeEntry;
+ return 0;
}
SingleTypeEntryHash TypeDatabase::entries() const
diff --git a/typesystem.cpp b/typesystem.cpp
index 8808e531..a08c2df2 100644
--- a/typesystem.cpp
+++ b/typesystem.cpp
@@ -45,6 +45,7 @@ Handler::Handler(TypeDatabase* database, bool generate)
m_ignoreDepth = 0;
tagNames["rejection"] = StackElement::Rejection;
+ tagNames["custom-type"] = StackElement::CustomTypeEntry;
tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
tagNames["container-type"] = StackElement::ContainerTypeEntry;
tagNames["object-type"] = StackElement::ObjectTypeEntry;
@@ -629,6 +630,9 @@ bool Handler::startElement(const QString &, const QString &n,
}
switch (element->type) {
+ case StackElement::CustomTypeEntry:
+ element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
+ break;
case StackElement::PrimitiveTypeEntry: {
QString targetLangName = attributes["target-lang-name"];
QString targetLangApiName = attributes["target-lang-api-name"];
diff --git a/typesystem_p.h b/typesystem_p.h
index 371321bc..e8f5f240 100644
--- a/typesystem_p.h
+++ b/typesystem_p.h
@@ -46,6 +46,7 @@ class StackElement
EnumTypeEntry = 0x9,
ContainerTypeEntry = 0xa,
FunctionTypeEntry = 0xb,
+ CustomTypeEntry = 0xc,
TypeEntryMask = 0xf,
// Documentation tags