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:
parent
86c55d8821
commit
030bfc50fb
5 changed files with 102 additions and 19 deletions
|
@ -14,7 +14,7 @@ Require-Bundle: org.eclipse.core.runtime,
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Bundle-Localization: plugin
|
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.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.internal.qt.core.parser;x-friends:="org.eclipse.cdt.qt.ui",
|
||||||
org.eclipse.cdt.qt.core,
|
org.eclipse.cdt.qt.core,
|
||||||
|
|
|
@ -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.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
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.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
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.ICPPASTFieldReference;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
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.ICPPASTVisibilityLabel;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
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.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
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.ITypeContainer;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
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.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.QtPlugin;
|
||||||
import org.eclipse.cdt.qt.core.index.IQMethod;
|
import org.eclipse.cdt.qt.core.index.IQMethod;
|
||||||
import org.eclipse.cdt.qt.core.index.IQObject;
|
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||||
|
@ -144,21 +146,17 @@ public class ASTUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ICPPClassType getReceiverType(IASTFunctionCallExpression fncall) {
|
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.
|
return null;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ public class AllQtTests extends TestSuite {
|
||||||
public static Test suite() throws Exception {
|
public static Test suite() throws Exception {
|
||||||
return
|
return
|
||||||
new TestSuite(
|
new TestSuite(
|
||||||
|
ASTUtilTests.class,
|
||||||
QMakeTests.class,
|
QMakeTests.class,
|
||||||
QGadgetTests.class,
|
QGadgetTests.class,
|
||||||
QObjectTests.class,
|
QObjectTests.class,
|
||||||
|
|
|
@ -112,18 +112,26 @@ public class BaseQtTestCase extends BaseTestCase {
|
||||||
loadComment("junit-QObject.hh");
|
loadComment("junit-QObject.hh");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getContentsForTest(int blocks) throws Exception {
|
private static String[] getContentsForTest(Class<?> testCaseCls, int frames, int blocks) throws Exception {
|
||||||
String callingMethod = Thread.currentThread().getStackTrace()[3].getMethodName();
|
String callingMethod = Thread.currentThread().getStackTrace()[frames].getMethodName();
|
||||||
CharSequence[] help= TestSourceReader.getContentsForTest(
|
CharSequence[] help= TestSourceReader.getContentsForTest(
|
||||||
QtTestPlugin.getDefault().getBundle(), "src", getClass(), callingMethod, blocks);
|
QtTestPlugin.getDefault().getBundle(), "src", testCaseCls, callingMethod, blocks);
|
||||||
String[] result= new String[help.length];
|
String[] result= new String[help.length];
|
||||||
int i= 0;
|
int i= 0;
|
||||||
for (CharSequence buf : help) {
|
for (CharSequence buf : help) {
|
||||||
result[i++]= buf.toString();
|
result[i++]= buf.toString();
|
||||||
}
|
}
|
||||||
return result;
|
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
|
* The implementation of TestSourceReader (called from BaseTestCase) imposes some restrictions
|
||||||
* on the caller of #loadComment.
|
* on the caller of #loadComment.
|
||||||
|
|
Loading…
Add table
Reference in a new issue