From 080bf4ecb8b7b70d6410e3342e37dacd5aef8ff3 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski <pgorszkowski@gmail.com> Date: Wed, 10 Apr 2013 23:30:18 +0200 Subject: [PATCH] C++: improve support for anonymous classes Fix: * highlighting * find usages * follow symbol * code completion Task-number: QTCREATORBUG-6497 Task-number: QTCREATORBUG-8963 Task-number: QTCREATORBUG-3610 Task-number: QTCREATORBUG-7579 Change-Id: I3dcaf1c515d0199c3e6bee72284fbb40064686ee Reviewed-by: Petar Perisin <petar.perisin@gmail.com> Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com> --- src/libs/3rdparty/cplusplus/AST.h | 21 ++++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 7 ++ src/libs/3rdparty/cplusplus/ASTMatch0.cpp | 8 ++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 10 ++ src/libs/3rdparty/cplusplus/ASTMatcher.h | 1 + .../3rdparty/cplusplus/ASTPatternBuilder.h | 6 + src/libs/3rdparty/cplusplus/ASTVisit.cpp | 7 ++ src/libs/3rdparty/cplusplus/ASTVisitor.h | 2 + src/libs/3rdparty/cplusplus/ASTfwd.h | 1 + src/libs/3rdparty/cplusplus/Bind.cpp | 8 +- src/libs/3rdparty/cplusplus/Bind.h | 1 + .../cplusplus/CPlusPlusForwardDeclarations.h | 1 + src/libs/3rdparty/cplusplus/Control.cpp | 17 +++ src/libs/3rdparty/cplusplus/Control.h | 3 + src/libs/3rdparty/cplusplus/Name.cpp | 3 + src/libs/3rdparty/cplusplus/Name.h | 2 + src/libs/3rdparty/cplusplus/NameVisitor.h | 1 + src/libs/3rdparty/cplusplus/Names.cpp | 26 +++++ src/libs/3rdparty/cplusplus/Names.h | 23 ++++ src/libs/3rdparty/cplusplus/Parser.cpp | 6 + src/libs/cplusplus/LookupContext.cpp | 26 ++++- src/libs/cplusplus/LookupContext.h | 1 + src/libs/cplusplus/NamePrettyPrinter.cpp | 5 + src/libs/cplusplus/NamePrettyPrinter.h | 1 + .../checksymbols/tst_checksymbols.cpp | 107 ++++++++++++++++++ .../cplusplus/findusages/tst_findusages.cpp | 47 +++++++- tests/tools/cplusplus-ast2png/dumpers.inc | 7 ++ 27 files changed, 341 insertions(+), 7 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 961bc2e1a7f..9699ff8e0d9 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -127,6 +127,7 @@ public: virtual AccessDeclarationAST *asAccessDeclaration() { return 0; } virtual AliasDeclarationAST *asAliasDeclaration() { return 0; } virtual AlignofExpressionAST *asAlignofExpression() { return 0; } + virtual AnonymousNameAST *asAnonymousName() { return 0; } virtual ArrayAccessAST *asArrayAccess() { return 0; } virtual ArrayDeclaratorAST *asArrayDeclarator() { return 0; } virtual ArrayInitializerAST *asArrayInitializer() { return 0; } @@ -2267,6 +2268,26 @@ protected: virtual bool match0(AST *, ASTMatcher *); }; +class CPLUSPLUS_EXPORT AnonymousNameAST: public NameAST +{ +public: + unsigned class_token; +public: + AnonymousNameAST() + : class_token(0) + {} + + virtual AnonymousNameAST *asAnonymousName() { return this; } + virtual unsigned firstToken() const { return 0; } + virtual unsigned lastToken() const { return 0; } + + virtual AnonymousNameAST *clone(MemoryPool *pool) const; + +protected: + virtual void accept0(ASTVisitor *visitor); + virtual bool match0(AST *, ASTMatcher *); +}; + class CPLUSPLUS_EXPORT SimpleNameAST: public NameAST { public: diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 73565b80375..0a8db781cbe 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -824,6 +824,13 @@ ConversionFunctionIdAST *ConversionFunctionIdAST::clone(MemoryPool *pool) const return ast; } +AnonymousNameAST *AnonymousNameAST::clone(MemoryPool *pool) const +{ + AnonymousNameAST *ast = new (pool) AnonymousNameAST; + ast->class_token = class_token; + return ast; +} + SimpleNameAST *SimpleNameAST::clone(MemoryPool *pool) const { SimpleNameAST *ast = new (pool) SimpleNameAST; diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index c49b5dae65a..69e3daf6156 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -552,6 +552,14 @@ bool ConversionFunctionIdAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool AnonymousNameAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (AnonymousNameAST *_other = pattern->asAnonymousName()) + return matcher->match(this, _other); + + return false; +} + bool SimpleNameAST::match0(AST *pattern, ASTMatcher *matcher) { if (SimpleNameAST *_other = pattern->asSimpleName()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index 4fbb9d6f8e0..3d74bbfcb56 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -1403,6 +1403,16 @@ bool ASTMatcher::match(ConversionFunctionIdAST *node, ConversionFunctionIdAST *p return true; } +bool ASTMatcher::match(AnonymousNameAST *node, AnonymousNameAST *pattern) +{ + (void) node; + (void) pattern; + + pattern->class_token = node->class_token; + + return true; +} + bool ASTMatcher::match(SimpleNameAST *node, SimpleNameAST *pattern) { (void) node; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index 29842253cda..eee507b9419 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -34,6 +34,7 @@ public: virtual bool match(AccessDeclarationAST *node, AccessDeclarationAST *pattern); virtual bool match(AliasDeclarationAST *node, AliasDeclarationAST *pattern); virtual bool match(AlignofExpressionAST *node, AlignofExpressionAST *pattern); + virtual bool match(AnonymousNameAST *node, AnonymousNameAST *pattern); virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern); virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern); virtual bool match(ArrayInitializerAST *node, ArrayInitializerAST *pattern); diff --git a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h index 04a0fdd12cf..a444c7e3f6b 100644 --- a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h +++ b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h @@ -543,6 +543,12 @@ public: return __ast; } + AnonymousNameAST *AnonymousName() + { + AnonymousNameAST *__ast = new (&pool) AnonymousNameAST; + return __ast; + } + SimpleNameAST *SimpleName() { SimpleNameAST *__ast = new (&pool) SimpleNameAST; diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 76adc01c53b..9fec2311272 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -596,6 +596,13 @@ void ConversionFunctionIdAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void AnonymousNameAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} + void SimpleNameAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index a7d3f728f63..d9578a40614 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -76,6 +76,7 @@ public: virtual bool visit(AccessDeclarationAST *) { return true; } virtual bool visit(AliasDeclarationAST *) { return true; } virtual bool visit(AlignofExpressionAST *) { return true; } + virtual bool visit(AnonymousNameAST *) { return true; } virtual bool visit(ArrayAccessAST *) { return true; } virtual bool visit(ArrayDeclaratorAST *) { return true; } virtual bool visit(ArrayInitializerAST *) { return true; } @@ -221,6 +222,7 @@ public: virtual void endVisit(AccessDeclarationAST *) {} virtual void endVisit(AliasDeclarationAST *) {} virtual void endVisit(AlignofExpressionAST *) {} + virtual void endVisit(AnonymousNameAST *) {} virtual void endVisit(ArrayAccessAST *) {} virtual void endVisit(ArrayDeclaratorAST *) {} virtual void endVisit(ArrayInitializerAST *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index 722a5b0d38d..7b79947cb92 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -34,6 +34,7 @@ class ASTMatcher; class AccessDeclarationAST; class AliasDeclarationAST; class AlignofExpressionAST; +class AnonymousNameAST; class ArrayAccessAST; class ArrayDeclaratorAST; class ArrayInitializerAST; diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index b21b167655a..3f2ffea7c8d 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2614,6 +2614,12 @@ bool Bind::visit(ConversionFunctionIdAST *ast) return false; } +bool Bind::visit(AnonymousNameAST *ast) +{ + ast->name = _name = control()->anonymousNameId(ast->class_token); + return false; +} + bool Bind::visit(SimpleNameAST *ast) { const Identifier *id = identifier(ast->identifier_token); @@ -2896,7 +2902,7 @@ bool Bind::visit(ClassSpecifierAST *ast) const Name *className = this->name(ast->name); - if (ast->name) { + if (ast->name && ! ast->name->asAnonymousName()) { sourceLocation = location(ast->name, sourceLocation); startScopeOffset = tokenAt(sourceLocation).end(); // at the end of the class name diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index ca2c6084ba1..04fed44a10a 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -237,6 +237,7 @@ protected: virtual bool visit(QualifiedNameAST *ast); virtual bool visit(OperatorFunctionIdAST *ast); virtual bool visit(ConversionFunctionIdAST *ast); + virtual bool visit(AnonymousNameAST *ast); virtual bool visit(SimpleNameAST *ast); virtual bool visit(DestructorNameAST *ast); virtual bool visit(TemplateIdAST *ast); diff --git a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h index 7a3b2e0f3bb..fe1316ddaaa 100644 --- a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h +++ b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h @@ -73,6 +73,7 @@ class SymbolTable; class NameVisitor; class Name; class Identifier; +class AnonymousNameId; class TemplateNameId; class DestructorNameId; class OperatorNameId; diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 8f6136534ff..e274a209060 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -101,6 +101,14 @@ template <> struct Compare<ArrayType> } }; +template <> struct Compare<AnonymousNameId> +{ + bool operator()(const AnonymousNameId &name, const AnonymousNameId &otherName) const + { + return name.classTokenIndex() < otherName.classTokenIndex(); + } +}; + template <> struct Compare<DestructorNameId> { bool operator()(const DestructorNameId &name, const DestructorNameId &otherName) const @@ -219,6 +227,11 @@ public: delete_array_entries(symbols); } + const AnonymousNameId *findOrInsertAnonymousNameId(unsigned classTokenIndex) + { + return anonymousNameIds.intern(AnonymousNameId(classTokenIndex)); + } + template <typename _Iterator> const TemplateNameId *findOrInsertTemplateNameId(const Identifier *id, bool isSpecialization, _Iterator first, _Iterator last) @@ -475,6 +488,7 @@ public: // ### replace std::map with lookup tables. ASAP! // names + Table<AnonymousNameId> anonymousNameIds; Table<DestructorNameId> destructorNameIds; Table<OperatorNameId> operatorNameIds; Table<ConversionNameId> conversionNameIds; @@ -550,6 +564,9 @@ DiagnosticClient *Control::diagnosticClient() const void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient) { d->diagnosticClient = diagnosticClient; } +const AnonymousNameId *Control::anonymousNameId(unsigned classTokenIndex) +{ return d->findOrInsertAnonymousNameId(classTokenIndex); } + const OperatorNameId *Control::findOperatorNameId(OperatorNameId::Kind operatorId) const { Table<OperatorNameId>::const_iterator i = d->operatorNameIds.find(operatorId); diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index cef4df40f75..538ecc27668 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -49,6 +49,9 @@ public: DiagnosticClient *diagnosticClient() const; void setDiagnosticClient(DiagnosticClient *diagnosticClient); + /// Returns the canonical anonymous name id + const AnonymousNameId *anonymousNameId(unsigned classTokenIndex); + /// Returns the canonical template name id. const TemplateNameId *templateNameId(const Identifier *id, bool isSpecialization, diff --git a/src/libs/3rdparty/cplusplus/Name.cpp b/src/libs/3rdparty/cplusplus/Name.cpp index 5a203d61ef8..a8d453fc02d 100644 --- a/src/libs/3rdparty/cplusplus/Name.cpp +++ b/src/libs/3rdparty/cplusplus/Name.cpp @@ -36,6 +36,9 @@ Name::~Name() bool Name::isNameId() const { return asNameId() != 0; } +bool Name::isAnonymousNameId() const +{ return asAnonymousNameId() != 0; } + bool Name::isTemplateNameId() const { return asTemplateNameId() != 0; } diff --git a/src/libs/3rdparty/cplusplus/Name.h b/src/libs/3rdparty/cplusplus/Name.h index 43dcf3d35cc..9d197484711 100644 --- a/src/libs/3rdparty/cplusplus/Name.h +++ b/src/libs/3rdparty/cplusplus/Name.h @@ -36,6 +36,7 @@ public: virtual const Identifier *identifier() const = 0; bool isNameId() const; + bool isAnonymousNameId() const; bool isTemplateNameId() const; bool isDestructorNameId() const; bool isOperatorNameId() const; @@ -44,6 +45,7 @@ public: bool isSelectorNameId() const; virtual const Identifier *asNameId() const { return 0; } + virtual const AnonymousNameId *asAnonymousNameId() const { return 0; } virtual const TemplateNameId *asTemplateNameId() const { return 0; } virtual const DestructorNameId *asDestructorNameId() const { return 0; } virtual const OperatorNameId *asOperatorNameId() const { return 0; } diff --git a/src/libs/3rdparty/cplusplus/NameVisitor.h b/src/libs/3rdparty/cplusplus/NameVisitor.h index bb0ef5335ff..c2a5f89da64 100644 --- a/src/libs/3rdparty/cplusplus/NameVisitor.h +++ b/src/libs/3rdparty/cplusplus/NameVisitor.h @@ -40,6 +40,7 @@ public: virtual bool preVisit(const Name *) { return true; } virtual void postVisit(const Name *) {} + virtual void visit(const AnonymousNameId *) {} virtual void visit(const Identifier *) {} virtual void visit(const TemplateNameId *) {} virtual void visit(const DestructorNameId *) {} diff --git a/src/libs/3rdparty/cplusplus/Names.cpp b/src/libs/3rdparty/cplusplus/Names.cpp index 4c5cb7db794..4a65fea2a87 100644 --- a/src/libs/3rdparty/cplusplus/Names.cpp +++ b/src/libs/3rdparty/cplusplus/Names.cpp @@ -249,3 +249,29 @@ bool SelectorNameId::isEqualTo(const Name *other) const return true; } +AnonymousNameId::AnonymousNameId(unsigned classTokenIndex) + : _classTokenIndex(classTokenIndex) +{ } + +AnonymousNameId::~AnonymousNameId() +{ } + +unsigned AnonymousNameId::classTokenIndex() const +{ + return _classTokenIndex; +} + +void AnonymousNameId::accept0(NameVisitor *visitor) const +{ visitor->visit(this); } + +const Identifier *AnonymousNameId::identifier() const +{ return 0; } + +bool AnonymousNameId::isEqualTo(const Name *other) const +{ + if (other) { + const AnonymousNameId *c = other->asAnonymousNameId(); + return (c && this->_classTokenIndex == c->_classTokenIndex); + } + return false; +} diff --git a/src/libs/3rdparty/cplusplus/Names.h b/src/libs/3rdparty/cplusplus/Names.h index e600ec1dafe..855dd4987f3 100644 --- a/src/libs/3rdparty/cplusplus/Names.h +++ b/src/libs/3rdparty/cplusplus/Names.h @@ -253,6 +253,29 @@ private: bool _hasArguments; }; +class CPLUSPLUS_EXPORT AnonymousNameId: public Name +{ +public: + AnonymousNameId(unsigned classTokenIndex); + virtual ~AnonymousNameId(); + + unsigned classTokenIndex() const; + + virtual const Identifier *identifier() const; + virtual bool isEqualTo(const Name *other) const; + + virtual const AnonymousNameId *asAnonymousNameId() const + { return this; } + +protected: + virtual void accept0(NameVisitor *visitor) const; + +private: + unsigned _classTokenIndex; +}; + + + } // namespace CPlusPlus #endif // CPLUSPLUS_NAMES_H diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 00b79dfc254..38938d3545a 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -2003,6 +2003,12 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node) NameAST *name = 0; parseName(name); + if (! name && LA() == T_LBRACE && (LA(0) == T_CLASS || LA(0) == T_STRUCT || LA(0) == T_UNION || LA(0) == T_ENUM)) { + AnonymousNameAST *ast = new (_pool) AnonymousNameAST; + ast->class_token = classkey_token; + name = ast; + } + bool parsed = false; const bool previousInFunctionBody = _inFunctionBody; diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index fab318e8ca8..dde50df687f 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -60,7 +60,7 @@ static void addNames(const Name *name, QList<const Name *> *names, bool addAllNa else if (const QualifiedNameId *q = name->asQualifiedNameId()) { addNames(q->base(), names); addNames(q->name(), names, addAllNames); - } else if (addAllNames || name->isNameId() || name->isTemplateNameId()) { + } else if (addAllNames || name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { names->append(name); } } @@ -716,7 +716,7 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name, } else if (! processed->contains(this)) { processed->insert(this); - if (name->isNameId() || name->isTemplateNameId()) { + if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { flush(); foreach (Symbol *s, symbols()) { @@ -798,10 +798,26 @@ ClassOrNamespace *ClassOrNamespace::findSpecializationWithPointer(const Template ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin) { Q_ASSERT(name != 0); - Q_ASSERT(name->isNameId() || name->isTemplateNameId()); + Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()); const_cast<ClassOrNamespace *>(this)->flush(); + const AnonymousNameId *anonymousNameId = name->asAnonymousNameId(); + if (anonymousNameId) { + QHash<const AnonymousNameId *, ClassOrNamespace *>::const_iterator cit + = _anonymouses.find(anonymousNameId); + if (cit != _anonymouses.end()) { + return cit.value(); + } else { + ClassOrNamespace *newAnonymous = _factory->allocClassOrNamespace(this); +#ifdef DEBUG_LOOKUP + newAnonymous->_name = anonymousNameId; +#endif // DEBUG_LOOKUP + _anonymouses[anonymousNameId] = newAnonymous; + return newAnonymous; + } + } + Table::const_iterator it = _classOrNamespaces.find(name); if (it == _classOrNamespaces.end()) return 0; @@ -1201,7 +1217,7 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa return findOrCreateType(q->base(), origin)->findOrCreateType(q->name(), origin); - } else if (name->isNameId() || name->isTemplateNameId()) { + } else if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { ClassOrNamespace *e = nestedType(name, origin); if (! e) { @@ -1470,7 +1486,7 @@ bool CreateBindings::visit(NamespaceAlias *a) return false; } else if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(a->namespaceName())) { - if (a->name()->isNameId() || a->name()->isTemplateNameId()) + if (a->name()->isNameId() || a->name()->isTemplateNameId() || a->name()->isAnonymousNameId()) _currentClassOrNamespace->addNestedType(a->name(), e); } else if (false) { diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index ead7d2dfe32..3dbe525766a 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -131,6 +131,7 @@ private: QSharedPointer<Control> _control; TemplateNameIdTable _specializations; QMap<const TemplateNameId *, ClassOrNamespace *> _instantiations; + QHash<const AnonymousNameId *, ClassOrNamespace *> _anonymouses; QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache; diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp index a638135d467..d78e3eaa654 100644 --- a/src/libs/cplusplus/NamePrettyPrinter.cpp +++ b/src/libs/cplusplus/NamePrettyPrinter.cpp @@ -268,3 +268,8 @@ void NamePrettyPrinter::visit(const SelectorNameId *name) } } } + +void NamePrettyPrinter::visit(const AnonymousNameId *name) +{ + _name = QString(QLatin1String("Anonymous:%1")).arg(name->classTokenIndex()); +} diff --git a/src/libs/cplusplus/NamePrettyPrinter.h b/src/libs/cplusplus/NamePrettyPrinter.h index 348ba84b105..f5f02970228 100644 --- a/src/libs/cplusplus/NamePrettyPrinter.h +++ b/src/libs/cplusplus/NamePrettyPrinter.h @@ -57,6 +57,7 @@ protected: virtual void visit(const ConversionNameId *name); virtual void visit(const QualifiedNameId *name); virtual void visit(const SelectorNameId *name); + virtual void visit(const AnonymousNameId *name); private: const Overview *_overview; diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index 25673a7f290..e3ff87c1899 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -188,6 +188,9 @@ private slots: void operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006(); void test_checksymbols_templated_functions(); void test_checksymbols_QTCREATORBUG9098(); + void test_checksymbols_AnonymousClass(); + void test_checksymbols_AnonymousClass_insideNamespace(); + void test_checksymbols_AnonymousClass_QTCREATORBUG8963(); }; void tst_CheckSymbols::test_checksymbols_TypeUse() @@ -1421,6 +1424,28 @@ void tst_CheckSymbols::test_checksymbols_templated_functions() TestData::check(source, expectedUses); } +void tst_CheckSymbols::test_checksymbols_AnonymousClass() +{ + const QByteArray source = + "struct\n" + "{\n" + " int foo;\n" + "} Foo;\n" + "\n" + "void fun()\n" + "{\n" + " foo = 3;\n" + "}\n" + ; + + const QList<Use> expectedUses = QList<Use>() + << Use(3, 7, 3, CppHighlightingSupport::FieldUse) + << Use(6, 6, 3, CppHighlightingSupport::FunctionUse) + ; + + TestData::check(source, expectedUses); +} + void tst_CheckSymbols::test_checksymbols_QTCREATORBUG9098() { const QByteArray source = @@ -1460,5 +1485,87 @@ void tst_CheckSymbols::test_checksymbols_QTCREATORBUG9098() TestData::check(source, expectedUses); } +void tst_CheckSymbols::test_checksymbols_AnonymousClass_insideNamespace() +{ + const QByteArray source = + "struct { int foo1; } Foo1;\n" + "void bar1()\n" + "{\n" + " Foo1.foo1 = 42;\n" + "}\n" + "namespace Ns1 {\n" + " struct { int foo2; } Foo2;\n" + " void bar2()\n" + " {\n" + " Foo2.foo2 = 42;\n" + " }\n" + "}\n" + "namespace Ns2 {\n" + " struct {\n" + " struct { struct { int foo3; }; };\n" + " void func() { foo3 = 42; }\n" + " } Foo3;\n" + " void bar3()\n" + " {\n" + " Foo3.foo3 = 42;\n" + " }\n" + "}\n" + ; + + const QList<Use> expectedUses = QList<Use>() + << Use(1, 14, 4, CppHighlightingSupport::FieldUse) + << Use(2, 6, 4, CppHighlightingSupport::FunctionUse) + << Use(4, 8, 4, CppHighlightingSupport::FieldUse) + << Use(6, 11, 3, CppHighlightingSupport::TypeUse) + << Use(7, 16, 4, CppHighlightingSupport::FieldUse) + << Use(8, 8, 4, CppHighlightingSupport::FunctionUse) + << Use(10, 10, 4, CppHighlightingSupport::FieldUse) + << Use(13, 11, 3, CppHighlightingSupport::TypeUse) + << Use(15, 27, 4, CppHighlightingSupport::FieldUse) + << Use(16, 10, 4, CppHighlightingSupport::FunctionUse) + << Use(18, 8, 4, CppHighlightingSupport::FunctionUse) + ; + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_AnonymousClass_QTCREATORBUG8963() +{ + const QByteArray source = + "typedef enum {\n" + " FIRST\n" + "} isNotInt;\n" + "typedef struct {\n" + " int isint;\n" + " int isNotInt;\n" + "} Struct;\n" + "void foo()\n" + "{\n" + " Struct s;\n" + " s.isint;\n" + " s.isNotInt;\n" + " FIRST;\n" + "}\n" + ; + + const QList<Use> expectedUses = QList<Use>() + << Use(2, 5, 5, CppHighlightingSupport::EnumerationUse) + << Use(3, 3, 8, CppHighlightingSupport::TypeUse) + << Use(5, 9, 5, CppHighlightingSupport::FieldUse) + << Use(6, 9, 8, CppHighlightingSupport::FieldUse) + << Use(7, 3, 6, CppHighlightingSupport::TypeUse) + << Use(8, 6, 3, CppHighlightingSupport::FunctionUse) + << Use(10, 5, 6, CppHighlightingSupport::TypeUse) + << Use(10, 12, 1, CppHighlightingSupport::LocalUse) + << Use(11, 5, 1, CppHighlightingSupport::LocalUse) + << Use(11, 7, 5, CppHighlightingSupport::FieldUse) + << Use(12, 5, 1, CppHighlightingSupport::LocalUse) + << Use(12, 7, 8, CppHighlightingSupport::FieldUse) + << Use(13, 5, 5, CppHighlightingSupport::EnumerationUse) + ; + + TestData::check(source, expectedUses); +} + QTEST_APPLESS_MAIN(tst_CheckSymbols) #include "tst_checksymbols.moc" diff --git a/tests/auto/cplusplus/findusages/tst_findusages.cpp b/tests/auto/cplusplus/findusages/tst_findusages.cpp index 0a4580b00a0..50331f0ff31 100644 --- a/tests/auto/cplusplus/findusages/tst_findusages.cpp +++ b/tests/auto/cplusplus/findusages/tst_findusages.cpp @@ -96,6 +96,8 @@ private Q_SLOTS: void instantiateTemplateWithNestedClass(); void operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006(); void operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005(); + void anonymousClass_QTCREATORBUG8963(); + }; void tst_FindUsages::inlineMethod() @@ -475,7 +477,6 @@ void tst_FindUsages::operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG90 QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 3U); - Snapshot snapshot; snapshot.insert(doc); @@ -488,6 +489,50 @@ void tst_FindUsages::operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG90 FindUsages findUsages(src, doc, snapshot); findUsages(fooDeclaration); + + QCOMPARE(findUsages.usages().size(), 2); +} + +void tst_FindUsages::anonymousClass_QTCREATORBUG8963() +{ + const QByteArray src = + "typedef enum {\n" + " FIRST\n" + "} isNotInt;\n" + "typedef struct {\n" + " int isint;\n" + " int isNotInt;\n" + "} Struct;\n" + "void foo()\n" + "{\n" + " Struct s;\n" + " s.isint;\n" + " s.isNotInt;\n" + " FIRST;\n" + "}\n" + ; + + Document::Ptr doc = Document::create("anonymousClass_QTCREATORBUG8963"); + doc->setUtf8Source(src); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QCOMPARE(doc->globalSymbolCount(), 5U); + + Snapshot snapshot; + snapshot.insert(doc); + + Class *structSymbol = doc->globalSymbolAt(2)->asClass(); + QVERIFY(structSymbol); + QCOMPARE(structSymbol->memberCount(), 2U); + Declaration *isNotIntDeclaration = structSymbol->memberAt(1)->asDeclaration(); + QVERIFY(isNotIntDeclaration); + QCOMPARE(isNotIntDeclaration->name()->identifier()->chars(), "isNotInt"); + + FindUsages findUsages(src, doc, snapshot); + findUsages(isNotIntDeclaration); + QCOMPARE(findUsages.usages().size(), 2); } diff --git a/tests/tools/cplusplus-ast2png/dumpers.inc b/tests/tools/cplusplus-ast2png/dumpers.inc index 1d3d20238b5..bc9c4857137 100644 --- a/tests/tools/cplusplus-ast2png/dumpers.inc +++ b/tests/tools/cplusplus-ast2png/dumpers.inc @@ -796,6 +796,13 @@ virtual bool visit(ConversionFunctionIdAST *ast) return false; } +virtual bool visit(AnonymousNameAST *ast) +{ + if (ast->class_token) + terminal(ast->class_token, ast); + return false; +} + virtual bool visit(SimpleNameAST *ast) { if (ast->identifier_token) -- GitLab