/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.compiler.ij.processors;
import gw.fs.IFile;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.expressions.ITypeLiteralExpression;
import gw.lang.reflect.*;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.module.IJreModule;
import gw.lang.reflect.module.IModule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DependencySink {
private final Set<IFile> files = new HashSet<>();
private final Set<String> namespaces = new HashSet<>();
private final Set<String> displayKeys = new HashSet<>();
public Set<IFile> getFiles() {
return files;
}
public Set<String> getDisplayKeys() {
return displayKeys;
}
public void addNamespace(String namespace) {
namespaces.add(namespace);
}
public void addTypes(Set<? extends IType> types) {
for (IType type : types) {
addType(type);
}
}
// Adding type
public void addType(IType type) {
if (type == null) {
throw new IllegalArgumentException("Trying to add null type as a dependency");
}
// we don't care about these types
if (type instanceof ITypeVariableType) {
return;
}
// unwrap meta type
if (type instanceof IMetaType) {
type = ((IMetaType) type).getType();
}
if (type != TypeSystem.getErrorType() /*&& !(expression instanceof ITypeLiteralExpression && isTypeLiteralInAncestry(expression.getParent()))*/) {
processType(type);
}
}
private boolean isTypeLiteralInAncestry(IParsedElement expression) {
if (expression == null) {
return false;
}
if (expression instanceof ITypeLiteralExpression) {
return true;
}
return isTypeLiteralInAncestry(expression.getParent());
}
private void processType(IType type) {
//if (!FileUtil.getTypesForFile(file).contains(type.getName())) {
// de-generify the type
IType genericType = TypeSystem.getPureGenericType(type);
if (genericType != null) {
type = genericType;
}
if (type instanceof ICompoundType) {
for (IType componentType : ((ICompoundType) type).getTypes()) {
processType(componentType);
}
} else {
// deproxy the type
type = IGosuClass.ProxyUtil.getProxiedType(type);
// get the outer-most enclosing type
while (type.getEnclosingType() != null) {
type = type.getEnclosingType();
}
// deproxy the type again
type = IGosuClass.ProxyUtil.getProxiedType(type);
//TODO-dp a Gosu class depends not only on concrete types but also on parameterized and array types, since they can be individually enhanced!
while (type.isArray()) {
type = type.getComponentType();
}
// deproxy the type not once, not twice, but thrice!
type = IGosuClass.ProxyUtil.getProxiedType(type);
files.addAll(getTypeFiles(type));
}
}
public void addDisplayKey(String key) {
final int beginIndex = key.indexOf("displaykey.");
if (beginIndex == -1) {
System.out.println(key);
}
displayKeys.add(beginIndex == -1 ? key : key.substring("displaykey.".length()));
}
private List<IFile> getTypeFiles(IType type) {
if (type == null) {
throw new NullPointerException("Null type passes in.");
}
final ITypeLoader typeLoader = type.getTypeLoader();
if (typeLoader == null) {
return Collections.emptyList(); // E.g. namespace type
}
final IModule module = typeLoader.getModule();
if (module instanceof IJreModule) {
return Collections.emptyList(); // Type from JDK
}
List<IFile> result = Collections.EMPTY_LIST;
if (type instanceof IFileBasedType) {
result = new ArrayList<>();
for (IFile file : ((IFileBasedType) type).getSourceFiles()) {
if (!file.isInJar()) {
result.add(file);
}
}
}
return result;
}
}