org.walkmod.javalang.compiler.reflection.ResultBuilderFromGenerics Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javalang-compiler Show documentation
Show all versions of javalang-compiler Show documentation
Library of compiler components to processs Java code.
/*
Copyright (C) 2015 Raquel Pau and Albert Coroleu.
Walkmod is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Walkmod is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Walkmod. If not, see .*/
package org.walkmod.javalang.compiler.reflection;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.walkmod.javalang.ast.type.Type;
import org.walkmod.javalang.compiler.Builder;
import org.walkmod.javalang.compiler.symbols.ASTSymbolTypeResolver;
import org.walkmod.javalang.compiler.symbols.ReferenceType;
import org.walkmod.javalang.compiler.symbols.Scope;
import org.walkmod.javalang.compiler.symbols.Symbol;
import org.walkmod.javalang.compiler.symbols.SymbolTable;
import org.walkmod.javalang.compiler.symbols.SymbolType;
import org.walkmod.javalang.exceptions.InvalidTypeException;
public class ResultBuilderFromGenerics implements Builder {
private List generics = null;
private Method method = null;
private Class> clazz = null;
private SymbolType scope = null;
private SymbolTable symbolTable;
public ResultBuilderFromGenerics(List generics, Method method) {
this.generics = generics;
this.method = method;
}
public ResultBuilderFromGenerics(SymbolType scope, Method method, SymbolTable symbolTable) {
this.scope = scope;
this.symbolTable = symbolTable;
this.method = method;
if (method != null) {
clazz = method.getDeclaringClass();
}
}
public ResultBuilderFromGenerics(SymbolType scope, Class> clazz, SymbolTable symbolTable) {
this.scope = scope;
this.symbolTable = symbolTable;
this.clazz = clazz;
}
@Override
public SymbolTable build(SymbolTable genericsSymbolTable) throws Exception {
if (generics != null) {
SymbolType[] syms = ASTSymbolTypeResolver.getInstance().valueOf(generics);
SymbolType scope = new SymbolType();
scope.setParameterizedTypes(Arrays.asList(syms));
genericsSymbolTable.pushScope();
updateTypeMapping(method.getGenericReturnType(), genericsSymbolTable, scope, true, new HashSet());
} else if (scope != null) {
String symbolName = scope.getClazz().getName();
if (scope.getClazz().isMemberClass()) {
symbolName = scope.getClazz().getCanonicalName();
}
Symbol> s = symbolTable.findSymbol(symbolName, ReferenceType.TYPE);
if (s != null) {
Scope scope = s.getInnerScope();
if (scope != null) {
Map typeParams = scope.getTypeParams();
Scope newScope = new Scope();
for (String key : typeParams.keySet()) {
SymbolType aux = typeParams.get(key).clone();
aux.setTemplateVariable(key);
newScope.addSymbol(key, aux, null);
}
genericsSymbolTable.pushScope(newScope);
}
}
updateTypeMapping(clazz, genericsSymbolTable, scope, false, new HashSet());
Scope newScope = new Scope();
genericsSymbolTable.pushScope(newScope);
if (method != null) {
TypeVariable>[] typeParams = method.getTypeParameters();
for (int i = 0; i < typeParams.length; i++) {
SymbolType aux = SymbolType.valueOf(typeParams[i], null);
aux.setTemplateVariable(typeParams[i].getName());
genericsSymbolTable.pushSymbol(typeParams[i].getName(), ReferenceType.TYPE_PARAM, aux, null);
}
}
} else {
Scope newScope = new Scope();
genericsSymbolTable.pushScope(newScope);
}
return genericsSymbolTable;
}
private void updateTypeMapping(java.lang.reflect.Type type, SymbolTable genericsSymbolTable,
SymbolType parameterizedType, boolean genericArgs, Set processedTypeVariables)
throws InvalidTypeException {
if (parameterizedType != null) {
if (type instanceof TypeVariable) {
TypeVariable> tv = (TypeVariable>) type;
String vname = tv.getName();
if (!processedTypeVariables.contains(vname)) {
processedTypeVariables.add(vname);
Symbol> s = genericsSymbolTable.findSymbol(vname);
if (s != null) {
boolean isInTheTopScope = genericsSymbolTable.getScopes().peek().findSymbol(vname) != null;
SymbolType st = s.getType();
if (st != null) {
SymbolType refactor = s.getType().refactor(vname, parameterizedType,
genericArgs || isInTheTopScope);
refactor.setTemplateVariable(vname);
s.setType(refactor);
} else {
s.setType(parameterizedType);
}
} else {
genericsSymbolTable.pushSymbol(vname, ReferenceType.TYPE, parameterizedType, null);
}
java.lang.reflect.Type[] bounds = tv.getBounds();
List paramBounds = parameterizedType.getBounds();
if (paramBounds != null) {
for (int i = 0; i < paramBounds.size() && i < bounds.length; i++) {
updateTypeMapping(bounds[i], genericsSymbolTable, paramBounds.get(i), genericArgs,
processedTypeVariables);
}
}
}
} else if (type instanceof WildcardType) {
WildcardType wildcard = (WildcardType) type;
java.lang.reflect.Type[] bounds = wildcard.getUpperBounds();
List paramBounds = parameterizedType.getBounds();
if (paramBounds != null) {
for (int i = 0; i < bounds.length; i++) {
updateTypeMapping(bounds[i], genericsSymbolTable, paramBounds.get(i), genericArgs,
processedTypeVariables);
}
}
bounds = wildcard.getLowerBounds();
paramBounds = parameterizedType.getLowerBounds();
if (paramBounds != null) {
for (int i = 0; i < bounds.length; i++) {
updateTypeMapping(bounds[i], genericsSymbolTable, paramBounds.get(i), genericArgs,
processedTypeVariables);
}
}
} else if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
java.lang.reflect.Type[] typeArgs = paramType.getActualTypeArguments();
List paramTypeParams = parameterizedType.getParameterizedTypes();
if (paramTypeParams != null) {
for (int i = 0; i < typeArgs.length; i++) {
SymbolType st = null;
if (i < paramTypeParams.size()) {
st = paramTypeParams.get(i);
}
updateTypeMapping(typeArgs[i], genericsSymbolTable, st, genericArgs, processedTypeVariables);
}
}
} else if (type instanceof GenericArrayType) {
GenericArrayType arrayType = (GenericArrayType) type;
SymbolType st = parameterizedType.clone();
st.setArrayCount(parameterizedType.getArrayCount() - 1);
updateTypeMapping(arrayType.getGenericComponentType(), genericsSymbolTable, st, genericArgs,
processedTypeVariables);
} else if (type instanceof Class) {
Class> clazz = (Class>) type;
Map updateMapping = new LinkedHashMap();
SymbolType rewrittenType = SymbolType.valueOf(clazz, parameterizedType, updateMapping,
null);
java.lang.reflect.TypeVariable[] tparams = clazz.getTypeParameters();
List paramTypes = rewrittenType.getParameterizedTypes();
if (paramTypes != null) {
Iterator it = paramTypes.iterator();
HashSet processed = new HashSet();
for (int i = 0; i < tparams.length && it.hasNext(); i++) {
SymbolType st = it.next();
if (st != null) {
st.setTemplateVariable(tparams[i].getName());
updateTypeMapping(tparams[i], genericsSymbolTable, st, true, processed);
}
}
}
}
}
}
}