Commit 4a0da2c6 authored by Erik Verbruggen's avatar Erik Verbruggen

Added Semantic checks for ObjC methods.

parent b713f177
......@@ -253,3 +253,20 @@ void NamePrettyPrinter::visit(QualifiedNameId *name)
_name += operator()(name->nameAt(index));
}
}
void NamePrettyPrinter::visit(SelectorNameId *name)
{
for (unsigned i = 0; i < name->nameCount(); ++i) {
Name *n = name->nameAt(i);
if (!n)
continue;
Identifier *id = n->identifier();
if (id) {
_name += QString::fromLatin1(id->chars(), id->size());
if (name->hasArguments() || name->nameCount() > 1)
_name += ':';
}
}
}
......@@ -55,6 +55,7 @@ protected:
virtual void visit(OperatorNameId *name);
virtual void visit(ConversionNameId *name);
virtual void visit(QualifiedNameId *name);
virtual void visit(SelectorNameId *name);
private:
const Overview *_overview;
......
......@@ -164,6 +164,12 @@ QVariant OverviewModel::data(const QModelIndex &index, int role) const
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())
name = QLatin1String("@interface ") + name;
if (! symbol->isScopedSymbol() || symbol->isFunction()) {
QString type = _overview.prettyType(symbol->type());
if (! type.isEmpty()) {
......
......@@ -2080,6 +2080,9 @@ unsigned ObjCMessageExpressionAST::lastToken() const
if (receiver_expression)
return receiver_expression->lastToken();
if (selector)
return selector->lastToken();
if (argument_list)
return argument_list->lastToken();
......@@ -2107,7 +2110,7 @@ unsigned ObjCMessageArgumentListAST::lastToken() const
unsigned ObjCMessageArgumentAST::firstToken() const
{
return parameter_key_identifier;
return parameter_value_expression->firstToken();
}
unsigned ObjCMessageArgumentAST::lastToken() const
......@@ -2115,10 +2118,8 @@ unsigned ObjCMessageArgumentAST::lastToken() const
if (parameter_value_expression)
return parameter_value_expression->lastToken();
if (colon_token)
return colon_token + 1;
return parameter_key_identifier + 1;
// ### assert?
return 0;
}
unsigned ObjCProtocolExpressionAST::firstToken() const
......
......@@ -2644,8 +2644,6 @@ protected:
class CPLUSPLUS_EXPORT ObjCMessageArgumentAST: public AST
{
public:
unsigned parameter_key_identifier;
unsigned colon_token;
ExpressionAST *parameter_value_expression;
public:
......@@ -2685,6 +2683,7 @@ class CPLUSPLUS_EXPORT ObjCMessageExpressionAST: public ExpressionAST
public:
unsigned lbracket_token;
ExpressionAST *receiver_expression;
ObjCSelectorAST *selector;
ObjCMessageArgumentListAST *argument_list;
unsigned rbracket_token;
......
......@@ -1295,6 +1295,7 @@ ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) cons
ObjCMessageExpressionAST *ast = new (pool) ObjCMessageExpressionAST;
ast->lbracket_token = lbracket_token;
if (receiver_expression) ast->receiver_expression = receiver_expression->clone(pool);
if (selector) ast->selector = selector->clone(pool);
if (argument_list) ast->argument_list = argument_list->clone(pool);
ast->rbracket_token = rbracket_token;
return ast;
......@@ -1311,8 +1312,6 @@ ObjCMessageArgumentListAST *ObjCMessageArgumentListAST::clone(MemoryPool *pool)
ObjCMessageArgumentAST *ObjCMessageArgumentAST::clone(MemoryPool *pool) const
{
ObjCMessageArgumentAST *ast = new (pool) ObjCMessageArgumentAST;
ast->parameter_key_identifier = parameter_key_identifier;
ast->colon_token = colon_token;
if (parameter_value_expression) ast->parameter_value_expression = parameter_value_expression->clone(pool);
return ast;
}
......
......@@ -1220,6 +1220,8 @@ void ObjCMessageExpressionAST::accept0(ASTVisitor *visitor)
// visit ObjCMessageExpressionAST
if (receiver_expression)
accept(receiver_expression, visitor);
if (selector)
accept(selector, visitor);
if (argument_list)
accept(argument_list, visitor);
// visit ExpressionAST
......@@ -1231,10 +1233,9 @@ void ObjCMessageArgumentListAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
// visit ObjCMessageArgumentListAST
if (arg)
accept(arg, visitor);
if (next)
accept(next, visitor);
for (ObjCMessageArgumentListAST *it = this; it; it = it->next)
if (it->arg)
accept(it->arg, visitor);
// visit AST
}
visitor->endVisit(this);
......
......@@ -100,6 +100,7 @@ class DestructorNameId;
class OperatorNameId;
class ConversionNameId;
class QualifiedNameId;
class SelectorNameId;
// types
class FullySpecifiedType;
......@@ -138,6 +139,7 @@ class ObjCClass;
class ObjCForwardClassDeclaration;
class ObjCProtocol;
class ObjCForwardProtocolDeclaration;
class ObjCMethod;
CPLUSPLUS_END_NAMESPACE
CPLUSPLUS_END_HEADER
......
......@@ -598,6 +598,36 @@ bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast)
return false;
}
bool CheckDeclaration::visit(ObjCMethodDefinitionAST *ast)
{
if (!ast->method_prototype)
return false;
FullySpecifiedType ty = semantic()->check(ast->method_prototype, _scope);
Function *fun = ty.type()->asFunctionType();
if (!fun)
return false;
Declaration *symbol = control()->newDeclaration(ast->firstToken(), fun->name());
symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
symbol->setType(fun->returnType());
symbol->setVisibility(semantic()->currentVisibility());
if (semantic()->isObjCClassMethod(ast->method_prototype->method_type_token))
symbol->setStorage(Symbol::Static);
_scope->enterSymbol(symbol);
if (! semantic()->skipFunctionBodies()) {
semantic()->check(ast->function_body, fun->members());
}
return false;
}
bool CheckDeclaration::visit(ObjCVisibilityDeclarationAST *ast)
{
int accessSpecifier = tokenKind(ast->visibility_token);
......
......@@ -96,6 +96,7 @@ protected:
virtual bool visit(ObjCClassDeclarationAST *ast);
virtual bool visit(ObjCClassInterfaceDefinitionAST *ast);
virtual bool visit(ObjCMethodDeclarationAST *ast);
virtual bool visit(ObjCMethodDefinitionAST *ast);
virtual bool visit(ObjCVisibilityDeclarationAST *ast);
private:
......
......@@ -383,4 +383,29 @@ bool CheckExpression::visit(MemberAccessAST *ast)
return false;
}
bool CheckExpression::visit(ObjCMessageExpressionAST *ast)
{
semantic()->check(ast->receiver_expression, _scope);
if (Name *name = semantic()->check(ast->selector, _scope))
_scope->addUse(ast->selector->firstToken(), name);
accept(ast->argument_list);
return false;
}
bool CheckExpression::visit(ObjCEncodeExpressionAST * /*ast*/)
{
// TODO: visit the type name, but store the type here? (EV)
return true;
}
bool CheckExpression::visit(ObjCSelectorExpressionAST *ast)
{
if (Name *name = semantic()->check(ast->selector, _scope))
_scope->addUse(ast->selector->firstToken(), name);
return false;
}
CPLUSPLUS_END_NAMESPACE
......@@ -110,6 +110,11 @@ protected:
virtual bool visit(PostIncrDecrAST *ast);
virtual bool visit(MemberAccessAST *ast);
// ObjC
virtual bool visit(ObjCMessageExpressionAST *ast);
virtual bool visit(ObjCEncodeExpressionAST *ast);
virtual bool visit(ObjCSelectorExpressionAST *ast);
private:
ExpressionAST *_expression;
FullySpecifiedType _fullySpecifiedType;
......
......@@ -376,8 +376,10 @@ bool CheckName::visit(TemplateIdAST *ast)
bool CheckName::visit(ObjCSelectorWithoutArgumentsAST *ast)
{
std::vector<Name *> names;
Identifier *id = identifier(ast->name_token);
_name = control()->nameId(id);
names.push_back(control()->nameId(id));
_name = control()->selectorNameId(&names[0], names.size(), false);
ast->selector_name = _name;
return false;
......@@ -392,7 +394,7 @@ bool CheckName::visit(ObjCSelectorWithArgumentsAST *ast)
names.push_back(name);
}
_name = control()->qualifiedNameId(&names[0], names.size(), false);
_name = control()->selectorNameId(&names[0], names.size(), true);
ast->selector_name = _name;
return false;
......
......@@ -196,6 +196,15 @@ public:
return it->second;
}
SelectorNameId *findOrInsertSelectorNameId(const std::vector<Name *> &names, bool hasArguments)
{
const SelectorNameIdKey key(names, hasArguments);
std::map<SelectorNameIdKey, SelectorNameId *>::iterator it = selectorNameIds.lower_bound(key);
if (it == selectorNameIds.end() || it->first != key)
it = selectorNameIds.insert(it, std::make_pair(key, new SelectorNameId(&names[0], names.size(), hasArguments)));
return it->second;
}
IntegerType *findOrInsertIntegerType(int kind)
{
const int key = int(kind);
......@@ -423,6 +432,27 @@ public:
}
};
struct SelectorNameIdKey {
std::vector<Name *> _names;
bool _hasArguments;
SelectorNameIdKey(const std::vector<Name *> &names, bool hasArguments): _names(names), _hasArguments(hasArguments) {}
bool operator==(const SelectorNameIdKey &other) const
{ return _names == other._names && _hasArguments == other._hasArguments; }
bool operator!=(const SelectorNameIdKey &other) const
{ return !operator==(other); }
bool operator<(const SelectorNameIdKey &other) const
{
if (_hasArguments == other._hasArguments)
return std::lexicographical_compare(_names.begin(), _names.end(), other._names.begin(), other._names.end());
else
return _hasArguments < other._hasArguments;
}
};
struct ArrayKey {
FullySpecifiedType type;
size_t size;
......@@ -491,6 +521,7 @@ public:
std::map<FullySpecifiedType, ConversionNameId *> conversionNameIds;
std::map<TemplateNameIdKey, TemplateNameId *> templateNameIds;
std::map<QualifiedNameIdKey, QualifiedNameId *> qualifiedNameIds;
std::map<SelectorNameIdKey, SelectorNameId *> selectorNameIds;
// types
VoidType voidType;
......@@ -615,6 +646,15 @@ QualifiedNameId *Control::qualifiedNameId(Name *const *names,
return d->findOrInsertQualifiedNameId(classOrNamespaceNames, isGlobal);
}
SelectorNameId *Control::selectorNameId(Name *const *names,
unsigned nameCount,
bool hasArguments)
{
std::vector<Name *> selectorNames(names, names + nameCount);
return d->findOrInsertSelectorNameId(selectorNames, hasArguments);
}
VoidType *Control::voidType()
{ return &d->voidType; }
......
......@@ -89,6 +89,10 @@ public:
unsigned nameCount,
bool isGlobal = false);
SelectorNameId *selectorNameId(Name *const *names,
unsigned nameCount,
bool hasArguments);
/// Returns a Type object of type VoidType.
VoidType *voidType();
......
......@@ -76,6 +76,9 @@ bool Name::isConversionNameId() const
bool Name::isQualifiedNameId() const
{ return asQualifiedNameId() != 0; }
bool Name::isSelectorNameId() const
{ return asSelectorNameId() != 0; }
void Name::accept(NameVisitor *visitor)
{
if (visitor->preVisit(this))
......
......@@ -71,6 +71,7 @@ public:
bool isOperatorNameId() const;
bool isConversionNameId() const;
bool isQualifiedNameId() const;
bool isSelectorNameId() const;
virtual const NameId *asNameId() const { return 0; }
virtual const TemplateNameId *asTemplateNameId() const { return 0; }
......@@ -78,6 +79,7 @@ public:
virtual const OperatorNameId *asOperatorNameId() const { return 0; }
virtual const ConversionNameId *asConversionNameId() const { return 0; }
virtual const QualifiedNameId *asQualifiedNameId() const { return 0; }
virtual const SelectorNameId *asSelectorNameId() const { return 0; }
virtual NameId *asNameId() { return 0; }
virtual TemplateNameId *asTemplateNameId() { return 0; }
......@@ -85,6 +87,7 @@ public:
virtual OperatorNameId *asOperatorNameId() { return 0; }
virtual ConversionNameId *asConversionNameId() { return 0; }
virtual QualifiedNameId *asQualifiedNameId() { return 0; }
virtual SelectorNameId *asSelectorNameId() { return 0; }
virtual bool isEqualTo(const Name *other) const = 0;
......
......@@ -74,6 +74,7 @@ public:
virtual void visit(OperatorNameId *) {}
virtual void visit(ConversionNameId *) {}
virtual void visit(QualifiedNameId *) {}
virtual void visit(SelectorNameId *) {}
};
CPLUSPLUS_END_NAMESPACE
......
......@@ -268,5 +268,62 @@ bool ConversionNameId::isEqualTo(const Name *other) const
return _type.isEqualTo(c->type());
}
SelectorNameId::SelectorNameId(Name *const names[],
unsigned nameCount,
bool hasArguments)
: _names(0),
_nameCount(nameCount),
_hasArguments(hasArguments)
{
if (_nameCount) {
_names = new Name *[_nameCount];
std::copy(&names[0], &names[nameCount], _names);
}
}
SelectorNameId::~SelectorNameId()
{ delete[] _names; }
void SelectorNameId::accept0(NameVisitor *visitor)
{ visitor->visit(this); }
Identifier *SelectorNameId::identifier() const
{
// FIXME: (EV)
return nameAt(0)->identifier();
}
unsigned SelectorNameId::nameCount() const
{ return _nameCount; }
Name *SelectorNameId::nameAt(unsigned index) const
{ return _names[index]; }
Name *const *SelectorNameId::names() const
{ return _names; }
bool SelectorNameId::hasArguments() const
{ return _hasArguments; }
bool SelectorNameId::isEqualTo(const Name *other) const
{
const SelectorNameId *q = other->asSelectorNameId();
if (! q)
return false;
else if (hasArguments() != q->hasArguments())
return false;
else {
const unsigned count = nameCount();
if (count != q->nameCount())
return false;
for (unsigned i = 0; i < count; ++i) {
Name *l = nameAt(i);
Name *r = q->nameAt(i);
if (! l->isEqualTo(r))
return false;
}
}
return true;
}
CPLUSPLUS_END_NAMESPACE
......@@ -271,6 +271,39 @@ private:
FullySpecifiedType _type;
};
class CPLUSPLUS_EXPORT SelectorNameId: public Name
{
public:
SelectorNameId(Name *const names[],
unsigned nameCount,
bool hasArguments);
virtual ~SelectorNameId();
virtual Identifier *identifier() const;
unsigned nameCount() const;
Name *nameAt(unsigned index) const;
Name *const *names() const;
bool hasArguments() const;
virtual bool isEqualTo(const Name *other) const;
virtual const SelectorNameId *asSelectorNameId() const
{ return this; }
virtual SelectorNameId *asSelectorNameId()
{ return this; }
protected:
virtual void accept0(NameVisitor *visitor);
private:
Name **_names;
unsigned _nameCount;
bool _hasArguments;
};
CPLUSPLUS_END_NAMESPACE
CPLUSPLUS_END_HEADER
......
......@@ -2967,7 +2967,7 @@ bool Parser::parseObjCMessageExpression(ExpressionAST *&node)
ast->lbracket_token = consumeToken();
parseObjCMessageReceiver(ast->receiver_expression);
parseObjCMessageArguments(ast->argument_list);
parseObjCMessageArguments(ast->selector, ast->argument_list);
match(T_RBRACKET, &(ast->rbracket_token));
node = ast;
......@@ -2979,25 +2979,34 @@ bool Parser::parseObjCMessageReceiver(ExpressionAST *&node)
return parseExpression(node);
}
bool Parser::parseObjCMessageArguments(ObjCMessageArgumentListAST *& node)
bool Parser::parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode)
{
if (LA() == T_RBRACKET)
return false; // nothing to do.
unsigned start = cursor();
ObjCMessageArgumentListAST *ast = new (_pool) ObjCMessageArgumentListAST;
ObjCMessageArgumentAST *argument = 0;
ObjCSelectorArgumentAST *selectorArgument = 0;
ObjCMessageArgumentAST *messageArgument = 0;
if (parseObjCSelectorArg(argument)) {
ast->arg = argument;
ObjCMessageArgumentListAST *lastArgument = ast;
if (parseObjCSelectorArg(selectorArgument, messageArgument)) {
ObjCSelectorArgumentListAST *selAst = new (_pool) ObjCSelectorArgumentListAST;
selAst->argument = selectorArgument;
ObjCSelectorArgumentListAST *lastSelector = selAst;
while (parseObjCSelectorArg(argument)) {
ObjCMessageArgumentListAST *argAst = new (_pool) ObjCMessageArgumentListAST;
argAst->arg = messageArgument;
ObjCMessageArgumentListAST *lastArgument = argAst;
while (parseObjCSelectorArg(selectorArgument, messageArgument)) {
// accept the selector args.
lastSelector->next = new (_pool) ObjCSelectorArgumentListAST;
lastSelector = lastSelector->next;
lastSelector->argument = selectorArgument;
lastArgument->next = new (_pool) ObjCMessageArgumentListAST;
lastArgument = lastArgument->next;
lastArgument->arg = argument;
lastArgument->arg = messageArgument;
}
if (LA() == T_COMMA) {
......@@ -3011,17 +3020,24 @@ bool Parser::parseObjCMessageArguments(ObjCMessageArgumentListAST *& node)
lastExpression = &(binaryExpression->right_expression);
}
}
ObjCSelectorWithArgumentsAST *selWithArgs = new (_pool) ObjCSelectorWithArgumentsAST;
selWithArgs->selector_arguments = selAst;
selNode = selWithArgs;
argNode = argAst;
} else {
rewind(start);
ast->arg = new (_pool) ObjCMessageArgumentAST;
parseObjCSelector(ast->arg->parameter_key_identifier);
ObjCSelectorWithoutArgumentsAST *sel = new (_pool) ObjCSelectorWithoutArgumentsAST;
parseObjCSelector(sel->name_token);
selNode = sel;
argNode = 0;
}
node = ast;
return true;
}
bool Parser::parseObjCSelectorArg(ObjCMessageArgumentAST *&node)
bool Parser::parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode)
{
unsigned selector_token = 0;
if (!parseObjCSelector(selector_token))
......@@ -3030,12 +3046,12 @@ bool Parser::parseObjCSelectorArg(ObjCMessageArgumentAST *&node)
if (LA() != T_COLON)
return false;
ObjCMessageArgumentAST *argument = new (_pool) ObjCMessageArgumentAST;
argument->parameter_key_identifier = selector_token;
argument->colon_token = consumeToken();
selNode = new (_pool) ObjCSelectorArgumentAST;
selNode->name_token = selector_token;
selNode->colon_token = consumeToken();
parseAssignmentExpression(argument->parameter_value_expression);
node = argument;
argNode = new (_pool) ObjCMessageArgumentAST;
parseAssignmentExpression(argNode->parameter_value_expression);
return true;
}
......
......@@ -226,8 +226,8 @@ public:
bool parseObjCMethodSignature();
bool parseObjCMessageExpression(ExpressionAST *&node);
bool parseObjCMessageReceiver(ExpressionAST *&node);
bool parseObjCMessageArguments(ObjCMessageArgumentListAST *&node);
bool parseObjCSelectorArg(ObjCMessageArgumentAST *&node);
bool parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode);
bool parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode);
bool parseObjCMethodDefinitionList(DeclarationListAST *&node);