From 544c338918b0e652b3369e7f03fb6f794ae80997 Mon Sep 17 00:00:00 2001 From: rpau Date: Sun, 20 Mar 2016 16:28:16 +0100 Subject: [PATCH] issue #20 solved --- pom.xml | 2 +- ...ractGenericsBuilderFromParameterTypes.java | 616 +++++++++--------- .../compiler/SymbolVisitorAdapterTest.java | 8 +- 3 files changed, 316 insertions(+), 310 deletions(-) diff --git a/pom.xml b/pom.xml index 46f34ec..1953587 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.walkmod javalang-compiler - 2.2.9 + 2.2.10 https://github.com/rpau/javalang-compiler javalang-compiler diff --git a/src/main/java/org/walkmod/javalang/compiler/reflection/AbstractGenericsBuilderFromParameterTypes.java b/src/main/java/org/walkmod/javalang/compiler/reflection/AbstractGenericsBuilderFromParameterTypes.java index 6a1e343..a62f141 100644 --- a/src/main/java/org/walkmod/javalang/compiler/reflection/AbstractGenericsBuilderFromParameterTypes.java +++ b/src/main/java/org/walkmod/javalang/compiler/reflection/AbstractGenericsBuilderFromParameterTypes.java @@ -32,6 +32,7 @@ import org.walkmod.javalang.ast.SymbolData; import org.walkmod.javalang.ast.expr.ClassExpr; import org.walkmod.javalang.ast.expr.Expression; +import org.walkmod.javalang.ast.expr.NullLiteralExpr; import org.walkmod.javalang.compiler.symbols.ReferenceType; import org.walkmod.javalang.compiler.symbols.Scope; import org.walkmod.javalang.compiler.symbols.Symbol; @@ -41,312 +42,313 @@ import org.walkmod.javalang.exceptions.InvalidTypeException; public abstract class AbstractGenericsBuilderFromParameterTypes { - private Map typeMapping; - - private SymbolTable typeParamsSymbolTable; - - private List args; - - private SymbolType[] typeArgs; - - private Type[] types; - - private SymbolTable symTable; - - public AbstractGenericsBuilderFromParameterTypes(Map typeMapping, List args, - SymbolType[] typeArgs, SymbolTable symTable) { - this.typeMapping = typeMapping; - this.args = args; - this.typeArgs = typeArgs; - this.symTable = symTable; - } - - public AbstractGenericsBuilderFromParameterTypes(Map typeMapping, SymbolTable symTable) { - this.typeMapping = typeMapping; - this.symTable = symTable; - } - - public SymbolTable getSymbolTable() { - return symTable; - } - - public AbstractGenericsBuilderFromParameterTypes() { - } - - public void setArgs(List args) { - this.args = args; - } - - public List getArgs() { - return args; - } - - public void setTypeArgs(SymbolType[] typeArgs) { - this.typeArgs = typeArgs; - } - - private SymbolType getType(ClassExpr classExpr) { - String name = classExpr.getType().toString(); - SymbolType type = symTable.getType(name, ReferenceType.TYPE); - if (type == null) { - Class clazz = null; - try { - clazz = TypesLoaderVisitor.getClassLoader().loadClass(name); - - String className = clazz.getName(); - type = new SymbolType(); - type.setName(className); - - } catch (ClassNotFoundException e) { - // a name expression could be "org.walkmod.A" and this node - // could be "org.walkmod" - - } - } - return type; - } - - public SymbolTable getTypeParamsSymbolTable() { - if (typeParamsSymbolTable == null) { - typeParamsSymbolTable = new SymbolTable(); - // we store in the symbol table the generics of the parameterized - // types of the implicit object - Scope methodCallScope = new Scope(); - typeParamsSymbolTable.pushScope(methodCallScope); - Map typeMapping = getTypeMapping(); - if (typeMapping != null) { - Set parameterizedTypeNames = typeMapping.keySet(); - for (String typeName : parameterizedTypeNames) { - SymbolType st = typeMapping.get(typeName).clone(); - st.setTemplateVariable(typeName); - typeParamsSymbolTable.pushSymbol(typeName, ReferenceType.TYPE, st, null); - } - } - } - return typeParamsSymbolTable; - } - - public void loadTypeMappingFromTypeArgs() throws Exception { - - loadTypeMappingFromTypeArgs(getTypeParamsSymbolTable()); - - } - - public void loadTypeMappingFromTypeArgs(SymbolTable symbolTable) throws Exception { - symbolTable.pushScope(); - java.lang.reflect.Type[] types = getTypes(); - - int pos = 0; - for (Type type : types) { - if (type instanceof ParameterizedType) { - - Type aux = ((ParameterizedType) type).getRawType(); - if (aux instanceof Class) { - if (((Class) aux).getName().equals("java.lang.Class")) { - Type[] targs = ((ParameterizedType) type).getActualTypeArguments(); - for (Type targ : targs) { - String letter = targ.toString(); - if (!"?".equals(letter)) { - if (pos < args.size()) { - Expression e = args.get(pos); - // String className = ""; - if (e instanceof ClassExpr) { - - SymbolType eType = getType(((ClassExpr) e)); - - symbolTable.pushSymbol(letter, ReferenceType.TYPE, eType, e); - - } else { - List params = e.getSymbolData().getParameterizedTypes(); - if (params != null && !params.isEmpty()) { - SymbolType eType = (SymbolType) params.get(0); - symbolTable.pushSymbol(letter, ReferenceType.TYPE, eType, e); - } - } - } else { - symbolTable.pushSymbol(letter, ReferenceType.TYPE, new SymbolType(Object.class), - null); - } - } - } - } - } - } - pos++; - } - } - - public void build() throws Exception { - buildTypeParamsTypes(); - closeTypeMapping(); - } - - public void buildTypeParamsTypes() throws Exception { - - loadTypeMappingFromTypeArgs(); - - for (int i = 0; i < types.length && i < typeArgs.length; i++) { - typeMappingUpdate(types[i], typeArgs[i]); - } - } - - public void closeTypeMapping() { - ArrayList> symbols = typeParamsSymbolTable.findSymbolsByType(); - ListIterator> it = symbols.listIterator(symbols.size()); - while (it.hasPrevious()) { - Symbol s = it.previous(); - typeMapping.put(s.getName(), s.getType()); - } - } - - private void typeMappingUpdate(Type type, SymbolType typeArg) throws InvalidTypeException { - if (type instanceof TypeVariable) { - String name = ((TypeVariable) type).getName(); - Symbol s = typeParamsSymbolTable.findSymbol(name, ReferenceType.TYPE, ReferenceType.TYPE_PARAM); - - SymbolType st = null; - if (s != null) { - st = s.getType(); - } - if ((s == null || st == null) - || (st.isTemplateVariable() && s.getReferenceType().equals(ReferenceType.TYPE_PARAM)) - || (Object.class.equals(st.getClazz()) && !s.getReferenceType().equals(ReferenceType.TYPE))) { - typeParamsSymbolTable.pushSymbol(name, ReferenceType.TYPE, typeArg, null); - } else { - if (s.getReferenceType().equals(ReferenceType.TYPE)) { - SymbolType aux = (SymbolType) st.merge(typeArg); - s.setType(aux); - } else { - // it is a type param, so it is not part of the implicit - // object - typeParamsSymbolTable.pushSymbol(name, ReferenceType.TYPE, typeArg, null); - } - } - - } else if (type instanceof ParameterizedType) { - - ParameterizedType paramType = (ParameterizedType) type; - Type[] args = paramType.getActualTypeArguments(); - if (typeArg != null) { - - Map updateMapping = new LinkedHashMap(); - - // class A implements B, if type is B, we need - // to know that K is String and M whatever has the typeArg - SymbolType rewrittenType = SymbolType.valueOf(paramType.getRawType(), typeArg, updateMapping, null); - - List callParams = typeArg.getParameterizedTypes(); - String name = rewrittenType.getName(); - if (name == null || !"java.lang.Class".equals(name)) { - - List rewrittenParams = rewrittenType.getParameterizedTypes(); - if (rewrittenParams != null) { - Iterator itP = rewrittenParams.iterator(); - Iterator auxIt = null; - if (callParams != null) { - auxIt = callParams.iterator(); - - } - int i = 0; - while (itP.hasNext() && i < args.length) { - SymbolType st = itP.next(); - if ((st.getName() == null || Object.class.equals(st.getClazz()))) { - if (auxIt != null && auxIt.hasNext()) { - // it is defined by the parameters of the - // implicit object.Eg: (List a = - // null; - // a.add("hello")); - typeMappingUpdate(args[i], auxIt.next()); - } else { - typeMappingUpdate(args[i], st); - } - } else { - // it is defined by the rewritten type eg: (A - // implements B) => st = String - typeMappingUpdate(args[i], st); - } - i++; - } - } - } - - } - - } else if (type instanceof WildcardType) { - if (typeArg != null) { - WildcardType wildcardType = (WildcardType) type; - - // ? super T -> upper is '?'. So it is Object - Type[] upper = wildcardType.getUpperBounds(); - List bounds = typeArg.getBounds(); - if (bounds == null) { - bounds = new LinkedList(); - bounds.add(typeArg); - } - - for (int i = 0; i < upper.length; i++) { - typeMappingUpdate(upper[i], bounds.get(i)); - } - // ? super T -> lower is 'T'. The type can contain lower bounds - // or is a resolved type - Type[] lower = wildcardType.getLowerBounds(); - List lowerBounds = typeArg.getLowerBounds(); - if (lowerBounds != null) { - bounds = lowerBounds; - } - if (bounds != null) { - for (int i = 0; i < lower.length; i++) { - typeMappingUpdate(lower[i], bounds.get(i)); - } - } - } - } else if (type instanceof GenericArrayType) { - if (typeArg != null) { - GenericArrayType arrayType = (GenericArrayType) type; - SymbolType aux = typeArg.clone(); - if (typeArg.getArrayCount() > 0) { - aux.setArrayCount(typeArg.getArrayCount() - 1); - } - - typeMappingUpdate(arrayType.getGenericComponentType(), aux); - } - } else if (type instanceof Class) { - if (typeArg != null) { - Class clazz = (Class) type; - Map updateMapping = new LinkedHashMap(); - - // class A implements B, if type is B, we need - // to know that K is String and M whatever has the typeArg - SymbolType rewrittenType = SymbolType.valueOf(clazz, typeArg, updateMapping, null); - TypeVariable[] tvs = clazz.getTypeParameters(); - List paramTypes = rewrittenType.getParameterizedTypes(); - if (paramTypes != null) { - Iterator it = paramTypes.iterator(); - for (int i = 0; i < tvs.length && it.hasNext(); i++) { - SymbolType st = it.next(); - if (st != null) { - typeMappingUpdate(tvs[i], st); - } - } - } - } - } - } - - public void setTypeMapping(Map typeMapping) { - this.typeMapping = typeMapping; - } - - public Map getTypeMapping() { - return typeMapping; - } - - public void setTypes(Type[] types) { - this.types = types; - } - - public Type[] getTypes() { - return types; - } + private Map typeMapping; + + private SymbolTable typeParamsSymbolTable; + + private List args; + + private SymbolType[] typeArgs; + + private Type[] types; + + private SymbolTable symTable; + + public AbstractGenericsBuilderFromParameterTypes(Map typeMapping, List args, + SymbolType[] typeArgs, SymbolTable symTable) { + this.typeMapping = typeMapping; + this.args = args; + this.typeArgs = typeArgs; + this.symTable = symTable; + } + + public AbstractGenericsBuilderFromParameterTypes(Map typeMapping, SymbolTable symTable) { + this.typeMapping = typeMapping; + this.symTable = symTable; + } + + public SymbolTable getSymbolTable() { + return symTable; + } + + public AbstractGenericsBuilderFromParameterTypes() { + } + + public void setArgs(List args) { + this.args = args; + } + + public List getArgs() { + return args; + } + + public void setTypeArgs(SymbolType[] typeArgs) { + this.typeArgs = typeArgs; + } + + private SymbolType getType(ClassExpr classExpr) { + String name = classExpr.getType().toString(); + SymbolType type = symTable.getType(name, ReferenceType.TYPE); + if (type == null) { + Class clazz = null; + try { + clazz = TypesLoaderVisitor.getClassLoader().loadClass(name); + + String className = clazz.getName(); + type = new SymbolType(); + type.setName(className); + + } catch (ClassNotFoundException e) { + // a name expression could be "org.walkmod.A" and this node + // could be "org.walkmod" + + } + } + return type; + } + + public SymbolTable getTypeParamsSymbolTable() { + if (typeParamsSymbolTable == null) { + typeParamsSymbolTable = new SymbolTable(); + // we store in the symbol table the generics of the parameterized + // types of the implicit object + Scope methodCallScope = new Scope(); + typeParamsSymbolTable.pushScope(methodCallScope); + Map typeMapping = getTypeMapping(); + if (typeMapping != null) { + Set parameterizedTypeNames = typeMapping.keySet(); + for (String typeName : parameterizedTypeNames) { + SymbolType st = typeMapping.get(typeName).clone(); + st.setTemplateVariable(typeName); + typeParamsSymbolTable.pushSymbol(typeName, ReferenceType.TYPE, st, null); + } + } + } + return typeParamsSymbolTable; + } + + public void loadTypeMappingFromTypeArgs() throws Exception { + + loadTypeMappingFromTypeArgs(getTypeParamsSymbolTable()); + + } + + public void loadTypeMappingFromTypeArgs(SymbolTable symbolTable) throws Exception { + symbolTable.pushScope(); + java.lang.reflect.Type[] types = getTypes(); + + int pos = 0; + for (Type type : types) { + if (type instanceof ParameterizedType) { + + Type aux = ((ParameterizedType) type).getRawType(); + if (aux instanceof Class) { + if (((Class) aux).getName().equals("java.lang.Class")) { + Type[] targs = ((ParameterizedType) type).getActualTypeArguments(); + for (Type targ : targs) { + String letter = targ.toString(); + if (!"?".equals(letter)) { + if (pos < args.size()) { + Expression e = args.get(pos); + // String className = ""; + if (e instanceof ClassExpr) { + + SymbolType eType = getType(((ClassExpr) e)); + + symbolTable.pushSymbol(letter, ReferenceType.TYPE, eType, e); + + } else { + if (!(e instanceof NullLiteralExpr)) { + List params = e.getSymbolData().getParameterizedTypes(); + if (params != null && !params.isEmpty()) { + SymbolType eType = (SymbolType) params.get(0); + symbolTable.pushSymbol(letter, ReferenceType.TYPE, eType, e); + } + } + } + } else { + symbolTable.pushSymbol(letter, ReferenceType.TYPE, new SymbolType(Object.class), null); + } + } + } + } + } + } + pos++; + } + } + + public void build() throws Exception { + buildTypeParamsTypes(); + closeTypeMapping(); + } + + public void buildTypeParamsTypes() throws Exception { + + loadTypeMappingFromTypeArgs(); + + for (int i = 0; i < types.length && i < typeArgs.length; i++) { + typeMappingUpdate(types[i], typeArgs[i]); + } + } + + public void closeTypeMapping() { + ArrayList> symbols = typeParamsSymbolTable.findSymbolsByType(); + ListIterator> it = symbols.listIterator(symbols.size()); + while (it.hasPrevious()) { + Symbol s = it.previous(); + typeMapping.put(s.getName(), s.getType()); + } + } + + private void typeMappingUpdate(Type type, SymbolType typeArg) throws InvalidTypeException { + if (type instanceof TypeVariable) { + String name = ((TypeVariable) type).getName(); + Symbol s = typeParamsSymbolTable.findSymbol(name, ReferenceType.TYPE, ReferenceType.TYPE_PARAM); + + SymbolType st = null; + if (s != null) { + st = s.getType(); + } + if ((s == null || st == null) + || (st.isTemplateVariable() && s.getReferenceType().equals(ReferenceType.TYPE_PARAM)) + || (Object.class.equals(st.getClazz()) && !s.getReferenceType().equals(ReferenceType.TYPE))) { + typeParamsSymbolTable.pushSymbol(name, ReferenceType.TYPE, typeArg, null); + } else { + if (s.getReferenceType().equals(ReferenceType.TYPE)) { + SymbolType aux = (SymbolType) st.merge(typeArg); + s.setType(aux); + } else { + // it is a type param, so it is not part of the implicit + // object + typeParamsSymbolTable.pushSymbol(name, ReferenceType.TYPE, typeArg, null); + } + } + + } else if (type instanceof ParameterizedType) { + + ParameterizedType paramType = (ParameterizedType) type; + Type[] args = paramType.getActualTypeArguments(); + if (typeArg != null) { + + Map updateMapping = new LinkedHashMap(); + + // class A implements B, if type is B, we need + // to know that K is String and M whatever has the typeArg + SymbolType rewrittenType = SymbolType.valueOf(paramType.getRawType(), typeArg, updateMapping, null); + + List callParams = typeArg.getParameterizedTypes(); + String name = rewrittenType.getName(); + if (name == null || !"java.lang.Class".equals(name)) { + + List rewrittenParams = rewrittenType.getParameterizedTypes(); + if (rewrittenParams != null) { + Iterator itP = rewrittenParams.iterator(); + Iterator auxIt = null; + if (callParams != null) { + auxIt = callParams.iterator(); + + } + int i = 0; + while (itP.hasNext() && i < args.length) { + SymbolType st = itP.next(); + if ((st.getName() == null || Object.class.equals(st.getClazz()))) { + if (auxIt != null && auxIt.hasNext()) { + // it is defined by the parameters of the + // implicit object.Eg: (List a = + // null; + // a.add("hello")); + typeMappingUpdate(args[i], auxIt.next()); + } else { + typeMappingUpdate(args[i], st); + } + } else { + // it is defined by the rewritten type eg: (A + // implements B) => st = String + typeMappingUpdate(args[i], st); + } + i++; + } + } + } + + } + + } else if (type instanceof WildcardType) { + if (typeArg != null) { + WildcardType wildcardType = (WildcardType) type; + + // ? super T -> upper is '?'. So it is Object + Type[] upper = wildcardType.getUpperBounds(); + List bounds = typeArg.getBounds(); + if (bounds == null) { + bounds = new LinkedList(); + bounds.add(typeArg); + } + + for (int i = 0; i < upper.length; i++) { + typeMappingUpdate(upper[i], bounds.get(i)); + } + // ? super T -> lower is 'T'. The type can contain lower bounds + // or is a resolved type + Type[] lower = wildcardType.getLowerBounds(); + List lowerBounds = typeArg.getLowerBounds(); + if (lowerBounds != null) { + bounds = lowerBounds; + } + if (bounds != null) { + for (int i = 0; i < lower.length; i++) { + typeMappingUpdate(lower[i], bounds.get(i)); + } + } + } + } else if (type instanceof GenericArrayType) { + if (typeArg != null) { + GenericArrayType arrayType = (GenericArrayType) type; + SymbolType aux = typeArg.clone(); + if (typeArg.getArrayCount() > 0) { + aux.setArrayCount(typeArg.getArrayCount() - 1); + } + + typeMappingUpdate(arrayType.getGenericComponentType(), aux); + } + } else if (type instanceof Class) { + if (typeArg != null) { + Class clazz = (Class) type; + Map updateMapping = new LinkedHashMap(); + + // class A implements B, if type is B, we need + // to know that K is String and M whatever has the typeArg + SymbolType rewrittenType = SymbolType.valueOf(clazz, typeArg, updateMapping, null); + TypeVariable[] tvs = clazz.getTypeParameters(); + List paramTypes = rewrittenType.getParameterizedTypes(); + if (paramTypes != null) { + Iterator it = paramTypes.iterator(); + for (int i = 0; i < tvs.length && it.hasNext(); i++) { + SymbolType st = it.next(); + if (st != null) { + typeMappingUpdate(tvs[i], st); + } + } + } + } + } + } + + public void setTypeMapping(Map typeMapping) { + this.typeMapping = typeMapping; + } + + public Map getTypeMapping() { + return typeMapping; + } + + public void setTypes(Type[] types) { + this.types = types; + } + + public Type[] getTypes() { + return types; + } } diff --git a/src/test/java/org/walkmod/javalang/compiler/SymbolVisitorAdapterTest.java b/src/test/java/org/walkmod/javalang/compiler/SymbolVisitorAdapterTest.java index 939f978..9633c8b 100644 --- a/src/test/java/org/walkmod/javalang/compiler/SymbolVisitorAdapterTest.java +++ b/src/test/java/org/walkmod/javalang/compiler/SymbolVisitorAdapterTest.java @@ -2005,6 +2005,10 @@ public void testFieldTemplateTypeRedefinition() throws Exception{ NameExpr ne = (NameExpr) mce.getScope(); Assert.assertEquals("java.util.List", ne.getSymbolData().getName()); } - - + + @Test + public void testTemplateParametersWithNullValues() throws Exception{ + CompilationUnit cu = run("public class ClassLiteral { T doClass(String x, Class clazz) {return null;}public void x() { doClass(\"x\", null); }}"); + Assert.assertNotNull(cu); + } }