diff options
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 6a2392ebb8e..4deccf48a94 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 01a074d934e..7b652028aee 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 b12509e2f5a..510d0ef83d5 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 20caa39d8a0..bbd7219d44a 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; |