summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libs/cplusplus/BackwardsScanner.cpp1
-rw-r--r--src/libs/cplusplus/ExpressionUnderCursor.cpp2
-rw-r--r--src/libs/cplusplus/LookupContext.cpp71
-rw-r--r--src/libs/cplusplus/LookupContext.h24
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp88
-rw-r--r--src/libs/cplusplus/ResolveExpression.h15
-rw-r--r--src/shared/cplusplus/CheckDeclaration.cpp4
-rw-r--r--src/shared/cplusplus/CheckDeclarator.cpp19
-rw-r--r--src/shared/cplusplus/CheckExpression.cpp2
-rw-r--r--src/shared/cplusplus/CheckName.cpp12
-rw-r--r--src/shared/cplusplus/Names.cpp4
-rw-r--r--src/shared/cplusplus/Scope.cpp3
-rw-r--r--src/shared/cplusplus/Semantic.cpp2
-rw-r--r--src/shared/cplusplus/Symbol.cpp12
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; }