tst_semantic.cpp 9.15 KB
Newer Older
1
2
3
4
5
6
7
8
9
10

#include <QtTest>
#include <QtDebug>

#include <Control.h>
#include <Parser.h>
#include <AST.h>
#include <Semantic.h>
#include <Scope.h>
#include <Symbols.h>
Roberto Raggi's avatar
Roberto Raggi committed
11
#include <CoreTypes.h>
12
13
#include <Names.h>
#include <Literals.h>
14
#include <DiagnosticClient.h>
15
16
17
18
19
20
21
22
23
24

CPLUSPLUS_USE_NAMESPACE

class tst_Semantic: public QObject
{
    Q_OBJECT

    Control control;

public:
25
26
27
    tst_Semantic()
    { control.setDiagnosticClient(&diag); }

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    TranslationUnit *parse(const QByteArray &source,
                           TranslationUnit::ParseMode mode)
    {
        StringLiteral *fileId = control.findOrInsertFileName("<stdin>");
        TranslationUnit *unit = new TranslationUnit(&control, fileId);
        unit->setSource(source.constData(), source.length());
        unit->parse(mode);
        return unit;
    }

    class Document {
        Q_DISABLE_COPY(Document)

    public:
        Document(TranslationUnit *unit)
43
            : unit(unit), globals(new Scope()), errorCount(0)
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
        { }

        ~Document()
        { delete globals; }

        void check()
        {
            QVERIFY(unit);
            QVERIFY(unit->ast());
            Semantic sem(unit->control());
            TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
            QVERIFY(ast);
            for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) {
                sem.check(decl, globals);
            }
        }

        TranslationUnit *unit;
        Scope *globals;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        unsigned errorCount;
    };

    class Diagnostic: public DiagnosticClient {
    public:
        int errorCount;

        Diagnostic()
            : errorCount(0)
        { }

        virtual void report(int, StringLiteral *,
                            unsigned, unsigned,
                            const char *, va_list)
        { ++errorCount; }
78
79
    };

80
81
82
    Diagnostic diag;


83
84
    QSharedPointer<Document> document(const QByteArray &source)
    {
85
        diag.errorCount = 0; // reset the error count.
86
87
88
        TranslationUnit *unit = parse(source, TranslationUnit::ParseTranlationUnit);
        QSharedPointer<Document> doc(new Document(unit));
        doc->check();
89
        doc->errorCount = diag.errorCount;
90
91
92
93
        return doc;
    }

private slots:
Roberto Raggi's avatar
Roberto Raggi committed
94
95
96
    void function_declaration_1();
    void function_declaration_2();
    void function_definition_1();
97
    void nested_class_1();
98
    void typedef_1();
Roberto Raggi's avatar
Roberto Raggi committed
99
    void typedef_2();
100
    void typedef_3();
101
102
};

Roberto Raggi's avatar
Roberto Raggi committed
103
void tst_Semantic::function_declaration_1()
104
105
{
    QSharedPointer<Document> doc = document("void foo();");
106
    QCOMPARE(doc->errorCount, 0U);
107
108
109
110
111
112
    QCOMPARE(doc->globals->symbolCount(), 1U);

    Declaration *decl = doc->globals->symbolAt(0)->asDeclaration();
    QVERIFY(decl);

    FullySpecifiedType declTy = decl->type();
Roberto Raggi's avatar
Roberto Raggi committed
113
    Function *funTy = declTy->asFunctionType();
114
115
116
117
118
119
120
121
122
123
124
125
    QVERIFY(funTy);
    QVERIFY(funTy->returnType()->isVoidType());
    QCOMPARE(funTy->argumentCount(), 0U);

    QVERIFY(decl->name()->isNameId());
    Identifier *funId = decl->name()->asNameId()->identifier();
    QVERIFY(funId);

    const QByteArray foo(funId->chars(), funId->size());
    QCOMPARE(foo, QByteArray("foo"));
}

Roberto Raggi's avatar
Roberto Raggi committed
126
127
128
void tst_Semantic::function_declaration_2()
{
    QSharedPointer<Document> doc = document("void foo(const QString &s);");
129
    QCOMPARE(doc->errorCount, 0U);
Roberto Raggi's avatar
Roberto Raggi committed
130
131
132
133
134
135
    QCOMPARE(doc->globals->symbolCount(), 1U);

    Declaration *decl = doc->globals->symbolAt(0)->asDeclaration();
    QVERIFY(decl);

    FullySpecifiedType declTy = decl->type();
Roberto Raggi's avatar
Roberto Raggi committed
136
    Function *funTy = declTy->asFunctionType();
Roberto Raggi's avatar
Roberto Raggi committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    QVERIFY(funTy);
    QVERIFY(funTy->returnType()->isVoidType());
    QCOMPARE(funTy->argumentCount(), 1U);

    // check the formal argument.
    Argument *arg = funTy->argumentAt(0)->asArgument();
    QVERIFY(arg);
    QVERIFY(arg->name());
    QVERIFY(! arg->hasInitializer());

    // check the argument's name.
    NameId *argNameId = arg->name()->asNameId();
    QVERIFY(argNameId);

    Identifier *argId = argNameId->identifier();
    QVERIFY(argId);

    QCOMPARE(QByteArray(argId->chars(), argId->size()), QByteArray("s"));

    // check the type of the formal argument
    FullySpecifiedType argTy = arg->type();
    QVERIFY(argTy->isReferenceType());
    QVERIFY(argTy->asReferenceType()->elementType().isConst());
160
161
162
163
164
165
166
    NamedType *namedTy = argTy->asReferenceType()->elementType()->asNamedType();
    QVERIFY(namedTy);
    QVERIFY(namedTy->name());
    Identifier *namedTypeId = namedTy->name()->asNameId()->identifier();
    QVERIFY(namedTypeId);
    QCOMPARE(QByteArray(namedTypeId->chars(), namedTypeId->size()),
             QByteArray("QString"));
Roberto Raggi's avatar
Roberto Raggi committed
167
168
169
170
171
172
173
174
175
176
177
178

    QVERIFY(decl->name()->isNameId());
    Identifier *funId = decl->name()->asNameId()->identifier();
    QVERIFY(funId);

    const QByteArray foo(funId->chars(), funId->size());
    QCOMPARE(foo, QByteArray("foo"));
}

void tst_Semantic::function_definition_1()
{
    QSharedPointer<Document> doc = document("void foo() {}");
179
    QCOMPARE(doc->errorCount, 0U);
Roberto Raggi's avatar
Roberto Raggi committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    QCOMPARE(doc->globals->symbolCount(), 1U);

    Function *funTy = doc->globals->symbolAt(0)->asFunction();
    QVERIFY(funTy);
    QVERIFY(funTy->returnType()->isVoidType());
    QCOMPARE(funTy->argumentCount(), 0U);

    QVERIFY(funTy->name()->isNameId());
    Identifier *funId = funTy->name()->asNameId()->identifier();
    QVERIFY(funId);

    const QByteArray foo(funId->chars(), funId->size());
    QCOMPARE(foo, QByteArray("foo"));
}
194

195
196
197
198
199
200
201
202
203
204
205
void tst_Semantic::nested_class_1()
{
    QSharedPointer<Document> doc = document(
"class Object {\n"
"    class Data;\n"
"    Data *d;\n"
"};\n"
"class Object::Data {\n"
"   Object *q;\n"
"};\n"
    );
206
    QCOMPARE(doc->errorCount, 0U);
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    QCOMPARE(doc->globals->symbolCount(), 2U);

    Class *classObject = doc->globals->symbolAt(0)->asClass();
    QVERIFY(classObject);
    QVERIFY(classObject->name());
    NameId *classObjectNameId = classObject->name()->asNameId();
    QVERIFY(classObjectNameId);
    Identifier *objectId = classObjectNameId->identifier();
    QCOMPARE(QByteArray(objectId->chars(), objectId->size()), QByteArray("Object"));
    QCOMPARE(classObject->baseClassCount(), 0U);
    QEXPECT_FAIL("", "Requires support for forward classes", Continue);
    QCOMPARE(classObject->members()->symbolCount(), 2U);

    Class *classObjectData = doc->globals->symbolAt(1)->asClass();
    QVERIFY(classObjectData);
    QVERIFY(classObjectData->name());
    QualifiedNameId *q = classObjectData->name()->asQualifiedNameId();
    QVERIFY(q);
    QCOMPARE(q->nameCount(), 2U);
    QVERIFY(q->nameAt(0)->asNameId());
    QVERIFY(q->nameAt(1)->asNameId());
    QCOMPARE(q->nameAt(0), classObject->name());
    QCOMPARE(doc->globals->lookat(q->nameAt(0)->asNameId()->identifier()), classObject);

    Declaration *decl = classObjectData->memberAt(0)->asDeclaration();
    QVERIFY(decl);
    PointerType *ptrTy = decl->type()->asPointerType();
    QVERIFY(ptrTy);
    NamedType *namedTy = ptrTy->elementType()->asNamedType();
    QVERIFY(namedTy);
    QVERIFY(namedTy->name()->asNameId());
    QCOMPARE(namedTy->name()->asNameId()->identifier(), objectId);
}

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
void tst_Semantic::typedef_1()
{
    QSharedPointer<Document> doc = document(
"typedef struct {\n"
"   int x, y;\n"
"} Point;\n"
"int main() {\n"
"   Point pt;\n"
"   pt.x = 1;\n"
"}\n"
    );

    QCOMPARE(doc->errorCount, 0U);
    QCOMPARE(doc->globals->symbolCount(), 3U);

    Class *anonStruct = doc->globals->symbolAt(0)->asClass();
    QVERIFY(anonStruct);
    QCOMPARE(anonStruct->memberCount(), 2U);

    Declaration *typedefPointDecl = doc->globals->symbolAt(1)->asDeclaration();
    QVERIFY(typedefPointDecl);
    QVERIFY(typedefPointDecl->isTypedef());
Roberto Raggi's avatar
Roberto Raggi committed
263
    QCOMPARE(typedefPointDecl->type()->asClassType(), anonStruct);
264
265
266
267
268

    Function *mainFun = doc->globals->symbolAt(2)->asFunction();
    QVERIFY(mainFun);
}

Roberto Raggi's avatar
Roberto Raggi committed
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
void tst_Semantic::typedef_2()
{
    QSharedPointer<Document> doc = document(
"struct _Point {\n"
"   int x, y;\n"
"};\n"
"typedef _Point Point;\n"
"int main() {\n"
"   Point pt;\n"
"   pt.x = 1;\n"
"}\n"
    );

    QCOMPARE(doc->errorCount, 0U);
    QCOMPARE(doc->globals->symbolCount(), 3U);

    Class *_pointStruct= doc->globals->symbolAt(0)->asClass();
    QVERIFY(_pointStruct);
    QCOMPARE(_pointStruct->memberCount(), 2U);

    Declaration *typedefPointDecl = doc->globals->symbolAt(1)->asDeclaration();
    QVERIFY(typedefPointDecl);
    QVERIFY(typedefPointDecl->isTypedef());
    QVERIFY(typedefPointDecl->type()->isNamedType());
    QCOMPARE(typedefPointDecl->type()->asNamedType()->name(), _pointStruct->name());

    Function *mainFun = doc->globals->symbolAt(2)->asFunction();
    QVERIFY(mainFun);
}

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
void tst_Semantic::typedef_3()
{
    QSharedPointer<Document> doc = document(
"typedef struct {\n"
"   int x, y;\n"
"} *PointPtr;\n"
    );

    QCOMPARE(doc->errorCount, 0U);
    QCOMPARE(doc->globals->symbolCount(), 2U);

    Class *_pointStruct= doc->globals->symbolAt(0)->asClass();
    QVERIFY(_pointStruct);
    QCOMPARE(_pointStruct->memberCount(), 2U);

    Declaration *typedefPointDecl = doc->globals->symbolAt(1)->asDeclaration();
    QVERIFY(typedefPointDecl);
    QVERIFY(typedefPointDecl->isTypedef());
    QVERIFY(typedefPointDecl->type()->isPointerType());
Roberto Raggi's avatar
Roberto Raggi committed
318
    QCOMPARE(typedefPointDecl->type()->asPointerType()->elementType()->asClassType(),
319
320
321
             _pointStruct);
}

322
323
QTEST_APPLESS_MAIN(tst_Semantic)
#include "tst_semantic.moc"