Fix anonymous classes directly from interfaces

- Fix the failing scenarios such as new Comaprator<String>() {...
This commit is contained in:
Juan Martín Sotuyo Dodero
2017-06-30 00:50:03 -03:00
parent 10aab46ba6
commit deaa47ebb0
3 changed files with 40 additions and 7 deletions

View File

@ -26,9 +26,14 @@ public class JavaTypeDefinition implements TypeDefinition {
this.clazz = clazz;
final TypeVariable<?>[] typeParameters;
// the anonymous class can't have generics, but we may be binding generics from super classes
if (clazz.isAnonymousClass()) {
// the anonymous class can't have generics, but we may be bounding generics from super classes
typeParameters = resolveTypeDefinition(clazz.getGenericSuperclass()).clazz.getTypeParameters();
// is this an anonymous class based on an interface or a class?
if (clazz.getSuperclass() == Object.class) {
typeParameters = clazz.getInterfaces()[0].getTypeParameters();
} else {
typeParameters = clazz.getSuperclass().getTypeParameters();
}
} else {
typeParameters = clazz.getTypeParameters();
}
@ -54,7 +59,7 @@ public class JavaTypeDefinition implements TypeDefinition {
}
final JavaTypeDefinition newDef = new JavaTypeDefinition(clazz);
// We can only cache types without generics, since their values are context-based
if (!newDef.isGeneric) {
CLASS_TYPE_DEF_CACHE.put(clazz, newDef);
@ -64,13 +69,13 @@ public class JavaTypeDefinition implements TypeDefinition {
}
public static JavaTypeDefinition forClass(final Class<?> clazz, final JavaTypeDefinition... boundGenerics) {
// With generics there is no cache
final JavaTypeDefinition typeDef = forClass(clazz);
if (typeDef == null) {
if (clazz == null) {
return null;
}
// With generics there is no cache
final JavaTypeDefinition typeDef = new JavaTypeDefinition(clazz);
for (final JavaTypeDefinition generic : boundGenerics) {
typeDef.genericArgs.add(generic);
}

View File

@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
@ -49,6 +50,7 @@ import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver;
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
import net.sourceforge.pmd.typeresolution.testdata.AnonymousClassFromInterface;
import net.sourceforge.pmd.typeresolution.testdata.AnonymousInnerClass;
import net.sourceforge.pmd.typeresolution.testdata.ArrayListFound;
import net.sourceforge.pmd.typeresolution.testdata.DefaultJavaLangImport;
@ -170,6 +172,15 @@ public class ClassTypeResolverTest {
Assert.assertTrue(statement.isReferenceToClassSameCompilationUnit());
}
@Test
public void testAnonymousClassFromInterface() throws Exception {
Node acu = parseAndTypeResolveForClass(AnonymousClassFromInterface.class, "1.8");
ASTAllocationExpression allocationExpression = acu.getFirstDescendantOfType(ASTAllocationExpression.class);
TypeNode child = (TypeNode) allocationExpression.jjtGetChild(0);
Assert.assertTrue(Comparator.class.isAssignableFrom(child.getType()));
Assert.assertSame(Integer.class, child.getTypeDefinition().getGenericType(0).getType());
}
@Test
public void testAnonymousInnerClass() throws ClassNotFoundException {
ASTCompilationUnit acu = parseAndTypeResolveForClass15(AnonymousInnerClass.class);

View File

@ -0,0 +1,17 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.typeresolution.testdata;
import java.util.Comparator;
public class AnonymousClassFromInterface {
public Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
};
}