diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 08f15f48576..38ced9002fe 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -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, 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 3be32730c9f..6a2392ebb8e 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 @@ -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; + return null; } /** 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 new file mode 100644 index 00000000000..b12509e2f5a --- /dev/null +++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/ASTUtilTests.java @@ -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 fnCalls = new ArrayList(); + 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 void collectChildren(List list, IASTNode node, Class cls) { + if (cls.isAssignableFrom(node.getClass())) + list.add(cls.cast(node)); + + for(IASTNode child : node.getChildren()) + collectChildren(list, child, cls); + } +} diff --git a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java index 5f47c68c67a..4282134d059 100644 --- a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java +++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java @@ -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, diff --git a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/BaseQtTestCase.java b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/BaseQtTestCase.java index 8bc1d1b755f..fd7210bf176 100644 --- a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/BaseQtTestCase.java +++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/BaseQtTestCase.java @@ -112,18 +112,26 @@ 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) { result[i++]= buf.toString(); } 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.