forked from qt-creator/qt-creator
C++: fix follow symbol for const arguments
Fixed case:
class Foo {};
void foo(int v) {}
void foo(const char *v) {}
void foo(const Foo &v) {}
void foo(char v) {}
void test()
{
foo(5);
foo("hoo");
foo('a');
char *var = "var";
foo(var); // Jumps to last override, regardless of its type
Foo f;
foo(f); // Jumps to last override
}
Task-number: QTCREATORBUG-13128
Change-Id: I038553bb3bdbe1c300fc01573c14b6fedf0320cd
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
committed by
Nikolai Kosjar
parent
2de666da61
commit
0ff1cba77b
@@ -200,6 +200,36 @@ private:
|
|||||||
ClassOrNamespace *_binding;
|
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
|
} // end of anonymous namespace
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
@@ -771,15 +801,6 @@ bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgu
|
|||||||
return funTy->maybeValidPrototype(actualArgumentCount);
|
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)
|
bool ResolveExpression::visit(CallAST *ast)
|
||||||
{
|
{
|
||||||
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
|
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
|
||||||
@@ -820,11 +841,13 @@ bool ResolveExpression::visit(CallAST *ast)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
actualTy = actual.first().type();
|
actualTy = actual.first().type();
|
||||||
} else
|
} else {
|
||||||
actualTy = formalTy;
|
actualTy = formalTy;
|
||||||
|
score += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (implicitConversion(actualTy, formalTy))
|
score += evaluateFunctionArgument(actualTy, formalTy);
|
||||||
++score;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedResults.insert(LookupMap::value_type(-score, base));
|
sortedResults.insert(LookupMap::value_type(-score, base));
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ protected:
|
|||||||
void addResults(const QList<LookupItem> &items);
|
void addResults(const QList<LookupItem> &items);
|
||||||
|
|
||||||
static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount);
|
static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount);
|
||||||
bool implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const;
|
|
||||||
|
|
||||||
using ASTVisitor::visit;
|
using ASTVisitor::visit;
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ private slots:
|
|||||||
void test_FollowSymbolUnderCursor_data();
|
void test_FollowSymbolUnderCursor_data();
|
||||||
void test_FollowSymbolUnderCursor();
|
void test_FollowSymbolUnderCursor();
|
||||||
|
|
||||||
|
void test_FollowSymbolUnderCursor_followCall_data();
|
||||||
|
void test_FollowSymbolUnderCursor_followCall();
|
||||||
|
|
||||||
void test_FollowSymbolUnderCursor_QObject_connect_data();
|
void test_FollowSymbolUnderCursor_QObject_connect_data();
|
||||||
void test_FollowSymbolUnderCursor_QObject_connect();
|
void test_FollowSymbolUnderCursor_QObject_connect();
|
||||||
|
|
||||||
|
|||||||
@@ -931,45 +931,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
|
|||||||
"};\n"
|
"};\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") << _(
|
QTest::newRow("infiniteLoopLocalTypedef_QTCREATORBUG-11999") << _(
|
||||||
"template<class MyTree>\n"
|
"template<class MyTree>\n"
|
||||||
"class TreeConstIterator\n"
|
"class TreeConstIterator\n"
|
||||||
@@ -993,6 +954,73 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor()
|
|||||||
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
|
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("variableDeclaration"); // without semicolon, can be ""
|
||||||
|
QTest::addColumn<QByteArray>("callArgument");
|
||||||
|
QTest::addColumn<QByteArray>("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()
|
void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QList<TestDocumentPtr> >("documents");
|
QTest::addColumn<QList<TestDocumentPtr> >("documents");
|
||||||
|
|||||||
Reference in New Issue
Block a user