Java, typedef: fix a bug with nested classes if the outter class is generic
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
21
pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericNested.java
vendored
Normal file
21
pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/FieldAccessGenericNested.java
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user