Skip to content

Commit

Permalink
Fix for #1560: include implicit interfaces in type hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Mar 21, 2024
1 parent ff3e9da commit 3e57ba2
Show file tree
Hide file tree
Showing 16 changed files with 271 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -3785,4 +3785,27 @@ public void testTypeAnnotation() throws Exception {
expectingCompiledClasses("p2.Script");
expectingNoProblems();
}

@Test // https://github.com/groovy/groovy-eclipse/issues/1560
public void testTypeHierarchy() throws Exception {
IPath[] paths = createSimpleProject("Project", true);

//@formatter:off
IPath path = env.addGroovyClass(paths[1], "Runs",
"class Runs implements Runnable {\n" +
" @Override void run() {\n" +
" }\n" +
"}\n");
//@formatter:on

IType type = env.getUnit(path).findPrimaryType();
var region = JavaCore.newRegion();
region.add(type);

IType[] interfaces = JavaCore.newTypeHierarchy(region, null, null).getSuperInterfaces(type);

assertEquals(2, interfaces.length);
assertEquals("Runnable", interfaces[0].getElementName());
assertEquals("GroovyObject", interfaces[1].getElementName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7721,7 +7721,7 @@ public void testCompileStatic10381() {
"1. ERROR in Main.groovy (at line 2)\n" +
"\tclass C implements p.A, p.B {\n" +
"\t ^\n" +
"Duplicate default methods named m with the parameters () and () are inherited from the types A and B\n" +
"Duplicate default methods named m with the parameters () and () are inherited from the types B and A\n" +
"----------\n");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -103,11 +102,10 @@ protected MethodBinding[] augmentMethodBindings(final MethodBinding[] methodBind

boolean implementsGroovyObject = false;
ReferenceBinding[] superInterfaces = sourceType.superInterfaces();
if (superInterfaces == null) superInterfaces = new ReferenceBinding[0];
if (superInterfaces.length > 1) Collections.reverse(Arrays.asList(superInterfaces));
if (superInterfaces == null) superInterfaces = Binding.NO_SUPERINTERFACES;

for (ReferenceBinding superInterface : superInterfaces) {
if (CharOperation.equals(superInterface.compoundName, GroovyCompilationUnitScope.GROOVY_LANG_GROOVYOBJECT)) {
for (int i = superInterfaces.length; i != 0;) {
if (CharOperation.equals(superInterfaces[--i].compoundName, GroovyCompilationUnitScope.GROOVY_LANG_GROOVYOBJECT)) {
implementsGroovyObject = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GROOVY PATCHED
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -149,9 +149,8 @@ public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestrict
this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
this.lookupEnvironment.completeTypeBindings(parsedUnit, true); // work done inside checkAndSetImports()
} else {
//System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
this.lookupEnvironment.problemReporter.abortDueToInternalError(
new StringBuffer(Messages.accept_cannot)
new StringBuilder(Messages.accept_cannot)
.append(sourceUnit.getFileName())
.toString());
}
Expand Down Expand Up @@ -226,7 +225,7 @@ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
if (typeBinding.isHierarchyInconsistent()) {
if (superBinding.problemId() == ProblemReasons.NotFound) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(superBinding.sourceName)); // note: this could be Map$Entry
this.builder.hierarchy.missingTypes.add(String.valueOf(superBinding.sourceName)); // note: this could be Map$Entry
return null;
} else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
char[] superclassName;
Expand All @@ -249,7 +248,7 @@ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(simpleName));
this.builder.hierarchy.missingTypes.add(String.valueOf(simpleName));
return null;
}
}
Expand Down Expand Up @@ -299,17 +298,17 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind
superInterfaceNames = hierarchyType.superInterfaceNames;
}
separator = '.';
} else{
} else {
return null;
}

ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
int bindingIndex = 0;
int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
IType[] superinterfaces = new IType[length];
IType[] superinterfaces = new IType[Math.max(bindingLength, length)];
int index = 0;
next : for (int i = 0; i < length; i++) {
next : for (int i = 0; i < length; i += 1) {
char[] superInterfaceName = superInterfaceNames[i];
int end = superInterfaceName.length;

Expand All @@ -332,7 +331,7 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind

// ensure that the binding corresponds to the interface defined by the user
if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
bindingIndex++;
bindingIndex += 1;
IGenericType genericType = this.bindingMap.get(interfaceBinding);
if (genericType != null) {
IType handle = this.builder.getHandle(genericType, interfaceBinding);
Expand All @@ -343,9 +342,21 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind
}
}
}
this.builder.hierarchy.missingTypes.add(new String(simpleName));
this.builder.hierarchy.missingTypes.add(String.valueOf(simpleName));
}
// GROOVY add
while (bindingIndex < bindingLength) {
ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex++].erasure();
IGenericType genericType = this.bindingMap.get(interfaceBinding);
if (genericType != null) {
var handle = this.builder.getHandle(genericType, interfaceBinding);
if (handle != null) {
superinterfaces[index++] = handle;
}
}
}
if (index != length)
// GROOVY end
if (index != superinterfaces.length)
System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
return superinterfaces;
}
Expand Down Expand Up @@ -413,7 +424,7 @@ private void fixSupertypeBindings() {
} catch (AbortCompilation e) {
// allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
this.builder.hierarchy.missingTypes.add(new String(typeBinding.superclass().sourceName()));
this.builder.hierarchy.missingTypes.add(String.valueOf(typeBinding.superclass().sourceName()));
this.hasMissingSuperClass = true;
}
try {
Expand Down Expand Up @@ -511,7 +522,7 @@ private void rememberAllTypes(CompilationUnitDeclaration parsedUnit, org.eclipse
if (types != null) {
for (int i = 0, length = types.length; i < length; i++) {
TypeDeclaration type = types[i];
rememberWithMemberTypes(type, cu.getType(new String(type.name)));
rememberWithMemberTypes(type, cu.getType(String.valueOf(type.name)));
}
}
if (!includeLocalTypes || (parsedUnit.localTypes == null && parsedUnit.functionalExpressions == null))
Expand Down Expand Up @@ -549,7 +560,7 @@ private void rememberWithMemberTypes(TypeDeclaration typeDecl, IType typeHandle)
if (memberTypes != null) {
for (int i = 0, length = memberTypes.length; i < length; i++) {
TypeDeclaration memberType = memberTypes[i];
rememberWithMemberTypes(memberType, typeHandle.getType(new String(memberType.name)));
rememberWithMemberTypes(memberType, typeHandle.getType(String.valueOf(memberType.name)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GROOVY PATCHED
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -149,9 +149,8 @@ public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestrict
this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
this.lookupEnvironment.completeTypeBindings(parsedUnit, true); // work done inside checkAndSetImports()
} else {
//System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
this.lookupEnvironment.problemReporter.abortDueToInternalError(
new StringBuffer(Messages.accept_cannot)
new StringBuilder(Messages.accept_cannot)
.append(sourceUnit.getFileName())
.toString());
}
Expand Down Expand Up @@ -226,7 +225,7 @@ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
if (typeBinding.isHierarchyInconsistent()) {
if (superBinding.problemId() == ProblemReasons.NotFound) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(superBinding.sourceName)); // note: this could be Map$Entry
this.builder.hierarchy.missingTypes.add(String.valueOf(superBinding.sourceName)); // note: this could be Map$Entry
return null;
} else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
char[] superclassName;
Expand All @@ -249,7 +248,7 @@ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
this.hasMissingSuperClass = true;
this.builder.hierarchy.missingTypes.add(new String(simpleName));
this.builder.hierarchy.missingTypes.add(String.valueOf(simpleName));
return null;
}
}
Expand Down Expand Up @@ -299,17 +298,17 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind
superInterfaceNames = hierarchyType.superInterfaceNames;
}
separator = '.';
} else{
} else {
return null;
}

ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
int bindingIndex = 0;
int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
IType[] superinterfaces = new IType[length];
IType[] superinterfaces = new IType[Math.max(bindingLength, length)];
int index = 0;
next : for (int i = 0; i < length; i++) {
next : for (int i = 0; i < length; i += 1) {
char[] superInterfaceName = superInterfaceNames[i];
int end = superInterfaceName.length;

Expand All @@ -332,7 +331,7 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind

// ensure that the binding corresponds to the interface defined by the user
if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
bindingIndex++;
bindingIndex += 1;
IGenericType genericType = this.bindingMap.get(interfaceBinding);
if (genericType != null) {
IType handle = this.builder.getHandle(genericType, interfaceBinding);
Expand All @@ -343,9 +342,21 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind
}
}
}
this.builder.hierarchy.missingTypes.add(new String(simpleName));
this.builder.hierarchy.missingTypes.add(String.valueOf(simpleName));
}
// GROOVY add
while (bindingIndex < bindingLength) {
ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex++].erasure();
IGenericType genericType = this.bindingMap.get(interfaceBinding);
if (genericType != null) {
var handle = this.builder.getHandle(genericType, interfaceBinding);
if (handle != null) {
superinterfaces[index++] = handle;
}
}
}
if (index != length)
// GROOVY end
if (index != superinterfaces.length)
System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
return superinterfaces;
}
Expand Down Expand Up @@ -413,7 +424,7 @@ private void fixSupertypeBindings() {
} catch (AbortCompilation e) {
// allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
this.builder.hierarchy.missingTypes.add(new String(typeBinding.superclass().sourceName()));
this.builder.hierarchy.missingTypes.add(String.valueOf(typeBinding.superclass().sourceName()));
this.hasMissingSuperClass = true;
}
try {
Expand Down Expand Up @@ -511,7 +522,7 @@ private void rememberAllTypes(CompilationUnitDeclaration parsedUnit, org.eclipse
if (types != null) {
for (int i = 0, length = types.length; i < length; i++) {
TypeDeclaration type = types[i];
rememberWithMemberTypes(type, cu.getType(new String(type.name)));
rememberWithMemberTypes(type, cu.getType(String.valueOf(type.name)));
}
}
if (!includeLocalTypes || (parsedUnit.localTypes.isEmpty() && parsedUnit.functionalExpressions == null))
Expand Down Expand Up @@ -546,7 +557,7 @@ private void rememberWithMemberTypes(TypeDeclaration typeDecl, IType typeHandle)
if (memberTypes != null) {
for (int i = 0, length = memberTypes.length; i < length; i++) {
TypeDeclaration memberType = memberTypes[i];
rememberWithMemberTypes(memberType, typeHandle.getType(new String(memberType.name)));
rememberWithMemberTypes(memberType, typeHandle.getType(String.valueOf(memberType.name)));
}
}
}
Expand Down
Loading

0 comments on commit 3e57ba2

Please sign in to comment.