Java, typedef: fix a bug with nested classes if the outter class is generic

This commit is contained in:
Bendegúz Nagy
2017-07-26 12:25:40 +02:00
parent b4e799aaef
commit 87bbe9e5b3
6 changed files with 74 additions and 13 deletions

View File

@ -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);
}

View File

@ -21,6 +21,7 @@ public class JavaTypeDefinition implements TypeDefinition {
private final Class<?> clazz;
private final List<JavaTypeDefinition> 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();

View File

@ -24,7 +24,12 @@ public class PMDASMVisitor extends ClassVisitor {
private String outerName;
private Map<String, String> packages = new HashMap<>();
private Map<String, String> 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

View File

@ -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<AbstractJavaTypeNode> 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();
}

View File

@ -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<T extends String> {
public class Nested {
Nested n;
T field;
GenericClass<T, Number> generic;
void foo() {
n.field = null;
n.generic.first = null;
}
}
}

View File

@ -53,8 +53,10 @@ public class FieldAccessGenericSimple extends GenericSuperClassA<Long> {
}
public class Nested extends GenericSuperClassA<Long> {
//T outterParameterField;
void foo() {
fieldA = new Long(0);
//outterParameterField = null;
}
}
}