diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java index 9fedc666e6..8d42607f5c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.typeresolution; import static net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution.getApplicableMethods; import static net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution.getBestMethodReturnType; +import static net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution.isGeneric; import static net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution.isMemberVisibleFromClass; import java.lang.reflect.Field; @@ -436,7 +437,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { // Carry over the type from the declaration Class nodeType = ((TypeNode) node.getNameDeclaration().getNode()).getType(); // FIXME : generic classes and class with generic super types could have the wrong type assigned here - if (nodeType != null) { + if (nodeType != null && !isGeneric(nodeType)) { node.setType(nodeType); return super.visit(node, data); } 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 c155a69946..4071aecae6 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 @@ -21,6 +21,7 @@ public class JavaTypeDefinition implements TypeDefinition { private final Class clazz; private final List genericArgs; private final boolean isGeneric; + private final JavaTypeDefinition enclosingClass; private JavaTypeDefinition(final Class clazz) { this.clazz = clazz; @@ -45,6 +46,8 @@ public class JavaTypeDefinition implements TypeDefinition { } else { this.genericArgs = Collections.emptyList(); } + + enclosingClass = forClass(clazz.getEnclosingClass()); } public static JavaTypeDefinition forClass(final Class clazz) { @@ -93,15 +96,23 @@ public class JavaTypeDefinition implements TypeDefinition { } public JavaTypeDefinition getGenericType(final String parameterName) { - final TypeVariable[] typeParameters = clazz.getTypeParameters(); - for (int i = 0; i < typeParameters.length; i++) { - if (typeParameters[i].getName().equals(parameterName)) { - return getGenericType(i); + for (JavaTypeDefinition currTypeDef = this; currTypeDef != null; currTypeDef = currTypeDef.enclosingClass) { + final TypeVariable[] typeParameters = currTypeDef.clazz.getTypeParameters(); + for (int i = 0; i < typeParameters.length; i++) { + if (typeParameters[i].getName().equals(parameterName)) { + return currTypeDef.getGenericType(i); + } } } - throw new IllegalArgumentException("No generic parameter by name " + parameterName - + " on class " + clazz.getSimpleName()); + // throw because we could not find parameterName + StringBuilder builder = new StringBuilder("No generic parameter by name ").append(parameterName); + for (JavaTypeDefinition currTypeDef = this; currTypeDef != null; currTypeDef = currTypeDef.enclosingClass) { + builder.append("\n on class "); + builder.append(clazz.getSimpleName()); + } + + throw new IllegalArgumentException(builder.toString()); } public JavaTypeDefinition getGenericType(final int index) { @@ -189,7 +200,7 @@ public class JavaTypeDefinition implements TypeDefinition { public boolean isPrimitive() { return clazz.isPrimitive(); } - + public boolean equivalent(JavaTypeDefinition def) { // TODO: JavaTypeDefinition generic equality return clazz.equals(def.clazz) && getTypeParameterCount() == def.getTypeParameterCount(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java index 86bcf75a3c..4e7c38059a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java @@ -24,7 +24,12 @@ public class PMDASMVisitor extends ClassVisitor { private String outerName; - private Map packages = new HashMap<>(); + private Map packages = new HashMap() { + @Override + public Object put(Object key, Object value) { + return super.put(key, value); + } + }; private AnnotationVisitor annotationVisitor = new PMDAnnotationVisitor(this); @@ -316,7 +321,7 @@ public class PMDASMVisitor extends ClassVisitor { @Override public void visitInnerClassType(String name) { - parent.parseClassName(name); + // parent.parseClassName(name); } @Override 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 67408eae3a..ac6f7edcb0 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 @@ -60,6 +60,7 @@ import net.sourceforge.pmd.typeresolution.testdata.EnumWithAnonymousInnerClass; import net.sourceforge.pmd.typeresolution.testdata.ExtraTopLevelClass; import net.sourceforge.pmd.typeresolution.testdata.FieldAccess; import net.sourceforge.pmd.typeresolution.testdata.FieldAccessGenericBounds; +import net.sourceforge.pmd.typeresolution.testdata.FieldAccessGenericNested; import net.sourceforge.pmd.typeresolution.testdata.FieldAccessGenericParameter; import net.sourceforge.pmd.typeresolution.testdata.FieldAccessGenericRaw; import net.sourceforge.pmd.typeresolution.testdata.FieldAccessGenericSimple; @@ -204,7 +205,7 @@ public class ClassTypeResolverTest { Assert.assertTrue(Converter.class.isAssignableFrom(child.getType())); Assert.assertSame(String.class, child.getTypeDefinition().getGenericType(0).getType()); } - + @Test public void testAnoymousExtendingObject() throws Exception { Node acu = parseAndTypeResolveForClass(AnoymousExtendingObject.class, "1.8"); @@ -968,7 +969,6 @@ public class ClassTypeResolverTest { acu.findChildNodesWithXPath("//StatementExpression/PrimaryExpression"), AbstractJavaTypeNode.class); - int index = 0; // genericField.first = ""; @@ -1153,6 +1153,28 @@ public class ClassTypeResolverTest { assertEquals("All expressions not tested", index, expressions.size()); } + @Test + public void testFieldAccessGenericNested() throws JaxenException { + ASTCompilationUnit acu = parseAndTypeResolveForClass15(FieldAccessGenericNested.class); + + List expressions = convertList( + acu.findChildNodesWithXPath("//StatementExpression/PrimaryExpression"), + AbstractJavaTypeNode.class); + + int index = 0; + + // n.field = null; + assertEquals(String.class, expressions.get(index).getType()); + assertEquals(String.class, getChildType(expressions.get(index++), 0)); + + // n.generic.first = null; + assertEquals(String.class, expressions.get(index).getType()); + assertEquals(String.class, getChildType(expressions.get(index++), 0)); + + // Make sure we got them all + assertEquals("All expressions not tested", index, expressions.size()); + } + @Test public void testFieldAccessStatic() throws JaxenException { ASTCompilationUnit acu = parseAndTypeResolveForClass15(FieldAccessStatic.class); @@ -1431,7 +1453,6 @@ public class ClassTypeResolverTest { } - private Class getChildType(Node node, int childIndex) { return ((TypeNode) node.jjtGetChild(childIndex)).getType(); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericNested.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericNested.java new file mode 100644 index 0000000000..061bebc894 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericNested.java @@ -0,0 +1,21 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass; + +public class FieldAccessGenericNested { + + public class Nested { + Nested n; + T field; + GenericClass generic; + + void foo() { + n.field = null; + n.generic.first = null; + } + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericSimple.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericSimple.java index 198b9fdb10..d90d57e02d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericSimple.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericSimple.java @@ -53,8 +53,10 @@ public class FieldAccessGenericSimple extends GenericSuperClassA { } public class Nested extends GenericSuperClassA { + //T outterParameterField; void foo() { fieldA = new Long(0); + //outterParameterField = null; } } }