diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/cplusplus/BackwardsScanner.cpp | 1 | ||||
-rw-r--r-- | src/libs/cplusplus/ExpressionUnderCursor.cpp | 2 | ||||
-rw-r--r-- | src/libs/cplusplus/LookupContext.cpp | 71 | ||||
-rw-r--r-- | src/libs/cplusplus/LookupContext.h | 24 | ||||
-rw-r--r-- | src/libs/cplusplus/ResolveExpression.cpp | 88 | ||||
-rw-r--r-- | src/libs/cplusplus/ResolveExpression.h | 15 | ||||
-rw-r--r-- | src/shared/cplusplus/CheckDeclaration.cpp | 4 | ||||
-rw-r--r-- | src/shared/cplusplus/CheckDeclarator.cpp | 19 | ||||
-rw-r--r-- | src/shared/cplusplus/CheckExpression.cpp | 2 | ||||
-rw-r--r-- | src/shared/cplusplus/CheckName.cpp | 12 | ||||
-rw-r--r-- | src/shared/cplusplus/Names.cpp | 4 | ||||
-rw-r--r-- | src/shared/cplusplus/Scope.cpp | 3 | ||||
-rw-r--r-- | src/shared/cplusplus/Semantic.cpp | 2 | ||||
-rw-r--r-- | src/shared/cplusplus/Symbol.cpp | 12 |
14 files changed, 238 insertions, 21 deletions
diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp index 7f1f6cdfe6..46fb15efe4 100644 --- a/src/libs/cplusplus/BackwardsScanner.cpp +++ b/src/libs/cplusplus/BackwardsScanner.cpp @@ -40,6 +40,7 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suf { _tokenize.setQtMocRunEnabled(true); _tokenize.setSkipComments(true); + _tokenize.setObjCEnabled(true); _text = _block.text().left(cursor.position() - cursor.block().position()); if (! suffix.isEmpty()) diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 995eeace37..67980ce4e1 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -106,6 +106,8 @@ int ExpressionUnderCursor::startOfExpression_helper(BackwardsScanner &tk, int in return startOfExpression(tk, index - 2); } else if (tk[index - 2].is(T_DOT_STAR) || tk[index - 2].is(T_ARROW_STAR)) { return startOfExpression(tk, index - 2); +// } else if (tk[index - 2].is(T_IDENTIFIER) && tk[index - 3].is(T_LBRACKET)) { +// return index - 3; } return index - 1; } else if (tk[index - 1].is(T_RPAREN)) { diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 4d3ed93275..653d86b0d0 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -89,8 +89,10 @@ bool LookupContext::maybeValidSymbol(Symbol *symbol, ResolveMode mode, const QList<Symbol *> &candidates) { - if (((mode & ResolveNamespace) && symbol->isNamespace()) || - ((mode & ResolveClass) && symbol->isClass()) || + if (((mode & ResolveNamespace) && symbol->isNamespace()) || + ((mode & ResolveClass) && symbol->isClass()) || + ((mode & ResolveObjCClass) && symbol->isObjCClass()) || + ((mode & ResolveObjCProtocol) && symbol->isObjCProtocol()) || (mode & ResolveSymbol)) { return ! candidates.contains(symbol); } @@ -527,6 +529,69 @@ void LookupContext::expandObjCMethod(ObjCMethod *method, expandedScopes->append(method->arguments()); } +void LookupContext::expandObjCClass(ObjCClass *klass, + const QList<Scope *> &visibleScopes, + QList<Scope *> *expandedScopes) const +{ + {// expand other @interfaces, @implementations and categories for this class: + const QList<Symbol *> classList = resolveObjCClass(klass->name(), visibleScopes); + foreach (Symbol *otherClass, classList) { + if (otherClass == klass) + continue; + expand(otherClass->asObjCClass()->members(), visibleScopes, expandedScopes); + } + } + + // expand definitions in the currect class: + for (unsigned i = 0; i < klass->memberCount(); ++i) { + Symbol *symbol = klass->memberAt(i); + if (Class *nestedClass = symbol->asClass()) { + if (! nestedClass->name()) { + expand(nestedClass->members(), visibleScopes, expandedScopes); + } + } else if (Enum *e = symbol->asEnum()) { + expand(e->members(), visibleScopes, expandedScopes); + } + } + + // expand the base class: + if (ObjCBaseClass *baseClass = klass->baseClass()) { + Name *baseClassName = baseClass->name(); + const QList<Symbol *> baseClassCandidates = resolveObjCClass(baseClassName, + visibleScopes); + + for (int j = 0; j < baseClassCandidates.size(); ++j) { + if (ObjCClass *baseClassSymbol = baseClassCandidates.at(j)->asObjCClass()) + expand(baseClassSymbol->members(), visibleScopes, expandedScopes); + } + } + + // expand the protocols: + for (unsigned i = 0; i < klass->protocolCount(); ++i) { + Name *protocolName = klass->protocolAt(i)->name(); + const QList<Symbol *> protocolCandidates = resolveObjCProtocol(protocolName, visibleScopes); + for (int j = 0; j < protocolCandidates.size(); ++j) { + if (ObjCProtocol *protocolSymbol = protocolCandidates.at(j)->asObjCProtocol()) + expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes); + } + } +} + +void LookupContext::expandObjCProtocol(ObjCProtocol *protocol, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const +{ + // First expand the protocol itself + expand(protocol->members(), visibleScopes, expandedScopes); + + // Then do the same for any incorporated protocol + for (unsigned i = 0; i < protocol->protocolCount(); ++i) { + ObjCBaseProtocol *baseProtocol = protocol->protocolAt(i); + const QList<Symbol *> protocolList = resolveObjCProtocol(baseProtocol->name(), visibleScopes); + foreach (Symbol *symbol, protocolList) + if (ObjCProtocol *protocolSymbol = symbol->asObjCProtocol()) + expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes); + } +} + void LookupContext::expand(Scope *scope, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const @@ -546,6 +611,8 @@ void LookupContext::expand(Scope *scope, expandFunction(fun, visibleScopes, expandedScopes); } else if (ObjCMethod *meth = scope->owner()->asObjCMethod()) { expandObjCMethod(meth, visibleScopes, expandedScopes); + } else if (ObjCClass *objcKlass = scope->owner()->asObjCClass()) { + expandObjCClass(objcKlass, visibleScopes, expandedScopes); } } diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index e9d84c83ae..6a69b3330b 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -75,12 +75,20 @@ public: QList<Symbol *> resolveClassOrNamespace(Name *name) const { return resolveClassOrNamespace(name, visibleScopes()); } + QList<Symbol *> resolveObjCClass(Name *name) const + { return resolveObjCClass(name, visibleScopes()); } + + QList<Symbol *> resolveObjCProtocol(Name *name) const + { return resolveObjCProtocol(name, visibleScopes()); } + enum ResolveMode { ResolveSymbol = 0x01, ResolveClass = 0x02, ResolveNamespace = 0x04, ResolveClassOrNamespace = ResolveClass | ResolveNamespace, - ResolveAll = ResolveSymbol | ResolveClassOrNamespace + ResolveObjCClass = 0x08, + ResolveObjCProtocol = 0x10, + ResolveAll = ResolveSymbol | ResolveClassOrNamespace | ResolveObjCClass | ResolveObjCProtocol }; QList<Symbol *> resolve(Name *name, const QList<Scope *> &visibleScopes, @@ -95,6 +103,12 @@ public: QList<Symbol *> resolveClassOrNamespace(Name *name, const QList<Scope *> &visibleScopes) const { return resolve(name, visibleScopes, ResolveClassOrNamespace); } + QList<Symbol *> resolveObjCClass(Name *name, const QList<Scope *> &visibleScopes) const + { return resolve(name, visibleScopes, ResolveObjCClass); } + + QList<Symbol *> resolveObjCProtocol(Name *name, const QList<Scope *> &visibleScopes) const + { return resolve(name, visibleScopes, ResolveObjCProtocol); } + QList<Scope *> visibleScopes() const { return _visibleScopes; } @@ -128,6 +142,14 @@ public: const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const; + void expandObjCClass(ObjCClass *klass, + const QList<Scope *> &visibleScopes, + QList<Scope *> *expandedScopes) const; + + void expandObjCProtocol(ObjCProtocol *protocol, + const QList<Scope *> &visibleScopes, + QList<Scope *> *expandedScopes) const; + void expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol, QList<Scope *> *expandedScopes) const; diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 9b8dceebd3..ba6952e7bf 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -738,11 +738,67 @@ ResolveExpression::resolveMember(Name *memberName, Class *klass, } +QList<ResolveExpression::Result> +ResolveExpression::resolveMember(Name *memberName, ObjCClass *klass) const +{ + QList<Result> results; + + if (!memberName || !klass) + return results; + + QList<Scope *> scopes; + _context.expand(klass->members(), _context.visibleScopes(), &scopes); + + QList<Symbol *> candidates = _context.resolve(memberName, scopes); + + foreach (Symbol *candidate, candidates) { + FullySpecifiedType ty = candidate->type(); + + results.append(Result(ty, candidate)); + } + + return removeDuplicates(results); +} + bool ResolveExpression::visit(PostIncrDecrAST *) { return false; } +bool ResolveExpression::visit(ObjCMessageExpressionAST *ast) +{ + QList<Result> receiverResults = operator()(ast->receiver_expression); + + if (!receiverResults.isEmpty()) { + Result result = receiverResults.first(); + FullySpecifiedType ty = result.first.simplified(); + Name *klassName = 0; + + if (const ObjCClass *classTy = ty->asObjCClassType()) { + // static access, e.g.: + // [NSObject description]; + klassName = classTy->name(); + } else if (const PointerType *ptrTy = ty->asPointerType()) { + const FullySpecifiedType pointeeTy = ptrTy->elementType(); + if (pointeeTy && pointeeTy->isNamedType()) { + // dynamic access, e.g.: + // NSObject *obj = ...; [obj release]; + klassName = pointeeTy->asNamedType()->name(); + } + } + + if (klassName&&ast->selector && ast->selector->selector_name) { + ResolveObjCClass resolveObjCClass; + QList<Symbol *> resolvedSymbols = resolveObjCClass(klassName, result, _context); + foreach (Symbol *resolvedSymbol, resolvedSymbols) + if (ObjCClass *klass = resolvedSymbol->asObjCClass()) + _results.append(resolveMember(ast->selector->selector_name, klass)); + } + } + + return false; +} + //////////////////////////////////////////////////////////////////////////////// ResolveClass::ResolveClass() { } @@ -811,3 +867,35 @@ QList<Symbol *> ResolveClass::resolveClass(Name *name, return resolvedSymbols; } + +ResolveObjCClass::ResolveObjCClass() +{} + +QList<Symbol *> ResolveObjCClass::operator ()(Name *name, + const ResolveExpression::Result &p, + const LookupContext &context) +{ + QList<Symbol *> resolvedSymbols; + + const QList<Symbol *> candidates = + context.resolve(name, context.visibleScopes(p)); + + foreach (Symbol *candidate, candidates) { + if (ObjCClass *klass = candidate->asObjCClass()) { + if (resolvedSymbols.contains(klass)) + continue; // we already know about `klass' + resolvedSymbols.append(klass); + } else if (candidate->isTypedef()) { + if (Declaration *decl = candidate->asDeclaration()) { + if (decl->type()->isObjCClassType()) { + ObjCClass *klass = decl->type()->asObjCClassType(); + if (resolvedSymbols.contains(klass)) + continue; + resolvedSymbols.append(klass); + } + } + } + } + + return resolvedSymbols; +} diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index 34541e9f45..adda2716c3 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -61,6 +61,8 @@ public: QList<Result> resolveMember(Name *memberName, Class *klass, Name *className = 0) const; + QList<Result> resolveMember(Name *memberName, ObjCClass *klass) const; + protected: QList<Result> switchResults(const QList<Result> &symbols); @@ -109,6 +111,9 @@ protected: virtual bool visit(PostIncrDecrAST *ast); virtual bool visit(MemberAccessAST *ast); + // Objective-C expressions + virtual bool visit(ObjCMessageExpressionAST *ast); + QList<Scope *> visibleScopes(const Result &result) const; private: @@ -136,6 +141,16 @@ private: QList<ResolveExpression::Result> _blackList; }; +class CPLUSPLUS_EXPORT ResolveObjCClass +{ +public: + ResolveObjCClass(); + + QList<Symbol *> operator()(Name *name, + const ResolveExpression::Result &p, + const LookupContext &context); +}; + } // end of namespace CPlusPlus diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp index 0d1546234f..728e87385d 100644 --- a/src/shared/cplusplus/CheckDeclaration.cpp +++ b/src/shared/cplusplus/CheckDeclaration.cpp @@ -662,15 +662,13 @@ bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast) Declaration *decl = control()->newDeclaration(ast->firstToken(), methodType->name()); decl->setType(methodType); symbol = decl; + symbol->setStorage(methodType->storage()); } 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; diff --git a/src/shared/cplusplus/CheckDeclarator.cpp b/src/shared/cplusplus/CheckDeclarator.cpp index 844cd9a5c7..9f28381105 100644 --- a/src/shared/cplusplus/CheckDeclarator.cpp +++ b/src/shared/cplusplus/CheckDeclarator.cpp @@ -246,21 +246,32 @@ bool CheckDeclarator::visit(ReferenceAST *) bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast) { + if (!ast) + return false; + + if (!ast->selector) { + // TODO: (EV) this currently happens when parsing: + // + (id<NSSomeProtocol>) zoo; + // where the parser will start doing template magic. We'll need to disambiguate this case. + return false; + } + FullySpecifiedType returnType = semantic()->check(ast->type_name, _scope); unsigned location = ast->firstToken(); - Name *name = semantic()->check(ast->selector, _scope); + semantic()->check(ast->selector, _scope); - ObjCMethod *method = control()->newObjCMethod(location, name); + ObjCMethod *method = control()->newObjCMethod(location, ast->selector->selector_name); ast->symbol = method; method->setSourceLocation(location); method->setScope(_scope); method->setVisibility(semantic()->currentVisibility()); method->setReturnType(returnType); + if (semantic()->isObjCClassMethod(tokenKind(ast->method_type_token))) + method->setStorage(Symbol::Static); if (ast->selector && ast->selector->asObjCSelectorWithArguments()) { - // TODO: add arguments (EV) for (ObjCMessageArgumentDeclarationListAST *it = ast->argument_list; it; it = it->next) { ObjCMessageArgumentDeclarationAST *argDecl = it->value; @@ -273,8 +284,6 @@ bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast) _fullySpecifiedType = FullySpecifiedType(method); - // TODO: check which specifiers are allowed here (EV) - return false; } diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp index 1c97bc91f1..01259d3c2c 100644 --- a/src/shared/cplusplus/CheckExpression.cpp +++ b/src/shared/cplusplus/CheckExpression.cpp @@ -368,7 +368,7 @@ bool CheckExpression::visit(MemberAccessAST *ast) bool CheckExpression::visit(ObjCMessageExpressionAST *ast) { - semantic()->check(ast->receiver_expression, _scope); + (void) semantic()->check(ast->receiver_expression, _scope); (void) semantic()->check(ast->selector, _scope); accept(ast->argument_list); // ### not necessary. diff --git a/src/shared/cplusplus/CheckName.cpp b/src/shared/cplusplus/CheckName.cpp index d3a9c2b244..6476b3295f 100644 --- a/src/shared/cplusplus/CheckName.cpp +++ b/src/shared/cplusplus/CheckName.cpp @@ -379,8 +379,9 @@ bool CheckName::visit(TemplateIdAST *ast) bool CheckName::visit(ObjCSelectorWithoutArgumentsAST *ast) { std::vector<Name *> names; - Identifier *id = identifier(ast->name_token); - names.push_back(control()->nameId(id)); + Identifier *id = control()->findOrInsertIdentifier(spell(ast->name_token)); + NameId *nameId = control()->nameId(id); + names.push_back(nameId); _name = control()->selectorNameId(&names[0], names.size(), false); ast->selector_name = _name; @@ -391,10 +392,9 @@ bool CheckName::visit(ObjCSelectorWithArgumentsAST *ast) { std::vector<Name *> names; for (ObjCSelectorArgumentListAST *it = ast->selector_argument_list; it; it = it->next) { - Identifier *id = identifier(it->value->name_token); - Name *name = control()->nameId(id); - - names.push_back(name); + Identifier *id = control()->findOrInsertIdentifier(spell(it->value->name_token)); + NameId *nameId = control()->nameId(id); + names.push_back(nameId); } if (!names.empty()) { diff --git a/src/shared/cplusplus/Names.cpp b/src/shared/cplusplus/Names.cpp index 9e60804e77..973e8d8366 100644 --- a/src/shared/cplusplus/Names.cpp +++ b/src/shared/cplusplus/Names.cpp @@ -289,7 +289,9 @@ void SelectorNameId::accept0(NameVisitor *visitor) Identifier *SelectorNameId::identifier() const { - // FIXME: (EV) + if (! _nameCount) + return 0; + return nameAt(0)->identifier(); } diff --git a/src/shared/cplusplus/Scope.cpp b/src/shared/cplusplus/Scope.cpp index 16026f8060..2c4eea10f7 100644 --- a/src/shared/cplusplus/Scope.cpp +++ b/src/shared/cplusplus/Scope.cpp @@ -245,6 +245,9 @@ Symbol *Scope::lookat(Identifier *id) const break; } else if (identity->isQualifiedNameId()) { assert(0); + } else if (SelectorNameId *selectorNameId = identity->asSelectorNameId()) { + if (selectorNameId->identifier()->isEqualTo(id)) + break; } } return symbol; diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp index 134e6c594a..8baf10d4b0 100644 --- a/src/shared/cplusplus/Semantic.cpp +++ b/src/shared/cplusplus/Semantic.cpp @@ -232,9 +232,7 @@ bool Semantic::isObjCClassMethod(int tokenKind) const case T_PLUS: return true; case T_MINUS: - return false; default: - // TODO EV: assert here? return false; } } diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp index c04df48baf..6cd6573aa6 100644 --- a/src/shared/cplusplus/Symbol.cpp +++ b/src/shared/cplusplus/Symbol.cpp @@ -104,6 +104,9 @@ protected: virtual void visit(QualifiedNameId *name) { _value = operator()(name->unqualifiedNameId()); } + virtual void visit(SelectorNameId *name) + { _value = name->identifier()->hashCode(); } + private: unsigned _value; }; @@ -151,6 +154,9 @@ protected: virtual void visit(QualifiedNameId *name) { _identity = name->unqualifiedNameId(); } + virtual void visit(SelectorNameId *name) + { _identity = name; } + private: Name *_identity; }; @@ -461,6 +467,12 @@ bool Symbol::isArgument() const bool Symbol::isBaseClass() const { return asBaseClass() != 0; } +bool Symbol::isObjCBaseClass() const +{ return asObjCBaseClass() != 0; } + +bool Symbol::isObjCBaseProtocol() const +{ return asObjCBaseProtocol() != 0; } + bool Symbol::isObjCClass() const { return asObjCClass() != 0; } |