Skip to content

Commit 285dd31

Browse files
committed
GROOVY-10887
1 parent 46b3df5 commit 285dd31

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/GenericInferencingTests.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2022 the original author or authors.
2+
* Copyright 2009-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1199,8 +1199,36 @@ public void testNestedGenerics8() {
11991199
assertType(contents, "val", "java.util.Map<java.lang.Class,java.lang.Class<java.lang.Integer>>");
12001200
}
12011201

1202-
@Test // https://github.com/groovy/groovy-eclipse/issues/1369
1202+
@Test
12031203
public void testNestedGenerics9() {
1204+
String contents =
1205+
"abstract class Channel {\n" +
1206+
"}\n" +
1207+
"class ChannelSpec<S extends ChannelSpec<S,C>, C extends Channel> {\n" +
1208+
" S prop(value) {\n" +
1209+
" this\n" +
1210+
" }\n" +
1211+
"}\n" +
1212+
"class Cat {\n" +
1213+
" static <X extends ChannelSpec<X,Y>, Y extends Channel> X m(X self) {\n" +
1214+
" self.prop(null)\n" + // returns self
1215+
" }\n" +
1216+
"}\n" +
1217+
1218+
"class DirectChannel extends Channel {\n" +
1219+
"}\n" +
1220+
"class DirectChannelSpec extends ChannelSpec<DirectChannelSpec,DirectChannel> {\n" +
1221+
"}\n" +
1222+
"use(Cat){new DirectChannelSpec().m()}\n";
1223+
1224+
assertType(contents, "prop", "X");
1225+
assertDeclaringType(contents, "prop", "ChannelSpec<X,Y>");
1226+
1227+
assertType(contents, "m", "DirectChannelSpec"); // GROOVY-10887
1228+
}
1229+
1230+
@Test // https://github.com/groovy/groovy-eclipse/issues/1369
1231+
public void testNestedGenerics10() {
12041232
String contents =
12051233
"interface Buildable<R> {\n" +
12061234
" R build()\n" +

base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/VariableScope.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2022 the original author or authors.
2+
* Copyright 2009-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1047,7 +1047,14 @@ public static void findAllInterfaces(ClassNode type, final Set<ClassNode> accumu
10471047
public static void createTypeHierarchy(ClassNode type, final Set<ClassNode> accumulator, final boolean useResolved) {
10481048
if (!useResolved) type = type.redirect();
10491049
if (!accumulator.contains(type)) {
1050+
ClassNode[] bounds = null;
10501051
if (!type.isInterface()) {
1052+
if (type.isGenericsPlaceHolder() && type.getGenericsTypes() != null) {
1053+
bounds = type.getGenericsTypes()[0].getUpperBounds();
1054+
if (bounds != null && bounds.length > 0) {
1055+
type = bounds[0]; // "T extends X ..."
1056+
}
1057+
}
10511058
accumulator.add(type);
10521059
// Groovy compiler has a different notion of 'resolved' than we do here.
10531060
// It considers a ClassNode resolved if it is primary or has type class.
@@ -1060,6 +1067,11 @@ public static void createTypeHierarchy(ClassNode type, final Set<ClassNode> accu
10601067
if (!type.equals(OBJECT_CLASS_NODE)) {
10611068
findAllInterfaces(type, accumulator, useResolved);
10621069
}
1070+
if (bounds != null && bounds.length > 1) {
1071+
for (int i = 1; i < bounds.length; i += 1) {
1072+
findAllInterfaces(bounds[i], accumulator, useResolved);
1073+
}
1074+
}
10631075
}
10641076
}
10651077

0 commit comments

Comments
 (0)