Package org.allspice.structuredtobc

Source Code of org.allspice.structuredtobc.ClassPool$Entry

/**
  This file is part of allspice.

    allspice is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    allspice 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with allspice.  If not, see <http://www.gnu.org/licenses/>.
**/
package org.allspice.structuredtobc;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.allspice.bytecode.TypeCode;
import org.allspice.bytecode.TypeName;
import org.allspice.structured.ClassDecl;
import org.allspice.structured.ClassType;
import org.allspice.structured.FieldDecl;
import org.allspice.structured.FieldOrMethod;
import org.allspice.structured.FileUnit;
import org.allspice.structured.MethodDecl;
import org.allspice.structured.VarDecl;
import org.allspice.structured.Visibility;
import org.allspice.structured.expr.ConstExpr;
import org.allspice.structured.expr.Expr;
import org.allspice.util.FIFO;
import org.allspice.util.ImmutableCollection;

import com.sun.org.apache.bcel.internal.classfile.Constant;
import com.sun.org.apache.bcel.internal.classfile.ConstantObject;
import com.sun.org.apache.bcel.internal.classfile.ConstantValue;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.ClassPath;
import com.sun.org.apache.bcel.internal.util.SyntheticRepository;

public class ClassPool {
  public final Map<FileUnit,FileUnitInfo> units = new HashMap<FileUnit,FileUnitInfo>() ;
  public final Map<TypeName,ClassStub> classStubs = new HashMap<TypeName,ClassStub>() ;
  public final Entry myClasses ;
  public static final ClassPath classPath = new ClassPath(ClassPath.getClassPath());
  public static final SyntheticRepository repo = SyntheticRepository.getInstance(classPath);
  public static Entry allClasses = new Entry() ;
  public static class FileUnitInfo {
    public final FileUnit unit ;
    public final Map<String,TypeName> aliases = new HashMap<String,TypeName>() ;
    public FileUnitInfo(FileUnit unit) {
      super();
      this.unit = unit;
    }
    public TypeName getFullQualified(String type) {
      if (type.endsWith("[]")) {
        return new TypeName(getFullQualified(type.substring(0,type.length() - 2))+"[]") ;
      }
      TypeName fq = aliases.get(type) ;
      if (fq != null) {
        return fq ;
      }
      return new TypeName(type) ;
    }

  }
  public ClassPool(Collection<FileUnit> fileUnits) {
    myClasses = allClasses.clone();
    for(FileUnit fu: fileUnits) {
      final FileUnitInfo fuinfo = new FileUnitInfo(fu);
      this.units.put(fu,fuinfo) ;
      for(ClassDecl cd: fu.classDecl) {
        TypeName cname = getClassName(fu,cd);
        myClasses.add(cname.toString().replace(".","/")) ;
      }
    }
    for(FileUnit fu: fileUnits) {
      final FileUnitInfo fuinfo = units.get(fu) ;
      for(String imp: fuinfo.unit.imports) {
        myClasses.addAliases(imp, fuinfo.aliases, "",false) ;
      }
      myClasses.addAliases("java.lang.*",fuinfo.aliases, "",true) ;
      if (fu.packageName != null) {
        myClasses.addAliases(fu.packageName+".*",fuinfo.aliases, "",true) ;
      }
    }
  }
  public boolean isPackageOrClass(String s) {
    for(FileUnitInfo fui: units.values()) {
      if (myClasses.isPackageOrClass(s) || fui.aliases.get(s) != null) {
        return true ;
      }
    }
    return allClasses.isPackageOrClass(s) ;
  }
  public boolean find(StubResolver resolver,TypeName s) throws CompilerException {
    if (s.equals(resolver.getTypeName())) {
      return true ;
    }
    ClassStub cl = resolver.getStub() ;
    if (cl.superClass != null) {
      if (find(cl.superClass,s)) {
        return true ;
      }
    }
    for(StubResolver iface: cl.ifaces) {
      if (find(iface,s)) {
        return true ;
      }
    }
    return false ;
  }
 
  public boolean isAutoConvertible(StubResolver resolver,TypeName s) {
    switch(TypeCode.getType(s)) {
    case DOUBLE:
      switch(resolver.getTypeCode()) {
      case DOUBLE:
      case FLOAT:
      case LONG:
      case SHORT:
      case INT:
      case CHAR:
      case BYTE:
        return true ;
      default:
        return false ;
      }
    case FLOAT:
      switch(resolver.getTypeCode()) {
      case FLOAT:
      case LONG:
      case INT:
      case SHORT:
      case CHAR:
      case BYTE:
        return true ;
      default:
        return false ;
      }
    case LONG:
      switch(resolver.getTypeCode()) {
      case LONG:
      case INT:
      case SHORT:
      case CHAR:
      case BYTE:
        return true ;
      default:
        return false ;
      }
    case INT:
      switch(resolver.getTypeCode()) {
      case INT:
      case SHORT:
      case CHAR:
      case BYTE:
        return true ;
      default:
        return false ;
      }
    case BYTE:
      switch(resolver.getTypeCode()) {
      case BYTE:
        return true ;
      default:
        return false ;
      }
    case CHAR:
      switch(resolver.getTypeCode()) {
      case CHAR:
        return true ;
      default:
        return false ;
      }
    case BOOLEAN:
      switch(resolver.getTypeCode()) {
      case BOOLEAN:
        return true ;
      default:
        return false ;
      }
    case SHORT:
      switch(resolver.getTypeCode()) {
      case BYTE:
      case SHORT:
        return true ;
      default:
        return false ;
      }

    case OBJECT:
      break ;
    default :
      return false ;
    }
    return false ;
  }

  public ClassDecl getClassDecl(TypeName name) {
    for(FileUnit fu: units.keySet()) {
      for(ClassDecl cd: fu.classDecl) {
        TypeName cname = getClassName(fu,cd) ;
        if (cname.equals(name)) {
          return cd ;
        }
      }
    }
    return null ;
  }
 
  public static class Entry implements Cloneable {
    public Set<String> items = new TreeSet<String>() ;
    public Map<String,Entry> entries = new HashMap<String,Entry>() ;
    public void addAliases(String s,Map<String,TypeName> aliases,String prefix,boolean ignoreIfPresent) {
      int pos = s.indexOf(".") ;
      if (pos >= 0) {
        String t = s.substring(0,pos) ;
        String u = s.substring(pos + 1) ;
        Entry e = entries.get(t) ;
        if (e == null) {
          return ;
        }
        final String newPrefix = prefix+t+".";
        e.addAliases(u,aliases,newPrefix,ignoreIfPresent) ;
      }
      else {
        if (s.equals("*")) {
          for(String item: items) {
            if (aliases.containsKey(item)) {
              if (!ignoreIfPresent) {
                aliases.put(item,null) ;
              }
            }
            else {
              aliases.put(item,new TypeName(prefix+item)) ;
            }
          }
        }
        else if (items.contains(s)) {
          if (aliases.containsKey(s)) {
            if (!ignoreIfPresent) {
              aliases.put(s,null) ;
            }
          }
          else {
            aliases.put(s,new TypeName(prefix+s)) ;
          }
        }
      }
    }
    public boolean isPackageOrClass(String s) {
      int pos = s.indexOf(".") ;
      if (pos >= 0) {
        String t = s.substring(0,pos) ;
        String u = s.substring(pos + 1) ;
        Entry e = entries.get(t) ;
        if (e == null) {
          return false ;
        }
        return e.isPackageOrClass(u) ;
      }
      else {
        return entries.containsKey(s) || items.contains(s) ;
      }
    }
    public void add(String s) {
      int pos = s.indexOf("/") ;
      if (pos >= 0) {
        String t = s.substring(0,pos) ;
        String u = s.substring(pos + 1) ;
        Entry e = entries.get(t) ;
        if (e == null) {
          e = new Entry() ;
          entries.put(t, e) ;
        }
        e.add(u) ;
      }
      else {
        items.add(s) ;
      }
    }
    @Override
    public String toString() {
      return "["+items+","+entries+"]" ;
    }
    public void spew() {
      System.out.println("items="+items) ;
      for(Map.Entry<String, Entry> e: entries.entrySet()) {
        System.out.println(e.getKey()+"{") ;
        e.getValue().spew();
        System.out.println("}") ;
      }
    }
    @Override
    protected Entry clone() {
      Entry cloned = new Entry() ;
      cloned.items = new HashSet<String>(items) ;
      for(Map.Entry<String, Entry> e: entries.entrySet()) {
        cloned.entries.put(e.getKey(),e.getValue().clone()) ;
      }
      return cloned ;
    }
  }
 
  public static void fill(File dir,String prefix) {
    for(File f: dir.listFiles()) {
      if (f.isDirectory()) {
        fill(f,prefix+f.getName()+"/") ;
      }
      else {
        if (f.getName().endsWith(".class")) {
          allClasses.add(prefix+f.getName().substring(0,f.getName().length() - 6)) ;
        }
      }
    }
  }
 
  static {
    String cp = ClassPath.getClassPath() ;
    StringTokenizer tok = new StringTokenizer(cp,System.getProperty("path.separator"));
    while(tok.hasMoreTokens()) {
      String path = tok.nextToken();
      File f = new File(path) ;
      if (f.isDirectory()) {
        fill(f,"") ;
      }
      else {
        try {
          ZipInputStream zis = new ZipInputStream(new FileInputStream(f)) ;
          try {
            for(;;) {
              ZipEntry entry = zis.getNextEntry();
              if (entry == null) {
                break ;
              }
              final String name = entry.getName();
              if (name.endsWith(".class")) {
                allClasses.add(name.substring(0,name.length() - 6)) ;
              }
            }
          }
          finally {
            zis.close() ;
          }
        } catch (IOException e) {
          continue ;
        }
      }
    }
  }
 
  public FileUnitInfo findFileUnit(FileUnit fu) {
    return units.get(fu) ;
  }
 
  private ClassStub getClassStub(TypeName name) throws CompilerException {
    if (classStubs.containsKey(name)) {
      return classStubs.get(name) ;
    }
    if (name.toString().endsWith("[]")) {
      ClassStub stub = new ClassStub(name,new SimpleResolver(TypeName.OBJECT),false) ;
      classStubs.put(name,stub) ;
      return stub ;
    }
    for(FileUnit fu: units.keySet()) {
      for(ClassDecl cd: fu.classDecl) {
        TypeName cname = ClassPool.getClassName(fu,cd) ;
        if (cname.equals(name)) {
          ClassStub stub = makeClassDeclStub(units.get(fu),cd);
          classStubs.put(name,stub) ;
          return stub ;
        }
      }
    }
    JavaClass jc = repo.findClass(name.toString()) ;
    if (jc == null) {
      try {
        jc = repo.loadClass(name.toString()) ;
      } catch (ClassNotFoundException e) {
        /* jc = null ; */
      }
    }
    if (jc != null) {
      ClassStub stub = makeJavaClassStub(jc) ;
      classStubs.put(name,stub) ;
      return stub ;
    }
    switch(TypeCode.getType(name)) {
    case VOID:
    case BOOLEAN:
    case BYTE:
    case CHAR:
    case DOUBLE:
    case FLOAT:
    case LONG:
    case INT:
    case SHORT:
      ClassStub stub = new ClassStub(name,null,false) ;
      classStubs.put(name,stub) ;
      return stub ;
    default:
      break ;
    }
    throw new UndefinedClass(name) ;
  }
 
  public class SimpleResolver implements StubResolver {
    final TypeName cname ;
   
    public SimpleResolver(TypeName cname) {
      super();
      this.cname = cname;
    }

    @Override
    public ClassStub getStub() throws CompilerException {
      return getClassStub(cname) ;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + getOuterType().hashCode();
      result = prime * result + ((cname == null) ? 0 : cname.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      SimpleResolver other = (SimpleResolver) obj;
      if (!getOuterType().equals(other.getOuterType()))
        return false;
      if (cname == null) {
        if (other.cname != null)
          return false;
      } else if (!cname.equals(other.cname))
        return false;
      return true;
    }

    private ClassPool getOuterType() {
      return ClassPool.this;
    }

    @Override
    public TypeName getTypeName() {
      return cname;
    }

    @Override
    public StubResolver getArrayBase() {
      return new SimpleResolver(cname.getArrayBase()) ;
    }

    @Override
    public TypeCode getTypeCode() {
      return TypeCode.getType(cname) ;
   
  }

  private ClassStub makeJavaClassStub(JavaClass realClass) {
    ClassStub stub;
    StubResolver superc ;
    if (realClass.getSuperclassName() != null && !realClass.getSuperclassName().equals(realClass.getClassName())) {
      superc = new SimpleResolver(new TypeName(realClass.getSuperclassName())) ;
    }
    else {
      superc = null ;
    }

    final TypeName cname = new TypeName(realClass.getClassName());
    stub = new ClassStub(cname,superc,realClass.isInterface()) ;
    StubResolver myStub = new SimpleResolver(cname) ;
   
    final com.sun.org.apache.bcel.internal.classfile.Method[] methods = realClass.getMethods();
    for(com.sun.org.apache.bcel.internal.classfile.Method meth: methods) {
      Type[] type = meth.getArgumentTypes();
      FIFO<StubResolver> types = new FIFO<StubResolver>() ;
      for(Type ptype: type) {
        types = types.insert(new SimpleResolver(new TypeName(ptype.toString()))) ;
      }
      boolean isStatic = false ;
      boolean isPrivate = false ;
      if ((meth.getModifiers() & Modifier.STATIC) != 0) {
        isStatic = true ;       
      }
      if ((meth.getModifiers() & Modifier.PRIVATE) != 0) {
        isPrivate = true ;       
      }
      final TypeName mname = new TypeName(meth.getReturnType().toString()) ;
      StubResolver retType = new SimpleResolver(mname) ;
      stub = stub.addMethod(new MethodStub(meth.getName(),myStub,retType,types,isStatic,isPrivate)) ;
    }
   
    com.sun.org.apache.bcel.internal.classfile.Field[] fields = realClass.getFields();
    for(com.sun.org.apache.bcel.internal.classfile.Field fld: fields) {
      final boolean isStatic = (fld.getModifiers() & Modifier.STATIC) != 0;
      final boolean isFinal = (fld.getModifiers() & Modifier.FINAL) != 0;
      StubResolver fldstub = new SimpleResolver(new TypeName(fld.getType().toString())) ;
      if (isStatic && isFinal) {
        ConstantValue cv = fld.getConstantValue();
        Object o ;
        if (cv != null) {
          Constant c = cv.getConstantPool().getConstant(cv.getConstantValueIndex());
          if (c instanceof ConstantObject) {
            o = ((ConstantObject)c).getConstantValue(cv.getConstantPool()) ;
            try {
              o = StdJavaExpressions.cast( this, fldstub, new ConstObj(o)) ;
            } catch (CompilerException e) {
              o = null ;
            }
          }
          else {
            o = null ;
          }
        }
        else {
          o = null ;
        }
        if (o != null) {
          final FieldStub fldDef = new FieldStub(fld.getName(),myStub,fldstub,isStatic,isFinal,new ConstExpr(o,null));
          stub = stub.addField(fldDef) ;
          continue ;
        }
      }
      stub = stub.addField(new FieldStub(fld.getName(),myStub,fldstub,isStatic,isFinal,null));

    }
   
    String[] ifaces = realClass.getInterfaceNames();
    for(String iface: ifaces) {
      stub = stub.addInterface(new SimpleResolver(new TypeName(iface))) ;
    }
    return stub;
  }
 
  private ClassStub makeClassDeclStub(FileUnitInfo finfo,ClassDecl cd) {
    ClassStub stub;
    TypeName cname = getClassName(finfo.unit,cd) ;
    StubResolver enclosing = new SimpleResolver(cname) ;
    stub = new ClassStub(cname,new SimpleResolver(finfo.getFullQualified(cd.superClass)),cd.classType == ClassType.INTERFACE) ;
    classStubs.put(cname,stub) ;
    boolean foundInit = false ;
    for(FieldOrMethod fom: cd.decls) {
      if (fom instanceof FieldDecl) {
        FieldDecl fdec = (FieldDecl)fom ;
        StubResolver fldstub = new SimpleResolver(finfo.getFullQualified(fdec.type)) ;
        stub = stub.addField(new FieldStub(fdec.name,enclosing,fldstub,fdec.fieldAttrs.isStatic,false,fdec.intializer));
      }
      else if (fom instanceof MethodDecl) {
        MethodDecl mdec = (MethodDecl)fom ;
        FIFO<StubResolver> types = new FIFO<StubResolver>() ;
        for(VarDecl vd: mdec.parameters) {
          types = types.insert(new SimpleResolver(finfo.getFullQualified(vd.type))) ;
        }
        boolean isStatic = false ;
        boolean isPrivate = false ;
        if (mdec.fieldAttrs.isStatic) {
          isStatic = true ;
        }
        if (mdec.fieldAttrs.visibility == Visibility.PRIVATE) {
          isPrivate = true ;
        }
        StubResolver retType = new SimpleResolver(finfo.getFullQualified(mdec.returnType)) ;
        stub = stub.addMethod(new MethodStub(mdec.name,enclosing,retType,types,isStatic,isPrivate)) ;
      }
    }
    if (!foundInit) {
      StubResolver retType = new SimpleResolver(TypeName.VOID) ;
      stub = stub.addMethod(new MethodStub("<init>",enclosing,retType,new FIFO<StubResolver>(),false,false)) ;
    }
    for(String iface: cd.interfaces) {
      stub = stub.addInterface(new SimpleResolver(finfo.getFullQualified(iface))) ;
    }
    return stub;
  }
 
  public boolean isAssignableFrom(TypeName t1,StubResolver s2) throws CompilerException {
    return isAutoConvertible(s2, t1) || isSubClass(t1,s2) ;
  }

  public boolean isSubClass(TypeName t1,StubResolver s2) throws CompilerException {
    if (find(s2,t1)) {
      return true ;
    }
    if (t1.isArray() && TypeCode.getType(s2.getTypeName()) == TypeCode.ARRAY) {
      return isSubClass(t1.getArrayBase(),new SimpleResolver(s2.getTypeName().getArrayBase())) ;
    }
    return false ;
  }

  public FieldStub getField(StubResolver realClass, String fname) throws CompilerException {
    ClassStub stub = realClass.getStub() ;
    {
      FieldStub fd = stub.fields.get(fname) ;
      if (fd != null) {
        return fd ;
      }
    }
    if (stub.superClass != null) {
      FieldStub fd = getField(stub.superClass,fname) ;
      if (fd != null) {
        return fd ;
      }
    }
    for(StubResolver iface: stub.ifaces) {
      FieldStub fd = getField(iface,fname) ;
      if (fd != null) {
        return fd ;
      }
    }
    return null ;
  }
 
  public boolean isSubSet(MethodStub ms1,MethodStub ms2) throws CompilerException {
    Iterator<StubResolver> i = ms1.types.iterator();
    Iterator<StubResolver> j = ms2.types.iterator();
    while(i.hasNext()) {
      StubResolver type1 = i.next();
      StubResolver type2 = j.next();
      if (!isAssignableFrom(type1.getTypeName(), type2)) {
        return false ;
      }
    }
    return true ;
  }

  public MethodStub getMethod(StubResolver realClassResolver, String mname,Collection<Expr> args,EvaluationContext context) throws CompilerException {
    List<MethodStub> methods = new ArrayList<MethodStub>() ;
    getMethods(realClassResolver,mname,args,context,methods) ;
    List<MethodStub> winners = new ArrayList<MethodStub>() ;
    for(MethodStub ms: methods) {
      Iterator<MethodStub> i = winners.iterator() ;
      boolean isLoser = false ;
      while(i.hasNext()) {
        MethodStub winner = i.next() ;
        if (isSubSet(ms, winner)) {
          isLoser = true ;
          break ;
        }
        else if (isSubSet(winner,ms)) {
          i.remove() ;
        }
      }
      if (!isLoser) {
        winners.add(ms) ;
      }
    }
    if (winners.isEmpty()) {
      return null ;
    }
    if (winners.size() > 1) {
      throw new AmbiguousMethod(mname) ;
    }
    return winners.get(0) ;
  }

 
  public void getMethods(StubResolver realClassResolver, String mname,Collection<Expr> args,EvaluationContext context,
      List<MethodStub> methodList) throws CompilerException {
    ClassStub realClass = realClassResolver.getStub() ;
    Collection<MethodStub> bucket = realClass.methods.get(ClassStub.getMethodBucketKey(mname,args.size())) ;
    if (bucket != null) {
      for(MethodStub fd: bucket) {
        if (parameterMatch(args, context, fd.types)) {
          methodList.add(fd) ;
        }
      }
    }
    if (mname.equals("<init>")) {
      for(String key :realClass.methods.keySet()) {
        if (key.startsWith("<init>:")) {
          return ;
        }
      }
      StubResolver retType = new SimpleResolver(TypeName.VOID) ;
      methodList.add(new MethodStub("<init>",new SimpleResolver(realClass.name),retType,new FIFO<StubResolver>(),false,false)) ;
      return ;
    }
    if (mname.equals("<clinit>")) {
      return ;
    }
    if (realClass.superClass != null) {
      getMethods(realClass.superClass,mname,args,context,methodList) ;
    }
    for(StubResolver iface: realClass.ifaces) {
      getMethods(iface,mname,args,context,methodList) ;
    }
  }
 
  private boolean parameterMatch(Collection<Expr> args,
      EvaluationContext context, ImmutableCollection<StubResolver> types) throws CompilerException {
    if (types.size() != args.size()) {
      return false ;
    }
    Iterator<StubResolver> i = types.iterator();
    Iterator<Expr> j = args.iterator();
    while(i.hasNext()) {
      StubResolver param = i.next();
      Expr arg = j.next();
      if (!context.isInstanceOf(param.getTypeName(),arg)) {
        return false ;
      }
    }
    return true;
  }
 
  public static TypeName getClassName(FileUnit fu,ClassDecl cd) {
    return new TypeName((fu.packageName == null ? "" : (fu.packageName+"."))+cd.name);
  }

}
TOP

Related Classes of org.allspice.structuredtobc.ClassPool$Entry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.