Merge branch 'genericFields'

This commit is contained in:
Bendegúz Nagy
2017-06-15 00:54:22 +02:00
22 changed files with 1041 additions and 88 deletions

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
public class ASTTypeArgument extends AbstractJavaNode {
public class ASTTypeArgument extends AbstractJavaTypeNode {
public ASTTypeArgument(int id) {
super(id);
}

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
public class ASTTypeBound extends AbstractJavaNode {
public class ASTTypeBound extends AbstractJavaTypeNode {
public ASTTypeBound(int id) {
super(id);
}

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
public class ASTTypeParameter extends AbstractJavaNode {
public class ASTTypeParameter extends AbstractJavaTypeNode {
public ASTTypeParameter(int id) {
super(id);
}

View File

@ -4,9 +4,10 @@
package net.sourceforge.pmd.lang.java.ast;
public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode implements TypeNode {
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
private Class<?> type;
public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode implements TypeNode {
private JavaTypeDefinition typeDefinition;
public AbstractJavaAccessTypeNode(int i) {
super(i);
@ -18,11 +19,25 @@ public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode
@Override
public Class<?> getType() {
return type;
if (typeDefinition != null) {
return typeDefinition.getType();
}
return null;
}
@Override
public void setType(Class<?> type) {
this.type = type;
typeDefinition = JavaTypeDefinition.build(type);
}
@Override
public JavaTypeDefinition getTypeDefinition() {
return typeDefinition;
}
@Override
public void setTypeDefinition(JavaTypeDefinition typeDefinition) {
this.typeDefinition = typeDefinition;
}
}

View File

@ -4,15 +4,16 @@
package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
/**
* An extension of the SimpleJavaNode which implements the TypeNode interface.
*
*
* @see AbstractJavaNode
* @see TypeNode
*/
public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements TypeNode {
private Class<?> type;
private JavaTypeDefinition typeDefinition;
public AbstractJavaTypeNode(int i) {
super(i);
@ -24,11 +25,25 @@ public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements T
@Override
public Class<?> getType() {
return type;
if (typeDefinition != null) {
return typeDefinition.getType();
}
return null;
}
@Override
public void setType(Class<?> type) {
this.type = type;
typeDefinition = JavaTypeDefinition.build(type);
}
@Override
public JavaTypeDefinition getTypeDefinition() {
return typeDefinition;
}
@Override
public void setTypeDefinition(JavaTypeDefinition typeDefinition) {
this.typeDefinition = typeDefinition;
}
}

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
/**
* This interface allows a Java Class to be associated with a node.
@ -13,16 +14,31 @@ public interface TypeNode extends Node {
/**
* Get the Java Class associated with this node.
*
*
* @return The Java Class, may return <code>null</code>.
*/
Class<?> getType();
/**
* Get the TypeDefinition associated with this node. The Class object
* contained in the TypeDefinition will always be equal to that which
* is returned by <code>getType()</code>.
*
* @return The TypeDefinition, may return <code>null</code>
*/
JavaTypeDefinition getTypeDefinition();
/**
* Set the TypeDefinition associated with this node.
*
* @param type A TypeDefinition object
*/
void setTypeDefinition(JavaTypeDefinition type);
/**
* Set the Java Class associated with this node.
*
* @param type
* A Java Class
*
* @param type A Java Class
*/
void setType(Class<?> type);
}

View File

@ -0,0 +1,45 @@
package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class JavaTypeDefinition implements TypeDefinition {
private final Class clazz;
private final List<JavaTypeDefinition> genericArgs;
public Class getType() {
return clazz;
}
public List<JavaTypeDefinition> getGenericArgs() {
return genericArgs;
}
JavaTypeDefinition(Class clazz, List<JavaTypeDefinition> genericArgs) {
this.clazz = clazz;
if (genericArgs == null) {
genericArgs = new ArrayList<>();
}
this.genericArgs = Collections.unmodifiableList(genericArgs);
}
// builder part of the class
// TODO: possibly add some sort of caching (with like a map or something)
public static JavaTypeDefinition build(Class clazz) {
return new JavaTypeDefinition(clazz, null);
}
public static JavaTypeDefinitionBuilder builder(Class clazz) {
return new JavaTypeDefinitionBuilder().setType(clazz);
}
public static JavaTypeDefinitionBuilder builder() {
return new JavaTypeDefinitionBuilder();
}
}

View File

@ -0,0 +1,35 @@
package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class JavaTypeDefinitionBuilder {
private Class clazz = null;
private List<JavaTypeDefinition> genericArgs = new ArrayList<>();
JavaTypeDefinitionBuilder() {}
public JavaTypeDefinitionBuilder addTypeArg(JavaTypeDefinition arg) {
genericArgs.add(arg);
return this;
}
public List<JavaTypeDefinition> getTypeArgs() {
return Collections.unmodifiableList(genericArgs);
}
public JavaTypeDefinitionBuilder getTypeArg(int index) {
genericArgs.get(index);
return this;
}
public JavaTypeDefinitionBuilder setType(Class clazz) {
this.clazz = clazz;
return this;
}
public JavaTypeDefinition build() {
return new JavaTypeDefinition(clazz, genericArgs);
}
}

View File

@ -0,0 +1,19 @@
package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
import java.util.List;
public interface TypeDefinition {
/**
* Get the raw Class type of the definition.
*
* @return Raw Class type.
*/
Class getType();
/**
* Get the list of type arguments for this TypeDefinition.
*
* @return An ordered and immutable list of type arguments.
*/
List<? extends TypeDefinition> getGenericArgs();
}

View File

@ -12,6 +12,8 @@ import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA;
/*
* Note: inherited fields of a nested class shadow outer scope variables
* Note: only if they are accessible!
*
* TODO: test static field access, array types
*/
public class FieldAccess extends SuperClassA {
public int field;

View File

@ -0,0 +1,28 @@
package net.sourceforge.pmd.typeresolution.testdata;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericSuperClassA;
public class FieldAccessGenericBounds extends GenericSuperClassA<Long> {
GenericClass<? super String, ?> superGeneric;
GenericClass<? extends Number, Object> upperBound;
public void astPrimaryNameCases() {
// test ?, ? super Something, ? extends Something
// Primary[Prefix[Name[superGeneric.first]]]
superGeneric.first = ""; // Object
superGeneric.second = null; // Object
inheritedSuperGeneric.first = ""; // Object
inheritedSuperGeneric.second = null; // Object
upperBound.first = null; // Number
inheritedUpperBound.first = null; // String
// test static imports
// Primary[Prefix[Name[instanceFields.generic.first]]]
//instanceFields.generic.first = "";
//staticGeneric.first = new Long(0);
}
}

View File

@ -0,0 +1,31 @@
package net.sourceforge.pmd.typeresolution.testdata;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
public class FieldAccessGenericParameter<T extends GenericClass<String, GenericClass<String, Integer>>,
S extends Double> {
T parameterGeneric;
S classGeneric;
<M extends Character> void foo() {
M localGeneric = null;
// access type dependant on class/method type arguments
// Primary[Prefix[Name[classGeneric]]]
classGeneric = null; // Double
localGeneric = null; // Character
// test type parameters extending generic types
// Primary[Prefix[Name[parameterGeneric.first]]]
parameterGeneric.second.second = new Integer(0);
}
<C extends Number> FieldAccessGenericParameter() {
C constructorGeneric = null;
// access type dependant on constructor type arugments
// Primary[Prefix[Name[localGeneric]]]
constructorGeneric = null; // Number
}
}

View File

@ -0,0 +1,33 @@
package net.sourceforge.pmd.typeresolution.testdata;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass2;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericSuperClassA;
public class FieldAccessGenericRaw<T extends GenericClass2> extends GenericSuperClassA<Long> {
GenericClass2 rawGeneric;
T parameterRawGeneric;
void foo() {
// test raw types
// Primary[Prefix[Name[rawGeneric.first]]]
rawGeneric.first = new Integer(0);
rawGeneric.second = new Integer(0);
rawGeneric.third = new Object();
rawGeneric.fourth.second = "";
rawGeneric.rawGeneric.second = new Integer(0);
// Primary[Prefix[Name[inheritedGeneric.first]]]
inheritedRawGeneric.first = new Integer(0);
inheritedRawGeneric.second = new Integer(0);
inheritedRawGeneric.third = new Object();
inheritedRawGeneric.fourth.second = "";
inheritedRawGeneric.rawGeneric.second = new Integer(0);
// Primary[Prefix[Name[parameterRawGeneric.first]]]
parameterRawGeneric.first = new Integer(0);
parameterRawGeneric.second = new Integer(0);
parameterRawGeneric.third = new Object();
parameterRawGeneric.fourth.second = "";
parameterRawGeneric.rawGeneric.second = new Integer(0);
}
}

View File

@ -0,0 +1,56 @@
package net.sourceforge.pmd.typeresolution.testdata;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericSuperClassA;
/*
* TODO: add anonymous class this (Allocation expression)
* TODO: add primitives, parameterized arrays
* TODO: diamond, type parmeter declarations can shadow Class declarations
*/
public class FieldAccessGenericSimple extends GenericSuperClassA<Long> {
GenericClass<String, Double> genericField;
GenericClass<String, GenericClass<Number, Double>> genericTypeArg;
FieldAccessGenericSimple fieldAcc;
void foo(GenericClass<Integer, Character> param) {
GenericClass<Float, Long> local = null;
// access a generic field through member field
// Primary[Prefix[Name[genericField.first]]]
genericField.first = "";
genericField.second = new Double(0);
// access a generic field whose type depends on a generic type argument
// Primary[Prefix[Name[genericTypeArg.second.second]]]
genericTypeArg.second.second = new Double(0);
// access a generic field through a local or a parameter
// Primary[Prefix[Name[param.first]]]
param.first = new Integer(0);
local.second = new Long(0);
// access a generic field whose type depends on indirect type arguments
// Primary[Prefix[Name[generic.generic.first]]]
param.generic.first = new Character('c');
local.generic.second = new Float(0);
genericField.generic.generic.generic.first = new Double(0);
// test inherited generic
// Primary[Prefix[Name[generic.first]]]
fieldA = new Long(0);
fieldB.generic.second = "";
// test inherited generic
// Primary[Prefix[Name[fieldAcc.fieldA]]]
fieldAcc.fieldA = new Long(0);
}
public class Nested extends GenericSuperClassA<Long> {
void foo() {
fieldA = new Long(0);
}
}
}

View File

@ -0,0 +1,44 @@
package net.sourceforge.pmd.typeresolution.testdata;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericSuperClassA;
public class FieldAccessPrimaryGenericSimple extends GenericSuperClassA<Long> {
GenericClass<String, Double> genericField;
GenericClass<String, GenericClass<Number, Double>> genericTypeArg;
void foo(GenericClass<Integer, Character> param) {
GenericClass<Float, Long> local = null;
// access a generic field through member field
// Primary[Prefix[this], Suffix[genericField], Suffix[first]]
this.genericField.first = "";
(this).genericField.second = new Double(0);
// access a generic field whose type depends on a generic type argument
// Primary[Prefix[this], Suffix[genericTypeArg], Suffix[second], Suffix[second]]
this.genericTypeArg.second.second = new Double(0);
// access a generic field whose type depends on indirect type arguments
// Primary[Prefix[this], Suffix[genericField], Suffix[generic], Suffix[generic]...]
(this).genericField.generic.generic.generic.first = new Double(0);
// test inherited generic
// Primary[Primary[Prefix[(this)]], Suffix[fieldA]]
(this).fieldA = new Long(0);
this.fieldB.generic.second = "";
// test inherited generic
// Primary[Prefix[super], Suffix[fieldA]]
super.fieldA = new Long(0);
super.fieldB.generic.second = "";
}
class Nested<T extends GenericClass<String, Number>> {
T field;
void foo() {
// Primary[Prefix[this], Suffix[field], Suffix[first]]
this.field.first = "";
}
}
}

View File

@ -5,6 +5,8 @@
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class GenericClass<T> {
public T a;
public class GenericClass<T, S> {
public T first;
public S second;
public GenericClass<S, T> generic;
}

View File

@ -0,0 +1,15 @@
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class GenericClass2<A extends Integer, B extends A, C,
S extends String,
D extends GenericClass<A, S>,
//, E extends GenericClass<E, E>,
F extends GenericClass2> {
public A first;
public B second;
public C third;
public D fourth;
//public E fifth; // recursion
public F sixth; // recursion
public GenericClass2 rawGeneric;
}

View File

@ -0,0 +1,8 @@
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class GenericSuperClassA<T> extends GenericSuperClassB<T, GenericClass<String, T>> {
public T fieldA;
public GenericClass2 inheritedRawGeneric;
public GenericClass<? super String, ?> inheritedSuperGeneric;
public GenericClass<? extends String, Object> inheritedUpperBound;
}

View File

@ -0,0 +1,5 @@
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class GenericSuperClassB<T, S> {
public S fieldB;
}

View File

@ -0,0 +1,10 @@
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class StaticFields {
public static StaticFields instanceFields;
public static int staticPrimitive;
public static GenericClass<Long, Integer> staticGeneric;
public long primitive;
public GenericClass<String, Number> generic;
}