Skip to content

Commit

Permalink
Fix for #1372: concrete type property as interface default method
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Jun 15, 2022
1 parent 9ab1fd2 commit 98d9813
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ public void testJavaInterfaceWithDefaultMethod3() {
"List<String> list = []\n" +
"list.toArray { n ->\n" +
" new String[n]\n" +
"}\n";
"}";
//@formatter:on

int offset = contents.indexOf("toArray");
Expand All @@ -1327,26 +1327,6 @@ public void testJavaInterfaceWithDefaultMethod3() {
}
}

@Test // GROOVY-10592
public void testJavaInterfaceWithStaticMethod() {
//@formatter:off
createJavaUnit("I",
"public interface I {\n" +
" static C getP() {\n" +
" }\n" +
" class C {\n" +
" }\n" +
"}");

String contents =
"I.getP();" +
"I.p"; // XXX
//@formatter:on

assertKnown(contents, "getP", "I", "getP", DeclarationKind.METHOD);
assertUnknown(contents, "p");
}

@Test // GRECLIPSE-1105
public void testFluentInterfaceWithFieldNameConflicts() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2645,10 +2645,10 @@ public void testInterfaceMethodAsProperty1() {

String contents = "def meth(foo.Baz b) {\n b.one + b.two\n}";

int start = contents.indexOf("one");
assertDeclaringType(contents, start, start + 3, "foo.Bar");
start = contents.indexOf("two");
assertDeclaringType(contents, start, start + 3, "foo.Baz");
int offset = contents.indexOf("one");
assertDeclaringType(contents, offset, offset + 3, "foo.Bar");
/**/offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test
Expand All @@ -2658,10 +2658,10 @@ public void testInterfaceMethodAsProperty2() {

String contents = "def meth(foo.Baz b) {\n b.one + b.two\n}";

int start = contents.indexOf("one");
assertDeclaringType(contents, start, start + 3, "foo.Bar");
start = contents.indexOf("two");
assertDeclaringType(contents, start, start + 3, "foo.Baz");
int offset = contents.indexOf("one");
assertDeclaringType(contents, offset, offset + 3, "foo.Bar");
/**/offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test
Expand All @@ -2671,10 +2671,48 @@ public void testInterfaceMethodAsProperty3() {

String contents = "abstract class C extends foo.Baz {}\ndef meth(C c) {\n c.one + c.two\n}\n";

int start = contents.indexOf("one");
assertDeclaringType(contents, start, start + 3, "foo.Bar");
start = contents.indexOf("two");
assertDeclaringType(contents, start, start + 3, "foo.Baz");
int offset = contents.indexOf("one");
assertDeclaringType(contents, offset, offset + 3, "foo.Bar");
/**/offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test
public void testInterfaceMethodAsProperty4() {
createJavaUnit("foo", "Bar", "package foo; public interface Bar {\n default int getOne() {\n return 1;\n}\n}\n");
createUnit("foo", "Baz", "package foo; abstract class Baz implements Bar {\n abstract def getTwo()\n}\n");

String contents = "abstract class C extends foo.Baz {}\ndef meth(C c) {\n c.one + c.two\n}\n";

int offset = contents.indexOf("one");
assertDeclaringType(contents, offset, offset + 3, "foo.Bar");
/**/offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test // GROOVY-10592
public void testInterfaceMethodAsProperty5() {
createJavaUnit("foo", "Bar", "package foo; public interface Bar {\n static int getOne() {\n return 1;\n}\n}\n");
createUnit("foo", "Baz", "package foo; abstract class Baz implements Bar {\n abstract def getTwo()\n}\n");

String contents = "abstract class C extends foo.Baz {}\ndef meth(C c) {\n c.one + c.two\n}\n";

assertUnknown(contents, "one");
int offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test
public void testInterfaceMethodAsProperty6() {
createUnit("foo", "Bar", "package foo; trait Bar {\n int getOne() {\n 1\n}\n}\n");
createUnit("foo", "Baz", "package foo; abstract class Baz implements Bar {\n int getTwo() {\n 2\n}\n}\n");

String contents = "class C extends foo.Baz {}\ndef meth(C c) {\n c.one + c.two\n}\n";

int offset = contents.indexOf("one");
assertDeclaringType(contents, offset, offset + 3, "foo.Bar");
/**/offset = contents.indexOf("two");
assertDeclaringType(contents, offset, offset + 3, "foo.Baz");
}

@Test
Expand All @@ -2684,10 +2722,10 @@ public void testIndirectInterfaceMethod() {

String contents = "abstract class C extends foo.Baz {}\ndef meth(C c) {\n c.getOne() + c.getTwo()\n}\n";

int start = contents.indexOf("getOne");
assertDeclaringType(contents, start, start + 6, "foo.Bar");
start = contents.indexOf("getTwo");
assertDeclaringType(contents, start, start + 6, "foo.Baz");
int offset = contents.indexOf("getOne");
assertDeclaringType(contents, offset, offset + 6, "foo.Bar");
/**/offset = contents.indexOf("getTwo");
assertDeclaringType(contents, offset, offset + 6, "foo.Baz");
}

@Test
Expand All @@ -2697,10 +2735,10 @@ public void testIndirectInterfaceConstant() {

String contents = "abstract class B extends A {}\nB b; b.ONE; b.TWO\n";

int start = contents.indexOf("ONE");
assertDeclaringType(contents, start, start + 3, "I");
start = contents.indexOf("TWO");
assertDeclaringType(contents, start, start + 3, "A");
int offset = contents.indexOf("ONE");
assertDeclaringType(contents, offset, offset + 3, "I");
/**/offset = contents.indexOf("TWO");
assertDeclaringType(contents, offset, offset + 3, "A");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7410,4 +7410,29 @@ public void testCompileStatic10592() {

runConformTest(sources, "worksworks");
}

@Test
public void testTypeChecked10592a() {
//@formatter:off
String[] sources = {
"Main.groovy",
"class Impl implements Face { }\n" +
"@groovy.transform.CompileStatic\n" +
"void test(Impl impl) {\n" +
" print impl.getValue()\n" +
" print impl.value\n" +
"}\n" +
"test(new Impl())\n",

"Face.java",
"interface Face {\n" +
" default String getValue() {\n" +
" return \"works\";\n" +
" }\n" +
"}\n",
};
//@formatter:on

runConformTest(sources, "worksworks");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5724,6 +5724,31 @@ public void testTypeChecked10592() {
runConformTest(sources, "works", "groovy.lang.MissingPropertyException: No such property: value for class: Face");
}

@Test
public void testTypeChecked10592a() {
//@formatter:off
String[] sources = {
"Main.groovy",
"class Impl implements Face {}\n" +
"@groovy.transform.TypeChecked\n" +
"void test(Impl impl) {\n" +
" print impl.getValue()\n" +
" print impl.value\n" +
"}\n" +
"test(new Impl())\n",

"Face.java",
"interface Face {\n" +
" default String getValue() {\n" +
" return \"works\";\n" +
" }\n" +
"}\n",
};
//@formatter:on

runConformTest(sources, "worksworks");
}

@Test
public void testTypeChecked10624() {
//@formatter:off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/
package org.eclipse.jdt.groovy.search;

import static org.eclipse.jdt.groovy.search.GenericsMapper.isVargs;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
import static org.eclipse.jdt.groovy.core.util.GroovyUtils.implementsTrait;

import java.util.LinkedHashSet;
import java.util.Set;
Expand All @@ -26,7 +27,6 @@
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.runtime.MetaClassHelper;
import org.eclipse.jdt.groovy.core.util.GroovyUtils;

/**
* Kind of accessor a method name may be and then does further processing on a method node if the name matches.
Expand All @@ -52,7 +52,7 @@ public boolean isAccessorKind(MethodNode node, boolean isCategory) {
case GETTER:
return (parameters == null || parameters.length == (!isCategory ? 0 : 1)) && !node.isVoidMethod();
case SETTER:
return (parameters != null && parameters.length == (!isCategory ? 1 : 2)) && (!isCategory || !isVargs(parameters));
return (parameters != null && parameters.length == (!isCategory ? 1 : 2)) && (!isCategory || !GenericsMapper.isVargs(parameters));
case ISSER:
return (parameters == null || parameters.length == (!isCategory ? 0 : 1)) && node.getReturnType().equals(ClassHelper.boolean_TYPE);
default:
Expand Down Expand Up @@ -107,7 +107,7 @@ public static Stream<MethodNode> findAccessorMethodsForPropertyName(String name,
methods = Stream.concat(methods, findAccessorMethodsForMethodName(methodName, declaringType, isCategory, kind));

// abstract types do not track undeclared abstract methods; concrete types do not track interface default methods
if (declaringType.isAbstract() || declaringType.isInterface() || GroovyUtils.implementsTrait(declaringType)) {
if (declaringType.isAbstract() || asBoolean(declaringType.getInterfaces()) || implementsTrait(declaringType)) {
Set<ClassNode> faces = new LinkedHashSet<>();
VariableScope.findAllInterfaces(declaringType, faces, false);
faces.remove(declaringType); // checked already
Expand Down

0 comments on commit 98d9813

Please sign in to comment.