bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast) { if (!ast->method_prototype) return false; FullySpecifiedType ty = semantic()->check(ast->method_prototype, _scope); ObjCMethod *methodType = ty.type()->asObjCMethodType(); if (!methodType) return false; Symbol *symbol; if (ast->function_body) { if (!semantic()->skipFunctionBodies()) { semantic()->check(ast->function_body, methodType->members()); } symbol = methodType; } else { Declaration *decl = control()->newDeclaration(ast->firstToken(), methodType->name()); decl->setType(methodType); symbol = decl; } symbol->setStartOffset(tokenAt(ast->firstToken()).offset); symbol->setEndOffset(tokenAt(ast->lastToken()).offset); symbol->setVisibility(semantic()->currentVisibility()); if (semantic()->isObjCClassMethod(ast->method_prototype->method_type_token)) symbol->setStorage(Symbol::Static); _scope->enterSymbol(symbol); return false; }
bool Scope::isObjCMethodScope() const { ObjCMethod *m = 0; if (_owner && 0 != (m = _owner->asObjCMethod())) return m->arguments() != this; return false; }
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); }
bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast) { FullySpecifiedType returnType = semantic()->check(ast->type_name, _scope); unsigned location = ast->firstToken(); Name *name = semantic()->check(ast->selector, _scope); ObjCMethod *method = control()->newObjCMethod(location, name); ast->symbol = method; method->setSourceLocation(location); method->setScope(_scope); method->setVisibility(semantic()->currentVisibility()); method->setReturnType(returnType); if (ast->selector && ast->selector->asObjCSelectorWithArguments()) { // TODO: add arguments (EV) for (ObjCMessageArgumentDeclarationListAST *it = ast->arguments; it; it = it->next) { ObjCMessageArgumentDeclarationAST *argDecl = it->argument_declaration; semantic()->check(argDecl, method->arguments()); } if (ast->dot_dot_dot_token) method->setVariadic(true); } _fullySpecifiedType = FullySpecifiedType(method); // TODO: check which specifiers are allowed here (EV) return false; }
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 }