summaryrefslogtreecommitdiff
path: root/src/libs/cplusplus
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/cplusplus')
-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
6 files changed, 198 insertions, 3 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