Commit 86a7b26f authored by Erik Verbruggen's avatar Erik Verbruggen

Fixed semantic checks for Objective-C methods and fast-enumeration.

parent ca34b0ca
......@@ -102,6 +102,8 @@ QIcon Icons::iconForSymbol(const Symbol *symbol) const
return _classIcon;
} else if (symbol->isObjCProtocol() || symbol->isObjCForwardProtocolDeclaration()) {
return _classIcon;
} else if (symbol->isObjCMethod()) {
return _funcPublicIcon;
} else if (symbol->isNamespace()) {
return _namespaceIcon;
} else if (symbol->isUsingNamespaceDirective() ||
......
......@@ -123,7 +123,7 @@ int OverviewModel::rowCount(const QModelIndex &parent) const
Q_ASSERT(parentSymbol);
if (ScopedSymbol *scopedSymbol = parentSymbol->asScopedSymbol()) {
if (!scopedSymbol->isFunction()) {
if (!scopedSymbol->isFunction() && !scopedSymbol->isObjCMethod()) {
Scope *parentScope = scopedSymbol->members();
Q_ASSERT(parentScope);
......@@ -168,9 +168,23 @@ QVariant OverviewModel::data(const QModelIndex &index, int role) const
name = QLatin1String("@class ") + name;
if (symbol->isObjCForwardProtocolDeclaration() || symbol->isObjCProtocol())
name = QLatin1String("@protocol ") + name;
if (symbol->isObjCClass())
name = QLatin1String("@interface ") + name;
if (! symbol->isScopedSymbol() || symbol->isFunction()) {
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->isObjCMethod()) {
ObjCMethod *method = symbol->asObjCMethod();
if (method->isStatic())
name = QLatin1Char('+') + name;
else
name = QLatin1Char('-') + name;
} else if (! symbol->isScopedSymbol() || symbol->isFunction()) {
QString type = _overview.prettyType(symbol->type());
if (! type.isEmpty()) {
if (! symbol->type()->isFunctionType())
......
......@@ -2997,7 +2997,7 @@ public:
SpecifierAST *attributes;
public: // annotations
Function *symbol;
ObjCMethod *symbol;
public:
virtual ObjCMethodPrototypeAST *asObjCMethodPrototype()
......@@ -3129,6 +3129,9 @@ public:
unsigned rparen_token;
StatementAST *body_statement;
public: // annotations
Block *symbol;
public:
virtual ObjCFastEnumerationAST *asObjCFastEnumeration()
{ return this; }
......
......@@ -552,7 +552,14 @@ bool CheckDeclaration::visit(ObjCClassDeclarationAST *ast)
klass->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = klass;
// TODO: walk category name, super-class, and protocols (EV)
klass->setInterface(ast->interface_token != 0);
if (ast->category_name) {
Name *categoryName = semantic()->check(ast->category_name, _scope);
klass->setCategoryName(categoryName);
}
// TODO: super-class, and protocols (EV)
_scope->enterSymbol(klass);
int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Protected);
......@@ -580,16 +587,25 @@ bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast)
return false;
FullySpecifiedType ty = semantic()->check(ast->method_prototype, _scope);
Function *fun = ty.type()->asFunctionType();
if (!fun)
ObjCMethod *methodType = ty.type()->asObjCMethodType();
if (!methodType)
return false;
Declaration *symbol = control()->newDeclaration(ast->firstToken(), fun->name());
symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
Symbol *symbol;
if (!ast->function_body) {
Declaration *decl = control()->newDeclaration(ast->firstToken(), methodType->name());
decl->setType(methodType);
symbol = decl;
} else {
if (!semantic()->skipFunctionBodies()) {
semantic()->check(ast->function_body, methodType->members());
}
symbol->setType(fun->returnType());
symbol = methodType;
}
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))
......@@ -597,10 +613,6 @@ bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast)
_scope->enterSymbol(symbol);
if (ast->function_body && !semantic()->skipFunctionBodies()) {
semantic()->check(ast->function_body, fun->members());
}
return false;
}
......
......@@ -254,14 +254,12 @@ bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast)
Name *name = semantic()->check(ast->selector, _scope);
Function *fun = control()->newFunction(location, name);
ast->symbol = fun;
fun->setSourceLocation(location);
fun->setScope(_scope);
fun->setMethodKey(Function::NormalMethod);
fun->setVisibility(semantic()->currentVisibility());
fun->setPureVirtual(false);
fun->setReturnType(returnType);
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: check the parameters (EV)
......@@ -270,11 +268,11 @@ bool CheckDeclarator::visit(ObjCMethodPrototypeAST *ast)
for (ObjCMessageArgumentDeclarationListAST *it = ast->arguments; it; it = it->next) {
ObjCMessageArgumentDeclarationAST *argDecl = it->argument_declaration;
semantic()->check(argDecl, fun->arguments());
semantic()->check(argDecl, method->arguments());
}
}
_fullySpecifiedType = FullySpecifiedType(fun);
_fullySpecifiedType = FullySpecifiedType(method);
// TODO: check which specifiers are allowed here (EV)
......
......@@ -170,6 +170,34 @@ bool CheckStatement::visit(ForeachStatementAST *ast)
return false;
}
bool CheckStatement::visit(ObjCFastEnumerationAST *ast)
{
Block *block = control()->newBlock(ast->for_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
if (ast->type_specifiers && ast->declarator) {
FullySpecifiedType ty = semantic()->check(ast->type_specifiers, _scope);
Name *name = 0;
ty = semantic()->check(ast->declarator, ty, _scope, &name);
unsigned location = ast->declarator->firstToken();
if (CoreDeclaratorAST *core_declarator = ast->declarator->core_declarator)
location = core_declarator->firstToken();
Declaration *decl = control()->newDeclaration(location, name);
decl->setType(ty);
_scope->enterSymbol(decl);
} else {
FullySpecifiedType exprTy = semantic()->check(ast->initializer, _scope);
(void) exprTy;
}
semantic()->check(ast->body_statement, _scope);
(void) switchScope(previousScope);
return false;
}
bool CheckStatement::visit(ForStatementAST *ast)
{
Block *block = control()->newBlock(ast->for_token);
......
......@@ -76,6 +76,7 @@ protected:
virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
virtual bool visit(ExpressionStatementAST *ast);
virtual bool visit(ForeachStatementAST *ast);
virtual bool visit(ObjCFastEnumerationAST *ast);
virtual bool visit(ForStatementAST *ast);
virtual bool visit(IfStatementAST *ast);
virtual bool visit(LabeledStatementAST *ast);
......
......@@ -125,6 +125,7 @@ public:
delete_array_entries(objcProtocols);
delete_array_entries(objcForwardClassDeclarations);
delete_array_entries(objcForwardProtocolDeclarations);
delete_array_entries(objcMethods);
}
NameId *findOrInsertNameId(Identifier *id)
......@@ -368,6 +369,13 @@ public:
return fwd;
}
ObjCMethod *newObjCMethod(unsigned sourceLocation, Name *name)
{
ObjCMethod *method = new ObjCMethod(translationUnit, sourceLocation, name);
objcMethods.push_back(method);
return method;
}
Enum *newEnum(unsigned sourceLocation, Name *name)
{
Enum *e = new Enum(translationUnit,
......@@ -549,6 +557,7 @@ public:
std::vector<ObjCProtocol *> objcProtocols;
std::vector<ObjCForwardClassDeclaration *> objcForwardClassDeclarations;
std::vector<ObjCForwardProtocolDeclaration *> objcForwardProtocolDeclarations;
std::vector<ObjCMethod *> objcMethods;
};
Control::Control()
......@@ -726,4 +735,7 @@ ObjCProtocol *Control::newObjCProtocol(unsigned sourceLocation, Name *name)
ObjCForwardProtocolDeclaration *Control::newObjCForwardProtocolDeclaration(unsigned sourceLocation, Name *name)
{ return d->newObjCForwardProtocolDeclaration(sourceLocation, name); }
ObjCMethod *Control::newObjCMethod(unsigned sourceLocation, Name *name)
{ return d->newObjCMethod(sourceLocation, name); }
CPLUSPLUS_END_NAMESPACE
......@@ -163,6 +163,9 @@ public:
/// Creates a new Objective-C protocol forward declaration symbol.
ObjCForwardProtocolDeclaration *newObjCForwardProtocolDeclaration(unsigned sourceLocation, Name *name = 0);
/// Creates a new Objective-C method symbol.
ObjCMethod *newObjCMethod(unsigned sourceLocation, Name *name = 0);
Identifier *findOrInsertIdentifier(const char *chars, unsigned size);
Identifier *findOrInsertIdentifier(const char *chars);
......
......@@ -465,4 +465,7 @@ bool Symbol::isObjCProtocol() const
bool Symbol::isObjCForwardProtocolDeclaration() const
{ return asObjCForwardProtocolDeclaration() != 0; }
bool Symbol::isObjCMethod() const
{ return asObjCMethod() != 0; }
CPLUSPLUS_END_NAMESPACE
......@@ -210,18 +210,21 @@ public:
/// Returns true if this Symbol is a ForwardClassDeclaration.
bool isForwardClassDeclaration() const;
/// Returns true if this Symbol is a Objective-C Class definition.
/// Returns true if this Symbol is an Objective-C Class declaration.
bool isObjCClass() const;
/// Returns true if this Symbol is a Objective-C Class forward declaration.
/// Returns true if this Symbol is an Objective-C Class forward declaration.
bool isObjCForwardClassDeclaration() const;
/// Returns true if this Symbol is a Objective-C Protocol definition.
/// Returns true if this Symbol is an Objective-C Protocol declaration.
bool isObjCProtocol() const;
/// Returns true if this Symbol is a Objective-C Protocol forward declaration.
/// Returns true if this Symbol is an Objective-C Protocol forward declaration.
bool isObjCForwardProtocolDeclaration() const;
/// Returns true if this Symbol is an Objective-C method declaration.
bool isObjCMethod() const;
virtual const ScopedSymbol *asScopedSymbol() const { return 0; }
virtual const Enum *asEnum() const { return 0; }
virtual const Function *asFunction() const { return 0; }
......@@ -238,6 +241,7 @@ public:
virtual const ObjCForwardClassDeclaration *asObjCForwardClassDeclaration() const { return 0; }
virtual const ObjCProtocol *asObjCProtocol() const { return 0; }
virtual const ObjCForwardProtocolDeclaration *asObjCForwardProtocolDeclaration() const { return 0; }
virtual const ObjCMethod *asObjCMethod() const { return 0; }
virtual ScopedSymbol *asScopedSymbol() { return 0; }
virtual Enum *asEnum() { return 0; }
......@@ -255,6 +259,7 @@ public:
virtual ObjCForwardClassDeclaration *asObjCForwardClassDeclaration() { return 0; }
virtual ObjCProtocol *asObjCProtocol() { return 0; }
virtual ObjCForwardProtocolDeclaration *asObjCForwardProtocolDeclaration() { return 0; }
virtual ObjCMethod *asObjCMethod() { return 0; }
/// Returns this Symbol's type.
virtual FullySpecifiedType type() const = 0;
......
......@@ -85,6 +85,7 @@ public:
virtual bool visit(ObjCForwardClassDeclaration *) { return true; }
virtual bool visit(ObjCProtocol *) { return true; }
virtual bool visit(ObjCForwardProtocolDeclaration *) { return true; }
virtual bool visit(ObjCMethod *) { return true; }
};
CPLUSPLUS_END_NAMESPACE
......
......@@ -554,7 +554,8 @@ void Class::visitSymbol0(SymbolVisitor *visitor)
}
ObjCClass::ObjCClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name):
ScopedSymbol(translationUnit, sourceLocation, name)
ScopedSymbol(translationUnit, sourceLocation, name),
_categoryName(0)
{
}
......@@ -655,4 +656,94 @@ FullySpecifiedType ObjCForwardProtocolDeclaration::type() const
void ObjCForwardProtocolDeclaration::visitSymbol0(SymbolVisitor *visitor)
{ visitor->visit(this); }
ObjCMethod::ObjCMethod(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
: ScopedSymbol(translationUnit, sourceLocation, name),
_flags(0)
{ _arguments = new Scope(this); }
ObjCMethod::~ObjCMethod()
{
delete _arguments;
}
bool ObjCMethod::isEqualTo(const Type *other) const
{
const ObjCMethod *o = other->asObjCMethodType();
if (! o)
return false;
Name *l = identity();
Name *r = o->identity();
if (l == r || (l && l->isEqualTo(r))) {
if (_arguments->symbolCount() != o->_arguments->symbolCount())
return false;
else if (! _returnType.isEqualTo(o->_returnType))
return false;
for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
Symbol *l = _arguments->symbolAt(i);
Symbol *r = o->_arguments->symbolAt(i);
if (! l->type().isEqualTo(r->type()))
return false;
}
return true;
}
return false;
}
void ObjCMethod::accept0(TypeVisitor *visitor)
{ visitor->visit(this); }
FullySpecifiedType ObjCMethod::type() const
{ return FullySpecifiedType(const_cast<ObjCMethod *>(this)); }
FullySpecifiedType ObjCMethod::returnType() const
{ return _returnType; }
void ObjCMethod::setReturnType(FullySpecifiedType returnType)
{ _returnType = returnType; }
bool ObjCMethod::hasReturnType() const
{
const FullySpecifiedType ty = returnType();
return ty.isValid() || ty.isSigned() || ty.isUnsigned();
}
unsigned ObjCMethod::argumentCount() const
{
if (! _arguments)
return 0;
return _arguments->symbolCount();
}
Symbol *ObjCMethod::argumentAt(unsigned index) const
{ return _arguments->symbolAt(index); }
Scope *ObjCMethod::arguments() const
{ return _arguments; }
bool ObjCMethod::hasArguments() const
{
return ! (argumentCount() == 0 ||
(argumentCount() == 1 && argumentAt(0)->type()->isVoidType()));
}
bool ObjCMethod::isVariadic() const
{ return f._isVariadic; }
void ObjCMethod::setVariadic(bool isVariadic)
{ f._isVariadic = isVariadic; }
void ObjCMethod::visitSymbol0(SymbolVisitor *visitor)
{
if (visitor->visit(this)) {
for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
visitSymbol(_arguments->symbolAt(i), visitor);
}
for (unsigned i = 0; i < memberCount(); ++i) {
visitSymbol(memberAt(i), visitor);
}
}
}
CPLUSPLUS_END_NAMESPACE
......@@ -543,6 +543,13 @@ public:
ObjCClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
virtual ~ObjCClass();
bool isInterface() const { return _isInterface; }
void setInterface(bool isInterface) { _isInterface = isInterface; }
bool isCategory() const { return _categoryName != 0; }
Name *categoryName() const { return _categoryName; }
void setCategoryName(Name *categoryName) { _categoryName = categoryName; }
// Symbol's interface
virtual FullySpecifiedType type() const;
......@@ -566,10 +573,68 @@ protected:
virtual void accept0(TypeVisitor *visitor);
private:
bool _isInterface;
Name *_categoryName;
Array<ObjCClass *> _baseClasses;
Array<ObjCProtocol *> _protocols;
};
class CPLUSPLUS_EXPORT ObjCMethod: public ScopedSymbol, public Type
{
public:
ObjCMethod(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
virtual ~ObjCMethod();
FullySpecifiedType returnType() const;
void setReturnType(FullySpecifiedType returnType);
/** Convenience function that returns whether the function returns something (including void). */
bool hasReturnType() const;
unsigned argumentCount() const;
Symbol *argumentAt(unsigned index) const;
Scope *arguments() const;
/** Convenience function that returns whether the function receives any arguments. */
bool hasArguments() const;
bool isVariadic() const;
void setVariadic(bool isVariadic);
// Symbol's interface
virtual FullySpecifiedType type() const;
// Type's interface
virtual bool isEqualTo(const Type *other) const;
virtual const ObjCMethod *asObjCMethod() const
{ return this; }
virtual ObjCMethod *asObjCMethod()
{ return this; }
virtual const ObjCMethod *asObjCMethodType() const
{ return this; }
virtual ObjCMethod *asObjCMethodType()
{ return this; }
protected:
virtual void visitSymbol0(SymbolVisitor *visitor);
virtual void accept0(TypeVisitor *visitor);
private:
FullySpecifiedType _returnType;
struct Flags {
unsigned _isVariadic: 1;
};
union {
unsigned _flags;
Flags f;
};
Scope *_arguments;
};
CPLUSPLUS_END_NAMESPACE
CPLUSPLUS_END_HEADER
......
......@@ -107,6 +107,9 @@ bool Type::isObjCClassType() const
bool Type::isObjCProtocolType() const
{ return asObjCProtocolType() != 0; }
bool Type::isObjCMethodType() const
{ return asObjCMethodType() != 0; }
void Type::accept(TypeVisitor *visitor)
{
if (visitor->preVisit(this))
......
......@@ -79,6 +79,7 @@ public:
bool isForwardClassDeclarationType() const;
bool isObjCClassType() const;
bool isObjCProtocolType() const;
bool isObjCMethodType() const;
virtual const VoidType *asVoidType() const { return 0; }
virtual const IntegerType *asIntegerType() const { return 0; }
......@@ -95,6 +96,7 @@ public:
virtual const ForwardClassDeclaration *asForwardClassDeclarationType() const { return 0; }
virtual const ObjCClass *asObjCClassType() const { return 0; }
virtual const ObjCProtocol *asObjCProtocolType() const { return 0; }
virtual const ObjCMethod *asObjCMethodType() const { return 0; }
virtual VoidType *asVoidType() { return 0; }
virtual IntegerType *asIntegerType() { return 0; }
......@@ -110,7 +112,8 @@ public:
virtual Enum *asEnumType() { return 0; }
virtual ForwardClassDeclaration *asForwardClassDeclarationType() { return 0; }
virtual ObjCClass *asObjCClassType() { return 0; }
virtual ObjCProtocol *asObjCProtocoTypel() { return 0; }
virtual ObjCProtocol *asObjCProtocolType() { return 0; }
virtual ObjCMethod *asObjCMethodType() { return 0; }
void accept(TypeVisitor *visitor);
static void accept(Type *type, TypeVisitor *visitor);
......
......@@ -83,6 +83,7 @@ public:
virtual void visit(ForwardClassDeclaration *) {}
virtual void visit(ObjCClass *) {}
virtual void visit(ObjCProtocol *) {}
virtual void visit(ObjCMethod *) {}
};
CPLUSPLUS_END_NAMESPACE
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment