diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2020-11-18 18:04:21 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2020-11-23 10:07:20 +0000 |
commit | d3fafcde0fd4f74112d20228ac7175a02ffcb821 (patch) | |
tree | d053af9a59ced07acc03384154b3ffc410185a2c | |
parent | b0dd6b748f68af8b53d5c3fc470e5758ddf969de (diff) |
CppEditor: Support decl/def switch for conversion operators
Fixes: QTCREATORBUG-21168
Change-Id: I515fe146a679e007c96fa8d23f1457dadf07db3c
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
-rw-r--r-- | src/libs/3rdparty/cplusplus/Control.cpp | 9 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Control.h | 1 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Scope.cpp | 21 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Scope.h | 1 | ||||
-rw-r--r-- | src/libs/cplusplus/LookupContext.cpp | 22 | ||||
-rw-r--r-- | src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp | 13 | ||||
-rw-r--r-- | src/plugins/cpptools/symbolfinder.cpp | 26 |
7 files changed, 81 insertions, 12 deletions
diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 4033b16028..1c0994604a 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -579,6 +579,15 @@ const OperatorNameId *Control::findOperatorNameId(OperatorNameId::Kind operatorI return &*i; } +const ConversionNameId *Control::findConversionNameId(const FullySpecifiedType &type) const +{ + for (const ConversionNameId &id : d->conversionNameIds) { + if (type.match(id.type())) + return &id; + } + return nullptr; +} + const Identifier *Control::findIdentifier(const char *chars, int size) const { return d->identifiers.findLiteral(chars, size); } diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index 59b3cf4ad9..4a2388f726 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -186,6 +186,7 @@ public: const Identifier *cpp11Final() const; const OperatorNameId *findOperatorNameId(OperatorNameId::Kind operatorId) const; + const ConversionNameId *findConversionNameId(const FullySpecifiedType &type) const; const Identifier *findIdentifier(const char *chars, int size) const; const Identifier *identifier(const char *chars, int size); diff --git a/src/libs/3rdparty/cplusplus/Scope.cpp b/src/libs/3rdparty/cplusplus/Scope.cpp index 43d8c98965..dcafc0c066 100644 --- a/src/libs/3rdparty/cplusplus/Scope.cpp +++ b/src/libs/3rdparty/cplusplus/Scope.cpp @@ -71,6 +71,7 @@ public: Symbol *lookat(const Identifier *id) const; Symbol *lookat(OperatorNameId::Kind operatorId) const; + Symbol *lookat(const ConversionNameId *convId) const; private: /// Returns the hash value for the given Symbol. @@ -181,6 +182,23 @@ Symbol *SymbolTable::lookat(OperatorNameId::Kind operatorId) const return symbol; } +Symbol *SymbolTable::lookat(const ConversionNameId *convId) const +{ + if (!_hash) + return nullptr; + + Symbol *symbol = _hash[0]; // See Symbol::HashCode + for (; symbol; symbol = symbol->_next) { + if (const Name *identity = symbol->unqualifiedName()) { + if (const ConversionNameId * const id = identity->asConversionNameId()) { + if (id->type().match(convId->type())) + break; + } + } + } + return symbol; +} + void SymbolTable::rehash() { _hashSize <<= 1; @@ -281,6 +299,9 @@ Symbol *Scope::find(const Identifier *id) const Symbol *Scope::find(OperatorNameId::Kind operatorId) const { return _members ? _members->lookat(operatorId) : nullptr; } +Symbol *Scope::find(const ConversionNameId *conv) const +{ return _members ? _members->lookat(conv) : nullptr; } + /// Set the start offset of the scope int Scope::startOffset() const { return _startOffset; } diff --git a/src/libs/3rdparty/cplusplus/Scope.h b/src/libs/3rdparty/cplusplus/Scope.h index c3b2a6ca37..39a10696a1 100644 --- a/src/libs/3rdparty/cplusplus/Scope.h +++ b/src/libs/3rdparty/cplusplus/Scope.h @@ -55,6 +55,7 @@ public: Symbol *find(const Identifier *id) const; Symbol *find(OperatorNameId::Kind operatorId) const; + Symbol *find(const ConversionNameId *conv) const; /// Set the start offset of the scope int startOffset() const; diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 2658b87b32..abd9852884 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -765,10 +765,10 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, const TemplateNameId *templateId, ClassOrNamespace *binding) { - if (! name) { + if (!name) return; - } else if (const OperatorNameId *op = name->asOperatorNameId()) { + if (const OperatorNameId *op = name->asOperatorNameId()) { for (Symbol *s = scope->find(op->kind()); s; s = s->next()) { if (! s->name()) continue; @@ -786,8 +786,24 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, result->append(item); } + return; + } + + if (const ConversionNameId * const conv = name->asConversionNameId()) { + if (Symbol * const s = scope->find(conv)) { + LookupItem item; + item.setDeclaration(s); + item.setBinding(binding); + + if (Symbol *inst = instantiateTemplateFunction(name, s->asTemplate())) + item.setType(inst->type()); + + result->append(item); + } + return; + } - } else if (const Identifier *id = name->identifier()) { + if (const Identifier *id = name->identifier()) { for (Symbol *s = scope->find(id); s; s = s->next()) { if (s->isFriend()) continue; // skip friends diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 7532b77e8d..5cf1e31d29 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -579,6 +579,19 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data() "float Test::var;\n" "int Test::$var;\n" "}\n"); + + QTest::newRow("conversionOperatorDecl2Def") + << _("struct Foo {\n" + " operator @int() const;\n" + "};\n") + << _("#include \"file.h\"\n" + "Foo::$operator int() const { return {}; }\n"); + QTest::newRow("conversionOperatorDef2Decl") + << _("struct Foo {\n" + " $operator int() const;\n" + "};\n") + << _("#include \"file.h\"\n" + "Foo::@operator int() const { return {}; }\n"); } void CppEditorPlugin::test_SwitchMethodDeclarationDefinition() diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp index 6ee966161c..0c0c1f3d15 100644 --- a/src/plugins/cpptools/symbolfinder.cpp +++ b/src/plugins/cpptools/symbolfinder.cpp @@ -58,6 +58,7 @@ class FindMatchingDefinition: public SymbolVisitor { Symbol *_declaration = nullptr; const OperatorNameId *_oper = nullptr; + const ConversionNameId *_conv = nullptr; const bool _strict; QList<Hit> _result; @@ -65,8 +66,10 @@ public: explicit FindMatchingDefinition(Symbol *declaration, bool strict) : _declaration(declaration), _strict(strict) { - if (_declaration->name()) + if (_declaration->name()) { _oper = _declaration->name()->asOperatorNameId(); + _conv = _declaration->name()->asConversionNameId(); + } } const QList<Hit> result() const { return _result; } @@ -75,10 +78,10 @@ public: bool visit(Function *fun) override { - if (_oper) { + if (_oper || _conv) { if (const Name *name = fun->unqualifiedName()) { - if (_oper->match(name)) - _result.append({fun, true}); + if ((_oper && _oper->match(name)) || (_conv && _conv->match(name))) + _result.append({fun, true}); } } else if (Function *decl = _declaration->type()->asFunctionType()) { if (fun->match(decl)) { @@ -181,13 +184,18 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration, continue; if (!id) { - if (!declaration->name()) - continue; - const OperatorNameId *oper = declaration->name()->asOperatorNameId(); - if (!oper) + const Name * const name = declaration->name(); + if (!name) continue; - if (!doc->control()->findOperatorNameId(oper->kind())) + if (const OperatorNameId * const oper = name->asOperatorNameId()) { + if (!doc->control()->findOperatorNameId(oper->kind())) + continue; + } else if (const ConversionNameId * const conv = name->asConversionNameId()) { + if (!doc->control()->findConversionNameId(conv->type())) + continue; + } else { continue; + } } FindMatchingDefinition candidates(declaration, strict); |