forked from qt-creator/qt-creator
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: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
e245f2d5f9
commit
d14767a6af
@@ -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);
|
||||
@@ -419,6 +450,10 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
||||
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))
|
||||
candidates = binding->find(name);
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user