diff options
author | Volodymyr Zibarov <gogan419@gmail.com> | 2020-05-14 23:07:05 +0300 |
---|---|---|
committer | Volodymyr Zibarov <gogan419@gmail.com> | 2020-05-29 12:39:28 +0000 |
commit | 9ee693ee229d28bd618e8dd44bc6b12750d43a29 (patch) | |
tree | 7a2a4dd6679fd3647228b5c39d1fc2724ff133a3 | |
parent | be97943372bc80d2440daa20cd658599d765b9a9 (diff) |
C++: fix built-in code model to work with shared_ptr on MSVC 2017
These changes target Find Usages feature to work with shared_ptr.
Improve libs/3rdparty/cplusplus and plugins/cplusplus:
parse __declspec() attribute,
call to variadic function template without specified template arguments,
if constexpr,
c++11 attributes [[value]],
function templates with default parameters,
resolve order for function vs template with default parameter,
template operator->() with default arguments,
template specialization with numeric values,
find best partial specialization,
fix partial specialization for non-first specialized argument
Fixes: QTCREATORBUG-7866
Fixes: QTCREATORBUG-20781
Fixes: QTCREATORBUG-22857
Fixes: QTCREATORBUG-17825
Change-Id: I31a080f7729edfb2ee9650f1aff48daeba5a673b
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: Nikolai Kosjar <pinaceae.pinus@gmail.com>
43 files changed, 1198 insertions, 58 deletions
diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 3b91838eec..a48067ab75 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -73,6 +73,16 @@ int GnuAttributeSpecifierAST::firstToken() const return attribute_token; } +int MsvcDeclspecSpecifierAST::firstToken() const +{ + return attribute_token; +} + +int StdAttributeSpecifierAST::firstToken() const +{ + return first_lbracket_token; +} + int BaseSpecifierAST::firstToken() const { if (virtual_token && access_specifier_token) @@ -1524,6 +1534,8 @@ int IfStatementAST::firstToken() const { if (if_token) return if_token; + if (constexpr_token) + return constexpr_token; if (lparen_token) return lparen_token; if (condition) @@ -1560,6 +1572,8 @@ int IfStatementAST::lastToken() const return candidate; if (lparen_token) return lparen_token + 1; + if (constexpr_token) + return constexpr_token + 1; if (if_token) return if_token + 1; return 1; @@ -4214,6 +4228,36 @@ int GnuAttributeSpecifierAST::lastToken() const return 1; } +int MsvcDeclspecSpecifierAST::lastToken() const +{ + if (rparen_token) + return rparen_token + 1; + if (attribute_list) + if (int candidate = attribute_list->lastToken()) + return candidate; + if (lparen_token) + return lparen_token + 1; + if (attribute_token) + return attribute_token + 1; + return 1; +} + +int StdAttributeSpecifierAST::lastToken() const +{ + if (second_rbracket_token) + return second_rbracket_token + 1; + if (first_rbracket_token) + return first_rbracket_token + 1; + if (attribute_list) + if (int candidate = attribute_list->lastToken()) + return candidate; + if (second_lbracket_token) + return second_lbracket_token + 1; + if (first_lbracket_token) + return first_lbracket_token + 1; + return 1; +} + /** \generated */ int PointerLiteralAST::firstToken() const { diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index f3eb70aa4a..a03f5b5f82 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -195,6 +195,7 @@ public: virtual LinkageSpecificationAST *asLinkageSpecification() { return nullptr; } virtual MemInitializerAST *asMemInitializer() { return nullptr; } virtual MemberAccessAST *asMemberAccess() { return nullptr; } + virtual MsvcDeclspecSpecifierAST *asMsvcDeclspecSpecifier() { return nullptr; } virtual NameAST *asName() { return nullptr; } virtual NamedTypeSpecifierAST *asNamedTypeSpecifier() { return nullptr; } virtual NamespaceAST *asNamespace() { return nullptr; } @@ -265,6 +266,7 @@ public: virtual SpecifierAST *asSpecifier() { return nullptr; } virtual StatementAST *asStatement() { return nullptr; } virtual StaticAssertDeclarationAST *asStaticAssertDeclaration() { return nullptr; } + virtual StdAttributeSpecifierAST *asStdAttributeSpecifier() { return nullptr; } virtual StringLiteralAST *asStringLiteral() { return nullptr; } virtual SwitchStatementAST *asSwitchStatement() { return nullptr; } virtual TemplateDeclarationAST *asTemplateDeclaration() { return nullptr; } @@ -475,6 +477,49 @@ protected: virtual bool match0(AST *, ASTMatcher *); }; +class CPLUSPLUS_EXPORT MsvcDeclspecSpecifierAST: public AttributeSpecifierAST +{ +public: + int attribute_token = 0; + int lparen_token = 0; + GnuAttributeListAST *attribute_list = nullptr; + int rparen_token = 0; + +public: + virtual MsvcDeclspecSpecifierAST *asMsvcDeclspecSpecifier() { return this; } + + virtual int firstToken() const; + virtual int lastToken() const; + + virtual MsvcDeclspecSpecifierAST *clone(MemoryPool *pool) const; + +protected: + virtual void accept0(ASTVisitor *visitor); + virtual bool match0(AST *, ASTMatcher *); +}; + +class CPLUSPLUS_EXPORT StdAttributeSpecifierAST: public AttributeSpecifierAST +{ +public: + int first_lbracket_token = 0; + int second_lbracket_token = 0; + GnuAttributeListAST *attribute_list = nullptr; + int first_rbracket_token = 0; + int second_rbracket_token = 0; + +public: + virtual StdAttributeSpecifierAST *asStdAttributeSpecifier() { return this; } + + virtual int firstToken() const; + virtual int lastToken() const; + + virtual StdAttributeSpecifierAST *clone(MemoryPool *pool) const; + +protected: + virtual void accept0(ASTVisitor *visitor); + virtual bool match0(AST *, ASTMatcher *); +}; + class CPLUSPLUS_EXPORT GnuAttributeAST: public AST { public: @@ -1610,6 +1655,7 @@ class CPLUSPLUS_EXPORT IfStatementAST: public StatementAST { public: int if_token = 0; + int constexpr_token = 0; int lparen_token = 0; ExpressionAST *condition = nullptr; int rparen_token = 0; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 65350e3eab..9ca371f3a9 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -81,6 +81,31 @@ GnuAttributeSpecifierAST *GnuAttributeSpecifierAST::clone(MemoryPool *pool) cons return ast; } +MsvcDeclspecSpecifierAST *MsvcDeclspecSpecifierAST::clone(MemoryPool *pool) const +{ + MsvcDeclspecSpecifierAST *ast = new (pool) MsvcDeclspecSpecifierAST; + ast->attribute_token = attribute_token; + ast->lparen_token = lparen_token; + for (GnuAttributeListAST *iter = attribute_list, **ast_iter = &ast->attribute_list; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) GnuAttributeListAST((iter->value) ? iter->value->clone(pool) : nullptr); + ast->rparen_token = rparen_token; + return ast; +} + +StdAttributeSpecifierAST *StdAttributeSpecifierAST::clone(MemoryPool *pool) const +{ + StdAttributeSpecifierAST *ast = new (pool) StdAttributeSpecifierAST; + ast->first_lbracket_token = first_lbracket_token; + ast->second_lbracket_token = second_lbracket_token; + for (GnuAttributeListAST *iter = attribute_list, **ast_iter = &ast->attribute_list; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) GnuAttributeListAST((iter->value) ? iter->value->clone(pool) : nullptr); + ast->first_rbracket_token = first_rbracket_token; + ast->second_rbracket_token = second_rbracket_token; + return ast; +} + GnuAttributeAST *GnuAttributeAST::clone(MemoryPool *pool) const { GnuAttributeAST *ast = new (pool) GnuAttributeAST; @@ -730,6 +755,7 @@ IfStatementAST *IfStatementAST::clone(MemoryPool *pool) const { IfStatementAST *ast = new (pool) IfStatementAST; ast->if_token = if_token; + ast->constexpr_token = constexpr_token; ast->lparen_token = lparen_token; if (condition) ast->condition = condition->clone(pool); diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index 66c6a1be4d..1a82d29f6e 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -72,6 +72,22 @@ bool GnuAttributeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool MsvcDeclspecSpecifierAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (MsvcDeclspecSpecifierAST *_other = pattern->asMsvcDeclspecSpecifier()) + return matcher->match(this, _other); + + return false; +} + +bool StdAttributeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (StdAttributeSpecifierAST *_other = pattern->asStdAttributeSpecifier()) + return matcher->match(this, _other); + + return false; +} + bool GnuAttributeAST::match0(AST *pattern, ASTMatcher *matcher) { if (GnuAttributeAST *_other = pattern->asGnuAttribute()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index d76180a8ca..321d14a263 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -117,6 +117,46 @@ bool ASTMatcher::match(GnuAttributeSpecifierAST *node, GnuAttributeSpecifierAST return true; } +bool ASTMatcher::match(MsvcDeclspecSpecifierAST *node, MsvcDeclspecSpecifierAST *pattern) +{ + (void) node; + (void) pattern; + + pattern->attribute_token = node->attribute_token; + + pattern->lparen_token = node->lparen_token; + + if (! pattern->attribute_list) + pattern->attribute_list = node->attribute_list; + else if (! AST::match(node->attribute_list, pattern->attribute_list, this)) + return false; + + pattern->rparen_token = node->rparen_token; + + return true; +} + +bool ASTMatcher::match(StdAttributeSpecifierAST *node, StdAttributeSpecifierAST *pattern) +{ + (void) node; + (void) pattern; + + pattern->first_lbracket_token = node->first_lbracket_token; + + pattern->second_lbracket_token = node->second_lbracket_token; + + if (! pattern->attribute_list) + pattern->attribute_list = node->attribute_list; + else if (! AST::match(node->attribute_list, pattern->attribute_list, this)) + return false; + + pattern->first_rbracket_token = node->first_rbracket_token; + + pattern->second_rbracket_token = node->second_rbracket_token; + + return true; +} + bool ASTMatcher::match(GnuAttributeAST *node, GnuAttributeAST *pattern) { (void) node; @@ -1246,6 +1286,8 @@ bool ASTMatcher::match(IfStatementAST *node, IfStatementAST *pattern) pattern->if_token = node->if_token; + pattern->constexpr_token = node->constexpr_token; + pattern->lparen_token = node->lparen_token; if (! pattern->condition) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index f6f3eae8d9..47d9ecf5bf 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -96,6 +96,7 @@ public: virtual bool match(LinkageSpecificationAST *node, LinkageSpecificationAST *pattern); virtual bool match(MemInitializerAST *node, MemInitializerAST *pattern); virtual bool match(MemberAccessAST *node, MemberAccessAST *pattern); + virtual bool match(MsvcDeclspecSpecifierAST *node, MsvcDeclspecSpecifierAST *pattern); virtual bool match(NamedTypeSpecifierAST *node, NamedTypeSpecifierAST *pattern); virtual bool match(NamespaceAST *node, NamespaceAST *pattern); virtual bool match(NamespaceAliasDefinitionAST *node, NamespaceAliasDefinitionAST *pattern); @@ -160,6 +161,7 @@ public: virtual bool match(SimpleSpecifierAST *node, SimpleSpecifierAST *pattern); virtual bool match(SizeofExpressionAST *node, SizeofExpressionAST *pattern); virtual bool match(StaticAssertDeclarationAST *node, StaticAssertDeclarationAST *pattern); + virtual bool match(StdAttributeSpecifierAST *node, StdAttributeSpecifierAST *pattern); virtual bool match(StringLiteralAST *node, StringLiteralAST *pattern); virtual bool match(SwitchStatementAST *node, SwitchStatementAST *pattern); virtual bool match(TemplateDeclarationAST *node, TemplateDeclarationAST *pattern); diff --git a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h index c2888b3e2e..9e2a263533 100644 --- a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h +++ b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h @@ -76,6 +76,20 @@ public: return ast; } + MsvcDeclspecSpecifierAST *MsvcDeclspecSpecifier(GnuAttributeListAST *attribute_list = nullptr) + { + MsvcDeclspecSpecifierAST *ast = new (&pool) MsvcDeclspecSpecifierAST; + ast->attribute_list = attribute_list; + return ast; + } + + StdAttributeSpecifierAST *StdAttributeSpecifier(GnuAttributeListAST *attribute_list = nullptr) + { + StdAttributeSpecifierAST *ast = new (&pool) StdAttributeSpecifierAST; + ast->attribute_list = attribute_list; + return ast; + } + GnuAttributeAST *GnuAttribute(ExpressionListAST *expression_list = nullptr) { GnuAttributeAST *ast = new (&pool) GnuAttributeAST; diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 5ebe6ba3a5..b9e954972e 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -70,6 +70,22 @@ void GnuAttributeSpecifierAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void MsvcDeclspecSpecifierAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(attribute_list, visitor); + } + visitor->endVisit(this); +} + +void StdAttributeSpecifierAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(attribute_list, visitor); + } + visitor->endVisit(this); +} + void GnuAttributeAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index a1740e12cd..7f45d4d06d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -138,6 +138,7 @@ public: virtual bool visit(LinkageSpecificationAST *) { return true; } virtual bool visit(MemInitializerAST *) { return true; } virtual bool visit(MemberAccessAST *) { return true; } + virtual bool visit(MsvcDeclspecSpecifierAST *) { return true; } virtual bool visit(NamedTypeSpecifierAST *) { return true; } virtual bool visit(NamespaceAST *) { return true; } virtual bool visit(NamespaceAliasDefinitionAST *) { return true; } @@ -202,6 +203,7 @@ public: virtual bool visit(SimpleSpecifierAST *) { return true; } virtual bool visit(SizeofExpressionAST *) { return true; } virtual bool visit(StaticAssertDeclarationAST *) { return true; } + virtual bool visit(StdAttributeSpecifierAST *) { return true; } virtual bool visit(StringLiteralAST *) { return true; } virtual bool visit(SwitchStatementAST *) { return true; } virtual bool visit(TemplateDeclarationAST *) { return true; } @@ -289,6 +291,7 @@ public: virtual void endVisit(LinkageSpecificationAST *) {} virtual void endVisit(MemInitializerAST *) {} virtual void endVisit(MemberAccessAST *) {} + virtual void endVisit(MsvcDeclspecSpecifierAST *) {} virtual void endVisit(NamedTypeSpecifierAST *) {} virtual void endVisit(NamespaceAST *) {} virtual void endVisit(NamespaceAliasDefinitionAST *) {} @@ -353,6 +356,7 @@ public: virtual void endVisit(SimpleSpecifierAST *) {} virtual void endVisit(SizeofExpressionAST *) {} virtual void endVisit(StaticAssertDeclarationAST *) {} + virtual void endVisit(StdAttributeSpecifierAST *) {} virtual void endVisit(StringLiteralAST *) {} virtual void endVisit(SwitchStatementAST *) {} virtual void endVisit(TemplateDeclarationAST *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index 2c55fd27d6..fb6de59abd 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -102,6 +102,7 @@ class LinkageBodyAST; class LinkageSpecificationAST; class MemInitializerAST; class MemberAccessAST; +class MsvcDeclspecSpecifierAST; class NameAST; class NamedTypeSpecifierAST; class NamespaceAST; @@ -172,6 +173,7 @@ class SizeofExpressionAST; class SpecifierAST; class StatementAST; class StaticAssertDeclarationAST; +class StdAttributeSpecifierAST; class StringLiteralAST; class SwitchStatementAST; class TemplateDeclarationAST; diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 486efffc3d..53a14f6def 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -918,6 +918,19 @@ void Bind::parameterDeclarationClause(ParameterDeclarationClauseAST *ast, int lp for (ParameterDeclarationListAST *it = ast->parameter_declaration_list; it; it = it->next) { this->declaration(it->value); + + // Check for '...' in last parameter declarator for variadic template + // (i.e. template<class ... T> void foo(T ... args);) + // those last dots are part of parameter declarator, not the parameter declaration clause + if (! it->next + && it->value->declarator != nullptr + && it->value->declarator->core_declarator != nullptr){ + DeclaratorIdAST* declId = it->value->declarator->core_declarator->asDeclaratorId(); + if (declId && declId->dot_dot_dot_token != 0){ + fun->setVariadic(true); + fun->setVariadicTemplate(true); + } + } } if (ast->dot_dot_dot_token) @@ -2767,10 +2780,27 @@ bool Bind::visit(DestructorNameAST *ast) bool Bind::visit(TemplateIdAST *ast) { // collect the template parameters - std::vector<FullySpecifiedType> templateArguments; + std::vector<TemplateArgument> templateArguments; for (ExpressionListAST *it = ast->template_argument_list; it; it = it->next) { ExpressionTy value = this->expression(it->value); - templateArguments.push_back(value); + if (value.isValid()) { + templateArguments.emplace_back(value); + } else { + // special case for numeric values + if (it->value->asNumericLiteral()) { + templateArguments + .emplace_back(value, + tokenAt(it->value->asNumericLiteral()->literal_token).number); + } else if (it->value->asBoolLiteral()) { + templateArguments + .emplace_back(value, tokenAt(it->value->asBoolLiteral()->literal_token).number); + } else { + // fall back to non-valid type in templateArguments + // for ast->template_argument_list and templateArguments sizes match + // TODO support other literals/expressions as default arguments + templateArguments.emplace_back(value); + } + } } const Identifier *id = identifier(ast->identifier_token); @@ -3014,6 +3044,22 @@ bool Bind::visit(GnuAttributeSpecifierAST *ast) return false; } +bool Bind::visit(MsvcDeclspecSpecifierAST *ast) +{ + for (GnuAttributeListAST *it = ast->attribute_list; it; it = it->next) { + this->attribute(it->value); + } + return false; +} + +bool Bind::visit(StdAttributeSpecifierAST *ast) +{ + for (GnuAttributeListAST *it = ast->attribute_list; it; it = it->next) { + this->attribute(it->value); + } + return false; +} + bool Bind::visit(TypeofSpecifierAST *ast) { ExpressionTy expression = this->expression(ast->expression); diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index ddeb46532e..f3f83f7088 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -253,6 +253,8 @@ protected: virtual bool visit(SimpleSpecifierAST *ast); virtual bool visit(AlignmentSpecifierAST *ast); virtual bool visit(GnuAttributeSpecifierAST *ast); + virtual bool visit(MsvcDeclspecSpecifierAST *ast); + virtual bool visit(StdAttributeSpecifierAST *ast); virtual bool visit(TypeofSpecifierAST *ast); virtual bool visit(DecltypeSpecifierAST *ast); virtual bool visit(ClassSpecifierAST *ast); diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 2bbe00c293..ff966ee332 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -629,7 +629,7 @@ const NumericLiteral *Control::numericLiteral(const char *chars) const TemplateNameId *Control::templateNameId(const Identifier *id, bool isSpecialization, - const FullySpecifiedType *const args, + const TemplateArgument *const args, int argv) { return d->findOrInsertTemplateNameId(id, isSpecialization, args, args + argv); diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index 348864a402..5556c41fdd 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -54,7 +54,7 @@ public: /// Returns the canonical template name id. const TemplateNameId *templateNameId(const Identifier *id, bool isSpecialization, - const FullySpecifiedType *const args = nullptr, + const TemplateArgument *const args = nullptr, int argc = 0); /// Returns the canonical destructor name id. diff --git a/src/libs/3rdparty/cplusplus/Keywords.cpp b/src/libs/3rdparty/cplusplus/Keywords.cpp index 9fb6185c6f..1637333b42 100644 --- a/src/libs/3rdparty/cplusplus/Keywords.cpp +++ b/src/libs/3rdparty/cplusplus/Keywords.cpp @@ -1079,6 +1079,23 @@ static inline int classify9(const char *s, LanguageFeatures features) } } } + else if (s[1] == 'd') { + if (s[2] == 'e') { + if (s[3] == 'c') { + if (s[4] == 'l') { + if (s[5] == 's') { + if (s[6] == 'p') { + if (s[7] == 'e') { + if (s[8] == 'c') { + return T__DECLSPEC; + } + } + } + } + } + } + } + } } else if (features.cxx11Enabled && s[0] == 'c') { if (s[1] == 'o') { @@ -1178,11 +1195,20 @@ static inline int classify10(const char *s, LanguageFeatures features) { if (s[0] == '_') { if (s[1] == '_') { - if (features.cxxEnabled && s[2] == 'd') { + if (s[2] == 'd') { if (s[3] == 'e') { if (s[4] == 'c') { if (s[5] == 'l') { - if (s[6] == 't') { + if (s[6] == 's') { + if (s[7] == 'p') { + if (s[8] == 'e') { + if (s[9] == 'c') { + return T___DECLSPEC; + } + } + } + } + else if (features.cxxEnabled && s[6] == 't') { if (s[7] == 'y') { if (s[8] == 'p') { if (s[9] == 'e') { diff --git a/src/libs/3rdparty/cplusplus/Keywords.kwgen b/src/libs/3rdparty/cplusplus/Keywords.kwgen index 26c8bcd81b..36300a8776 100644 --- a/src/libs/3rdparty/cplusplus/Keywords.kwgen +++ b/src/libs/3rdparty/cplusplus/Keywords.kwgen @@ -37,6 +37,8 @@ __asm__ __attribute __attribute__ __alignof__ +_declspec +__declspec __const __const__ __inline diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index 89e0ce512d..e0fee4feac 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -1052,10 +1052,17 @@ void Lexer::scanIdentifier(Token *tok, unsigned extraProcessedChars) yyinp(); } int yylen = _currentChar - yytext; - if (f._scanKeywords) + if (f._scanKeywords) { tok->f.kind = classify(yytext, yylen, _languageFeatures); - else + + if (tok->f.kind == T_FALSE || tok->f.kind == T_TRUE) { + if (control()) { + tok->number = control()->numericLiteral(yytext, yylen); + } + } + } else { tok->f.kind = T_IDENTIFIER; + } if (tok->f.kind == T_IDENTIFIER) { tok->f.kind = classifyOperator(yytext, yylen); diff --git a/src/libs/3rdparty/cplusplus/Matcher.cpp b/src/libs/3rdparty/cplusplus/Matcher.cpp index 8ef26017c6..298a24d79b 100644 --- a/src/libs/3rdparty/cplusplus/Matcher.cpp +++ b/src/libs/3rdparty/cplusplus/Matcher.cpp @@ -324,8 +324,8 @@ bool Matcher::match(const TemplateNameId *name, const TemplateNameId *otherName) if (name->templateArgumentCount() != otherName->templateArgumentCount()) return false; for (unsigned i = 0, ei = name->templateArgumentCount(); i != ei; ++i) { - const FullySpecifiedType &l = name->templateArgumentAt(i); - const FullySpecifiedType &r = otherName->templateArgumentAt(i); + const TemplateArgument &l = name->templateArgumentAt(i); + const TemplateArgument &r = otherName->templateArgumentAt(i); if (! l.match(r, this)) return false; } diff --git a/src/libs/3rdparty/cplusplus/Names.cpp b/src/libs/3rdparty/cplusplus/Names.cpp index 6bcc988f37..dc77d47c0b 100644 --- a/src/libs/3rdparty/cplusplus/Names.cpp +++ b/src/libs/3rdparty/cplusplus/Names.cpp @@ -93,10 +93,17 @@ bool TemplateNameId::match0(const Name *otherName, Matcher *matcher) const const Identifier *TemplateNameId::identifier() const { return _identifier; } +bool TemplateArgument::match(const TemplateArgument &otherTy, Matcher *matcher) const +{ + if (_numericLiteral != otherTy._numericLiteral) + return false; + return type().match(otherTy.type(), matcher); +} + int TemplateNameId::templateArgumentCount() const { return int(_templateArguments.size()); } -const FullySpecifiedType &TemplateNameId::templateArgumentAt(int index) const +const TemplateArgument &TemplateNameId::templateArgumentAt(int index) const { return _templateArguments[index]; } bool TemplateNameId::Compare::operator()(const TemplateNameId *name, diff --git a/src/libs/3rdparty/cplusplus/Names.h b/src/libs/3rdparty/cplusplus/Names.h index cea93911c6..b615394438 100644 --- a/src/libs/3rdparty/cplusplus/Names.h +++ b/src/libs/3rdparty/cplusplus/Names.h @@ -73,6 +73,51 @@ private: const Name *_name; }; +class CPLUSPLUS_EXPORT TemplateArgument +{ +public: + TemplateArgument() + : _expressionTy(nullptr) + , _numericLiteral(nullptr) + {} + + TemplateArgument(const FullySpecifiedType &type, const NumericLiteral *numericLiteral = nullptr) + : _expressionTy(type) + , _numericLiteral(numericLiteral) + {} + + bool hasType() const { return _expressionTy.isValid(); } + + bool hasNumericLiteral() const { return _numericLiteral != nullptr; } + + const FullySpecifiedType &type() const { return _expressionTy; } + FullySpecifiedType &type() { return _expressionTy; } + + const NumericLiteral *numericLiteral() const { return _numericLiteral; } + + bool operator==(const TemplateArgument &other) const + { + return _expressionTy == other._expressionTy && _numericLiteral == other._numericLiteral; + } + bool operator!=(const TemplateArgument &other) const + { + return _expressionTy != other._expressionTy || _numericLiteral != other._numericLiteral; + } + bool operator<(const TemplateArgument &other) const + { + if (_expressionTy == other._expressionTy) { + return _numericLiteral < other._numericLiteral; + } + return _expressionTy < other._expressionTy; + } + + bool match(const TemplateArgument &otherTy, Matcher *matcher = nullptr) const; + +private: + FullySpecifiedType _expressionTy; + const NumericLiteral *_numericLiteral = nullptr; +}; + class CPLUSPLUS_EXPORT TemplateNameId: public Name { public: @@ -89,12 +134,12 @@ public: // ### find a better name int templateArgumentCount() const; - const FullySpecifiedType &templateArgumentAt(int index) const; + const TemplateArgument &templateArgumentAt(int index) const; virtual const TemplateNameId *asTemplateNameId() const { return this; } - typedef std::vector<FullySpecifiedType>::const_iterator TemplateArgumentIterator; + typedef std::vector<TemplateArgument>::const_iterator TemplateArgumentIterator; TemplateArgumentIterator firstTemplateArgument() const { return _templateArguments.begin(); } TemplateArgumentIterator lastTemplateArgument() const { return _templateArguments.end(); } @@ -111,7 +156,7 @@ protected: private: const Identifier *_identifier; - std::vector<FullySpecifiedType> _templateArguments; + std::vector<TemplateArgument> _templateArguments; // now TemplateNameId can be a specialization or an instantiation bool _isSpecialization; }; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index fd7b963a87..28dddc507e 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -770,6 +770,18 @@ bool Parser::parseDeclaration(DeclarationAST *&node) else if (LA() == T_AT_PROPERTY) return parseObjCPropertyDeclaration(node, attributes); rewind(start); + } else if (LA() == T___DECLSPEC) { + const int start = cursor(); + SpecifierListAST *attributes = nullptr, **attr = &attributes; + while (parseMsvcDeclspecSpecifier(*attr)) + attr = &(*attr)->next; + rewind(start); + } else if (lookAtStdAttribute()) { + const int start = cursor(); + SpecifierListAST *attributes = nullptr, **attr = &attributes; + while (parseStdAttributeSpecifier(*attr)) + attr = &(*attr)->next; + rewind(start); } if (LA() == T_EXTERN && LA(2) == T_TEMPLATE) @@ -3761,6 +3773,11 @@ bool Parser::parseIfStatement(StatementAST *&node) if (LA() == T_IF) { IfStatementAST *ast = new (_pool) IfStatementAST; ast->if_token = consumeToken(); + if (LA() == T_CONSTEXPR) { + // "if constexpr" added in cxx17, but we don't check cxx version here + // because msvc 2019 compiler uses "if constexpr" in headers despite cxx version set for the project + ast->constexpr_token = consumeToken(); + } match(T_LPAREN, &ast->lparen_token); parseCondition(ast->condition); match(T_RPAREN, &ast->rparen_token); @@ -3961,6 +3978,8 @@ bool Parser::lookAtBuiltinTypeSpecifier() const // [gcc] extensions case T___TYPEOF__: case T___ATTRIBUTE__: + // [msvc] extensions + case T___DECLSPEC: return true; default: return false; @@ -4020,8 +4039,22 @@ bool Parser::parseAttributeSpecifier(SpecifierListAST *&attribute_list) attr_ptr = &(*attr_ptr)->next; } return true; + case T___DECLSPEC: + while (LA() == T___DECLSPEC) { + parseMsvcDeclspecSpecifier(*attr_ptr); + attr_ptr = &(*attr_ptr)->next; + } + return true; default: - return false; + { + bool foundAttributes = false; + while (lookAtStdAttribute()) { + parseStdAttributeSpecifier(*attr_ptr); + attr_ptr = &(*attr_ptr)->next; + foundAttributes = true; + } + return foundAttributes; + } } } @@ -4078,11 +4111,46 @@ bool Parser::parseGnuAttributeList(GnuAttributeListAST *&node) return true; } +bool Parser::parseMsvcDeclspecSpecifier(SpecifierListAST *&node) +{ + DEBUG_THIS_RULE(); + if (LA() != T___DECLSPEC) + return false; + + MsvcDeclspecSpecifierAST *ast = new (_pool) MsvcDeclspecSpecifierAST; + ast->attribute_token = consumeToken(); + match(T_LPAREN, &ast->lparen_token); + parseGnuAttributeList(ast->attribute_list); + match(T_RPAREN, &ast->rparen_token); + node = new (_pool) SpecifierListAST(ast); + return true; +} + +bool Parser::parseStdAttributeSpecifier(SpecifierListAST *&node) +{ + DEBUG_THIS_RULE(); + if (!lookAtStdAttribute()) + return false; + + StdAttributeSpecifierAST *ast = new (_pool) StdAttributeSpecifierAST; + match(T_LBRACKET, &ast->first_lbracket_token); + match(T_LBRACKET, &ast->second_lbracket_token); + parseGnuAttributeList(ast->attribute_list); + match(T_RBRACKET, &ast->first_rbracket_token); + match(T_RBRACKET, &ast->second_rbracket_token); + node = new (_pool) SpecifierListAST(ast); + return true; +} + bool Parser::parseBuiltinTypeSpecifier(SpecifierListAST *&node) { DEBUG_THIS_RULE(); if (LA() == T___ATTRIBUTE__) { return parseGnuAttributeSpecifier(node); + } else if (LA() == T___DECLSPEC) { + return parseMsvcDeclspecSpecifier(node); + } else if (lookAtStdAttribute()) { + return parseStdAttributeSpecifier(node); } else if (LA() == T___TYPEOF__) { TypeofSpecifierAST *ast = new (_pool) TypeofSpecifierAST; ast->typeof_token = consumeToken(); @@ -5748,6 +5816,11 @@ bool Parser::parseNoExceptOperatorExpression(ExpressionAST *&node) return false; } +bool Parser::lookAtStdAttribute() const +{ + return _languageFeatures.cxx11Enabled && LA() == T_LBRACKET && LA(2) == T_LBRACKET; +} + bool Parser::lookAtObjCSelector() const { switch (LA()) { @@ -6797,6 +6870,8 @@ bool Parser::parseLambdaDeclarator(LambdaDeclaratorAST *&node) SpecifierListAST **attr = &ast->attributes; while (parseGnuAttributeSpecifier(*attr)) attr = &(*attr)->next; + while (parseStdAttributeSpecifier(*attr)) + attr = &(*attr)->next; if (LA() == T_MUTABLE) ast->mutable_token = consumeToken(); @@ -6821,6 +6896,8 @@ bool Parser::parseTrailingReturnType(TrailingReturnTypeAST *&node) SpecifierListAST **attr = &ast->attributes; while (parseGnuAttributeSpecifier(*attr)) attr = &(*attr)->next; + while (parseStdAttributeSpecifier(*attr)) + attr = &(*attr)->next; parseTrailingTypeSpecifierSeq(ast->type_specifier_list); parseAbstractDeclarator(ast->declarator, ast->type_specifier_list); diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index 750c590b40..b8efe2765e 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -170,6 +170,9 @@ public: bool parseGnuAttributeSpecifier(SpecifierListAST *&node); bool parseGnuAttributeList(GnuAttributeListAST *&node); + bool parseMsvcDeclspecSpecifier(SpecifierListAST *&node); + bool parseStdAttributeSpecifier(SpecifierListAST *&node); + bool parseDeclSpecifierSeq(SpecifierListAST *&node, bool noStorageSpecifiers = false, bool onlySimpleTypeSpecifiers = false); @@ -247,6 +250,8 @@ public: bool peekAtObjCContextKeyword(int kind); bool parseObjCContextKeyword(int kind, int &in_token); + bool lookAtStdAttribute() const; + bool lookAtObjCSelector() const; // c99 diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index aba1be3494..22f355dce4 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -191,7 +191,7 @@ Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original) if (const TemplateNameId * templateNameId = namedType->name()->asTemplateNameId()) { if (templateNameId->templateArgumentCount()) { - newType = clone->type(templateNameId->templateArgumentAt(0), nullptr); + newType = clone->type(templateNameId->templateArgumentAt(0).type(), nullptr); newType = FullySpecifiedType(clone->control()->pointerType(newType)); } } @@ -469,6 +469,12 @@ bool Function::isVariadic() const void Function::setVariadic(bool isVariadic) { f._isVariadic = isVariadic; } +bool Function::isVariadicTemplate() const +{ return f._isVariadicTemplate; } + +void Function::setVariadicTemplate(bool isVariadicTemplate) +{ f._isVariadicTemplate = isVariadicTemplate; } + bool Function::isConst() const { return f._isConst; } @@ -523,6 +529,9 @@ bool Function::maybeValidPrototype(int actualArgumentCount) const break; } + if (isVariadicTemplate()) + --minNumberArguments; + if (actualArgumentCount < minNumberArguments) { // not enough arguments. return false; diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index 71a076ac80..a5e833696c 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -346,6 +346,9 @@ public: bool isVariadic() const; void setVariadic(bool isVariadic); + bool isVariadicTemplate() const; + void setVariadicTemplate(bool isVariadicTemplate); + bool isConst() const; void setConst(bool isConst); @@ -397,6 +400,7 @@ private: unsigned _isOverride: 1; unsigned _isFinal: 1; unsigned _isVariadic: 1; + unsigned _isVariadicTemplate: 1; unsigned _isPureVirtual: 1; unsigned _isConst: 1; unsigned _isVolatile: 1; diff --git a/src/libs/3rdparty/cplusplus/Templates.cpp b/src/libs/3rdparty/cplusplus/Templates.cpp index 75ee4e95fa..92e5ab14fc 100644 --- a/src/libs/3rdparty/cplusplus/Templates.cpp +++ b/src/libs/3rdparty/cplusplus/Templates.cpp @@ -439,9 +439,9 @@ void CloneName::visit(const AnonymousNameId *name) void CloneName::visit(const TemplateNameId *name) { - std::vector<FullySpecifiedType> args(name->templateArgumentCount()); + std::vector<TemplateArgument> args(name->templateArgumentCount()); for (int i = 0; i < int(args.size()); ++i) - args[i] = _clone->type(name->templateArgumentAt(i), _subst); + args[i].type() = _clone->type(name->templateArgumentAt(i).type(), _subst); if (args.empty()) _name = _control->templateNameId(_clone->identifier(name->identifier()), name->isSpecialization()); else diff --git a/src/libs/3rdparty/cplusplus/Token.cpp b/src/libs/3rdparty/cplusplus/Token.cpp index 0159b1ed7d..1d9127b2dd 100644 --- a/src/libs/3rdparty/cplusplus/Token.cpp +++ b/src/libs/3rdparty/cplusplus/Token.cpp @@ -177,6 +177,9 @@ const char *token_names[] = { ("__thread"), ("__typeof__"), + // msvc + ("__declspec"), + // objc @keywords ("@catch"), ("@class"), diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index 44efde0553..f545978669 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -186,6 +186,8 @@ enum Kind { T___THREAD, T___TYPEOF__, + T___DECLSPEC, + // obj c++ @ keywords T_FIRST_OBJC_AT_KEYWORD, @@ -298,6 +300,7 @@ enum Kind { T_FOREACH = T_Q_FOREACH, T_SIGNALS = T_Q_SIGNALS, T_Q_OVERRIDE = T_Q_PROPERTY, + T__DECLSPEC = T___DECLSPEC, }; class CPLUSPLUS_EXPORT Token diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp index c52963b023..c760809aa5 100644 --- a/src/libs/cplusplus/CppRewriter.cpp +++ b/src/libs/cplusplus/CppRewriter.cpp @@ -257,9 +257,9 @@ public: void visit(const TemplateNameId *name) override { - QVarLengthArray<FullySpecifiedType, 8> args(name->templateArgumentCount()); + QVarLengthArray<TemplateArgument, 8> args(name->templateArgumentCount()); for (int i = 0; i < name->templateArgumentCount(); ++i) - args[i] = rewrite->rewriteType(name->templateArgumentAt(i)); + args[i] = rewrite->rewriteType(name->templateArgumentAt(i).type()); temps.append(control()->templateNameId(identifier(name->identifier()), name->isSpecialization(), args.data(), args.size())); } diff --git a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp index d3653137b3..11efc5bf96 100644 --- a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp +++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp @@ -242,9 +242,9 @@ private: void visit(const TemplateNameId *name) override { - QVarLengthArray<FullySpecifiedType, 8> arguments(name->templateArgumentCount()); + QVarLengthArray<TemplateArgument, 8> arguments(name->templateArgumentCount()); for (int i = 0; i < name->templateArgumentCount(); ++i) { - FullySpecifiedType argTy = name->templateArgumentAt(i); + FullySpecifiedType argTy = name->templateArgumentAt(i).type(); arguments[i] = q->apply(argTy); } @@ -265,10 +265,10 @@ private: return id; } else if (const TemplateNameId *templId = name->asTemplateNameId()) { - QVarLengthArray<FullySpecifiedType, 8> arguments(templId->templateArgumentCount()); + QVarLengthArray<TemplateArgument, 8> arguments(templId->templateArgumentCount()); for (int templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount(); ++templateArgIndex) { - FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex); + FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex).type(); arguments[templateArgIndex] = q->apply(argTy); } const Identifier *id = control()->identifier(templId->identifier()->chars(), @@ -404,7 +404,7 @@ FullySpecifiedType DeprecatedGenTemplateInstance::instantiate(const Name *classN DeprecatedGenTemplateInstance::Substitution subst; for (int i = 0; i < templId->templateArgumentCount(); ++i) { - FullySpecifiedType templArgTy = templId->templateArgumentAt(i); + FullySpecifiedType templArgTy = templId->templateArgumentAt(i).type(); if (i < templ->templateParameterCount()) { const Name *templArgName = templ->templateParameterAt(i)->name(); diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index addaac7134..95a5035a62 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -1978,6 +1978,22 @@ bool FindUsages::visit(GnuAttributeSpecifierAST *ast) return false; } +bool FindUsages::visit(MsvcDeclspecSpecifierAST *ast) +{ + for (GnuAttributeListAST *it = ast->attribute_list; it; it = it->next) { + this->attribute(it->value); + } + return false; +} + +bool FindUsages::visit(StdAttributeSpecifierAST *ast) +{ + for (GnuAttributeListAST *it = ast->attribute_list; it; it = it->next) { + this->attribute(it->value); + } + return false; +} + bool FindUsages::visit(TypeofSpecifierAST *ast) { // unsigned typeof_token = ast->typeof_token; diff --git a/src/libs/cplusplus/FindUsages.h b/src/libs/cplusplus/FindUsages.h index 3fd13a30a2..011bdd677e 100644 --- a/src/libs/cplusplus/FindUsages.h +++ b/src/libs/cplusplus/FindUsages.h @@ -254,6 +254,8 @@ protected: // SpecifierAST virtual bool visit(SimpleSpecifierAST *ast); virtual bool visit(GnuAttributeSpecifierAST *ast); + virtual bool visit(MsvcDeclspecSpecifierAST *ast); + virtual bool visit(StdAttributeSpecifierAST *ast); virtual bool visit(TypeofSpecifierAST *ast); virtual bool visit(DecltypeSpecifierAST *ast); virtual bool visit(ClassSpecifierAST *ast); diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 8c5a883e7d..d4776418ca 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -773,6 +773,10 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, LookupItem item; item.setDeclaration(s); item.setBinding(binding); + + if (Symbol *inst = instantiateTemplateFunction(name, s->asTemplate())) + item.setType(inst->type()); + result->append(item); } @@ -811,15 +815,8 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, item.setType(ty); // override the type. } - // instantiate function template - if (name->isTemplateNameId() && s->isTemplate() && s->asTemplate()->declaration() - && s->asTemplate()->declaration()->isFunction()) { - const TemplateNameId *instantiation = name->asTemplateNameId(); - Template *specialization = s->asTemplate(); - Symbol *instantiatedFunctionTemplate = instantiateTemplateFunction(instantiation, - specialization); - item.setType(instantiatedFunctionTemplate->type()); // override the type. - } + if (Symbol *inst = instantiateTemplateFunction(name, s->asTemplate())) + item.setType(inst->type()); result->append(item); } @@ -1026,22 +1023,22 @@ ClassOrNamespace *ClassOrNamespace::findSpecialization(const TemplateNameId *tem // and initialization(in future it should be more clever) if (specializationTemplateArgumentCount == initializationTemplateArgumentCount) { for (int i = 0; i < initializationTemplateArgumentCount; ++i) { - const FullySpecifiedType &specializationTemplateArgument + const TemplateArgument &specializationTemplateArgument = specializationNameId->templateArgumentAt(i); - const FullySpecifiedType &initializationTemplateArgument + const TemplateArgument &initializationTemplateArgument = templId->templateArgumentAt(i); PointerType *specPointer - = specializationTemplateArgument.type()->asPointerType(); + = specializationTemplateArgument.type().type()->asPointerType(); // specialization and initialization argument have to be a pointer // additionally type of pointer argument of specialization has to be namedType - if (specPointer && initializationTemplateArgument.type()->isPointerType() + if (specPointer && initializationTemplateArgument.type().type()->isPointerType() && specPointer->elementType().type()->isNamedType()) { return cit->second; } ArrayType *specArray - = specializationTemplateArgument.type()->asArrayType(); - if (specArray && initializationTemplateArgument.type()->isArrayType()) { + = specializationTemplateArgument.type().type()->asArrayType(); + if (specArray && initializationTemplateArgument.type().type()->isArrayType()) { if (const NamedType *argumentNamedType = specArray->elementType().type()->asNamedType()) { if (const Name *argumentName = argumentNamedType->name()) { @@ -1142,7 +1139,33 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, = findSpecialization(templId, specializations); if (specializationWithPointer) reference = specializationWithPointer; - // TODO: find the best specialization(probably partial) for this instantiation + + int maximumArgumentsMatched = 0; + + for (const std::pair<const TemplateNameId *, ClassOrNamespace *> &p : + specializations) { + const TemplateNameId *templateSpecialization = p.first; + ClassOrNamespace *specializationClassOrNamespace = p.second; + + const int argumentCountOfInitialization = templId->templateArgumentCount(); + const int argumentCountOfSpecialization = + templateSpecialization->templateArgumentCount(); + + int argumentsMatched = 0; + for (int i = 0; + i < argumentCountOfInitialization && i < argumentCountOfSpecialization; + ++i) { + if (templId->templateArgumentAt(i) == + templateSpecialization->templateArgumentAt(i)) { + argumentsMatched++; + } + } + + if (argumentsMatched > maximumArgumentsMatched) { + reference = specializationClassOrNamespace; + maximumArgumentsMatched = argumentsMatched; + } + } } } } @@ -1227,12 +1250,39 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, if (!name) continue; - FullySpecifiedType ty = (i < argumentCountOfInitialization) ? - templId->templateArgumentAt(i): + int argumentPositionInReferenceClass=i; + + if (referenceClass->name() && referenceClass->name()->asTemplateNameId()) { + argumentPositionInReferenceClass=-1; + const TemplateNameId* refTemp = referenceClass->name()->asTemplateNameId(); + for (int argPos=0; argPos < refTemp->templateArgumentCount(); argPos++) { + const Type* argType = refTemp->templateArgumentAt(argPos).type().type(); + if (argType->asNamedType() + && argType->asNamedType()->name() == name) { + argumentPositionInReferenceClass = argPos; + break; + } + if (argType->asPointerType() + && argType->asPointerType()->elementType().type()->asNamedType() + && argType->asPointerType()->elementType().type() + ->asNamedType()->name() == name) { + argumentPositionInReferenceClass = argPos; + break; + } + } + + if (argumentPositionInReferenceClass < 0) { + continue; + } + } + + + FullySpecifiedType ty = (argumentPositionInReferenceClass < argumentCountOfInitialization) ? + templId->templateArgumentAt(argumentPositionInReferenceClass).type(): cloner.type(tParam->type(), &subst); if (i < templSpecArgumentCount - && templSpecId->templateArgumentAt(i)->isPointerType()) { + && templSpecId->templateArgumentAt(i).type()->isPointerType()) { if (PointerType *pointerType = ty->asPointerType()) ty = pointerType->elementType(); } @@ -1281,7 +1331,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, const int parameterIndex = templParams.value(nameId); if (parameterIndex < argumentCountOfInitialization) { const FullySpecifiedType &fullType = - templId->templateArgumentAt(parameterIndex); + templId->templateArgumentAt(parameterIndex).type(); if (fullType.isValid()) { if (NamedType *namedType = fullType.type()->asNamedType()) baseBinding = lookupType(namedType->name()); @@ -1300,7 +1350,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, for (int i = 0; i < argumentCountOfSpecialization; ++i) { const Name *name = templateSpecialization->templateParameterAt(i)->name(); FullySpecifiedType ty = (i < argumentCountOfInitialization) ? - templId->templateArgumentAt(i): + templId->templateArgumentAt(i).type(): templateSpecialization->templateParameterAt(i)->type(); map.bind(name, ty); @@ -1927,10 +1977,28 @@ bool CreateBindings::visit(ObjCMethod *) return false; } -Symbol *CreateBindings::instantiateTemplateFunction(const TemplateNameId *instantiation, +Symbol *CreateBindings::instantiateTemplateFunction(const Name *instantiationName, Template *specialization) const { - const int argumentCountOfInitialization = instantiation->templateArgumentCount(); + if (!specialization || !specialization->declaration() + || !specialization->declaration()->isFunction()) + return nullptr; + + int argumentCountOfInstantiation = 0; + const TemplateNameId *instantiation = nullptr; + if (instantiationName->isTemplateNameId()) { + instantiation = instantiationName->asTemplateNameId(); + argumentCountOfInstantiation = instantiation->templateArgumentCount(); + } else { + // no template arguments passed in function call + // check if all template parameters have default arguments (only check first parameter) + if (specialization->templateParameterCount() == 0) + return nullptr; + TypenameArgument *parameter = specialization->templateParameterAt(0)->asTypenameArgument(); + if (!parameter || !parameter->type().isValid()) + return nullptr; + } + const int argumentCountOfSpecialization = specialization->templateParameterCount(); Clone cloner(_control.data()); @@ -1944,8 +2012,8 @@ Symbol *CreateBindings::instantiateTemplateFunction(const TemplateNameId *instan if (!name) continue; - FullySpecifiedType ty = (i < argumentCountOfInitialization) ? - instantiation->templateArgumentAt(i): + FullySpecifiedType ty = (i < argumentCountOfInstantiation) ? + instantiation->templateArgumentAt(i).type(): cloner.type(tParam->type(), &subst); subst.bind(cloner.name(name, &subst), ty); diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 22035362fd..e3224f1bab 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -266,7 +266,7 @@ protected: virtual bool visit(ObjCMethod *); private: - Symbol *instantiateTemplateFunction(const TemplateNameId *instantiation, + Symbol *instantiateTemplateFunction(const Name *instantiationName, Template *specialization) const; Snapshot _snapshot; diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp index 5d9c5770e0..99498ae492 100644 --- a/src/libs/cplusplus/NamePrettyPrinter.cpp +++ b/src/libs/cplusplus/NamePrettyPrinter.cpp @@ -80,7 +80,7 @@ void NamePrettyPrinter::visit(const TemplateNameId *name) if (index != 0) _name += QLatin1String(", "); - FullySpecifiedType argTy = name->templateArgumentAt(index); + FullySpecifiedType argTy = name->templateArgumentAt(index).type(); QString arg = overview()->prettyType(argTy); if (arg.isEmpty()) _name += QString::fromLatin1("_Tp%1").arg(index + 1); diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 2eca9b53f3..d4321309b4 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -918,6 +918,13 @@ bool ResolveExpression::visit(CallAST *ast) } } + if (_results.size()>1){ + // move functions with known bindings to begin of results list + std::stable_partition(_results.begin(), _results.end(), [](const LookupItem &item) -> bool { + return item.binding(); + }); + } + return false; } @@ -1109,11 +1116,23 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas continue; Scope *functionScope = overload->enclosingScope(); - if (overload->type()->isFunctionType()) { + FullySpecifiedType overloadType = r.type(); + if (! overloadType.isValid()) + overloadType = overload->type(); + + Function *instantiatedFunction = nullptr; + + if (overloadType->isFunctionType()) { FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload); - Function *instantiatedFunction = overloadTy->asFunctionType(); - Q_ASSERT(instantiatedFunction != nullptr); + instantiatedFunction = overloadTy->asFunctionType(); + } else if (overloadType->isTemplateType() + && overloadType->asTemplateType()->declaration() + && overloadType->asTemplateType()->declaration()->isFunction()) { + instantiatedFunction = overloadType->asTemplateType()->declaration()->asFunction(); + } + + if (instantiatedFunction != nullptr) { FullySpecifiedType retTy = instantiatedFunction->returnType().simplified(); diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 73e28c89e1..bb05d69bb7 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -437,6 +437,7 @@ static bool canReplaceSpecifier(TranslationUnit *translationUnit, SpecifierAST * case T_AUTO: case T___TYPEOF__: case T___ATTRIBUTE__: + case T___DECLSPEC: return true; default: return false; diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index 4d4cf6e795..6925b711c8 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -863,6 +863,7 @@ bool CodeFormatter::tryDeclaration() case T_AUTO: case T___TYPEOF__: case T___ATTRIBUTE__: + case T___DECLSPEC: case T_STATIC: case T_FRIEND: case T_CONST: @@ -1590,7 +1591,7 @@ void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, in if (m_styleSettings.indentDeclarationsRelativeToAccessSpecifiers && topState.type == class_open) { if (tokenAt(1).is(T_COLON) || tokenAt(2).is(T_COLON) - || (tokenAt(tokenCount() - 1).is(T_COLON) && tokenAt(1).is(T___ATTRIBUTE__))) { + || (tokenAt(tokenCount() - 1).is(T_COLON) && (tokenAt(1).is(T___ATTRIBUTE__) || tokenAt(1).is(T___DECLSPEC)))) { *indentDepth = topState.savedIndentDepth; if (m_styleSettings.indentAccessSpecifiers) *indentDepth += m_tabSettings.m_indentSize; diff --git a/src/plugins/cpptools/cppcodemodelinspectordumper.cpp b/src/plugins/cpptools/cppcodemodelinspectordumper.cpp index 333708c48b..4670533d29 100644 --- a/src/plugins/cpptools/cppcodemodelinspectordumper.cpp +++ b/src/plugins/cpptools/cppcodemodelinspectordumper.cpp @@ -341,6 +341,7 @@ QString Utils::toString(CPlusPlus::Kind kind) TOKEN_AND_ALIASES(T___ATTRIBUTE__, T___ATTRIBUTE); TOKEN(T___THREAD); TOKEN_AND_ALIASES(T___TYPEOF__, T_TYPEOF/T___TYPEOF); + TOKEN_AND_ALIASES(T___DECLSPEC, T__DECLSPEC); TOKEN(T_AT_CATCH); TOKEN(T_AT_CLASS); TOKEN(T_AT_COMPATIBILITY_ALIAS); diff --git a/src/plugins/cpptools/cpppointerdeclarationformatter.cpp b/src/plugins/cpptools/cpppointerdeclarationformatter.cpp index 82df823af1..391e5b2a82 100644 --- a/src/plugins/cpptools/cpppointerdeclarationformatter.cpp +++ b/src/plugins/cpptools/cpppointerdeclarationformatter.cpp @@ -98,12 +98,13 @@ static unsigned firstTypeSpecifierWithoutFollowingAttribute( case T_TYPEDEF: case T_CONSTEXPR: case T___ATTRIBUTE__: + case T___DECLSPEC: continue; default: // Check if attributes follow for (unsigned i = index; i <= endToken; ++i) { const int tokenKind = translationUnit->tokenKind(i); - if (tokenKind == T___ATTRIBUTE__) + if (tokenKind == T___ATTRIBUTE__ || tokenKind == T___DECLSPEC) return 0; } *found = true; diff --git a/src/tools/cplusplus-ast2png/dumpers.inc b/src/tools/cplusplus-ast2png/dumpers.inc index 166c014013..177b2f268c 100644 --- a/src/tools/cplusplus-ast2png/dumpers.inc +++ b/src/tools/cplusplus-ast2png/dumpers.inc @@ -81,6 +81,34 @@ virtual bool visit(GnuAttributeSpecifierAST *ast) return false; } +virtual bool visit(MsvcDeclspecSpecifierAST *ast) +{ + if (ast->attribute_token) + terminal(ast->attribute_token, ast); + if (ast->lparen_token) + terminal(ast->lparen_token, ast); + for (GnuAttributeListAST *iter = ast->attribute_list; iter; iter = iter->next) + nonterminal(iter->value); + if (ast->rparen_token) + terminal(ast->rparen_token, ast); + return false; +} + +virtual bool visit(StdAttributeSpecifierAST *ast) +{ + if (ast->first_lbracket_token) + terminal(ast->first_lbracket_token, ast); + if (ast->second_lbracket_token) + terminal(ast->second_lbracket_token, ast); + for (GnuAttributeListAST *iter = ast->attribute_list; iter; iter = iter->next) + nonterminal(iter->value); + if (ast->first_rbracket_token) + terminal(ast->first_rbracket_token, ast); + if (ast->second_rbracket_token) + terminal(ast->second_rbracket_token, ast); + return false; +} + virtual bool visit(GnuAttributeAST *ast) { if (ast->identifier_token) @@ -714,6 +742,8 @@ virtual bool visit(IfStatementAST *ast) { if (ast->if_token) terminal(ast->if_token, ast); + if (ast->constexpr_token) + terminal(ast->constexpr_token, ast); if (ast->lparen_token) terminal(ast->lparen_token, ast); nonterminal(ast->condition); diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index eaac17ade3..c44fc4279e 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -118,6 +118,8 @@ private slots: void crash_test_1(); void thread_local_1(); + void msvc_attributes_declspec(); + // expressions void simple_name_1(); void template_id_1(); @@ -141,6 +143,7 @@ private slots: void if_statement_2(); void if_statement_3(); void if_else_statement(); + void if_constexpr(); void while_statement(); void while_condition_statement(); void for_statement(); @@ -169,6 +172,7 @@ private slots: //! checks for both correct ellipsis tokens in //! "template<class ...Args> class T : Args... {};" void cpp11_variadic_inheritance(); + void cpp11_attributes(); // Q_PROPERTY void cpp_qproperty(); @@ -281,6 +285,14 @@ void tst_AST::thread_local_1() QCOMPARE(Token::name(T___THREAD), "__thread"); } +void tst_AST::msvc_attributes_declspec() +{ + const char *inp = "class __declspec(novtable) Name{};"; + QSharedPointer<TranslationUnit> unit(parseDeclaration(inp)); + QVERIFY(unit->ast()); + QCOMPARE(diag.errorCount, 0); +} + void tst_AST::simple_declaration_1() { QSharedPointer<TranslationUnit> unit(parseStatement("\n" @@ -1322,6 +1334,43 @@ void tst_AST::cpp11_variadic_inheritance() QVERIFY(ba->ellipsis_token != 0); // important } +void tst_AST::cpp11_attributes() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration( + "[[noreturn]] void f() {throw \"error\";}", + false, false, true)); + AST *ast = unit->ast(); + QVERIFY(ast != nullptr); + + DeclarationAST *d = ast->asDeclaration(); + QVERIFY(d != nullptr); + + FunctionDefinitionAST *f = d->asFunctionDefinition(); + QVERIFY(f != nullptr); + QVERIFY(f->decl_specifier_list != nullptr); + QVERIFY(f->decl_specifier_list->value != nullptr); + + StdAttributeSpecifierAST *attr = f->decl_specifier_list->value->asStdAttributeSpecifier(); + QVERIFY(attr != nullptr); +} + +void tst_AST::if_constexpr() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("if constexpr (a) b;",true)); + + AST *ast = unit->ast(); + QVERIFY(ast != 0); + + IfStatementAST *stmt = ast->asIfStatement(); + QVERIFY(stmt != 0); + QCOMPARE(stmt->if_token, 1); + QCOMPARE(stmt->constexpr_token, 2); + QCOMPARE(stmt->lparen_token, 3); + QVERIFY(stmt->condition != 0); + QCOMPARE(stmt->rparen_token, 5); + QVERIFY(stmt->statement != 0); +} + void tst_AST::cpp_qproperty() { QFETCH(QByteArray, source); diff --git a/tests/auto/cplusplus/findusages/tst_findusages.cpp b/tests/auto/cplusplus/findusages/tst_findusages.cpp index d961cb449d..2b38759ed2 100644 --- a/tests/auto/cplusplus/findusages/tst_findusages.cpp +++ b/tests/auto/cplusplus/findusages/tst_findusages.cpp @@ -115,6 +115,16 @@ private Q_SLOTS: void inAlignas(); void memberAccessAsTemplate(); + + void variadicFunctionTemplate(); + void typeTemplateParameterWithDefault(); + void resolveOrder_for_templateFunction_vs_function(); + void templateArrowOperator_with_defaultType(); + void templateSpecialization_with_IntArgument(); + void templateSpecialization_with_BoolArgument(); + void templatePartialSpecialization(); + void templatePartialSpecialization_2(); + void template_SFINAE_1(); }; void tst_FindUsages::dump(const QList<Usage> &usages) const @@ -1076,5 +1086,499 @@ void tst_FindUsages::memberAccessAsTemplate() } } +void tst_FindUsages::variadicFunctionTemplate() +{ + const QByteArray src = "struct S{int value;};\n" + "template<class ... Types> S foo(Types & ... args){return S();}\n" + "int main(){\n" + " foo().value;\n" + " foo(1).value;\n" + " foo(1,2).value;\n" + "}"; + + Document::Ptr doc = Document::create("variadicFunctionTemplate"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=1); + + Snapshot snapshot; + snapshot.insert(doc); + + { // Test "S::value" + Class *c = doc->globalSymbolAt(0)->asClass(); + QVERIFY(c); + QCOMPARE(c->name()->identifier()->chars(), "S"); + QCOMPARE(c->memberCount(), 1); + + Declaration *v = c->memberAt(0)->asDeclaration(); + QVERIFY(v); + QCOMPARE(v->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + find(v); + QCOMPARE(find.usages().size(), 4); + } +} + +void tst_FindUsages::typeTemplateParameterWithDefault() +{ + const QByteArray src = "struct X{int value;};\n" + "struct S{int value;};\n" + "template<class T = S> T foo(){return T();}\n" + "int main(){\n" + " foo<X>().value;\n" + " foo<S>().value;\n" + " foo().value;\n" // this is S.value + "}"; + + Document::Ptr doc = Document::create("typeTemplateParameterWithDefault"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=2); + + Snapshot snapshot; + snapshot.insert(doc); + + { // Test "S::value" + Class *x = doc->globalSymbolAt(0)->asClass(); + QVERIFY(x); + QCOMPARE(x->name()->identifier()->chars(), "X"); + QCOMPARE(x->memberCount(), 1); + + Class *s = doc->globalSymbolAt(1)->asClass(); + QVERIFY(s); + QCOMPARE(s->name()->identifier()->chars(), "S"); + QCOMPARE(s->memberCount(), 1); + + Declaration *xv = x->memberAt(0)->asDeclaration(); + QVERIFY(xv); + QCOMPARE(xv->name()->identifier()->chars(), "value"); + + Declaration *sv = s->memberAt(0)->asDeclaration(); + QVERIFY(sv); + QCOMPARE(sv->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + find(xv); + QCOMPARE(find.usages().size(), 2); + find(sv); + QCOMPARE(find.usages().size(), 3); + } +} + +void tst_FindUsages::resolveOrder_for_templateFunction_vs_function() +{ + const QByteArray src = "struct X{int value;};\n" + "struct S{int value;};\n" + "X foo(){return X();}\n" + "template<class T = S> T foo(){return T();}\n" + "int main(){\n" + " foo().value;\n" // this is X.value + "}"; + + Document::Ptr doc = Document::create("resolveOrder_for_templateFunction_vs_function"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=1); + + Snapshot snapshot; + snapshot.insert(doc); + + { // Test "S::value" + Class *x = doc->globalSymbolAt(0)->asClass(); + QVERIFY(x); + QCOMPARE(x->name()->identifier()->chars(), "X"); + QCOMPARE(x->memberCount(), 1); + + Declaration *xv = x->memberAt(0)->asDeclaration(); + QVERIFY(xv); + QCOMPARE(xv->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + find(xv); + QCOMPARE(find.usages().size(), 2); + } +} + +void tst_FindUsages::templateArrowOperator_with_defaultType() +{ + const QByteArray src = "struct S{int value;};\n" + "struct C{\n" + " S* s;\n" + " template<class T = S> \n" + " T* operator->(){return &s;}\n" + "};\n" + "int main(){\n" + " C().operator -> ()->value;\n" + " C()->value;\n" + "}\n"; + + Document::Ptr doc = Document::create("templateArrowOperator_with_defaultType"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=1); + + Snapshot snapshot; + snapshot.insert(doc); + + { // Test "S::value" + Class *s = doc->globalSymbolAt(0)->asClass(); + QVERIFY(s); + QCOMPARE(s->name()->identifier()->chars(), "S"); + QCOMPARE(s->memberCount(), 1); + + Declaration *sv = s->memberAt(0)->asDeclaration(); + QVERIFY(sv); + QCOMPARE(sv->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + find(sv); + QCOMPARE(find.usages().size(), 3); + } +} + +void tst_FindUsages::templateSpecialization_with_IntArgument() +{ + const QByteArray src = "\n" + "struct S0{ int value = 0; };\n" + "struct S1{ int value = 1; };\n" + "struct S2{ int value = 2; };\n" + "template<int N> struct S { S0 s; };\n" + "template<> struct S<1> { S1 s; };\n" + "template<> struct S<2> { S2 s; };\n" + "int main()\n" + "{\n" + " S<0> s0;\n" + " S<1> s1;\n" + " S<2> s2;\n" + " s0.s.value;\n" + " s1.s.value;\n" + " s2.s.value;\n" + "}\n"; + + Document::Ptr doc = Document::create("templateSpecialization_with_IntArgument"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=3); + + Snapshot snapshot; + snapshot.insert(doc); + + { + Class *s[3] = { + doc->globalSymbolAt(0)->asClass(), + doc->globalSymbolAt(1)->asClass(), + doc->globalSymbolAt(2)->asClass(), + }; + + QVERIFY(s[0]); + QVERIFY(s[1]); + QVERIFY(s[2]); + + QCOMPARE(s[0]->name()->identifier()->chars(), "S0"); + QCOMPARE(s[1]->name()->identifier()->chars(), "S1"); + QCOMPARE(s[2]->name()->identifier()->chars(), "S2"); + + QCOMPARE(s[0]->memberCount(), 1); + QCOMPARE(s[1]->memberCount(), 1); + QCOMPARE(s[2]->memberCount(), 1); + + Declaration *sv[3] = { + s[0]->memberAt(0)->asDeclaration(), + s[1]->memberAt(0)->asDeclaration(), + s[2]->memberAt(0)->asDeclaration(), + }; + + QVERIFY(sv[0]); + QVERIFY(sv[1]); + QVERIFY(sv[2]); + + QCOMPARE(sv[0]->name()->identifier()->chars(), "value"); + QCOMPARE(sv[1]->name()->identifier()->chars(), "value"); + QCOMPARE(sv[2]->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + + find(sv[0]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 1); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 12); + QCOMPARE(find.usages()[1].col, 9); + + find(sv[1]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 2); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 13); + QCOMPARE(find.usages()[1].col, 9); + + find(sv[2]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 3); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 14); + QCOMPARE(find.usages()[1].col, 9); + } +} + +void tst_FindUsages::templateSpecialization_with_BoolArgument() +{ + const QByteArray src = "\n" + "struct S0{ int value = 0; };\n" + "struct S1{ int value = 1; };\n" + "template<bool B> struct S { S0 s; };\n" + "template<> struct S<true> { S1 s; };\n" + "int main()\n" + "{\n" + " S<false> s0;\n" + " S<true> s1;\n" + " s0.s.value;\n" + " s1.s.value;\n" + "}\n"; + + Document::Ptr doc = Document::create("templateSpecialization_with_BoolArgument"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=3); + + Snapshot snapshot; + snapshot.insert(doc); + + { + Class *s[2] = { + doc->globalSymbolAt(0)->asClass(), + doc->globalSymbolAt(1)->asClass(), + }; + + QVERIFY(s[0]); + QVERIFY(s[1]); + + QCOMPARE(s[0]->name()->identifier()->chars(), "S0"); + QCOMPARE(s[1]->name()->identifier()->chars(), "S1"); + + QCOMPARE(s[0]->memberCount(), 1); + QCOMPARE(s[1]->memberCount(), 1); + + Declaration *sv[2] = { + s[0]->memberAt(0)->asDeclaration(), + s[1]->memberAt(0)->asDeclaration(), + }; + + QVERIFY(sv[0]); + QVERIFY(sv[1]); + + QCOMPARE(sv[0]->name()->identifier()->chars(), "value"); + QCOMPARE(sv[1]->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + + find(sv[0]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 1); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 9); + QCOMPARE(find.usages()[1].col, 9); + + find(sv[1]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 2); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 10); + QCOMPARE(find.usages()[1].col, 9); + } +} + +void tst_FindUsages::templatePartialSpecialization() +{ + const QByteArray src = "\n" + "struct S0{ int value = 0; };\n" + "struct S1{ int value = 1; };\n" + "template<class T, class U> struct S { S0 ss; };\n" + "template<class U> struct S<float, U> { S1 ss; };\n" + "int main()\n" + "{\n" + " S<int, int> s0;\n" + " S<float, int> s1;\n" + " s0.ss.value;\n" + " s1.ss.value;\n" + "}\n"; + + Document::Ptr doc = Document::create("templatePartialSpecialization"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=3); + + Snapshot snapshot; + snapshot.insert(doc); + + { + Class *s[2] = { + doc->globalSymbolAt(0)->asClass(), + doc->globalSymbolAt(1)->asClass(), + }; + + QVERIFY(s[0]); + QVERIFY(s[1]); + + QCOMPARE(s[0]->name()->identifier()->chars(), "S0"); + QCOMPARE(s[1]->name()->identifier()->chars(), "S1"); + + QCOMPARE(s[0]->memberCount(), 1); + QCOMPARE(s[1]->memberCount(), 1); + + Declaration *sv[2] = { + s[0]->memberAt(0)->asDeclaration(), + s[1]->memberAt(0)->asDeclaration(), + }; + + QVERIFY(sv[0]); + QVERIFY(sv[1]); + + QCOMPARE(sv[0]->name()->identifier()->chars(), "value"); + QCOMPARE(sv[1]->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + + find(sv[0]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 1); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 9); + QCOMPARE(find.usages()[1].col, 10); + + find(sv[1]); + QCOMPARE(find.usages().size(), 2); + + QCOMPARE(find.usages()[0].line, 2); + QCOMPARE(find.usages()[0].col, 15); + QCOMPARE(find.usages()[1].line, 10); + QCOMPARE(find.usages()[1].col, 10); + } +} + +void tst_FindUsages::templatePartialSpecialization_2() +{ + const QByteArray src = +R"( +struct S0{int value=0;}; +struct S1{int value=1;}; +struct S2{int value=2;}; +template<class T1, class T2> struct S{T1 ss;}; +template<class U> struct S<int, U>{ U ss; }; +template<class V> struct S<V*, int>{ V *ss; }; +int main() +{ + S<S0, float> s0; + s0.ss.value; + S<int, S1> s1; + s1.ss.value; + S<S2*, int> s2; + s2.ss->value; +} +)"; + + Document::Ptr doc = Document::create("templatePartialSpecialization_2"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=3); + + Snapshot snapshot; + snapshot.insert(doc); + + FindUsages find(src, doc, snapshot); + + Class *s[3]; + Declaration *sv[3]; + for (int i = 0; i < 3; i++) { + s[i] = doc->globalSymbolAt(i)->asClass(); + QVERIFY(s[i]); + QCOMPARE(s[i]->memberCount(), 1); + sv[i] = s[i]->memberAt(0)->asDeclaration(); + QVERIFY(sv[i]); + QCOMPARE(sv[i]->name()->identifier()->chars(), "value"); + } + QCOMPARE(s[0]->name()->identifier()->chars(), "S0"); + QCOMPARE(s[1]->name()->identifier()->chars(), "S1"); + QCOMPARE(s[2]->name()->identifier()->chars(), "S2"); + + find(sv[0]); + QCOMPARE(find.usages().size(), 2); + + find(sv[1]); + QCOMPARE(find.usages().size(), 2); + + find(sv[2]); + QCOMPARE(find.usages().size(), 2); +} + +void tst_FindUsages::template_SFINAE_1() +{ + const QByteArray src = +R"( +struct S{int value=1;}; +template<class, class> struct is_same {}; +template<class T> struct is_same<T, T> {using type = int;}; +template<class T = S, typename is_same<T, S>::type = 0> T* foo(){return new T();} +int main(){ + foo()->value; +} +)"; + + Document::Ptr doc = Document::create("template_SFINAE_1"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QVERIFY(doc->globalSymbolCount()>=1); + + Snapshot snapshot; + snapshot.insert(doc); + + Class *s = doc->globalSymbolAt(0)->asClass(); + QVERIFY(s); + QCOMPARE(s->name()->identifier()->chars(), "S"); + QCOMPARE(s->memberCount(), 1); + + Declaration *sv = s->memberAt(0)->asDeclaration(); + QVERIFY(sv); + QCOMPARE(sv->name()->identifier()->chars(), "value"); + + FindUsages find(src, doc, snapshot); + find(sv); + QCOMPARE(find.usages().size(), 2); +} + QTEST_APPLESS_MAIN(tst_FindUsages) #include "tst_findusages.moc" diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 51c1fadf7e..deda2aab2c 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -612,7 +612,7 @@ void tst_Semantic::template_instance_1() Declaration *decl = templ->memberAt(1)->asClass()->memberAt(0)->asDeclaration(); QVERIFY(decl); - FullySpecifiedType templArgs[] = {control->integerType(IntegerType::Int)}; + TemplateArgument templArgs[] = {FullySpecifiedType(control->integerType(IntegerType::Int))}; const Name *templId = control->templateNameId(control->identifier("QList"), false, templArgs, 1); FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, control); |