diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/ClosureInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/ClosureInferencingTests.java index c178d01a30..b36f695169 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/ClosureInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/ClosureInferencingTests.java @@ -696,7 +696,7 @@ public void testNestedClosure5() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 1L.with {\n" + " abs\n" + " }\n" + "}"; @@ -711,13 +711,13 @@ public void testNestedClosure6() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 1L.with {\n" + " abs()\n" + " }\n" + "}"; //@formatter:on - assertType(contents, "abs", "java.lang.Integer"); + assertType(contents, "abs", "java.lang.Long"); } @Test @@ -725,13 +725,13 @@ public void testNestedClosure7() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 1L.with {\n" + " delegate.abs()\n" + " }\n" + "}"; //@formatter:on - assertType(contents, "abs", "java.lang.Integer"); + assertType(contents, "abs", "java.lang.Long"); } @Test @@ -739,7 +739,7 @@ public void testNestedClosure8() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 1L.with {\n" + " this.abs()\n" + " }\n" + "}"; @@ -754,7 +754,7 @@ public void testNestedClosure9() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 42.with {\n" + " this\n" + " }\n" + "}"; @@ -768,7 +768,7 @@ public void testNestedClosure10() { String contents = //@formatter:off "''.with {\n" + - " 1.with {\n" + + " 42.with {\n" + " owner.thisObject\n" + " owner.getThisObject()\n" + " }\n" + diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DGMInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DGMInferencingTests.java index 426e6f7cb4..da1a0159ad 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DGMInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DGMInferencingTests.java @@ -390,6 +390,7 @@ public void testDGM29() { public void testDGM30() { String contents = //@formatter:off + "import groovy.io.FileType\n" + "new File('test').eachFileMatch(FileType.FILES, 1) { it.name }"; //@formatter:on @@ -684,10 +685,10 @@ public void testDGM49() { public void testDGM50() { String contents = //@formatter:off - "def answer = (-42).&abs\n"; + "def answer = (-42L).&abs\n"; //@formatter:on - assertExprType(contents, "abs", "java.lang.Integer"); + assertExprType(contents, "abs", "java.lang.Long"); } @Test // https://github.com/groovy/groovy-eclipse/issues/1027 diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java index c9be180b46..9ded0f3e22 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java @@ -38,6 +38,7 @@ import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.GenericsType; +import org.codehaus.groovy.ast.ImmutableClassNode; import org.codehaus.groovy.ast.ImportNode; import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.MethodNode; @@ -50,6 +51,7 @@ import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.ast.tools.GeneralUtils; import org.codehaus.groovy.control.CompilePhase; +import org.codehaus.groovy.runtime.MetaClassHelper; import org.codehaus.groovy.transform.ASTTransformation; import org.codehaus.groovy.transform.GroovyASTTransformation; import org.codehaus.groovy.transform.trait.Traits; @@ -391,10 +393,7 @@ private static boolean isAssignable(boolean array, ClassNode source, ClassNode t } boolean result; - /*if (source.hasClass() && target.hasClass()) { - // this matches primitives more thoroughly, but getTypeClass can fail if class has not been loaded - result = MetaClassHelper.isAssignableFrom(target.getTypeClass(), source.getTypeClass()); - } else*/ if (target.isInterface()) { + if (target.isInterface()) { result = GeneralUtils.isOrImplements(source, target); } else if (array) { if (target.isGenericsPlaceHolder() || target.equals(ClassHelper.OBJECT_TYPE)) { @@ -404,7 +403,12 @@ private static boolean isAssignable(boolean array, ClassNode source, ClassNode t result = source.isDerivedFrom(target); } } else { - result = getWrapperTypeIfPrimitive(source).isDerivedFrom(getWrapperTypeIfPrimitive(target)); + if (source.redirect() instanceof ImmutableClassNode && target.redirect() instanceof ImmutableClassNode) { + // this matches primitives more thoroughly, but getTypeClass fails if class isn't loaded + result = MetaClassHelper.isAssignableFrom(target.getTypeClass(), source.getTypeClass()); + } else { + result = getWrapperTypeIfPrimitive(source).isDerivedFrom(target); + } } // if target is like , check source against B diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/CategoryTypeLookup.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/CategoryTypeLookup.java index 86cdfd8a50..48d269d17e 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/CategoryTypeLookup.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/CategoryTypeLookup.java @@ -39,7 +39,7 @@ public class CategoryTypeLookup implements ITypeLookup { @Override - public TypeLookupResult lookupType(Expression node, VariableScope scope, ClassNode objectExpressionType) { + public TypeLookupResult lookupType(final Expression node, final VariableScope scope, final ClassNode objectExpressionType) { if (node instanceof VariableExpression || isCompatibleConstantExpression(node, scope, objectExpressionType)) { String simpleName = node.getText(); ClassNode selfType = GroovyUtils.getWrapperTypeIfPrimitive( @@ -92,8 +92,8 @@ public TypeLookupResult lookupType(Expression node, VariableScope scope, ClassNo return null; } - protected static boolean isCompatibleConstantExpression(Expression node, VariableScope scope, ClassNode selfType) { - if (node instanceof ConstantExpression && !scope.isTopLevel()) { + protected static boolean isCompatibleConstantExpression(final Expression node, final VariableScope scope, final ClassNode selfType) { + if (node instanceof ConstantExpression && !scope.isTopLevel() && !VariableScope.VOID_CLASS_NODE.equals(selfType)) { org.codehaus.groovy.ast.ASTNode enclosingNode = scope.getEnclosingNode(); if (!(enclosingNode instanceof AttributeExpression || (enclosingNode instanceof MethodPointerExpression && VariableScope.CLASS_CLASS_NODE.equals(selfType)))) { @@ -103,7 +103,7 @@ protected static boolean isCompatibleConstantExpression(Expression node, Variabl return false; } - protected static boolean isCompatibleCategoryMethod(MethodNode method, ClassNode firstArgumentType, VariableScope scope) { + protected static boolean isCompatibleCategoryMethod(final MethodNode method, final ClassNode firstArgumentType, final VariableScope scope) { if (method.isStatic()) { Parameter[] paramters = method.getParameters(); if (paramters != null && paramters.length > 0) { @@ -119,15 +119,15 @@ protected static boolean isCompatibleCategoryMethod(MethodNode method, ClassNode return false; } - protected static boolean isTypeCompatible(ClassNode source, ClassNode target) { + protected static boolean isTypeCompatible(final ClassNode source, final ClassNode target) { if (SimpleTypeLookup.isTypeCompatible(source, target) != Boolean.FALSE) { if (!(VariableScope.CLASS_CLASS_NODE.equals(source) && source.isUsingGenerics()) || VariableScope.OBJECT_CLASS_NODE.equals(target) || !target.isUsingGenerics()) { return true; } else { - source = source.getGenericsTypes()[0].getType(); - target = target.getGenericsTypes()[0].getType(); - if (SimpleTypeLookup.isTypeCompatible(source, target) != Boolean.FALSE) { + ClassNode sourceGT = source.getGenericsTypes()[0].getType(); + ClassNode targetGT = target.getGenericsTypes()[0].getType(); + if (SimpleTypeLookup.isTypeCompatible(sourceGT, targetGT) != Boolean.FALSE) { return true; } } @@ -135,18 +135,18 @@ protected static boolean isTypeCompatible(ClassNode source, ClassNode target) { return false; } - protected static boolean isDefaultGroovyMethod(MethodNode method, VariableScope scope) { + protected static boolean isDefaultGroovyMethod(final MethodNode method, final VariableScope scope) { return (VariableScope.DGM_CLASS_NODE.equals(method.getDeclaringClass()) || scope.isDefaultCategory(method.getDeclaringClass())); } - protected static boolean isDefaultGroovyStaticMethod(MethodNode method, VariableScope scope) { + protected static boolean isDefaultGroovyStaticMethod(final MethodNode method, final VariableScope scope) { return (VariableScope.DGSM_CLASS_NODE.equals(method.getDeclaringClass()) || scope.isDefaultStaticCategory(method.getDeclaringClass())); } /** * Selects the candidate that most closely matches the method call arguments. */ - protected static MethodNode selectBestMatch(List candidates, List argumentTypes) { + protected static MethodNode selectBestMatch(final List candidates, final List argumentTypes) { MethodNode method = null; for (MethodNode candidate : candidates) { if (argumentTypes.size() == candidate.getParameters().length) { @@ -170,8 +170,14 @@ protected static MethodNode selectBestMatch(List candidates, List arguments, Parameter[] parameters) { + protected static long calculateParameterDistance(final List arguments, final Parameter[] parameters) { try { + if (arguments.size() == 1 && parameters.length == 1) { + Class[] args = {arguments.get(0).getTypeClass()}; + Class[] prms = {parameters[0].getType().getTypeClass()}; + return MetaClassHelper.calculateParameterDistance(args, new ParameterTypes(prms)); + } + // weight self type higher to prevent considering getAt(Map, Object) // and getAt(Object, String) equally for the arguments (Map, String) diff --git a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy index d16616d253..da5e8c8742 100644 --- a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy @@ -771,7 +771,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { @Test void testCodeSelectConstuctorMultipleConstructors3() { - IMethod method = assertConstructor('new Date(0L)', 'Date') + IMethod method = assertConstructor('new Date(0)', 'Date') assert method.parameters.length == 1: 'Should have found constructor with 1 arg' assert method.parameterTypes[0] == 'J' : 'Should have found constructor Date(long)' } diff --git a/ide/org.codehaus.groovy.eclipse.codeassist/src/org/codehaus/groovy/eclipse/codeassist/completions/GroovyExtendedCompletionContext.java b/ide/org.codehaus.groovy.eclipse.codeassist/src/org/codehaus/groovy/eclipse/codeassist/completions/GroovyExtendedCompletionContext.java index c24baf2117..26611906b8 100644 --- a/ide/org.codehaus.groovy.eclipse.codeassist/src/org/codehaus/groovy/eclipse/codeassist/completions/GroovyExtendedCompletionContext.java +++ b/ide/org.codehaus.groovy.eclipse.codeassist/src/org/codehaus/groovy/eclipse/codeassist/completions/GroovyExtendedCompletionContext.java @@ -158,7 +158,8 @@ protected void addFields(ClassNode targetType, Map visible } for (IMethod method : type.getMethods()) { ClassNode methodReturnTypeClassNode = toClassNode(method.getReturnType()); - if (GroovyUtils.isAssignable(methodReturnTypeClassNode, targetType)) { + if (!VariableScope.VOID_CLASS_NODE.equals(methodReturnTypeClassNode) && + GroovyUtils.isAssignable(methodReturnTypeClassNode, targetType)) { if ((method.getParameterTypes() == null || method.getParameterTypes().length == 0) && (method.getElementName().startsWith("get") || method.getElementName().startsWith("is"))) { visibleElements.putIfAbsent(method.getElementName(), method);