forked from qt-creator/qt-creator
C++: name of function of class problem
It fixes: * highlighing * find usage * follow symbol when function of class has the same name as: * local variable * template parameter * other struct/union/class/enum * function argument in function scope. Task-number: QTCREATORBUG-8902 Change-Id: Iddc0f764af689babb40d39460d174bac7b919b31 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Sergey Shambir <sergey.shambir.auto@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
9c2a352027
commit
bde6667240
@@ -335,8 +335,14 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
if (name->identifier() != 0 && scope->isBlock()) {
|
if (name->identifier() != 0 && scope->isBlock()) {
|
||||||
bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty()) {
|
||||||
break; // it's a local.
|
// it's a local.
|
||||||
|
//for qualified it can be outside of the local scope
|
||||||
|
if (name->isQualifiedNameId())
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < scope->memberCount(); ++i) {
|
for (unsigned i = 0; i < scope->memberCount(); ++i) {
|
||||||
if (UsingNamespaceDirective *u = scope->memberAt(i)->asUsingNamespaceDirective()) {
|
if (UsingNamespaceDirective *u = scope->memberAt(i)->asUsingNamespaceDirective()) {
|
||||||
@@ -352,8 +358,14 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
} else if (Function *fun = scope->asFunction()) {
|
} else if (Function *fun = scope->asFunction()) {
|
||||||
bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty()) {
|
||||||
break; // it's an argument or a template parameter.
|
// it's an argument or a template parameter.
|
||||||
|
//for qualified it can be outside of the local scope
|
||||||
|
if (name->isQualifiedNameId())
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (fun->name() && fun->name()->isQualifiedNameId()) {
|
if (fun->name() && fun->name()->isQualifiedNameId()) {
|
||||||
if (ClassOrNamespace *binding = bindings()->lookupType(fun)) {
|
if (ClassOrNamespace *binding = bindings()->lookupType(fun)) {
|
||||||
@@ -379,8 +391,14 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
} else if (Template *templ = scope->asTemplate()) {
|
} else if (Template *templ = scope->asTemplate()) {
|
||||||
bindings()->lookupInScope(name, templ, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
bindings()->lookupInScope(name, templ, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty()) {
|
||||||
return candidates; // it's a template parameter.
|
// it's a template parameter.
|
||||||
|
//for qualified it can be outside of the local scope
|
||||||
|
if (name->isQualifiedNameId())
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (scope->asNamespace()
|
} else if (scope->asNamespace()
|
||||||
|| scope->asClass()
|
|| scope->asClass()
|
||||||
|
@@ -1240,6 +1240,7 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST
|
|||||||
{
|
{
|
||||||
unsigned startToken = ast->firstToken();
|
unsigned startToken = ast->firstToken();
|
||||||
bool isDestructor = false;
|
bool isDestructor = false;
|
||||||
|
bool isConstructor = false;
|
||||||
if (DestructorNameAST *dtor = ast->asDestructorName()) {
|
if (DestructorNameAST *dtor = ast->asDestructorName()) {
|
||||||
isDestructor = true;
|
isDestructor = true;
|
||||||
if (dtor->unqualified_name)
|
if (dtor->unqualified_name)
|
||||||
@@ -1264,6 +1265,8 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST
|
|||||||
if (isDestructor != c->name()->isDestructorNameId())
|
if (isDestructor != c->name()->isDestructorNameId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
isConstructor = isConstructorDeclaration(c);
|
||||||
|
|
||||||
Function *funTy = c->type()->asFunctionType();
|
Function *funTy = c->type()->asFunctionType();
|
||||||
if (! funTy) {
|
if (! funTy) {
|
||||||
//Try to find a template function
|
//Try to find a template function
|
||||||
@@ -1296,7 +1299,9 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matchType != Match_None) {
|
if (matchType != Match_None) {
|
||||||
|
// decide how constructor and destructor should be highlighted
|
||||||
if (highlightCtorDtorAsType
|
if (highlightCtorDtorAsType
|
||||||
|
&& (isConstructor || isDestructor)
|
||||||
&& maybeType(ast->name)
|
&& maybeType(ast->name)
|
||||||
&& kind == SemanticInfo::FunctionUse) {
|
&& kind == SemanticInfo::FunctionUse) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1399,3 +1404,12 @@ void CheckSymbols::flush()
|
|||||||
_usages.clear();
|
_usages.clear();
|
||||||
_usages.reserve(cap);
|
_usages.reserve(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckSymbols::isConstructorDeclaration(Symbol *declaration)
|
||||||
|
{
|
||||||
|
Class *clazz = declaration->enclosingClass();
|
||||||
|
if (clazz && clazz->name())
|
||||||
|
return declaration->name()->isEqualTo(clazz->name());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -165,6 +165,8 @@ protected:
|
|||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool isConstructorDeclaration(Symbol *declaration);
|
||||||
|
|
||||||
Document::Ptr _doc;
|
Document::Ptr _doc;
|
||||||
LookupContext _context;
|
LookupContext _context;
|
||||||
TypeOfExpression typeOfExpression;
|
TypeOfExpression typeOfExpression;
|
||||||
|
@@ -176,6 +176,10 @@ private slots:
|
|||||||
void test_checksymbols_StaticUse();
|
void test_checksymbols_StaticUse();
|
||||||
void test_checksymbols_VariableHasTheSameNameAsEnumUse();
|
void test_checksymbols_VariableHasTheSameNameAsEnumUse();
|
||||||
void test_checksymbols_NestedClassOfEnclosingTemplateUse();
|
void test_checksymbols_NestedClassOfEnclosingTemplateUse();
|
||||||
|
void test_checksymbols_8902_staticFunctionHighlightingAsMember_localVariable();
|
||||||
|
void test_checksymbols_8902_staticFunctionHighlightingAsMember_functionArgument();
|
||||||
|
void test_checksymbols_8902_staticFunctionHighlightingAsMember_templateParameter();
|
||||||
|
void test_checksymbols_8902_staticFunctionHighlightingAsMember_struct();
|
||||||
|
|
||||||
void test_checksymbols_QTCREATORBUG8890_danglingPointer();
|
void test_checksymbols_QTCREATORBUG8890_danglingPointer();
|
||||||
void test_checksymbols_QTCREATORBUG8974_danglingPointer();
|
void test_checksymbols_QTCREATORBUG8974_danglingPointer();
|
||||||
@@ -446,6 +450,112 @@ void tst_CheckSymbols::test_checksymbols_NestedClassOfEnclosingTemplateUse()
|
|||||||
TestData::check(source, expectedUses);
|
TestData::check(source, expectedUses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_CheckSymbols::test_checksymbols_8902_staticFunctionHighlightingAsMember_localVariable()
|
||||||
|
{
|
||||||
|
const QByteArray source =
|
||||||
|
"struct Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" static int foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"void bar()\n"
|
||||||
|
"{\n"
|
||||||
|
" int foo = Foo::foo();\n"
|
||||||
|
"}\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
const QList<Use> expectedUses = QList<Use>()
|
||||||
|
<< Use(1, 8, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(3, 16, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(6, 6, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(8, 9, 3, SemanticInfo::LocalUse)
|
||||||
|
<< Use(8, 15, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(8, 20, 3, SemanticInfo::FunctionUse)
|
||||||
|
;
|
||||||
|
|
||||||
|
TestData::check(source, expectedUses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_CheckSymbols::test_checksymbols_8902_staticFunctionHighlightingAsMember_functionArgument()
|
||||||
|
{
|
||||||
|
const QByteArray source =
|
||||||
|
"struct Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" static int foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"void bar(int foo)\n"
|
||||||
|
"{\n"
|
||||||
|
" Foo::foo();\n"
|
||||||
|
"}\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
const QList<Use> expectedUses = QList<Use>()
|
||||||
|
<< Use(1, 8, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(3, 16, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(6, 6, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(6, 14, 3, SemanticInfo::LocalUse)
|
||||||
|
<< Use(8, 5, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(8, 10, 3, SemanticInfo::FunctionUse)
|
||||||
|
;
|
||||||
|
|
||||||
|
TestData::check(source, expectedUses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_CheckSymbols::test_checksymbols_8902_staticFunctionHighlightingAsMember_templateParameter()
|
||||||
|
{
|
||||||
|
const QByteArray source =
|
||||||
|
"struct Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" static int foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <class foo>\n"
|
||||||
|
"void bar()\n"
|
||||||
|
"{\n"
|
||||||
|
" Foo::foo();\n"
|
||||||
|
"}\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
const QList<Use> expectedUses = QList<Use>()
|
||||||
|
<< Use(1, 8, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(3, 16, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(6, 17, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(7, 6, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(9, 5, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(9, 10, 3, SemanticInfo::FunctionUse)
|
||||||
|
;
|
||||||
|
|
||||||
|
TestData::check(source, expectedUses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_CheckSymbols::test_checksymbols_8902_staticFunctionHighlightingAsMember_struct()
|
||||||
|
{
|
||||||
|
const QByteArray source =
|
||||||
|
"struct Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" static int foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct foo {};\n"
|
||||||
|
"void bar()\n"
|
||||||
|
"{\n"
|
||||||
|
" Foo::foo();\n"
|
||||||
|
"}\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
const QList<Use> expectedUses = QList<Use>()
|
||||||
|
<< Use(1, 8, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(3, 16, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(6, 8, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(7, 6, 3, SemanticInfo::FunctionUse)
|
||||||
|
<< Use(9, 5, 3, SemanticInfo::TypeUse)
|
||||||
|
<< Use(9, 10, 3, SemanticInfo::FunctionUse)
|
||||||
|
;
|
||||||
|
|
||||||
|
TestData::check(source, expectedUses);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_CheckSymbols::test_checksymbols_QTCREATORBUG8890_danglingPointer()
|
void tst_CheckSymbols::test_checksymbols_QTCREATORBUG8890_danglingPointer()
|
||||||
{
|
{
|
||||||
const QByteArray source =
|
const QByteArray source =
|
||||||
|
Reference in New Issue
Block a user