diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index b0b18871f9a..01725841158 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -200,6 +200,36 @@ private: ClassOrNamespace *_binding; }; +static int evaluateFunctionArgument(const FullySpecifiedType &actualTy, + const FullySpecifiedType &formalTy) +{ + int score = 0; + if (actualTy.type()->match(formalTy.type())) { + ++score; + if (actualTy.isConst() == formalTy.isConst()) + ++score; + } else if (actualTy.simplified().type()->match(formalTy.simplified().type())) { + ++score; + if (actualTy.simplified().isConst() == formalTy.simplified().isConst()) + ++score; + } else { + PointerType *actualAsPointer = actualTy.type()->asPointerType(); + PointerType *formalAsPointer = formalTy.type()->asPointerType(); + + if (actualAsPointer && formalAsPointer) { + FullySpecifiedType actualElementType = actualAsPointer->elementType(); + FullySpecifiedType formalElementType = formalAsPointer->elementType(); + if (actualElementType.type()->match(formalElementType.type())) { + ++score; + if (actualElementType.isConst() == formalElementType.isConst()) + ++score; + } + } + } + + return score; +} + } // end of anonymous namespace ///////////////////////////////////////////////////////////////////// @@ -771,15 +801,6 @@ bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgu return funTy->maybeValidPrototype(actualArgumentCount); } -bool ResolveExpression::implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const -{ - if (sourceTy.match(targetTy)) - return true; - else if (sourceTy.simplified().match(targetTy.simplified())) - return true; - return false; -} - bool ResolveExpression::visit(CallAST *ast) { const QList baseResults = resolve(ast->base_expression, _scope); @@ -820,11 +841,13 @@ bool ResolveExpression::visit(CallAST *ast) continue; actualTy = actual.first().type(); - } else + } else { actualTy = formalTy; + score += 2; + continue; + } - if (implicitConversion(actualTy, formalTy)) - ++score; + score += evaluateFunctionArgument(actualTy, formalTy); } sortedResults.insert(LookupMap::value_type(-score, base)); diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index be8d0629409..dca059028bb 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -77,7 +77,6 @@ protected: void addResults(const QList &items); static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount); - bool implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const; using ASTVisitor::visit; diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index 6b0817b14c3..ffb9d2c9547 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -100,6 +100,9 @@ private slots: void test_FollowSymbolUnderCursor_data(); void test_FollowSymbolUnderCursor(); + void test_FollowSymbolUnderCursor_followCall_data(); + void test_FollowSymbolUnderCursor_followCall(); + void test_FollowSymbolUnderCursor_QObject_connect_data(); void test_FollowSymbolUnderCursor_QObject_connect(); diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 811552971f6..2637efc51de 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -931,45 +931,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data() "};\n" ); - QTest::newRow("matchFunctionSignature_FollowCall_1") << _( - "class Bar {};\n" - "void $foo(int) {}\n" - "void foo(const char *) {}\n" - "void foo(const Bar &) {}\n" - "void foo(char) {}\n" - "\n" - "void t()\n" - "{\n" - " @foo(5);\n" - "}\n" - ); - - QTest::newRow("matchFunctionSignature_FollowCall_2") << _( - "class Bar {};\n" - "void foo(int) {}\n" - "void $foo(const char *) {}\n" - "void foo(const Bar &) {}\n" - "void foo(char) {}\n" - "\n" - "void t()\n" - "{\n" - " @foo(\"hoo\");\n" - "}\n" - ); - - QTest::newRow("matchFunctionSignature_FollowCall_3") << _( - "class Bar {};\n" - "void foo(int) {}\n" - "void foo(const char *) {}\n" - "void foo(const Bar &) {}\n" - "void $foo(char) {}\n" - "\n" - "void t()\n" - "{\n" - " @foo('a');\n" - "}\n" - ); - QTest::newRow("infiniteLoopLocalTypedef_QTCREATORBUG-11999") << _( "template\n" "class TreeConstIterator\n" @@ -993,6 +954,73 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor() F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source)); } +void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall_data() +{ + QTest::addColumn("variableDeclaration"); // without semicolon, can be "" + QTest::addColumn("callArgument"); + QTest::addColumn("expectedSignature"); // you might need to add a function + // declaration with such a signature + + QTest::newRow("intLiteral-to-int") + << _("") + << _("5") + << _("int"); + QTest::newRow("charLiteral-to-const-char-ptr") + << _("") + << _("\"hoo\"") + << _("const char *"); + QTest::newRow("charLiteral-to-int") + << _("") + << _("'a'") + << _("char"); + + QTest::newRow("charPtr-to-constCharPtr") + << _("char *var = \"var\"") + << _("var") + << _("const char *"); + QTest::newRow("charPtr-to-constCharPtr") + << _("char *var = \"var\"") + << _("var") + << _("const char *"); + QTest::newRow("constCharPtr-to-constCharPtr") + << _("const char *var = \"var\"") + << _("var") + << _("const char *"); + + QTest::newRow("Bar-to-constBarRef") + << _("Bar var") + << _("var") + << _("const Bar &"); +} + +void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall() +{ + QFETCH(QByteArray, variableDeclaration); + QFETCH(QByteArray, callArgument); + QFETCH(QByteArray, expectedSignature); + + const QByteArray templateSource = + "class Bar {};\n" + "void fun(int);\n" + "void fun(const char *);\n" + "void fun(const Bar &);\n" + "void fun(char);\n" + "void fun(double);\n" + "\n" + "void t()\n" + "{\n" + " " + variableDeclaration + ";\n" + " @fun(" + callArgument + ");\n" + "}\n"; + + const QByteArray matchText = " fun(" + expectedSignature + ")"; + const QByteArray replaceText = " $fun(" + expectedSignature + ")"; + QByteArray source = templateSource; + source.replace(matchText, replaceText); + QVERIFY(source != templateSource); + F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source)); +} + void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data() { QTest::addColumn >("documents");