forked from qt-creator/qt-creator
Added Semantic checks for ObjC methods.
This commit is contained in:
@@ -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);
|
||||
bool parseObjCMethodDefinition(DeclarationAST *&node);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user