Skip to main content
summaryrefslogtreecommitdiffstats
path: root/qt
diff options
context:
space:
mode:
authorAndrew Eidsness2014-01-20 20:23:35 -0500
committerDoug Schaefer2014-01-20 22:40:56 -0500
commitfd074ab029192695eec04970dbe62738a242f925 (patch)
tree2a7a715e5a0775688c124289e3bf80d9e415e479 /qt
parent25a0992a6370fcc181cd715f2fac9b4dccb5a633 (diff)
downloadorg.eclipse.cdt-fd074ab029192695eec04970dbe62738a242f925.tar.gz
org.eclipse.cdt-fd074ab029192695eec04970dbe62738a242f925.tar.xz
org.eclipse.cdt-fd074ab029192695eec04970dbe62738a242f925.zip
Bug 425102 QObject::connect content assist still broken
The content assistant was treating all function calls in the same way. Here is an example showing the two cases that should be handled: qobj.connect( qobj.func(), SIGNAL( sig() ), SLOT( slot() ) ); In this case sig() applies to the return type of qobj::func() and slot() applies to qobj (the same instance that connect is called upon). The previous implementation of the assistant was not making a distinction between these two cases. I've added another test case to confirm behaviour in this area. Change-Id: I8f76a5d5ae7384ea5162c5d36abeebb4c79c394b Signed-off-by: Andrew Eidsness <eclipse@jfront.com> Reviewed-on: https://git.eclipse.org/r/20848 Tested-by: Hudson CI Reviewed-by: Doug Schaefer <dschaefer@qnx.com> IP-Clean: Doug Schaefer <dschaefer@qnx.com>
Diffstat (limited to 'qt')
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/ASTUtil.java17
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtFunctionCallUtil.java18
-rw-r--r--qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java71
-rw-r--r--qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QObjectConnectCompletion.java11
4 files changed, 96 insertions, 21 deletions
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/ASTUtil.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/ASTUtil.java
index 6a2392ebb8..4deccf48a9 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/ASTUtil.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/ASTUtil.java
@@ -25,6 +25,7 @@ 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;
@@ -146,8 +147,20 @@ 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
+ // If the expression is calling a member function then find the type of the
+ // receiver.
+ IASTExpression fnName = fncall.getFunctionNameExpression();
+ if (fnName instanceof ICPPASTFieldReference) {
+ ICPPASTFieldReference fieldRef = (ICPPASTFieldReference) fnName;
+ ICPPASTExpression receiver = fieldRef.getFieldOwner();
+
+ IType recvType = getBaseType(receiver);
+ if (recvType instanceof ICPPClassType)
+ return (ICPPClassType) recvType;
+ }
+
+ // Otherwise check for a call to implicit 'this'. See details in 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)
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtFunctionCallUtil.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtFunctionCallUtil.java
index 01a074d934..7b652028ae 100644
--- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtFunctionCallUtil.java
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtFunctionCallUtil.java
@@ -14,8 +14,8 @@ import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTName;
-import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.qt.core.QtKeywords;
/**
@@ -93,30 +93,32 @@ public class QtFunctionCallUtil {
* that will be used for this method. Returns null if the argument is not a Qt method call or
* if the associated node cannot be found.
*/
- public static IASTNode getTypeNode(IASTFunctionCallExpression call, IASTInitializerClause[] args, int argIndex) {
+ public static IType getTargetType(IASTFunctionCallExpression call, IASTInitializerClause[] args, int argIndex) {
int sigExpIndex = getExpansionArgIndex(args, 0, SignalRegex);
if (argIndex == sigExpIndex)
- return getSignalTargetNode(sigExpIndex, call, args);
+ return getSignalTargetType(sigExpIndex, call, args);
int methodExpIndex = getExpansionArgIndex(args, sigExpIndex + 1, MethodRegex);
if (argIndex == methodExpIndex)
- return getMethodTargetNode(methodExpIndex, sigExpIndex, call, args);
+ return getMethodTargetType(methodExpIndex, sigExpIndex, call, args);
// Otherwise the given argument is not a SIGNAL or SLOT expansion.
return null;
}
- private static IASTNode getSignalTargetNode(int sigExpIndex, IASTFunctionCallExpression call, IASTInitializerClause[] args) {
+ private static IType getSignalTargetType(int sigExpIndex, IASTFunctionCallExpression call, IASTInitializerClause[] args) {
// When the SIGNAL expansion is first, the type is based on the receiver of
// the function call. Otherwise the type is the previous argument.
- return sigExpIndex == 0 ? call : args[sigExpIndex - 1];
+ return ASTUtil.getBaseType(sigExpIndex == 0 ? call : args[sigExpIndex - 1]);
}
- private static IASTNode getMethodTargetNode(int methodExpIndex, int sigExpIndex, IASTFunctionCallExpression call, IASTInitializerClause[] args) {
+ private static IType getMethodTargetType(int methodExpIndex, int sigExpIndex, IASTFunctionCallExpression call, IASTInitializerClause[] args) {
// If the method is right after the signal, then the type is based on the receiver
// of the function call. Otherwise the method type is based on the parameter right
// before the expansion.
- return (methodExpIndex == (sigExpIndex + 1)) ? call : args[methodExpIndex - 1];
+ if (methodExpIndex == (sigExpIndex + 1))
+ return ASTUtil.getReceiverType(call);
+ return ASTUtil.getBaseType(args[methodExpIndex - 1]);
}
private static int getExpansionArgIndex(IASTInitializerClause[] args, int begin, Pattern macroNameRegex) {
diff --git a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java
index b12509e2f5..510d0ef83d 100644
--- a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java
+++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java
@@ -10,9 +10,13 @@ package org.eclipse.cdt.qt.tests;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
+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.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
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;
@@ -20,9 +24,10 @@ import org.eclipse.cdt.internal.qt.core.ASTUtil;
public class ASTUtilTests extends AST2TestBase {
+ // class Type { public: void function() { } };
// class T
// {
- // void callee() { }
+ // void callee() { Type instance; instance.function(); }
// void caller() { this->callee(); callee(); T::callee(); }
// };
// void T::callee() { this->caller(); caller(); T::caller(); }
@@ -33,7 +38,7 @@ public class ASTUtilTests extends AST2TestBase {
// Find the callee function call.
ArrayList<IASTFunctionCallExpression> fnCalls = new ArrayList<IASTFunctionCallExpression>();
collectChildren(fnCalls, tu, IASTFunctionCallExpression.class);
- assertEquals(6, fnCalls.size());
+ assertEquals(7, fnCalls.size());
assertNotNull(fnCalls.get(0));
assertNotNull(fnCalls.get(1));
@@ -41,24 +46,80 @@ public class ASTUtilTests extends AST2TestBase {
assertNotNull(fnCalls.get(3));
assertNotNull(fnCalls.get(4));
assertNotNull(fnCalls.get(5));
+ assertNotNull(fnCalls.get(6));
- ICPPClassType recvr0 = ASTUtil.getReceiverType(fnCalls.get(0));
+ // explicit type
+ IASTFunctionCallExpression call = fnCalls.get(0);
+ ICPPClassType recvr0 = ASTUtil.getReceiverType(call);
+ assertNotNull(recvr0);
+ assertEquals("Type", recvr0.getName());
+
+ // implicit this
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));
+ ICPPClassType recvr6 = ASTUtil.getReceiverType(fnCalls.get(6));
- assertNotNull(recvr0);
assertNotNull(recvr1);
assertNotNull(recvr2);
assertNotNull(recvr3);
assertNotNull(recvr4);
assertNotNull(recvr5);
- assertSame(recvr0, recvr1);
+ assertNotNull(recvr6);
assertSame(recvr1, recvr2);
assertSame(recvr3, recvr4);
assertSame(recvr4, recvr5);
+ assertSame(recvr5, recvr6);
+ }
+
+ // class C1
+ // {
+ // public:
+ // void f( C1 * ) { }
+ // C1 * g() { return this; }
+ // };
+ // void h() { C1 c; c.f( c.g() ); }
+ public void testBaseTypeOfFunctionCall() throws Exception {
+ IASTTranslationUnit tu = parse();
+ assertNotNull(tu);
+
+ // Find the C1 type.
+ ArrayList<ICPPASTCompositeTypeSpecifier> specs = new ArrayList<ICPPASTCompositeTypeSpecifier>();
+ collectChildren(specs, tu, ICPPASTCompositeTypeSpecifier.class);
+ assertEquals(1, specs.size());
+
+ ICPPASTCompositeTypeSpecifier spec = specs.get(0);
+ assertNotNull(spec);
+
+ IASTName specName = spec.getName();
+ assertNotNull(specName);
+ assertEquals("C1", specName.getRawSignature());
+
+ // Find the function call expression "c.get()".
+ ArrayList<IASTFunctionCallExpression> fnCalls = new ArrayList<IASTFunctionCallExpression>();
+ collectChildren(fnCalls, tu, IASTFunctionCallExpression.class);
+ assertEquals(2, fnCalls.size());
+
+ IASTFunctionCallExpression c_f = fnCalls.get(0);
+ IASTFunctionCallExpression c_g = fnCalls.get(1);
+ assertNotNull(c_f);
+ assertNotNull(c_g);
+
+ IASTExpression nameExpr = c_f.getFunctionNameExpression();
+ assertNotNull(nameExpr);
+ assertEquals("c.f", nameExpr.getRawSignature());
+
+ IType recvType = ASTUtil.getReceiverType(c_f);
+ assertTrue(recvType instanceof ICPPClassType);
+
+ nameExpr = c_g.getFunctionNameExpression();
+ assertNotNull(nameExpr);
+ assertEquals("c.g", nameExpr.getRawSignature());
+
+ recvType = ASTUtil.getBaseType(c_g);
+ assertTrue(recvType instanceof ICPPClassType);
}
private IASTTranslationUnit parse() throws Exception {
diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QObjectConnectCompletion.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QObjectConnectCompletion.java
index 20caa39d8a..bbd7219d44 100644
--- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QObjectConnectCompletion.java
+++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QObjectConnectCompletion.java
@@ -185,14 +185,13 @@ public class QObjectConnectCompletion {
return fields;
}
- private static Collection<QObjectConnectCompletion> getCompletionsFor(IASTNode targetNode, IASTInitializerClause arg) {
+ private static Collection<QObjectConnectCompletion> getCompletionsFor(IType targetType, IASTInitializerClause arg) {
- IType targetType = ASTUtil.getBaseType(targetNode);
if (!(targetType instanceof ICPPClassType))
return null;
ICPPClassType cls = (ICPPClassType) targetType;
- QtIndex qtIndex = QtIndex.getIndex(ASTUtil.getProject(targetNode));
+ QtIndex qtIndex = QtIndex.getIndex(ASTUtil.getProject(arg));
if (qtIndex == null)
return null;
@@ -285,13 +284,13 @@ public class QObjectConnectCompletion {
int argIndex = args.length - 1;
// Find the type node that is used for this expansion.
- IASTNode typeNode = QtFunctionCallUtil.getTypeNode(call, args, argIndex);
- if (typeNode == null)
+ IType targetType = QtFunctionCallUtil.getTargetType(call, args, argIndex);
+ if (targetType == null)
return null;
// Returns completions for the given expansion using the given type as the
// source for Qt methods.
- return getCompletionsFor(typeNode, args[argIndex]);
+ return getCompletionsFor(targetType, args[argIndex]);
}
return null;

Back to the top