diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index ccef3893db4..94cdbc9611a 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -523,6 +523,8 @@ unsigned ClassSpecifierAST::firstToken() const if (name) if (unsigned candidate = name->firstToken()) return candidate; + if (final_token) + return final_token; if (colon_token) return colon_token; if (base_clause_list) @@ -557,6 +559,8 @@ unsigned ClassSpecifierAST::lastToken() const return candidate; if (colon_token) return colon_token + 1; + if (final_token) + return final_token + 1; if (name) if (unsigned candidate = name->lastToken()) return candidate; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 22bc1024fea..24e031c72e5 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -1168,6 +1168,7 @@ public: unsigned classkey_token; SpecifierListAST *attribute_list; NameAST *name; + unsigned final_token; unsigned colon_token; BaseSpecifierListAST *base_clause_list; unsigned dot_dot_dot_token; @@ -1183,6 +1184,7 @@ public: : classkey_token(0) , attribute_list(0) , name(0) + , final_token(0) , colon_token(0) , base_clause_list(0) , dot_dot_dot_token(0) diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 0d08f48af8a..6a3b7a5ddac 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -362,6 +362,7 @@ ClassSpecifierAST *ClassSpecifierAST::clone(MemoryPool *pool) const *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0); if (name) ast->name = name->clone(pool); + ast->final_token = final_token; ast->colon_token = colon_token; for (BaseSpecifierListAST *iter = base_clause_list, **ast_iter = &ast->base_clause_list; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index 0b09d086e04..a773c07b3ed 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -593,6 +593,8 @@ bool ASTMatcher::match(ClassSpecifierAST *node, ClassSpecifierAST *pattern) else if (! AST::match(node->name, pattern->name, this)) return false; + pattern->final_token = node->final_token; + pattern->colon_token = node->colon_token; if (! pattern->base_clause_list) diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index eb9ec735b27..357e045ffd5 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2660,6 +2660,20 @@ bool Bind::visit(TemplateIdAST *ast) bool Bind::visit(SimpleSpecifierAST *ast) { 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: if (_type.isConst()) translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token)); @@ -3106,6 +3120,8 @@ bool Bind::visit(FunctionDeclaratorAST *ast) // propagate the cv-qualifiers fun->setConst(type.isConst()); fun->setVolatile(type.isVolatile()); + fun->setOverride(type.isOverride()); + fun->setFinal(type.isFinal()); this->exceptionSpecification(ast->exception_specification, type); if (ast->as_cpp_initializer != 0) { diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 6864b8aaa41..a1b80825042 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -507,6 +507,8 @@ public: const Identifier *objcRetainId; const Identifier *objcCopyId; const Identifier *objcNonatomicId; + const Identifier *cpp11Override; + const Identifier *cpp11Final; TopLevelDeclarationProcessor *processor; }; @@ -525,6 +527,9 @@ Control::Control() d->objcRetainId = identifier("retain"); d->objcCopyId = identifier("copy"); d->objcNonatomicId = identifier("nonatomic"); + + d->cpp11Override = identifier("override"); + d->cpp11Final = identifier("final"); } Control::~Control() @@ -764,6 +769,12 @@ const Identifier *Control::objcCopyId() const const Identifier *Control::objcNonatomicId() const { return d->objcNonatomicId; } +const Identifier *Control::cpp11Override() const +{ return d->cpp11Override; } + +const Identifier *Control::cpp11Final() const +{ return d->cpp11Final; } + Symbol **Control::firstSymbol() const { if (d->symbols.empty()) diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index 024d1208214..4132d5f3cfa 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -178,6 +178,9 @@ public: const Identifier *objcRetainId() const; const Identifier *objcCopyId() const; const Identifier *objcNonatomicId() const; + // C++11 context keywords + const Identifier *cpp11Override() const; + const Identifier *cpp11Final() const; const OperatorNameId *findOperatorNameId(OperatorNameId::Kind operatorId) const; diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp index 6ed6f4e105d..0fbd3f41b9c 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp @@ -55,6 +55,8 @@ FullySpecifiedType FullySpecifiedType::qualifiedType() const ty.setInline(false); ty.setVirtual(false); + ty.setOverride(false); + ty.setFinal(false); ty.setExplicit(false); ty.setDeprecated(false); @@ -140,6 +142,18 @@ bool FullySpecifiedType::isVirtual() const void FullySpecifiedType::setVirtual(bool 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 { return f._isExplicit; } @@ -226,6 +240,8 @@ void FullySpecifiedType::copySpecifiers(const FullySpecifiedType &type) // function specifiers f._isInline = type.f._isInline; f._isVirtual = type.f._isVirtual; + f._isOverride = type.f._isOverride; + f._isFinal = type.f._isFinal; f._isExplicit = type.f._isExplicit; } @@ -235,4 +251,4 @@ bool FullySpecifiedType::match(const FullySpecifiedType &otherTy, TypeMatcher *m return false; return type()->matchType(otherTy.type(), matcher); -} \ No newline at end of file +} diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h index c6f71d2dffd..895e171df58 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h @@ -79,6 +79,12 @@ public: bool isVirtual() const; void setVirtual(bool isVirtual); + bool isOverride() const; + void setOverride(bool isOverride); + + bool isFinal() const; + void setFinal(bool isFinal); + bool isExplicit() const; void setExplicit(bool isExplicit); @@ -132,6 +138,8 @@ private: // function specifiers unsigned _isInline: 1; unsigned _isVirtual: 1; + unsigned _isOverride: 1; + unsigned _isFinal: 1; unsigned _isExplicit: 1; // speficiers from attributes diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 1011297f415..2bbbe7547d7 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1178,6 +1178,40 @@ bool Parser::parseCvQualifiers(SpecifierListAST *&node) 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) { DEBUG_THIS_RULE(); @@ -1442,6 +1476,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_specif ast->rparen_token = consumeToken(); // ### parse attributes parseCvQualifiers(ast->cv_qualifier_list); + parseOverrideFinalQualifiers(ast->cv_qualifier_list); // ### parse ref-qualifiers parseExceptionSpecification(ast->exception_specification); @@ -1572,11 +1607,26 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node, SpecifierListAST *dec return true; } +/** + * @brief Reads enumeration type declaration, examples: + * @code + enum { + debug = 1 + }; + enum class Format { + FormatPNG, + FormatJPEG + }; + * @endcode + */ bool Parser::parseEnumSpecifier(SpecifierListAST *&node) { DEBUG_THIS_RULE(); if (LA() == T_ENUM) { unsigned enum_token = consumeToken(); + if (_cxx0xEnabled && LA() == T_CLASS) + consumeToken(); + NameAST *name = 0; parseName(name); if (LA() == T_LBRACE) { @@ -1874,9 +1924,12 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node) } if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) { - warning(cursor(), "skip identifier `%s'", - tok().spell()); - consumeToken(); + const Identifier *id = tok(2).identifier; + if (!id->equalTo(_control->cpp11Final())) { + warning(cursor(), "skip identifier `%s'", + tok().spell()); + consumeToken(); + } } NameAST *name = 0; @@ -1889,6 +1942,13 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node) unsigned colon_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) { BaseSpecifierListAST *base_clause_list = 0; @@ -1919,6 +1979,7 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node) ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST; ast->classkey_token = classkey_token; ast->attribute_list = attributes; + ast->final_token = final_token; ast->name = name; ast->colon_token = colon_token; ast->base_clause_list = base_clause_list; @@ -3772,8 +3833,11 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *de } else if (! has_type_specifier && lookAtClassKey()) { unsigned startOfTypeSpecifier = cursor(); if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || - (LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER && - (LA(2) == T_COLON || LA(2) == T_LBRACE)))) { + (LA() == T_COLON || LA() == 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); if (! parseClassSpecifier(*decl_specifier_seq_ptr)) { error(startOfTypeSpecifier, diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index 24a1b3f0128..406e8f2d69e 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -82,6 +82,7 @@ public: bool parseConstantExpression(ExpressionAST *&node); bool parseCtorInitializer(CtorInitializerAST *&node); bool parseCvQualifiers(SpecifierListAST *&node); + bool parseOverrideFinalQualifiers(SpecifierListAST *&node); bool parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_specifier_list); bool parseDeclaration(DeclarationAST *&node); bool parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *declaringClass = 0); diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index e7af2981b08..2ac8075f1c2 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -358,6 +358,18 @@ bool Function::isVirtual() const void Function::setVirtual(bool 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 { return f._isVariadic; } diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index 2d1d5158f44..e7fae948925 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -323,6 +323,12 @@ public: bool isVirtual() const; void setVirtual(bool isVirtual); + bool isOverride() const; + void setOverride(bool isOverride); + + bool isFinal() const; + void setFinal(bool isFinal); + bool isVariadic() const; void setVariadic(bool isVariadic); @@ -371,6 +377,8 @@ private: FullySpecifiedType _returnType; struct Flags { unsigned _isVirtual: 1; + unsigned _isOverride: 1; + unsigned _isFinal: 1; unsigned _isVariadic: 1; unsigned _isPureVirtual: 1; unsigned _isConst: 1; diff --git a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp index 402104e2ec4..2da14e4f652 100644 --- a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp +++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp @@ -134,6 +134,8 @@ private: fun->setConst(funTy->isConst()); fun->setVolatile(funTy->isVolatile()); fun->setVirtual(funTy->isVirtual()); + fun->setOverride(funTy->isOverride()); + fun->setFinal(funTy->isFinal()); fun->setAmbiguous(funTy->isAmbiguous()); fun->setVariadic(funTy->isVariadic()); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 7f98f0842f1..13eb6dcde77 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -1775,6 +1775,8 @@ void CPPEditorWidget::setFontSettings(const TextEditor::FontSettings &fs) fs.toTextCharFormat(TextEditor::C_PREPROCESSOR); m_semanticHighlightFormatMap[SemanticInfo::FunctionUse] = fs.toTextCharFormat(TextEditor::C_FUNCTION); + m_semanticHighlightFormatMap[SemanticInfo::PseudoKeywordUse] = + 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 diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index e77673195ec..1687e322ab0 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -506,6 +506,14 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast) decl->enclosingScope()), nameAST, funTy->argumentCount())) { 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; } + +/** + * \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) { AST *thisFunction = _astStack.takeLast(); diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h index a1bf9b77a84..da0ba3938d5 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -151,6 +151,8 @@ protected: virtual bool visit(GotoStatementAST *ast); virtual bool visit(LabeledStatementAST *ast); + virtual bool visit(SimpleSpecifierAST *ast); + virtual bool visit(ClassSpecifierAST *ast); virtual bool visit(MemInitializerAST *ast); virtual bool visit(EnumeratorAST *ast); diff --git a/src/plugins/cpptools/cppsemanticinfo.h b/src/plugins/cpptools/cppsemanticinfo.h index 3ad425136e2..f87feb334d1 100644 --- a/src/plugins/cpptools/cppsemanticinfo.h +++ b/src/plugins/cpptools/cppsemanticinfo.h @@ -52,7 +52,8 @@ public: VirtualMethodUse, LabelUse, MacroUse, - FunctionUse + FunctionUse, + PseudoKeywordUse }; typedef TextEditor::SemanticHighlighter::Result Use;