Commit d14767a6 authored by Przemyslaw Gorszkowski's avatar Przemyslaw Gorszkowski Committed by Erik Verbruggen

C++: fix highlighting type when there is using Namespace::Class

If type is not found we try to find 'using' declaration for this type.

Task-number: QTCREATORBUG-7903

Change-Id: I569db9e1a8504a5da3115ebbed2e823d5924f6ca
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent e245f2d5
......@@ -210,7 +210,7 @@ bool FindUsages::checkCandidates(const QList<LookupItem> &candidates) const
if (s->enclosingScope()->isTemplate()) {
if (s->enclosingScope()->enclosingScope() != _declSymbol->enclosingScope())
return false;
} else if (s->enclosingScope() != _declSymbol->enclosingScope()) {
} else if (! s->isUsingDeclaration() && s->enclosingScope() != _declSymbol->enclosingScope()) {
return false;
}
}
......
......@@ -247,6 +247,33 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target,
return n;
}
QList<LookupItem> LookupContext::lookupByUsing(const Name *name, Scope *scope) const
{
QList<LookupItem> candidates;
// if it is a nameId there can be a using declaration for it
if (name->isNameId()) {
for (unsigned i = 0, count = scope->memberCount(); i < count; ++i) {
if (UsingDeclaration *u = scope->memberAt(i)->asUsingDeclaration()) {
if (const QualifiedNameId *q = u->name()->asQualifiedNameId()) {
if (q->name()->isEqualTo(name)) {
candidates = bindings()->globalNamespace()->find(q);
// if it is not a global scope(scope of scope is not equal 0)
// then add current using declaration as a candidate
if (scope->scope()) {
LookupItem item;
item.setDeclaration(u);
item.setScope(scope);
candidates.append(item);
}
}
}
}
}
}
return candidates;
}
QSharedPointer<CreateBindings> LookupContext::bindings() const
{
......@@ -365,6 +392,10 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
}
}
candidates = lookupByUsing(name, scope);
if (! candidates.isEmpty())
return candidates;
} else if (Function *fun = scope->asFunction()) {
bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0);
......@@ -390,7 +421,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
}
}
// contunue, and look at the enclosing scope.
// continue, and look at the enclosing scope.
} else if (ObjCMethod *method = scope->asObjCMethod()) {
bindings()->lookupInScope(name, method, &candidates, /*templateId = */ 0, /*binding=*/ 0);
......@@ -416,8 +447,12 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
if (ClassOrNamespace *binding = bindings()->lookupType(scope))
candidates = binding->find(name);
if (! candidates.isEmpty())
return candidates;
if (! candidates.isEmpty())
return candidates;
candidates = lookupByUsing(name, scope);
if (! candidates.isEmpty())
return candidates;
} else if (scope->isObjCClass() || scope->isObjCProtocol()) {
if (ClassOrNamespace *binding = bindings()->lookupType(scope))
......
......@@ -311,6 +311,8 @@ public:
}
private:
QList<LookupItem> lookupByUsing(const Name *name, Scope *scope) const;
// The current expression.
Document::Ptr _expressionDocument;
......
......@@ -1592,6 +1592,15 @@ CPPEditorWidget::Link CPPEditorWidget::findLinkAt(const QTextCursor &cursor, boo
break;
}
}
} else if (d->isUsingDeclaration()) {
int tokenBeginLineNumber = 0, tokenBeginColumnNumber = 0;
convertPosition(beginOfToken, &tokenBeginLineNumber, &tokenBeginColumnNumber);
if (unsigned(tokenBeginLineNumber) > d->line()
|| (unsigned(tokenBeginLineNumber) == d->line()
&& unsigned(tokenBeginColumnNumber) > d->column())) {
result = r; // take the symbol under cursor.
break;
}
}
}
}
......
......@@ -115,6 +115,9 @@ private slots:
void test_FollowSymbolUnderCursor_baseClassFunctionIntroducedByUsingDeclaration();
void test_FollowSymbolUnderCursor_funWithSameNameAsBaseClassFunIntroducedByUsingDeclaration();
void test_FollowSymbolUnderCursor_funLocalVarHidesOuterClass();
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_globalNamespace();
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_namespace();
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_insideFunction();
void test_doxygen_comments_qt_style();
void test_doxygen_comments_qt_style_continuation();
......
......@@ -706,6 +706,59 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_funLocalVarHidesOuterClass()
data.run();
}
void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_globalNamespace()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"using NS::$Foo;\n"
"void fun()\n"
"{\n"
" @Foo foo;\n"
"}\n"
;
TestCase data(source);
data.run();
}
void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_namespace()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"namespace NS1 {\n"
"void fun()\n"
"{\n"
" using NS::$Foo;\n"
" @Foo foo;\n"
"}\n"
"}\n"
;
TestCase data(source);
data.run();
}
void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_insideFunction()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"void fun()\n"
"{\n"
" using NS::$Foo;\n"
" @Foo foo;\n"
"}\n"
;
TestCase data(source);
data.run();
}
/*
Potential test cases improving name lookup.
......
......@@ -191,6 +191,9 @@ private slots:
void test_checksymbols_AnonymousClass();
void test_checksymbols_AnonymousClass_insideNamespace();
void test_checksymbols_AnonymousClass_QTCREATORBUG8963();
void test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_globalNamespace();
void test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_namespace();
void test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_insideFunction();
};
void tst_CheckSymbols::test_checksymbols_TypeUse()
......@@ -1567,5 +1570,87 @@ void tst_CheckSymbols::test_checksymbols_AnonymousClass_QTCREATORBUG8963()
TestData::check(source, expectedUses);
}
void tst_CheckSymbols::test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_globalNamespace()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"using NS::Foo;\n"
"void fun()\n"
"{\n"
" Foo foo;\n"
"}\n"
;
const QList<Use> expectedUses = QList<Use>()
<< Use(1, 11, 2, CppHighlightingSupport::TypeUse)
<< Use(2, 7, 3, CppHighlightingSupport::TypeUse)
<< Use(4, 7, 2, CppHighlightingSupport::TypeUse)
<< Use(4, 11, 3, CppHighlightingSupport::TypeUse)
<< Use(5, 6, 3, CppHighlightingSupport::FunctionUse)
<< Use(7, 5, 3, CppHighlightingSupport::TypeUse)
<< Use(7, 9, 3, CppHighlightingSupport::LocalUse)
;
TestData::check(source, expectedUses);
}
void tst_CheckSymbols::test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_namespace()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"namespace NS1 {\n"
"using NS::Foo;\n"
"void fun()\n"
"{\n"
" Foo foo;\n"
"}\n"
"}\n"
;
const QList<Use> expectedUses = QList<Use>()
<< Use(1, 11, 2, CppHighlightingSupport::TypeUse)
<< Use(2, 7, 3, CppHighlightingSupport::TypeUse)
<< Use(4, 11, 3, CppHighlightingSupport::TypeUse)
<< Use(5, 7, 2, CppHighlightingSupport::TypeUse)
<< Use(5, 11, 3, CppHighlightingSupport::TypeUse)
<< Use(6, 6, 3, CppHighlightingSupport::FunctionUse)
<< Use(8, 5, 3, CppHighlightingSupport::TypeUse)
<< Use(8, 9, 3, CppHighlightingSupport::LocalUse)
;
TestData::check(source, expectedUses);
}
void tst_CheckSymbols::test_checksymbols_highlightingTypeWhenUsingNamespaceClass_QTCREATORBUG7903_insideFunction()
{
const QByteArray source =
"namespace NS {\n"
"class Foo {};\n"
"}\n"
"void fun()\n"
"{\n"
" using NS::Foo;\n"
" Foo foo;\n"
"}\n"
;
const QList<Use> expectedUses = QList<Use>()
<< Use(1, 11, 2, CppHighlightingSupport::TypeUse)
<< Use(2, 7, 3, CppHighlightingSupport::TypeUse)
<< Use(4, 6, 3, CppHighlightingSupport::FunctionUse)
<< Use(6, 11, 2, CppHighlightingSupport::TypeUse)
<< Use(6, 15, 3, CppHighlightingSupport::TypeUse)
<< Use(7, 5, 3, CppHighlightingSupport::TypeUse)
<< Use(7, 9, 3, CppHighlightingSupport::LocalUse)
;
TestData::check(source, expectedUses);
}
QTEST_APPLESS_MAIN(tst_CheckSymbols)
#include "tst_checksymbols.moc"
......@@ -97,6 +97,9 @@ private Q_SLOTS:
void operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006();
void operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005();
void anonymousClass_QTCREATORBUG8963();
void using_insideGlobalNamespace();
void using_insideNamespace();
void using_insideFunction();
};
......@@ -536,6 +539,129 @@ void tst_FindUsages::anonymousClass_QTCREATORBUG8963()
QCOMPARE(findUsages.usages().size(), 2);
}
void tst_FindUsages::using_insideGlobalNamespace()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"using NS::Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideGlobalNamespace");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3U);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1U);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
}
void tst_FindUsages::using_insideNamespace()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"namespace NS1\n"
"{\n"
"using NS::Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
"}\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideNamespace");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2U);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1U);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
}
void tst_FindUsages::using_insideFunction()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"void foo()\n"
"{\n"
" using NS::Struct;\n"
" Struct s;\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideFunction");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2U);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1U);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
}
void tst_FindUsages::operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005()
{
const QByteArray src = "\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment