C++: fix code completion for typedef of pointer

Fix code completion and highlighting member of typedefed pointers.
It works when typedef is inside or outside of the function.

Task-number: QTCREATORBUG-8671
Task-number: QTCREATORBUG-8672
Change-Id: I9cc87080bf443f7ffa6a90ef5ba582b87700f2db
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
parent 432aaf00
......@@ -848,7 +848,7 @@ public:
}
private:
NamedType *getNamedType(FullySpecifiedType& type)
NamedType *getNamedType(FullySpecifiedType& type) const
{
NamedType *namedTy = type->asNamedType();
if (! namedTy) {
......@@ -858,19 +858,57 @@ private:
return namedTy;
}
QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope, ClassOrNamespace *binding)
QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope,
ClassOrNamespace *binding) const
{
QList<LookupItem> namedTypeItems;
if (binding)
namedTypeItems = binding->lookup(name);
if (ClassOrNamespace *scopeCon = _context.lookupType(scope))
namedTypeItems += scopeCon->lookup(name);
QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope);
if (namedTypeItems.isEmpty()) {
if (binding)
namedTypeItems = binding->lookup(name);
if (ClassOrNamespace *scopeCon = _context.lookupType(scope))
namedTypeItems += scopeCon->lookup(name);
}
return namedTypeItems;
}
/// Return all typedefs with given name from given scope up to function scope.
static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope)
{
QList<LookupItem> results;
Scope *enclosingBlockScope = 0;
for (Block *block = scope->asBlock(); block;
block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) {
const unsigned memberCount = block->memberCount();
for (unsigned i = 0; i < memberCount; ++i) {
Symbol *symbol = block->memberAt(i);
if (Declaration *declaration = symbol->asDeclaration()) {
if (isTypedefWithName(declaration, name)) {
LookupItem item;
item.setDeclaration(declaration);
item.setScope(block);
item.setType(declaration->type());
results.append(item);
}
}
}
enclosingBlockScope = block->enclosingScope();
}
return results;
}
static bool isTypedefWithName(const Declaration *declaration, const Name *name)
{
if (declaration->isTypedef()) {
const Identifier *identifier = declaration->name()->identifier();
if (name->identifier()->isEqualTo(identifier))
return true;
}
return false;
}
bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type,
Scope **scope, QSet<Symbol *>& visited)
Scope **scope, QSet<Symbol *>& visited) const
{
bool foundTypedef = false;
foreach (const LookupItem &it, namedTypeItems) {
......@@ -931,6 +969,11 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
if (ClassOrNamespace *binding = findClass(type, scope))
return binding;
} else if (PointerType *ptrTy = ty->asPointerType()) {
FullySpecifiedType type = ptrTy->elementType();
if (ClassOrNamespace *binding = findClass(type, scope))
return binding;
} else if (ClassOrNamespace *binding = findClass(ty, scope)) {
// lookup for overloads of operator->
......
......@@ -1483,3 +1483,90 @@ void CppToolsPlugin::test_completion_typedef_of_pointer_of_type_and_replace_acce
QVERIFY(completions.contains(QLatin1String("m")));
QVERIFY(replaceAccessOperator);
}
void CppToolsPlugin::test_completion_typedef_of_pointer()
{
TestData data;
data.srcText = "\n"
"struct Foo { int bar; };\n"
"typedef Foo *FooPtr;\n"
"void main()\n"
"{\n"
" FooPtr ptr;\n"
" @\n"
" // padding so we get the scope right\n"
"}";
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("ptr->");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
void CppToolsPlugin::test_completion_typedef_of_pointer_inside_function()
{
TestData data;
data.srcText = "\n"
"struct Foo { int bar; };\n"
"void f()\n"
"{\n"
" typedef Foo *FooPtr;\n"
" FooPtr ptr;\n"
" @\n"
" // padding so we get the scope right\n"
"}";
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("ptr->");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
void CppToolsPlugin::test_completion_typedef_is_inside_function_before_declaration_block()
{
TestData data;
data.srcText = "\n"
"struct Foo { int bar; };\n"
"void f()\n"
"{\n"
" typedef Foo *FooPtr;\n"
" if (true) {\n"
" FooPtr ptr;\n"
" @\n"
" // padding so we get the scope right\n"
" }"
"}"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("ptr->");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
......@@ -118,6 +118,9 @@ private slots:
void test_completion_member_access_operator_1();
void test_completion_typedef_of_type_and_replace_access_operator();
void test_completion_typedef_of_pointer_of_type_and_replace_access_operator();
void test_completion_typedef_of_pointer();
void test_completion_typedef_of_pointer_inside_function();
void test_completion_typedef_is_inside_function_before_declaration_block();
void test_format_pointerdeclaration_in_simpledeclarations();
void test_format_pointerdeclaration_in_simpledeclarations_data();
......
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