From 0e249b38eff264c184a76d9d196c00d850eeaea8 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Sat, 30 Mar 2024 14:28:36 -0500 Subject: [PATCH] Fix for #1564: find and resolve declaration from type variable bound(s) --- .../search/DeclarationInferencingTests.java | 4 +- .../tests/search/GenericInferencingTests.java | 51 ++++++++++++++++--- .../tests/search/InferencingTestSuite.java | 4 +- .../groovy/tests/search/InferencingTests.java | 10 ++-- .../tests/search/StaticInferencingTests.java | 12 ++--- .../tests/search/TraitInferencingTests.java | 3 +- .../jdt/groovy/search/SimpleTypeLookup.java | 31 ++++++----- .../jdt/groovy/search/TypeLookupResult.java | 10 ++-- .../tests/CodeSelectFieldsTests.groovy | 4 +- .../tests/CodeSelectMethodsTests.groovy | 6 +-- .../eclipse/core/inference/STCTypeLookup.java | 3 +- 11 files changed, 94 insertions(+), 44 deletions(-) diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DeclarationInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DeclarationInferencingTests.java index 3e0e144e54..378afc58c7 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DeclarationInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/DeclarationInferencingTests.java @@ -1613,11 +1613,11 @@ public void testJavaInterfaceWithDefaultMethod3() { int offset = contents.indexOf("toArray"); try { // Java 11 adds default method toArray(IntFunction) to the Collection interface java.util.Collection.class.getDeclaredMethod("toArray", java.util.function.IntFunction.class); - MethodNode method = assertDeclaration(contents, offset, offset + 7, "java.util.Collection", "toArray", DeclarationKind.METHOD); + MethodNode method = assertDeclaration(contents, offset, offset + 7, "java.util.Collection", "toArray", DeclarationKind.METHOD); assertEquals("java.util.function.IntFunction", printTypeName(method.getParameters()[0].getType())); assertType(contents, "n", "java.lang.Integer"); } catch (Exception e) { - MethodNode method = assertDeclaration(contents, offset, offset + 7, "java.util.List", "toArray", DeclarationKind.METHOD); + MethodNode method = assertDeclaration(contents, offset, offset + 7, "java.util.List", "toArray", DeclarationKind.METHOD); assertEquals("T[]", printTypeName(method.getParameters()[0].getType())); } } diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java index 49bc996e45..c5028b5efa 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java @@ -584,7 +584,7 @@ public void testMap22() { assertType(contents, offset, offset + 3, "java.util.LinkedHashMap"); offset = contents.indexOf(".&put") + 2; - assertDeclaration(contents, offset, offset + 3, "java.util.HashMap", "put", DeclarationKind.METHOD); + assertDeclaration(contents, offset, offset + 3, "java.util.HashMap", "put", DeclarationKind.METHOD); offset = contents.indexOf("put("); assertType(contents, offset, offset + 3, "groovy.lang.Closure"); @@ -601,7 +601,7 @@ public void testMap22() { // offset = contents.lastIndexOf(".&put") + 2; - assertDeclaration(contents, offset, offset + 3, "java.util.HashMap", "put", DeclarationKind.METHOD); + assertDeclaration(contents, offset, offset + 3, "java.util.HashMap", "put", DeclarationKind.METHOD); offset = contents.lastIndexOf("put("); assertType(contents, offset, offset + 3, "groovy.lang.Closure"); @@ -1011,7 +1011,7 @@ public void testClosure16() { assumeTrue(isParrotParser()); String contents = "Optional.of(21).map(num -> num * 2).get()\n"; assertType(contents, "get", "java.lang.Integer"); - assertDeclaringType(contents, "get", "java.util.Optional"); + assertDeclaringType(contents, "get", "java.util.Optional"); } @Test // https://github.com/groovy/groovy-eclipse/issues/1199 @@ -1182,6 +1182,45 @@ public void testTypeVariable3() { assertDeclaringType(contents, "getName", "java.lang.Thread"); } + @Test // https://github.com/groovy/groovy-eclipse/issues/1564 + public void testTypeVariable4() { + String contents = + "class C {\n" + + " void test(T thingy) {\n" + + " thingy.run()\n" + + " }\n" + + "}\n"; + + assertType(contents, "run", "java.lang.Void"); + assertDeclaringType(contents, "run", "java.lang.Runnable"); + } + + @Test + public void testTypeVariable5() { + String contents = + "class C> {\n" + + " void test(T thingy) {\n" + + " thingy.get(0)\n" + + " }\n" + + "}\n"; + + assertType(contents, "get", "java.lang.String"); + assertDeclaringType(contents, "get", "java.util.List"); + } + + @Test + public void testTypeVariable6() { + String contents = + "class C> {\n" + + " void test(T thingy) {\n" + + " thingy.get(0)\n" + + " }\n" + + "}\n"; + + assertType(contents, "get", "java.lang.String"); + assertDeclaringType(contents, "get", "java.util.List"); + } + @Test // GRECLIPSE-997 public void testNestedGenerics1() { String contents = @@ -1288,7 +1327,7 @@ public void testNestedGenerics9() { "use(Cat){new DirectChannelSpec().m()}\n"; assertType(contents, "prop", "X"); - assertDeclaringType(contents, "prop", "ChannelSpec"); + assertDeclaringType(contents, "prop", "ChannelSpec"); assertType(contents, "m", "DirectChannelSpec"); // GROOVY-10887 } @@ -1602,7 +1641,7 @@ public void testStaticMethod11() { String toFind = "removeAll"; int start = contents.indexOf(toFind), end = start + toFind.length(); assertType(contents, start, end, "java.lang.Boolean"); - MethodNode m = assertDeclaration(contents, start, end, "java.util.List", toFind, DeclarationKind.METHOD); + MethodNode m = assertDeclaration(contents, start, end, "java.util.List", toFind, DeclarationKind.METHOD); assertEquals("java.util.Collection", printTypeName(m.getParameters()[0].getType())); } @@ -1613,7 +1652,7 @@ public void testStaticMethod12() { String toFind = "addAll"; int start = contents.indexOf(toFind), end = start + toFind.length(); assertType(contents, start, end, "java.lang.Boolean"); - MethodNode m = assertDeclaration(contents, start, end, "java.util.List", toFind, DeclarationKind.METHOD); + MethodNode m = assertDeclaration(contents, start, end, "java.util.List", toFind, DeclarationKind.METHOD); assertEquals("Parameter type should be resolved", "java.util.Collection", printTypeName(m.getParameters()[0].getType())); } diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTestSuite.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTestSuite.java index c4ce2f01ea..c6c712efd3 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTestSuite.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTestSuite.java @@ -147,8 +147,8 @@ private SearchRequestor assertDeclaringType(GroovyCompilationUnit unit, int expr return requestor; } - protected N assertDeclaration(String contents, int exprStart, int exprUntil, String expectedType, String name, DeclarationKind kind) { - SearchRequestor requestor = assertDeclaringType(createUnit(DEFAULT_UNIT_NAME, contents), exprStart, exprUntil, expectedType, false); + protected N assertDeclaration(String contents, int exprStart, int exprUntil, String expectedDeclType, String name, DeclarationKind kind) { + SearchRequestor requestor = assertDeclaringType(createUnit(DEFAULT_UNIT_NAME, contents), exprStart, exprUntil, expectedDeclType, false); switch (kind) { case CLASS: diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTests.java index fa044a3d7e..e713a14dcb 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/InferencingTests.java @@ -1790,7 +1790,7 @@ public void testSuperInterfaceMethod2() { assertUnknown(contents, "reversed"); } else { assertType(contents, "reversed", "java.util.Comparator"); - assertDeclaringType(contents, "reversed", "java.util.Comparator"); + assertDeclaringType(contents, "reversed", "java.util.Comparator"); } } @@ -2314,7 +2314,7 @@ public void testAnonInner5() { public void testAnonInner6() { String contents = "def aic = new Comparable() {\n int compareTo(String that) {}\n}\n" + "aic.compareTo('x')"; - assertDeclaringType(contents, "compareTo", "java.lang.Comparable"); + assertDeclaringType(contents, "compareTo", "java.lang.Comparable"); } @Test @@ -2322,7 +2322,7 @@ public void testAnonInner7() { String contents = "def aic = new Comparable() {\n int compareTo(Integer that) {}\n}\n" + "aic = new Comparable() {\n int compareTo(String that) {}\n}\n" + "aic.compareTo('x')"; - assertDeclaringType(contents, "compareTo", "java.lang.Comparable"); + assertDeclaringType(contents, "compareTo", "java.lang.Comparable"); } @Test // https://github.com/groovy/groovy-eclipse/issues/378 @@ -2543,7 +2543,7 @@ public void testListSort3() { "} as Comparator)\n"; int offset = contents.lastIndexOf("sort"); assertType(contents, offset, offset + 4, jdkListSort ? "java.lang.Void" : "java.util.List"); - assertDeclaringType(contents, offset, offset + 4, jdkListSort ? "java.util.List" : "org.codehaus.groovy.runtime.DefaultGroovyMethods"); + assertDeclaringType(contents, offset, offset + 4, jdkListSort ? "java.util.List" : "org.codehaus.groovy.runtime.DefaultGroovyMethods"); } @Test // https://github.com/groovy/groovy-eclipse/issues/368 @@ -2561,7 +2561,7 @@ public void testListRemove() { " }\n" + "}"; int offset = contents.indexOf("a.remove") + 2; - MethodNode m = assertDeclaration(contents, offset, offset + "remove".length(), "java.util.List", "remove", DeclarationKind.METHOD); + MethodNode m = assertDeclaration(contents, offset, offset + "remove".length(), "java.util.List", "remove", DeclarationKind.METHOD); assertEquals("Should resolve to remove(int) due to return type of inner call", "int", printTypeName(m.getParameters()[0].getType())); } diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/StaticInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/StaticInferencingTests.java index d6b8857765..29ff81cf05 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/StaticInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/StaticInferencingTests.java @@ -173,42 +173,42 @@ public void testClassReference20() { public void testClassReference22() { String contents = "String.getPackage()"; assertType(contents, "getPackage", "java.lang.Package"); - assertDeclaringType(contents, "getPackage", "java.lang.Class"); + assertDeclaringType(contents, "getPackage", "java.lang.Class"); } @Test public void testClassReference23() { String contents = "String.package"; assertType(contents, "package", "java.lang.Package"); - assertDeclaringType(contents, "package", "java.lang.Class"); + assertDeclaringType(contents, "package", "java.lang.Class"); } @Test public void testClassReference24() { String contents = "String.class.getPackage()"; assertType(contents, "getPackage", "java.lang.Package"); - assertDeclaringType(contents, "getPackage", "java.lang.Class"); + assertDeclaringType(contents, "getPackage", "java.lang.Class"); } @Test public void testClassReference25() { String contents = "String.class.package"; assertType(contents, "package", "java.lang.Package"); - assertDeclaringType(contents, "package", "java.lang.Class"); + assertDeclaringType(contents, "package", "java.lang.Class"); } @Test public void testClassReference26() { String contents = "def clazz = String; clazz.getPackage()"; assertType(contents, "getPackage", "java.lang.Package"); - assertDeclaringType(contents, "getPackage", "java.lang.Class"); + assertDeclaringType(contents, "getPackage", "java.lang.Class"); } @Test public void testClassReference27() { String contents = "def clazz = String; clazz.package"; assertType(contents, "package", "java.lang.Package"); - assertDeclaringType(contents, "package", "java.lang.Class"); + assertDeclaringType(contents, "package", "java.lang.Class"); } @Test diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/TraitInferencingTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/TraitInferencingTests.java index 51e7eaa488..b451def388 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/TraitInferencingTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/TraitInferencingTests.java @@ -799,7 +799,8 @@ public void testPublicMethod7() { "}\n"; //@formatter:on - assertDeclType(source, "m", "A"); + assertDeclType(source, "m", "A"); + assertExprType(source, "m", "java.lang.Number"); assertExprType(source, "x", "java.lang.Number"); } diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/SimpleTypeLookup.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/SimpleTypeLookup.java index c5874a824d..b93394eceb 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/SimpleTypeLookup.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/SimpleTypeLookup.java @@ -98,12 +98,12 @@ public TypeLookupResult lookupType(final Expression node, final VariableScope sc @Override public TypeLookupResult lookupType(final FieldNode node, final VariableScope scope) { - return new TypeLookupResult(node.getType(), node.getDeclaringClass(), node, TypeConfidence.EXACT, scope); + return new TypeLookupResult(node.getType(), getDeclaringTypeFromDeclaration(node, null), node, TypeConfidence.EXACT, scope); } @Override public TypeLookupResult lookupType(final MethodNode node, final VariableScope scope) { - return new TypeLookupResult(node.getReturnType(), node.getDeclaringClass(), node, TypeConfidence.EXACT, scope); + return new TypeLookupResult(node.getReturnType(), getDeclaringTypeFromDeclaration(node, null), node, TypeConfidence.EXACT, scope); } @Override @@ -118,7 +118,7 @@ public TypeLookupResult lookupType(final ClassNode node, final VariableScope sco type = node.getOuterClass(); } } - return new TypeLookupResult(type, type, node, TypeConfidence.EXACT, scope); + return new TypeLookupResult(type, type.getPlainNodeReference(), node, TypeConfidence.EXACT, scope); } @Override @@ -173,7 +173,7 @@ protected TypeLookupResult findType(final Expression node, final ClassNode decla MethodNode target; // use value from node metadata if it's available if (scope.isMethodCall() && (target = getMethodTarget(node)) != null) { - return new TypeLookupResult(target.getReturnType(), target.getDeclaringClass(), target, confidence, scope); + return new TypeLookupResult(target.getReturnType(), getDeclaringTypeFromDeclaration(target, declaringType), target, confidence, scope); } if (node instanceof VariableExpression) { @@ -434,7 +434,7 @@ protected TypeLookupResult findTypeForNameWithKnownObjectExpression(final String confidence = TypeConfidence.LOOSELY_INFERRED; } if (method != method.getOriginal() && (isTraitBridge(method) || isTraitHelper(method.getDeclaringClass()))) { - resolvedDeclaringType = method.getOriginal().getDeclaringClass(); + resolvedDeclaringType = getDeclaringTypeFromDeclaration(method.getOriginal(), resolvedDeclaringType); declaration = method.getOriginal(); // the trait method } } @@ -505,7 +505,7 @@ protected TypeLookupResult findTypeForVariable(final VariableExpression var, fin } type = getTypeFromDeclaration(decl); - resolvedDeclaringType = ((AnnotatedNode) decl).getDeclaringClass(); + resolvedDeclaringType = getDeclaringTypeFromDeclaration(decl, declaringType); if (decl instanceof MethodNode || !((Variable) decl).isDynamicTyped()) variableInfo = null; } } else if (accessedVar instanceof DynamicVariable) { @@ -643,6 +643,17 @@ protected ASTNode findDeclaration(final String name, final ClassNode declaringTy return findDeclaration(name, VariableScope.OBJECT_CLASS_NODE, isLhsExpression, isStaticExpression, 0, methodCallArgumentTypes); } + if (declaringType.isGenericsPlaceHolder()) { + ClassNode[] bounds = GroovyUtils.getTypeParameterBounds(declaringType); + for (ClassNode tvb : bounds) { + ASTNode decl = findDeclaration(name, tvb, isLhsExpression, isStaticExpression, directFieldAccess, methodCallArgumentTypes); + if (decl != null) { + return decl; + } + } + if (bounds.length > 0) return null; + } + boolean isCallExpression = (!isLhsExpression && methodCallArgumentTypes != null); if (isCallExpression) { @@ -1092,13 +1103,7 @@ protected static ClassNode getDeclaringTypeFromDeclaration(final ASTNode declara } else { declaringType = VariableScope.OBJECT_CLASS_NODE; } - // retain inferredDeclaringType's generics if possible - if (inferredDeclaringType.equals(declaringType) && - !inferredDeclaringType.isGenericsPlaceHolder()) { - return inferredDeclaringType; - } else { - return declaringType.getPlainNodeReference(); - } + return declaringType.getPlainNodeReference(); // Java includes type args } protected static Optional findTraitField(final String name, final ClassNode type) { diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/TypeLookupResult.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/TypeLookupResult.java index c0356dc488..e869f4f17e 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/TypeLookupResult.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/TypeLookupResult.java @@ -170,6 +170,10 @@ public TypeLookupResult resolveTypeParameterization(final ClassNode objExprType, } if (ClassHelper.isPrimitiveType(objectType)) { objectType = ClassHelper.getWrapper(objectType); + } else if (objectType.isGenericsPlaceHolder()) { // T extends Type & Face; select Type or Face + objectType = Arrays.stream(GroovyUtils.getTypeParameterBounds(objectType)).filter(bound -> + bound.isDerivedFrom(declaringType) || bound.implementsInterface(declaringType) + ).findFirst().orElse(objectType); } else if (objectType.equals(VariableScope.CLASS_CLASS_NODE) && !declaringType.equals(VariableScope.CLASS_CLASS_NODE) && !isGroovy) { objectType = VariableScope.getFirstGenerics(objectType); // peel Class<> @@ -186,7 +190,7 @@ public TypeLookupResult resolveTypeParameterization(final ClassNode objExprType, if (!isStatic && method.getName().equals("getClass") && method.getParameters().length == 0) { ClassNode classType = VariableScope.clone(method.getReturnType()); classType.getGenericsTypes()[0].setUpperBounds(new ClassNode[] {objectType}); - return new TypeLookupResult(classType, method.getDeclaringClass(), method, confidence, scope, extraDoc); + return new TypeLookupResult(classType, declaringType, method, confidence, scope, extraDoc); } if (!GroovyUtils.isUsingGenerics(method) || !(GenericsUtils.hasUnresolvedGenerics(method.getReturnType()) || GroovyUtils.getParameterTypes(method.getParameters()).stream().anyMatch(GenericsUtils::hasUnresolvedGenerics))) { @@ -220,7 +224,7 @@ public TypeLookupResult resolveTypeParameterization(final ClassNode objExprType, MethodNode source = method; // effectively final version Parameter target = params[Math.min(index, params.length - 1)]; method = findClosureSignature(target, source, scope.getEnclosingModuleNode().getContext(), cat.call).map(types -> { - GenericsMapper gm = GenericsMapper.gatherGenerics(java.util.Arrays.asList(types), cat.declaringType, source); + GenericsMapper gm = GenericsMapper.gatherGenerics(Arrays.asList(types), cat.declaringType, source); MethodNode mn = VariableScope.resolveTypeParameterization(gm, source); return mn; }).orElse(method); @@ -280,7 +284,7 @@ public TypeLookupResult resolveTypeParameterization(final ClassNode objExprType, } if (method != declaration || returnType != method.getReturnType()) { - return new TypeLookupResult(returnType, method.getDeclaringClass(), method, this); + return new TypeLookupResult(returnType, declaringType, method, this); } } } diff --git a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy index 0b415efba8..87fe55100f 100644 --- a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ final class CodeSelectFieldsTests extends BrowsingTestSuite { | } |}'''.stripMargin() ], 'items') - assert elem.key == 'LFoo;.items)Ljava/util/List;' + assert elem.key == 'LFoo;.items)Ljava/util/List;' } @Test 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 8c99246344..337cec68e0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -184,7 +184,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { assert element.declaringType.fullyQualifiedName == 'SuperInterface' } - @Test // https://github.com/groovy/groovy-eclipse/issues/145x + @Test // https://github.com/groovy/groovy-eclipse/issues/1457 void testCodeSelectMethodInParameterizedClass() { String contents = '''\ |class Foo { @@ -196,7 +196,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { |} |'''.stripMargin() IJavaElement element = assertCodeSelect([contents], 'meth') - assert element.key == 'LFoo;.meth(Ljava/util/Set;)Ljava/util/Set;' + assert element.key == 'LFoo;.meth(Ljava/util/Set;)Ljava/util/Set;' } @Test diff --git a/ide/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/inference/STCTypeLookup.java b/ide/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/inference/STCTypeLookup.java index b2cf0a14f9..e3abcb2806 100644 --- a/ide/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/inference/STCTypeLookup.java +++ b/ide/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/inference/STCTypeLookup.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -153,6 +153,7 @@ public TypeLookupResult lookupType(final Expression expr, final VariableScope sc } if (inferredType instanceof ClassNode) { + if (declaringType != null) declaringType = declaringType.getPlainNodeReference(); // compound assignment (+=, ?=, etc.) may involve separate declarations for read and write if (confidence.isAtLeast(TypeConfidence.INFERRED) && isCompoundAssignTarget(expr, scope)) { if (declaration instanceof MethodNode) {