Commit d7994a88 authored by Erik Verbruggen's avatar Erik Verbruggen
Browse files

Added tests for FindUsages in Objective-C code.

parent 555436bc
TEMPLATE = subdirs
SUBDIRS = shared ast semantic lookup preprocessor
SUBDIRS = shared ast semantic lookup preprocessor findusages
CONFIG += ordered
TEMPLATE = app
CONFIG += qt warn_on console depend_includepath
QT += testlib
include(../shared/shared.pri)
SOURCES += tst_findusages.cpp
TARGET=tst_$$TARGET
#include <QtTest>
#include <QObject>
#include <QList>
#include <AST.h>
#include <ASTVisitor.h>
#include <TranslationUnit.h>
#include <CppBindings.h>
#include <CppDocument.h>
#include <FindUsages.h>
#include <Literals.h>
#include <LookupContext.h>
#include <Name.h>
#include <ResolveExpression.h>
#include <Symbols.h>
#include <Overview.h>
using namespace CPlusPlus;
class CollectNames: public ASTVisitor
{
public:
CollectNames(TranslationUnit *xUnit): ASTVisitor(xUnit) {}
QList<NameAST*> operator()(const char *name) {
_name = name;
_exprs.clear();
accept(translationUnit()->ast());
return _exprs;
}
virtual bool preVisit(AST *ast) {
if (NameAST *nameAst = ast->asName())
if (!qstrcmp(_name, nameAst->name->identifier()->chars()))
_exprs.append(nameAst);
return true;
}
private:
QList<NameAST*> _exprs;
const char *_name;
};
class tst_FindUsages: public QObject
{
Q_OBJECT
private Q_SLOTS:
// Objective-C
void objc_args();
// void objc_methods();
// void objc_fields();
// void objc_classes();
};
#if 0
@interface Clazz {} +(void)method:(int)arg; @end
@implementation Clazz +(void)method:(int)arg {
[Clazz method:arg];
}
@end
#endif
const QByteArray objcSource = "\n"
"@interface Clazz {} +(void)method:(int)arg; @end\n"
"@implementation Clazz +(void)method:(int)arg {\n"
" [Clazz method:arg];\n"
"}\n"
"@end\n";
void tst_FindUsages::objc_args()
{
Document::Ptr doc = Document::create("objc_args");
doc->setSource(objcSource);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2U);
Snapshot snapshot;
snapshot.insert(doc);
TranslationUnit *xUnit = doc->translationUnit();
QList<NameAST*>exprs = CollectNames(xUnit)("arg");
QCOMPARE(exprs.size(), 3);
ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
QVERIFY(iface);
QVERIFY(iface->isInterface());
QCOMPARE(iface->memberCount(), 1U);
Declaration *methodIface = iface->memberAt(0)->asDeclaration();
QVERIFY(methodIface);
QCOMPARE(methodIface->identifier()->chars(), "method");
QVERIFY(methodIface->type()->isObjCMethodType());
ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass();
QVERIFY(impl);
QVERIFY(!impl->isInterface());
QCOMPARE(impl->memberCount(), 1U);
ObjCMethod *methodImpl = impl->memberAt(0)->asObjCMethod();
QVERIFY(methodImpl);
QCOMPARE(methodImpl->identifier()->chars(), "method");
QCOMPARE(methodImpl->argumentCount(), 1U);
Argument *arg = methodImpl->argumentAt(0)->asArgument();
QCOMPARE(arg->identifier()->chars(), "arg");
FindUsages findUsages(doc, snapshot);
findUsages.setGlobalNamespaceBinding(bind(doc, snapshot));
findUsages(arg);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.references().size(), 3);
}
QTEST_APPLESS_MAIN(tst_FindUsages)
#include "tst_findusages.moc"
......@@ -63,6 +63,7 @@ private Q_SLOTS:
void simple_class_1();
void class_with_baseclass();
void class_with_protocol_with_protocol();
void iface_impl_scoping();
};
void tst_Lookup::base_class_defined_1()
......@@ -311,10 +312,78 @@ void tst_Lookup::class_with_protocol_with_protocol()
QList<LookupItem> results = resolver.resolveMember(p1method->name(), zooImpl);
QCOMPARE(results.size(), 1);
QCOMPARE(results.at(0).lastVisibleSymbol(), p1method);
}
results = resolver.resolveMember(p1method->name(), zooImpl);
QCOMPARE(results.size(), 1);
QCOMPARE(results.at(0).lastVisibleSymbol(), p1method);
void tst_Lookup::iface_impl_scoping()
{
const QByteArray source = "\n"
"@interface Scooping{}-(int)method1:(int)arg;-(void)method2;@end\n"
"@implementation Scooping-(int)method1:(int)arg{return arg;}@end\n";
Document::Ptr doc = Document::create("class_with_protocol_with_protocol");
doc->setSource(source);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2U);
Snapshot snapshot;
snapshot.insert(doc);
Document::Ptr emptyDoc = Document::create("<empty>");
ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
QVERIFY(iface);
QVERIFY(iface->isInterface());
ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass();
QVERIFY(impl);
QVERIFY(!impl->isInterface());
QCOMPARE(iface->memberCount(), 2U);
QCOMPARE(impl->memberCount(), 1U);
ObjCMethod *method1Impl = impl->memberAt(0)->asObjCMethod();
QVERIFY(method1Impl);
QCOMPARE(method1Impl->identifier()->chars(), "method1");
// get the body of method1
QCOMPARE(method1Impl->memberCount(), 1U);
Block *method1Body = method1Impl->memberAt(0)->asBlock();
QVERIFY(method1Body);
const LookupContext ctxt(method1Body, emptyDoc, doc, snapshot);
{ // verify if we can resolve "arg" in the body
QCOMPARE(method1Impl->argumentCount(), 1U);
Argument *arg = method1Impl->argumentAt(0)->asArgument();
QVERIFY(arg);
QVERIFY(arg->name());
QVERIFY(arg->name()->identifier());
QCOMPARE(arg->name()->identifier()->chars(), "arg");
const QList<Symbol *> candidates = ctxt.resolve(arg->name());
QCOMPARE(candidates.size(), 1);
QVERIFY(candidates.at(0)->type()->asIntegerType());
}
Declaration *method2 = iface->memberAt(1)->asDeclaration();
QVERIFY(method2);
QCOMPARE(method2->identifier()->chars(), "method2");
{ // verify if we can resolve "method2" in the body
const QList<Symbol *> candidates = ctxt.resolve(method2->name());
QCOMPARE(candidates.size(), 1);
QCOMPARE(candidates.at(0), method2);
}
{ // now let's see if the resolver can do the same for method2
const ResolveExpression resolver(ctxt);
const QList<LookupItem> results = resolver.resolveMember(method2->name(),
impl);
QCOMPARE(results.size(), 1);
QCOMPARE(results.at(0).lastVisibleSymbol(), method2);
}
}
QTEST_APPLESS_MAIN(tst_Lookup)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment