Added support for override/final and enum classes

Change-Id: I6dfe9dd606781046ff5a1ed61315741d2f332cb8
Reviewed-by: Christian Kamm <christian.d.kamm@nokia.com>
This commit is contained in:
Sergey Shambir
2012-06-25 23:49:17 +04:00
committed by Christian Kamm
parent 656ecfbf59
commit 95c5ab2746
18 changed files with 201 additions and 7 deletions

View File

@@ -523,6 +523,8 @@ unsigned ClassSpecifierAST::firstToken() const
if (name) if (name)
if (unsigned candidate = name->firstToken()) if (unsigned candidate = name->firstToken())
return candidate; return candidate;
if (final_token)
return final_token;
if (colon_token) if (colon_token)
return colon_token; return colon_token;
if (base_clause_list) if (base_clause_list)
@@ -557,6 +559,8 @@ unsigned ClassSpecifierAST::lastToken() const
return candidate; return candidate;
if (colon_token) if (colon_token)
return colon_token + 1; return colon_token + 1;
if (final_token)
return final_token + 1;
if (name) if (name)
if (unsigned candidate = name->lastToken()) if (unsigned candidate = name->lastToken())
return candidate; return candidate;

View File

@@ -1168,6 +1168,7 @@ public:
unsigned classkey_token; unsigned classkey_token;
SpecifierListAST *attribute_list; SpecifierListAST *attribute_list;
NameAST *name; NameAST *name;
unsigned final_token;
unsigned colon_token; unsigned colon_token;
BaseSpecifierListAST *base_clause_list; BaseSpecifierListAST *base_clause_list;
unsigned dot_dot_dot_token; unsigned dot_dot_dot_token;
@@ -1183,6 +1184,7 @@ public:
: classkey_token(0) : classkey_token(0)
, attribute_list(0) , attribute_list(0)
, name(0) , name(0)
, final_token(0)
, colon_token(0) , colon_token(0)
, base_clause_list(0) , base_clause_list(0)
, dot_dot_dot_token(0) , dot_dot_dot_token(0)

View File

@@ -362,6 +362,7 @@ ClassSpecifierAST *ClassSpecifierAST::clone(MemoryPool *pool) const
*ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0); *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
if (name) if (name)
ast->name = name->clone(pool); ast->name = name->clone(pool);
ast->final_token = final_token;
ast->colon_token = colon_token; ast->colon_token = colon_token;
for (BaseSpecifierListAST *iter = base_clause_list, **ast_iter = &ast->base_clause_list; for (BaseSpecifierListAST *iter = base_clause_list, **ast_iter = &ast->base_clause_list;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next) iter; iter = iter->next, ast_iter = &(*ast_iter)->next)

View File

@@ -593,6 +593,8 @@ bool ASTMatcher::match(ClassSpecifierAST *node, ClassSpecifierAST *pattern)
else if (! AST::match(node->name, pattern->name, this)) else if (! AST::match(node->name, pattern->name, this))
return false; return false;
pattern->final_token = node->final_token;
pattern->colon_token = node->colon_token; pattern->colon_token = node->colon_token;
if (! pattern->base_clause_list) if (! pattern->base_clause_list)

View File

@@ -2660,6 +2660,20 @@ bool Bind::visit(TemplateIdAST *ast)
bool Bind::visit(SimpleSpecifierAST *ast) bool Bind::visit(SimpleSpecifierAST *ast)
{ {
switch (tokenKind(ast->specifier_token)) { switch (tokenKind(ast->specifier_token)) {
case T_IDENTIFIER: {
const Identifier *id = tokenAt(ast->specifier_token).identifier;
if (id->isEqualTo(control()->cpp11Override())) {
if (_type.isOverride())
translationUnit()->error(ast->specifier_token, "duplicate `override'");
_type.setOverride(true);
}
else if (id->isEqualTo(control()->cpp11Final())) {
if (_type.isFinal())
translationUnit()->error(ast->specifier_token, "duplicate `final'");
_type.setFinal(true);
}
}
break;
case T_CONST: case T_CONST:
if (_type.isConst()) if (_type.isConst())
translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token)); translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token));
@@ -3106,6 +3120,8 @@ bool Bind::visit(FunctionDeclaratorAST *ast)
// propagate the cv-qualifiers // propagate the cv-qualifiers
fun->setConst(type.isConst()); fun->setConst(type.isConst());
fun->setVolatile(type.isVolatile()); fun->setVolatile(type.isVolatile());
fun->setOverride(type.isOverride());
fun->setFinal(type.isFinal());
this->exceptionSpecification(ast->exception_specification, type); this->exceptionSpecification(ast->exception_specification, type);
if (ast->as_cpp_initializer != 0) { if (ast->as_cpp_initializer != 0) {

View File

@@ -507,6 +507,8 @@ public:
const Identifier *objcRetainId; const Identifier *objcRetainId;
const Identifier *objcCopyId; const Identifier *objcCopyId;
const Identifier *objcNonatomicId; const Identifier *objcNonatomicId;
const Identifier *cpp11Override;
const Identifier *cpp11Final;
TopLevelDeclarationProcessor *processor; TopLevelDeclarationProcessor *processor;
}; };
@@ -525,6 +527,9 @@ Control::Control()
d->objcRetainId = identifier("retain"); d->objcRetainId = identifier("retain");
d->objcCopyId = identifier("copy"); d->objcCopyId = identifier("copy");
d->objcNonatomicId = identifier("nonatomic"); d->objcNonatomicId = identifier("nonatomic");
d->cpp11Override = identifier("override");
d->cpp11Final = identifier("final");
} }
Control::~Control() Control::~Control()
@@ -764,6 +769,12 @@ const Identifier *Control::objcCopyId() const
const Identifier *Control::objcNonatomicId() const const Identifier *Control::objcNonatomicId() const
{ return d->objcNonatomicId; } { return d->objcNonatomicId; }
const Identifier *Control::cpp11Override() const
{ return d->cpp11Override; }
const Identifier *Control::cpp11Final() const
{ return d->cpp11Final; }
Symbol **Control::firstSymbol() const Symbol **Control::firstSymbol() const
{ {
if (d->symbols.empty()) if (d->symbols.empty())

View File

@@ -178,6 +178,9 @@ public:
const Identifier *objcRetainId() const; const Identifier *objcRetainId() const;
const Identifier *objcCopyId() const; const Identifier *objcCopyId() const;
const Identifier *objcNonatomicId() const; const Identifier *objcNonatomicId() const;
// C++11 context keywords
const Identifier *cpp11Override() const;
const Identifier *cpp11Final() const;
const OperatorNameId *findOperatorNameId(OperatorNameId::Kind operatorId) const; const OperatorNameId *findOperatorNameId(OperatorNameId::Kind operatorId) const;

View File

@@ -55,6 +55,8 @@ FullySpecifiedType FullySpecifiedType::qualifiedType() const
ty.setInline(false); ty.setInline(false);
ty.setVirtual(false); ty.setVirtual(false);
ty.setOverride(false);
ty.setFinal(false);
ty.setExplicit(false); ty.setExplicit(false);
ty.setDeprecated(false); ty.setDeprecated(false);
@@ -140,6 +142,18 @@ bool FullySpecifiedType::isVirtual() const
void FullySpecifiedType::setVirtual(bool isVirtual) void FullySpecifiedType::setVirtual(bool isVirtual)
{ f._isVirtual = isVirtual; } { f._isVirtual = isVirtual; }
bool FullySpecifiedType::isOverride() const
{ return f._isOverride; }
void FullySpecifiedType::setOverride(bool isOverride)
{ f._isOverride = isOverride; }
bool FullySpecifiedType::isFinal() const
{ return f._isFinal; }
void FullySpecifiedType::setFinal(bool isFinal)
{ f._isFinal = isFinal; }
bool FullySpecifiedType::isExplicit() const bool FullySpecifiedType::isExplicit() const
{ return f._isExplicit; } { return f._isExplicit; }
@@ -226,6 +240,8 @@ void FullySpecifiedType::copySpecifiers(const FullySpecifiedType &type)
// function specifiers // function specifiers
f._isInline = type.f._isInline; f._isInline = type.f._isInline;
f._isVirtual = type.f._isVirtual; f._isVirtual = type.f._isVirtual;
f._isOverride = type.f._isOverride;
f._isFinal = type.f._isFinal;
f._isExplicit = type.f._isExplicit; f._isExplicit = type.f._isExplicit;
} }

View File

@@ -79,6 +79,12 @@ public:
bool isVirtual() const; bool isVirtual() const;
void setVirtual(bool isVirtual); void setVirtual(bool isVirtual);
bool isOverride() const;
void setOverride(bool isOverride);
bool isFinal() const;
void setFinal(bool isFinal);
bool isExplicit() const; bool isExplicit() const;
void setExplicit(bool isExplicit); void setExplicit(bool isExplicit);
@@ -132,6 +138,8 @@ private:
// function specifiers // function specifiers
unsigned _isInline: 1; unsigned _isInline: 1;
unsigned _isVirtual: 1; unsigned _isVirtual: 1;
unsigned _isOverride: 1;
unsigned _isFinal: 1;
unsigned _isExplicit: 1; unsigned _isExplicit: 1;
// speficiers from attributes // speficiers from attributes

View File

@@ -1178,6 +1178,40 @@ bool Parser::parseCvQualifiers(SpecifierListAST *&node)
return start != cursor(); return start != cursor();
} }
/**
* \brief Handles override and final from C++ 2011, they are pseudo keywords and has special meaning only in function declaration
*/
bool Parser::parseOverrideFinalQualifiers(SpecifierListAST *&node)
{
DEBUG_THIS_RULE();
if (!_cxx0xEnabled)
return false;
unsigned start = cursor();
SpecifierListAST **ast = &node;
while (*ast)
ast = &(*ast)->next;
while (LA() == T_IDENTIFIER) {
const Identifier &id = *(_translationUnit->tokenAt(cursor()).identifier);
if (id.equalTo(_control->cpp11Override())
|| id.equalTo(_control->cpp11Final())) {
SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
spec->specifier_token = consumeToken();
*ast = new (_pool) SpecifierListAST(spec);
ast = &(*ast)->next;
}
else {
break;
}
}
return (start != cursor());
}
bool Parser::parsePtrOperator(PtrOperatorListAST *&node) bool Parser::parsePtrOperator(PtrOperatorListAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
@@ -1442,6 +1476,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_specif
ast->rparen_token = consumeToken(); ast->rparen_token = consumeToken();
// ### parse attributes // ### parse attributes
parseCvQualifiers(ast->cv_qualifier_list); parseCvQualifiers(ast->cv_qualifier_list);
parseOverrideFinalQualifiers(ast->cv_qualifier_list);
// ### parse ref-qualifiers // ### parse ref-qualifiers
parseExceptionSpecification(ast->exception_specification); parseExceptionSpecification(ast->exception_specification);
@@ -1572,11 +1607,26 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node, SpecifierListAST *dec
return true; return true;
} }
/**
* @brief Reads enumeration type declaration, examples:
* @code
enum {
debug = 1
};
enum class Format {
FormatPNG,
FormatJPEG
};
* @endcode
*/
bool Parser::parseEnumSpecifier(SpecifierListAST *&node) bool Parser::parseEnumSpecifier(SpecifierListAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_ENUM) { if (LA() == T_ENUM) {
unsigned enum_token = consumeToken(); unsigned enum_token = consumeToken();
if (_cxx0xEnabled && LA() == T_CLASS)
consumeToken();
NameAST *name = 0; NameAST *name = 0;
parseName(name); parseName(name);
if (LA() == T_LBRACE) { if (LA() == T_LBRACE) {
@@ -1874,10 +1924,13 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node)
} }
if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) { if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) {
const Identifier *id = tok(2).identifier;
if (!id->equalTo(_control->cpp11Final())) {
warning(cursor(), "skip identifier `%s'", warning(cursor(), "skip identifier `%s'",
tok().spell()); tok().spell());
consumeToken(); consumeToken();
} }
}
NameAST *name = 0; NameAST *name = 0;
parseName(name); parseName(name);
@@ -1889,6 +1942,13 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node)
unsigned colon_token = 0; unsigned colon_token = 0;
unsigned dot_dot_dot_token = 0; unsigned dot_dot_dot_token = 0;
unsigned final_token = 0;
if (LA() == T_IDENTIFIER) {
const Identifier *id = tok().identifier;
if (id->equalTo(_control->cpp11Final()))
final_token = consumeToken();
}
if (LA() == T_COLON || LA() == T_LBRACE) { if (LA() == T_COLON || LA() == T_LBRACE) {
BaseSpecifierListAST *base_clause_list = 0; BaseSpecifierListAST *base_clause_list = 0;
@@ -1919,6 +1979,7 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node)
ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST; ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST;
ast->classkey_token = classkey_token; ast->classkey_token = classkey_token;
ast->attribute_list = attributes; ast->attribute_list = attributes;
ast->final_token = final_token;
ast->name = name; ast->name = name;
ast->colon_token = colon_token; ast->colon_token = colon_token;
ast->base_clause_list = base_clause_list; ast->base_clause_list = base_clause_list;
@@ -3772,8 +3833,11 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *de
} else if (! has_type_specifier && lookAtClassKey()) { } else if (! has_type_specifier && lookAtClassKey()) {
unsigned startOfTypeSpecifier = cursor(); unsigned startOfTypeSpecifier = cursor();
if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) ||
(LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER && (LA() == T_COLON || LA() == T_LBRACE
(LA(2) == T_COLON || LA(2) == T_LBRACE)))) { || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER // MACRO Name followed by : or {
&& (LA(2) == T_COLON || LA(2) == T_LBRACE))
|| (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER && // MACRO Name final followed by : or {
(LA(3) == T_COLON || LA(3) == T_LBRACE)))) {
rewind(startOfTypeSpecifier); rewind(startOfTypeSpecifier);
if (! parseClassSpecifier(*decl_specifier_seq_ptr)) { if (! parseClassSpecifier(*decl_specifier_seq_ptr)) {
error(startOfTypeSpecifier, error(startOfTypeSpecifier,

View File

@@ -82,6 +82,7 @@ public:
bool parseConstantExpression(ExpressionAST *&node); bool parseConstantExpression(ExpressionAST *&node);
bool parseCtorInitializer(CtorInitializerAST *&node); bool parseCtorInitializer(CtorInitializerAST *&node);
bool parseCvQualifiers(SpecifierListAST *&node); bool parseCvQualifiers(SpecifierListAST *&node);
bool parseOverrideFinalQualifiers(SpecifierListAST *&node);
bool parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_specifier_list); bool parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_specifier_list);
bool parseDeclaration(DeclarationAST *&node); bool parseDeclaration(DeclarationAST *&node);
bool parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *declaringClass = 0); bool parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *declaringClass = 0);

View File

@@ -358,6 +358,18 @@ bool Function::isVirtual() const
void Function::setVirtual(bool isVirtual) void Function::setVirtual(bool isVirtual)
{ f._isVirtual = isVirtual; } { f._isVirtual = isVirtual; }
bool Function::isOverride() const
{ return f._isOverride; }
void Function::setOverride(bool isOverride)
{ f._isOverride = isOverride; }
bool Function::isFinal() const
{ return f._isFinal; }
void Function::setFinal(bool isFinal)
{ f._isFinal = isFinal; }
bool Function::isVariadic() const bool Function::isVariadic() const
{ return f._isVariadic; } { return f._isVariadic; }

View File

@@ -323,6 +323,12 @@ public:
bool isVirtual() const; bool isVirtual() const;
void setVirtual(bool isVirtual); void setVirtual(bool isVirtual);
bool isOverride() const;
void setOverride(bool isOverride);
bool isFinal() const;
void setFinal(bool isFinal);
bool isVariadic() const; bool isVariadic() const;
void setVariadic(bool isVariadic); void setVariadic(bool isVariadic);
@@ -371,6 +377,8 @@ private:
FullySpecifiedType _returnType; FullySpecifiedType _returnType;
struct Flags { struct Flags {
unsigned _isVirtual: 1; unsigned _isVirtual: 1;
unsigned _isOverride: 1;
unsigned _isFinal: 1;
unsigned _isVariadic: 1; unsigned _isVariadic: 1;
unsigned _isPureVirtual: 1; unsigned _isPureVirtual: 1;
unsigned _isConst: 1; unsigned _isConst: 1;

View File

@@ -134,6 +134,8 @@ private:
fun->setConst(funTy->isConst()); fun->setConst(funTy->isConst());
fun->setVolatile(funTy->isVolatile()); fun->setVolatile(funTy->isVolatile());
fun->setVirtual(funTy->isVirtual()); fun->setVirtual(funTy->isVirtual());
fun->setOverride(funTy->isOverride());
fun->setFinal(funTy->isFinal());
fun->setAmbiguous(funTy->isAmbiguous()); fun->setAmbiguous(funTy->isAmbiguous());
fun->setVariadic(funTy->isVariadic()); fun->setVariadic(funTy->isVariadic());

View File

@@ -1775,6 +1775,8 @@ void CPPEditorWidget::setFontSettings(const TextEditor::FontSettings &fs)
fs.toTextCharFormat(TextEditor::C_PREPROCESSOR); fs.toTextCharFormat(TextEditor::C_PREPROCESSOR);
m_semanticHighlightFormatMap[SemanticInfo::FunctionUse] = m_semanticHighlightFormatMap[SemanticInfo::FunctionUse] =
fs.toTextCharFormat(TextEditor::C_FUNCTION); fs.toTextCharFormat(TextEditor::C_FUNCTION);
m_semanticHighlightFormatMap[SemanticInfo::PseudoKeywordUse] =
fs.toTextCharFormat(TextEditor::C_KEYWORD);
m_keywordFormat = fs.toTextCharFormat(TextEditor::C_KEYWORD); m_keywordFormat = fs.toTextCharFormat(TextEditor::C_KEYWORD);
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link // only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link

View File

@@ -506,6 +506,14 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast)
decl->enclosingScope()), decl->enclosingScope()),
nameAST, funTy->argumentCount())) { nameAST, funTy->argumentCount())) {
declrIdNameAST = nameAST; declrIdNameAST = nameAST;
// Add a diagnostic message if non-virtual function has override/final marker
if ((_usages.back().kind != SemanticInfo::VirtualMethodUse)) {
if (funTy->isOverride())
warning(declrIdNameAST, "Only virtual methods can be marked `override'");
else if (funTy->isFinal())
warning(declrIdNameAST, "Only virtual methods can be marked `final'");
}
} }
} }
} }
@@ -952,6 +960,37 @@ bool CheckSymbols::visit(LabeledStatementAST *ast)
return false; return false;
} }
/**
* \brief Highlights "override" and "final" pseudokeywords like true keywords
*/
bool CheckSymbols::visit(SimpleSpecifierAST *ast)
{
if (ast->specifier_token)
{
const Token &tk = tokenAt(ast->specifier_token);
if (tk.is(T_IDENTIFIER))
{
const Identifier &id = *(tk.identifier);
if (id.equalTo(_doc->control()->cpp11Override())
|| id.equalTo(_doc->control()->cpp11Final()))
{
addUse(ast->specifier_token, SemanticInfo::PseudoKeywordUse);
}
}
}
return false;
}
bool CheckSymbols::visit(ClassSpecifierAST *ast)
{
if (ast->final_token)
addUse(ast->final_token, SemanticInfo::PseudoKeywordUse);
return true;
}
bool CheckSymbols::visit(FunctionDefinitionAST *ast) bool CheckSymbols::visit(FunctionDefinitionAST *ast)
{ {
AST *thisFunction = _astStack.takeLast(); AST *thisFunction = _astStack.takeLast();

View File

@@ -151,6 +151,8 @@ protected:
virtual bool visit(GotoStatementAST *ast); virtual bool visit(GotoStatementAST *ast);
virtual bool visit(LabeledStatementAST *ast); virtual bool visit(LabeledStatementAST *ast);
virtual bool visit(SimpleSpecifierAST *ast);
virtual bool visit(ClassSpecifierAST *ast);
virtual bool visit(MemInitializerAST *ast); virtual bool visit(MemInitializerAST *ast);
virtual bool visit(EnumeratorAST *ast); virtual bool visit(EnumeratorAST *ast);

View File

@@ -52,7 +52,8 @@ public:
VirtualMethodUse, VirtualMethodUse,
LabelUse, LabelUse,
MacroUse, MacroUse,
FunctionUse FunctionUse,
PseudoKeywordUse
}; };
typedef TextEditor::SemanticHighlighter::Result Use; typedef TextEditor::SemanticHighlighter::Result Use;