1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-16 13:35:22 +02:00

Bug 425102 QObject::connect content assist broken

The QObject::connect content assistant does not work when the receiver
of the function call is an implicit this.  E.g.,

class Q : public QObject { Q_OBJECT
    f()
    {
        this->connect( ... );   // works
        connect( ... );         // does not work
        QObject::connect( ... ) // does not work
    }
};

I've changed the Qt's ASTUtil.getReceiverType to navigate to the
ICPPClassType through the IScope's.  The previous implementation was
relying on the connect function call being an IASTField

I've also added a test case for this problem.

Change-Id: I96c29a9a452280068bda39a63414c50008bfad37
Signed-off-by: Andrew Eidsness <eclipse@jfront.com>
Reviewed-on: https://git.eclipse.org/r/20399
Tested-by: Hudson CI
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
Andrew Eidsness 2014-01-08 12:57:25 -05:00 committed by Doug Schaefer
parent 86c55d8821
commit 030bfc50fb
5 changed files with 102 additions and 19 deletions

View file

@ -14,7 +14,7 @@ Require-Bundle: org.eclipse.core.runtime,
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
Export-Package: org.eclipse.cdt.internal.qt.core;x-friends:="org.eclipse.cdt.qt.ui",
Export-Package: org.eclipse.cdt.internal.qt.core;x-friends:="org.eclipse.cdt.qt.ui,org.eclipse.cdt.qt.tests",
org.eclipse.cdt.internal.qt.core.index;x-friends:="org.eclipse.cdt.qt.tests",
org.eclipse.cdt.internal.qt.core.parser;x-friends:="org.eclipse.cdt.qt.ui",
org.eclipse.cdt.qt.core,

View file

@ -22,13 +22,14 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.model.ICProject;
@ -36,6 +37,7 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.cdt.qt.core.index.IQMethod;
import org.eclipse.cdt.qt.core.index.IQObject;
@ -144,21 +146,17 @@ public class ASTUtil {
}
public static ICPPClassType getReceiverType(IASTFunctionCallExpression fncall) {
// See the thread that starts at:
// http://dev.eclipse.org/mhonarc/lists/cdt-dev/msg26972.html
try {
for(IScope scope = CPPVisitor.getContainingScope(fncall); scope != null; scope = scope.getParent())
if (scope instanceof ICPPClassScope)
return ((ICPPClassScope) scope).getClassType();
} catch (DOMException e) {
QtPlugin.log(e);
}
// NOTE: This cannot rely on the Evaluation because we're in a contest assist context.
// At this point is likely that the full function call is not complete, so at least
// some of the eval leads to a Problem. We don't need the Eval anyhow, just lookup
// the type of the receiver.
IASTExpression fnName = fncall.getFunctionNameExpression();
if (!(fnName instanceof ICPPASTFieldReference))
return null;
ICPPASTFieldReference fieldRef = (ICPPASTFieldReference) fnName;
ICPPASTExpression receiver = fieldRef.getFieldOwner();
IType recvType = getBaseType(receiver);
return recvType instanceof ICPPClassType ? (ICPPClassType) recvType : null;
}
/**

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2014 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.tests;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.tests.ast2.AST2TestBase;
import org.eclipse.cdt.internal.qt.core.ASTUtil;
public class ASTUtilTests extends AST2TestBase {
// class T
// {
// void callee() { }
// void caller() { this->callee(); callee(); T::callee(); }
// };
// void T::callee() { this->caller(); caller(); T::caller(); }
public void testGetReceiverType() throws Exception {
IASTTranslationUnit tu = parse();
assertNotNull(tu);
// Find the callee function call.
ArrayList<IASTFunctionCallExpression> fnCalls = new ArrayList<IASTFunctionCallExpression>();
collectChildren(fnCalls, tu, IASTFunctionCallExpression.class);
assertEquals(6, fnCalls.size());
assertNotNull(fnCalls.get(0));
assertNotNull(fnCalls.get(1));
assertNotNull(fnCalls.get(2));
assertNotNull(fnCalls.get(3));
assertNotNull(fnCalls.get(4));
assertNotNull(fnCalls.get(5));
ICPPClassType recvr0 = ASTUtil.getReceiverType(fnCalls.get(0));
ICPPClassType recvr1 = ASTUtil.getReceiverType(fnCalls.get(1));
ICPPClassType recvr2 = ASTUtil.getReceiverType(fnCalls.get(2));
ICPPClassType recvr3 = ASTUtil.getReceiverType(fnCalls.get(3));
ICPPClassType recvr4 = ASTUtil.getReceiverType(fnCalls.get(4));
ICPPClassType recvr5 = ASTUtil.getReceiverType(fnCalls.get(5));
assertNotNull(recvr0);
assertNotNull(recvr1);
assertNotNull(recvr2);
assertNotNull(recvr3);
assertNotNull(recvr4);
assertNotNull(recvr5);
assertSame(recvr0, recvr1);
assertSame(recvr1, recvr2);
assertSame(recvr3, recvr4);
assertSame(recvr4, recvr5);
}
private IASTTranslationUnit parse() throws Exception {
String[] contents = BaseQtTestCase.getContentsForTest(getClass(), 1);
return parse(contents[0], ParserLanguage.CPP);
}
private static <T> void collectChildren(List<T> list, IASTNode node, Class<T> cls) {
if (cls.isAssignableFrom(node.getClass()))
list.add(cls.cast(node));
for(IASTNode child : node.getChildren())
collectChildren(list, child, cls);
}
}

View file

@ -15,6 +15,7 @@ public class AllQtTests extends TestSuite {
public static Test suite() throws Exception {
return
new TestSuite(
ASTUtilTests.class,
QMakeTests.class,
QGadgetTests.class,
QObjectTests.class,

View file

@ -112,10 +112,10 @@ public class BaseQtTestCase extends BaseTestCase {
loadComment("junit-QObject.hh");
}
private String[] getContentsForTest(int blocks) throws Exception {
String callingMethod = Thread.currentThread().getStackTrace()[3].getMethodName();
private static String[] getContentsForTest(Class<?> testCaseCls, int frames, int blocks) throws Exception {
String callingMethod = Thread.currentThread().getStackTrace()[frames].getMethodName();
CharSequence[] help= TestSourceReader.getContentsForTest(
QtTestPlugin.getDefault().getBundle(), "src", getClass(), callingMethod, blocks);
QtTestPlugin.getDefault().getBundle(), "src", testCaseCls, callingMethod, blocks);
String[] result= new String[help.length];
int i= 0;
for (CharSequence buf : help) {
@ -124,6 +124,14 @@ public class BaseQtTestCase extends BaseTestCase {
return result;
}
private String[] getContentsForTest(int blocks) throws Exception {
return getContentsForTest(getClass(), 4, blocks);
}
/*package*/ static String[] getContentsForTest(Class<?> testCaseCls, int blocks) throws Exception {
return getContentsForTest(testCaseCls, 4, blocks);
}
/**
* The implementation of TestSourceReader (called from BaseTestCase) imposes some restrictions
* on the caller of #loadComment.