Skip to content

Commit 4889efc

Browse files
Marcelo Lirahugopl
Marcelo Lira
authored andcommitted
Added the "<custom-type>" tag, and better requirements for function signatures.
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 <[email protected]> Reviewed by Paulo Alcantara <[email protected]>
1 parent ab94961 commit 4889efc

8 files changed

+82
-57
lines changed

abstractmetabuilder.cpp

+19-2
Original file line numberDiff line numberDiff line change
@@ -2018,8 +2018,25 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct
20182018
}
20192019

20202020
if (!type) {
2021-
type = new TypeEntry(typeInfo.name, TypeEntry::CustomType, vr);
2022-
typeDb->addType(type);
2021+
QStringList candidates;
2022+
SingleTypeEntryHash entries = typeDb->entries();
2023+
foreach (QString candidate, entries.keys()) {
2024+
// Let's try to find the type in different scopes.
2025+
if (candidate.endsWith("::"+typeName))
2026+
candidates << candidate;
2027+
}
2028+
2029+
QString msg = QString("Type '%1' wasn't found in the type database.\n").arg(typeName);
2030+
2031+
if (candidates.isEmpty())
2032+
qFatal(qPrintable(QString(msg + "Declare it in the type system using the proper <*-type> tag.")), NULL);
2033+
2034+
msg += "Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n";
2035+
candidates.sort();
2036+
foreach (const QString& candidate, candidates) {
2037+
msg += " " + candidate + "\n";
2038+
}
2039+
qFatal(qPrintable(msg), NULL);
20232040
}
20242041

20252042
AbstractMetaType* metaType = createMetaType();

doc/typesystem_specifying_types.rst

+20
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,26 @@ container-type
328328

329329
The *optional* **since** value is used to specify the API version of this container.
330330

331+
332+
.. _custom-type:
333+
334+
custom-type
335+
^^^^^^^^^^^
336+
337+
The custom-type node simply makes the parser aware of the existence of a target
338+
language type, thus avoiding errors when trying to find a type used in function
339+
signatures and other places. The proper handling of the custom type is meant to
340+
be done by a generator using the APIExractor.
341+
342+
.. code-block:: xml
343+
344+
<typesystem>
345+
<custom-type name="..." />
346+
</typesystem>
347+
348+
The **name** attribute is the name of the custom type, e.g., "PyObject".
349+
350+
331351
.. _function:
332352

333353
function

tests/testaddfunction.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void TestAddFunction::testAddFunction()
6767
{
6868
const char cppCode[] = "struct B {}; struct A { void a(int); };";
6969
const char xmlCode[] = "\
70-
<typesystem package=\"Foo\">\
70+
<typesystem package='Foo'>\
7171
<primitive-type name='int' />\
7272
<primitive-type name='float' />\
7373
<value-type name='B' />\
@@ -108,7 +108,8 @@ void TestAddFunction::testAddFunctionConstructor()
108108
{
109109
const char cppCode[] = "struct A { A() {} };";
110110
const char xmlCode[] = "\
111-
<typesystem package=\"Foo\">\
111+
<typesystem package='Foo'>\
112+
<primitive-type name='int' />\
112113
<value-type name='A'>\
113114
<add-function signature='A(int)' />\
114115
</value-type>\
@@ -130,7 +131,7 @@ void TestAddFunction::testAddFunctionTagDefaultValues()
130131
{
131132
const char cppCode[] = "struct A {};";
132133
const char xmlCode[] = "\
133-
<typesystem package=\"Foo\">\
134+
<typesystem package='Foo'>\
134135
<value-type name='A'>\
135136
<add-function signature='func()' />\
136137
</value-type>\
@@ -151,7 +152,7 @@ void TestAddFunction::testAddFunctionCodeSnippets()
151152
{
152153
const char cppCode[] = "struct A {};";
153154
const char xmlCode[] = "\
154-
<typesystem package=\"Foo\">\
155+
<typesystem package='Foo'>\
155156
<value-type name='A'>\
156157
<add-function signature='func()'>\
157158
<inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\
@@ -178,7 +179,7 @@ void TestAddFunction::testAddFunctionWithoutParenteses()
178179

179180
const char cppCode[] = "struct A {};";
180181
const char xmlCode[] = "\
181-
<typesystem package=\"Foo\">\
182+
<typesystem package='Foo'>\
182183
<value-type name='A'>\
183184
<add-function signature='func'>\
184185
<inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\
@@ -207,7 +208,7 @@ void TestAddFunction::testAddFunctionWithDefaultArgs()
207208

208209
const char cppCode[] = "struct A { };";
209210
const char xmlCode[] = "\
210-
<typesystem package=\"Foo\">\
211+
<typesystem package='Foo'>\
211212
<primitive-type name='int'/> \
212213
<value-type name='A'>\
213214
<add-function signature='func(int, int)'>\
@@ -232,7 +233,7 @@ void TestAddFunction::testAddFunctionAtModuleLevel()
232233
{
233234
const char cppCode[] = "struct A { };";
234235
const char xmlCode[] = "\
235-
<typesystem package=\"Foo\">\
236+
<typesystem package='Foo'>\
236237
<primitive-type name='int'/> \
237238
<value-type name='A'/>\
238239
<add-function signature='func(int, int)'>\
@@ -270,7 +271,7 @@ void TestAddFunction::testAddFunctionWithVarargs()
270271

271272
const char cppCode[] = "struct A {};";
272273
const char xmlCode[] = "\
273-
<typesystem package=\"Foo\">\
274+
<typesystem package='Foo'>\
274275
<primitive-type name='int'/> \
275276
<primitive-type name='char'/> \
276277
<value-type name='A'>\
@@ -293,7 +294,7 @@ void TestAddFunction::testAddStaticFunction()
293294
{
294295
const char cppCode[] = "struct A { };";
295296
const char xmlCode[] = "\
296-
<typesystem package=\"Foo\">\
297+
<typesystem package='Foo'>\
297298
<primitive-type name='int'/> \
298299
<value-type name='A'>\
299300
<add-function signature='func(int, int)' static='yes'>\
@@ -314,7 +315,7 @@ void TestAddFunction::testAddGlobalFunction()
314315
{
315316
const char cppCode[] = "struct A { };struct B {};";
316317
const char xmlCode[] = "\
317-
<typesystem package=\"Foo\">\
318+
<typesystem package='Foo'>\
318319
<primitive-type name='int'/> \
319320
<value-type name='A' />\
320321
<add-function signature='globalFunc(int, int)' static='yes'>\
@@ -385,9 +386,10 @@ void TestAddFunction::testAddFunctionOnTypedef()
385386
const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;";
386387
const char xmlCode[] = "\
387388
<typesystem package='Package'>\
389+
<custom-type name='PySequence'/>\
388390
<primitive-type name='int'/>\
389391
<value-type name='FooInt'>\
390-
<add-function signature='FooInt(PySequence*)'>\
392+
<add-function signature='FooInt(PySequence)'>\
391393
<inject-code class='target' position='beginning'>custom_code();</inject-code>\
392394
</add-function>\
393395
<add-function signature='method()'>\

tests/testimplicitconversions.cpp

+19-23
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,20 @@ void TestImplicitConversions::testWithPrivateCtors()
3030
const char* cppCode ="\
3131
class B;\
3232
class C;\
33-
\
3433
class A {\
3534
A(const B&);\
3635
public:\
3736
A(const C&);\
3837
};\
39-
\
4038
class B {};\
4139
class C {};\
4240
";
4341
const char* xmlCode = "\
44-
<typesystem package=\"Foo\"> \
45-
<value-type name=\"A\"/> \
46-
<value-type name=\"B\"/> \
47-
<value-type name=\"C\"/> \
48-
</typesystem>";
42+
<typesystem package='Foo'> \
43+
<value-type name='A'/> \
44+
<value-type name='B'/> \
45+
<value-type name='C'/> \
46+
</typesystem>";
4947
TestUtil t(cppCode, xmlCode);
5048
AbstractMetaClassList classes = t.builder()->classes();
5149
QCOMPARE(classes.count(), 3);
@@ -65,18 +63,17 @@ void TestImplicitConversions::testWithModifiedVisibility()
6563
public:\
6664
A(const B&);\
6765
};\
68-
\
6966
class B {};\
7067
";
7168
const char* xmlCode = "\
72-
<typesystem package=\"Foo\">\
73-
<value-type name=\"A\">\
69+
<typesystem package='Foo'>\
70+
<value-type name='A'>\
7471
<modify-function signature='A(const B&amp;)'>\
7572
<access modifier='private' />\
7673
</modify-function>\
7774
</value-type>\
78-
<value-type name=\"B\"/>\
79-
</typesystem>";
75+
<value-type name='B'/>\
76+
</typesystem>";
8077
TestUtil t(cppCode, xmlCode);
8178
AbstractMetaClassList classes = t.builder()->classes();
8279
QCOMPARE(classes.count(), 2);
@@ -96,20 +93,20 @@ void TestImplicitConversions::testWithAddedCtor()
9693
public:\
9794
A(const B&);\
9895
};\
99-
\
10096
class B {};\
10197
class C {};\
10298
";
10399
const char* xmlCode = "\
104-
<typesystem package=\"Foo\">\
105-
<value-type name=\"A\">\
100+
<typesystem package='Foo'>\
101+
<custom-type name='TARGETLANGTYPE' />\
102+
<value-type name='A'>\
106103
<add-function signature='A(const C&amp;)' />\
107104
</value-type>\
108-
<value-type name=\"B\">\
105+
<value-type name='B'>\
109106
<add-function signature='B(TARGETLANGTYPE*)' />\
110107
</value-type>\
111-
<value-type name=\"C\"/>\
112-
</typesystem>";
108+
<value-type name='C'/>\
109+
</typesystem>";
113110
TestUtil t(cppCode, xmlCode);
114111
AbstractMetaClassList classes = t.builder()->classes();
115112
QCOMPARE(classes.count(), 3);
@@ -133,10 +130,10 @@ void TestImplicitConversions::testWithExternalConversionOperator()
133130
};\
134131
";
135132
const char* xmlCode = "\
136-
<typesystem package=\"Foo\">\
137-
<value-type name=\"A\"/>\
138-
<value-type name=\"B\"/>\
139-
</typesystem>";
133+
<typesystem package='Foo'>\
134+
<value-type name='A'/>\
135+
<value-type name='B'/>\
136+
</typesystem>";
140137
TestUtil t(cppCode, xmlCode);
141138
AbstractMetaClassList classes = t.builder()->classes();
142139
QCOMPARE(classes.count(), 2);
@@ -159,4 +156,3 @@ void TestImplicitConversions::testWithExternalConversionOperator()
159156
QTEST_APPLESS_MAIN(TestImplicitConversions)
160157

161158
#include "testimplicitconversions.moc"
162-

tests/testnestedtypes.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void TestNestedTypes::testDuplicationOfNestedTypes()
9393
<typesystem package='Foo'> \
9494
<namespace-type name='Namespace'>\
9595
<value-type name='SomeClass'>\
96-
<add-function signature='createSomeClass(SomeClass)'/>\
96+
<add-function signature='createSomeClass(Namespace::SomeClass)'/>\
9797
</value-type>\
9898
</namespace-type>\
9999
</typesystem>";
@@ -114,7 +114,7 @@ void TestNestedTypes::testDuplicationOfNestedTypes()
114114
TypeEntry* t1 = TypeDatabase::instance()->findType("Namespace::SomeClass");
115115
QVERIFY(t1);
116116
TypeEntry* t2 = TypeDatabase::instance()->findType("SomeClass");
117-
QCOMPARE(t1, t2);
117+
QVERIFY(!t2);
118118
}
119119

120120
QTEST_APPLESS_MAIN(TestNestedTypes)

typedatabase.cpp

+4-19
Original file line numberDiff line numberDiff line change
@@ -141,29 +141,14 @@ PrimitiveTypeEntry* TypeDatabase::findTargetLangPrimitiveType(const QString& tar
141141

142142
TypeEntry* TypeDatabase::findType(const QString& name) const
143143
{
144-
TypeEntry* typeEntry = 0;
145-
QList<TypeEntry *> typeEntries = findTypes(name);
146-
147-
if (typeEntries.isEmpty()) {
148-
SingleTypeEntryHash entriesHash = entries();
149-
foreach (QString typeName, entriesHash.keys()) {
150-
// Let's try to find the type in different scopes.
151-
// We will prefer the ones with the least depth.
152-
if (typeName.endsWith("::"+name)
153-
&& (!typeEntry || typeEntry->qualifiedCppName().count("::") < typeName.count("::"))) {
154-
typeEntry = entriesHash[typeName];
155-
}
156-
}
157-
}
158-
159-
foreach (TypeEntry* entry, typeEntries) {
144+
QList<TypeEntry *> entries = findTypes(name);
145+
foreach (TypeEntry *entry, entries) {
160146
if (entry &&
161147
(!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
162-
typeEntry = entry;
163-
break;
148+
return entry;
164149
}
165150
}
166-
return typeEntry;
151+
return 0;
167152
}
168153

169154
SingleTypeEntryHash TypeDatabase::entries() const

typesystem.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Handler::Handler(TypeDatabase* database, bool generate)
4545
m_ignoreDepth = 0;
4646

4747
tagNames["rejection"] = StackElement::Rejection;
48+
tagNames["custom-type"] = StackElement::CustomTypeEntry;
4849
tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
4950
tagNames["container-type"] = StackElement::ContainerTypeEntry;
5051
tagNames["object-type"] = StackElement::ObjectTypeEntry;
@@ -629,6 +630,9 @@ bool Handler::startElement(const QString &, const QString &n,
629630
}
630631

631632
switch (element->type) {
633+
case StackElement::CustomTypeEntry:
634+
element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
635+
break;
632636
case StackElement::PrimitiveTypeEntry: {
633637
QString targetLangName = attributes["target-lang-name"];
634638
QString targetLangApiName = attributes["target-lang-api-name"];

typesystem_p.h

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class StackElement
4646
EnumTypeEntry = 0x9,
4747
ContainerTypeEntry = 0xa,
4848
FunctionTypeEntry = 0xb,
49+
CustomTypeEntry = 0xc,
4950
TypeEntryMask = 0xf,
5051

5152
// Documentation tags

0 commit comments

Comments
 (0)