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:
Przemyslaw Gorszkowski
2013-04-07 09:05:22 +02:00
committed by Erik Verbruggen
parent 9c2a352027
commit bde6667240
4 changed files with 150 additions and 6 deletions

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 =