void tst_Lookup::class_with_protocol_with_protocol() { const QByteArray source = "\n" "@protocol P1 -(void)p1method; @end\n" "@protocol P2 <P1> -(void)p2method; @end\n" "@interface Zoo <P2> {} +(id)alloc; -(id)init; @end\n" "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n"; Document::Ptr doc = Document::create("class_with_protocol_with_protocol"); doc->setUtf8Source(source); doc->parse(); doc->check(); QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 4U); Snapshot snapshot; snapshot.insert(doc); ObjCProtocol *P1 = doc->globalSymbolAt(0)->asObjCProtocol(); QVERIFY(P1); QCOMPARE(P1->memberCount(), 1U); QCOMPARE(P1->protocolCount(), 0U); Declaration *p1method = P1->memberAt(0)->asDeclaration(); QVERIFY(p1method); QCOMPARE(QLatin1String(p1method->name()->identifier()->chars()), QLatin1String("p1method")); ObjCProtocol *P2 = doc->globalSymbolAt(1)->asObjCProtocol(); QVERIFY(P2); QCOMPARE(P2->memberCount(), 1U); QCOMPARE(P2->protocolCount(), 1U); QCOMPARE(QLatin1String(P2->protocolAt(0)->name()->identifier()->chars()), QLatin1String("P1")); ObjCClass *zooImpl = doc->globalSymbolAt(3)->asObjCClass(); QVERIFY(zooImpl); const LookupContext context(doc, snapshot); { const QList<LookupItem> candidates = context.lookup(P1->name(), zooImpl->enclosingScope()); QCOMPARE(candidates.size(), 1); QVERIFY(candidates.at(0).declaration() == P1); } { const QList<LookupItem> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->enclosingScope()); QCOMPARE(candidates.size(), 1); QVERIFY(candidates.first().declaration() == P1); } QList<LookupItem> results = context.lookup(p1method->name(), zooImpl); QCOMPARE(results.size(), 1); QCOMPARE(results.at(0).declaration(), p1method); }
bool CheckDeclaration::visit(ObjCClassDeclarationAST *ast) { unsigned sourceLocation; if (ast->class_name) sourceLocation = ast->class_name->firstToken(); else sourceLocation = ast->firstToken(); Name *className = semantic()->check(ast->class_name, _scope); ObjCClass *klass = control()->newObjCClass(sourceLocation, className); klass->setStartOffset(tokenAt(ast->firstToken()).offset); klass->setEndOffset(tokenAt(ast->lastToken()).offset); ast->symbol = klass; klass->setInterface(ast->interface_token != 0); if (ast->category_name) { Name *categoryName = semantic()->check(ast->category_name, _scope); klass->setCategoryName(categoryName); } if (ast->superclass) { Name *superClassName = semantic()->check(ast->superclass, _scope); ObjCBaseClass *superKlass = control()->newObjCBaseClass(ast->superclass->firstToken(), superClassName); klass->setBaseClass(superKlass); } if (ast->protocol_refs && ast->protocol_refs->identifier_list) { for (IdentifierListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) { NameAST* name = iter->name; Name *protocolName = semantic()->check(name, _scope); ObjCBaseProtocol *baseProtocol = control()->newObjCBaseProtocol(name->firstToken(), protocolName); klass->addProtocol(baseProtocol); } } _scope->enterSymbol(klass); int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Protected); if (ast->inst_vars_decl) { for (DeclarationListAST *it = ast->inst_vars_decl->instance_variables; it; it = it->next) { semantic()->check(it->declaration, klass->members()); } } (void) semantic()->switchObjCVisibility(Function::Public); for (DeclarationListAST *it = ast->member_declarations; it; it = it->next) { semantic()->check(it->declaration, klass->members()); } (void) semantic()->switchObjCVisibility(previousObjCVisibility); return false; }
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->setUtf8Source(source); doc->parse(); doc->check(); QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 2U); Snapshot snapshot; snapshot.insert(doc); 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(), 2U); Argument *method1Arg = method1Impl->memberAt(0)->asArgument(); QVERIFY(method1Arg); QCOMPARE(method1Arg->identifier()->chars(), "arg"); QVERIFY(method1Arg->type()->isIntegerType()); Block *method1Body = method1Impl->memberAt(1)->asBlock(); QVERIFY(method1Body); const LookupContext context(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"); QVERIFY(arg->type()->isIntegerType()); const QList<LookupItem> candidates = context.lookup(arg->name(), method1Body->enclosingScope()); QCOMPARE(candidates.size(), 1); QVERIFY(candidates.at(0).declaration()->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<LookupItem> candidates = context.lookup(method2->name(), method1Body->enclosingScope()); QCOMPARE(candidates.size(), 1); QCOMPARE(candidates.at(0).declaration(), method2); } }
void tst_Lookup::class_with_baseclass() { const QByteArray source = "\n" "@implementation BaseZoo {} -(void)baseDecl; -(void)baseMethod{} @end\n" "@interface Zoo: BaseZoo {} +(id)alloc; -(id)init; @end\n" "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n"; Document::Ptr doc = Document::create("class_with_baseclass"); doc->setUtf8Source(source); doc->parse(); doc->check(); QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 3U); Snapshot snapshot; snapshot.insert(doc); Document::Ptr emptyDoc = Document::create("<empty>"); ObjCClass *baseZoo = doc->globalSymbolAt(0)->asObjCClass(); QVERIFY(baseZoo); QVERIFY(!baseZoo->isInterface()); QCOMPARE(baseZoo->memberCount(), 2U); ObjCClass *zooIface = doc->globalSymbolAt(1)->asObjCClass(); QVERIFY(zooIface); QVERIFY(zooIface->isInterface()); QVERIFY(zooIface->baseClass()->name() == baseZoo->name()); ObjCClass *zooImpl = doc->globalSymbolAt(2)->asObjCClass(); QVERIFY(zooImpl); QVERIFY(!zooImpl->isInterface()); QCOMPARE(zooImpl->memberCount(), 3U); Declaration *baseDecl = baseZoo->memberAt(0)->asDeclaration(); QVERIFY(baseDecl); QVERIFY(baseDecl->name() && baseDecl->name()->identifier()); QCOMPARE(QLatin1String(baseDecl->name()->identifier()->chars()), QLatin1String("baseDecl")); ObjCMethod *baseMethod = baseZoo->memberAt(1)->asObjCMethod(); QVERIFY(baseMethod); QVERIFY(baseMethod->name() && baseMethod->name()->identifier()); QCOMPARE(QLatin1String(baseMethod->name()->identifier()->chars()), QLatin1String("baseMethod")); const LookupContext context(doc, snapshot); LookupScope *objClass = context.lookupType(baseZoo->name(), zooImpl->enclosingScope()); QVERIFY(objClass != 0); QVERIFY(objClass->symbols().contains(baseZoo)); QList<LookupItem> results = context.lookup(baseDecl->name(), zooImpl); QCOMPARE(results.size(), 1); QCOMPARE(results.at(0).declaration(), baseDecl); results = context.lookup(baseMethod->name(), zooImpl); QCOMPARE(results.size(), 1); QCOMPARE(results.at(0).declaration(), baseMethod); }
void tst_Lookup::simple_class_1() { const QByteArray source = "\n" "@interface Zoo {} +(id)alloc; -(id)init; @end\n" "@implementation Zoo +(id)alloc{} -(id)init{} -(void)dealloc{} @end\n"; Document::Ptr doc = Document::create("simple_class_1"); doc->setUtf8Source(source); doc->parse(); doc->check(); QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 2U); Snapshot snapshot; snapshot.insert(doc); ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass(); QVERIFY(iface); QVERIFY(iface->isInterface()); QCOMPARE(iface->memberCount(), 2U); ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass(); QVERIFY(impl); QVERIFY(!impl->isInterface()); QCOMPARE(impl->memberCount(), 3U); Declaration *allocMethodIface = iface->memberAt(0)->asDeclaration(); QVERIFY(allocMethodIface); QVERIFY(allocMethodIface->name() && allocMethodIface->name()->identifier()); QCOMPARE(QLatin1String(allocMethodIface->name()->identifier()->chars()), QLatin1String("alloc")); ObjCMethod *allocMethodImpl = impl->memberAt(0)->asObjCMethod(); QVERIFY(allocMethodImpl); QVERIFY(allocMethodImpl->name() && allocMethodImpl->name()->identifier()); QCOMPARE(QLatin1String(allocMethodImpl->name()->identifier()->chars()), QLatin1String("alloc")); ObjCMethod *deallocMethod = impl->memberAt(2)->asObjCMethod(); QVERIFY(deallocMethod); QVERIFY(deallocMethod->name() && deallocMethod->name()->identifier()); QCOMPARE(QLatin1String(deallocMethod->name()->identifier()->chars()), QLatin1String("dealloc")); const LookupContext context(doc, snapshot); // check class resolving: LookupScope *klass = context.lookupType(impl->name(), impl->enclosingScope()); QVERIFY(klass != 0); QCOMPARE(klass->symbols().size(), 2); QVERIFY(klass->symbols().contains(iface)); QVERIFY(klass->symbols().contains(impl)); // check method resolving: QList<LookupItem> results = context.lookup(allocMethodImpl->name(), impl); QCOMPARE(results.size(), 2); QCOMPARE(results.at(0).declaration(), allocMethodIface); QCOMPARE(results.at(1).declaration(), allocMethodImpl); results = context.lookup(deallocMethod->name(), impl); QCOMPARE(results.size(), 1); QCOMPARE(results.at(0).declaration(), deallocMethod); }
QVariant OverviewModel::data(const QModelIndex &index, int role) const { // account for no symbol item if (!index.parent().isValid() && index.row() == 0) { switch (role) { case Qt::DisplayRole: if (rowCount() > 1) return tr("<Select Symbol>"); else return tr("<No Symbols>"); default: return QVariant(); } //switch } switch (role) { case Qt::DisplayRole: { Symbol *symbol = static_cast<Symbol *>(index.internalPointer()); QString name = _overview.prettyName(symbol->name()); if (name.isEmpty()) name = QLatin1String("anonymous"); if (symbol->isObjCForwardClassDeclaration()) name = QLatin1String("@class ") + name; if (symbol->isObjCForwardProtocolDeclaration() || symbol->isObjCProtocol()) name = QLatin1String("@protocol ") + name; if (symbol->isObjCClass()) { ObjCClass *clazz = symbol->asObjCClass(); if (clazz->isInterface()) name = QLatin1String("@interface ") + name; else name = QLatin1String("@implementation ") + name; if (clazz->isCategory()) name += QLatin1String(" (") + _overview.prettyName(clazz->categoryName()) + QLatin1Char(')'); } if (symbol->isObjCPropertyDeclaration()) name = QLatin1String("@property ") + name; if (Template *t = symbol->asTemplate()) if (Symbol *templateDeclaration = t->declaration()) { QStringList parameters; for (unsigned i = 0; i < t->templateParameterCount(); ++i) parameters.append(_overview.prettyName(t->templateParameterAt(i)->name())); name += QLatin1Char('<') + parameters.join(QLatin1String(", ")) + QLatin1Char('>'); symbol = templateDeclaration; } if (symbol->isObjCMethod()) { ObjCMethod *method = symbol->asObjCMethod(); if (method->isStatic()) name = QLatin1Char('+') + name; else name = QLatin1Char('-') + name; } else if (! symbol->isScope() || symbol->isFunction()) { QString type = _overview.prettyType(symbol->type()); if (Function *f = symbol->type()->asFunctionType()) { name += type; type = _overview.prettyType(f->returnType()); } if (! type.isEmpty()) name += QLatin1String(": ") + type; } return name; } case Qt::EditRole: { Symbol *symbol = static_cast<Symbol *>(index.internalPointer()); QString name = _overview.prettyName(symbol->name()); if (name.isEmpty()) name = QLatin1String("anonymous"); return name; } case Qt::DecorationRole: { Symbol *symbol = static_cast<Symbol *>(index.internalPointer()); return _icons.iconForSymbol(symbol); } break; case FileNameRole: { Symbol *symbol = static_cast<Symbol *>(index.internalPointer()); return QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()); } case LineNumberRole: { Symbol *symbol = static_cast<Symbol *>(index.internalPointer()); return symbol->line(); } default: return QVariant(); } // switch }