From deaa47ebb08dcf18b635cc626041a9f423d6c7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 30 Jun 2017 00:50:03 -0300 Subject: [PATCH] Fix anonymous classes directly from interfaces - Fix the failing scenarios such as new Comaprator() {... --- .../typedefinition/JavaTypeDefinition.java | 19 ++++++++++++------- .../typeresolution/ClassTypeResolverTest.java | 11 +++++++++++ .../testdata/AnonymousClassFromInterface.java | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousClassFromInterface.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java index 2bc06b2cba..e57306bcb9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java @@ -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); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index effb9d7a29..cce1e875bd 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -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); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousClassFromInterface.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousClassFromInterface.java new file mode 100644 index 0000000000..2c1998b52f --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousClassFromInterface.java @@ -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 comparator = new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return 0; + } + }; +}