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