WALA/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/translator/polyglot/PolyglotJava2CAstTranslator...

2368 lines
74 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*****************************************************************************/
/*
* Created on Aug 22, 2005
*/
package com.ibm.wala.cast.java.translator.polyglot;
import polyglot.ast.*;
import polyglot.ast.Binary.Operator;
import polyglot.ast.ConstructorCall.Kind;
import polyglot.types.*;
import polyglot.util.Position;
import polyglot.util.SubtypeSet;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.cast.java.loader.Util;
import com.ibm.wala.cast.java.translator.JavaProcedureEntity;
import com.ibm.wala.cast.java.translator.TranslatorToCAst;
import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap;
import com.ibm.wala.cast.java.types.JavaType;
import com.ibm.wala.cast.tree.*;
import com.ibm.wala.cast.tree.impl.*;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.Atom;
import com.ibm.wala.util.IteratorPlusOne;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import java.io.*;
import java.net.*;
import java.util.*;
public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
protected final CAst fFactory= new CAstImpl();
protected final NodeFactory fNodeFactory;
protected final TypeSystem fTypeSystem;
protected Type fNPEType;
protected Type fREType; // RuntimeException
protected final ClassLoaderReference fClassLoaderRef;
private CAstTypeDictionary fTypeDict;
private TranslatingVisitor fTranslator;
protected final boolean DEBUG= true;
/**
* Map from Polyglot local ClassTypes to their enclosing methods. Used by localTypeToTypeID().<br>
* Needed since Polyglot doesn't provide this information. (It doesn't need to, since it
* doesn't need to generate unambiguous names for such entities -- it hands the source
* off to javac to generate bytecode. It probably also wouldn't want to, since that would
* create back-pointers from Type objects in the TypeSystem to AST's.)
*/
protected Map fLocalTypeMap = new LinkedHashMap();
final protected TranslatingVisitor getTranslator() {
if (fTranslator == null)
fTranslator= createTranslator();
return fTranslator;
}
protected TranslatingVisitor createTranslator() {
return new JavaTranslatingVisitorImpl();
}
protected CAstTypeDictionary getTypeDict() {
if (fTypeDict == null) {
fTypeDict= createTypeDict();
}
return fTypeDict;
}
protected PolyglotTypeDictionary createTypeDict() {
return new PolyglotTypeDictionary(fTypeSystem, this);
}
protected static CAstOperator mapUnaryOpcode(Unary.Operator operator) {
if (operator.equals(Unary.BIT_NOT))
return CAstOperator.OP_BITNOT;
if (operator.equals(Unary.NEG))
return CAstOperator.OP_SUB; // CAst will handle OP_SUB with only 1 arg properly !!! Hah!
if (operator.equals(Unary.NOT))
return CAstOperator.OP_NOT;
if (operator.equals(Unary.POS))
return CAstOperator.OP_ADD; // CAst will throw away OP_ADD with only 1 arg!!!
if (operator.equals(Unary.POST_DEC))
return CAstOperator.OP_SUB; // translator will produce different CAstNode types for post dec
if (operator.equals(Unary.POST_INC))
return CAstOperator.OP_ADD; // translator will produce different CAstNode types for post inc
if (operator.equals(Unary.PRE_DEC))
return CAstOperator.OP_SUB; // translator will produce different CAstNode types for pre dec
if (operator.equals(Unary.PRE_INC))
return CAstOperator.OP_ADD; // translator will produce different CAstNode types for pre inc
Assertions.UNREACHABLE("Java2CAstTranslator.JavaTranslatingVisitorImpl.mapUnaryOpcode(): unrecognized unary operator.");
return null;
}
protected static CAstOperator mapBinaryOpcode(Binary.Operator operator) {
if (operator.equals(Binary.ADD))
return CAstOperator.OP_ADD;
if (operator.equals(Binary.BIT_AND))
return CAstOperator.OP_BIT_AND;
if (operator.equals(Binary.BIT_OR))
return CAstOperator.OP_BIT_OR;
if (operator.equals(Binary.BIT_XOR))
return CAstOperator.OP_BIT_XOR;
if (operator.equals(Binary.COND_AND))
return CAstOperator.OP_REL_AND;
if (operator.equals(Binary.COND_OR))
return CAstOperator.OP_REL_OR;
if (operator.equals(Binary.DIV))
return CAstOperator.OP_DIV;
if (operator.equals(Binary.EQ))
return CAstOperator.OP_EQ;
if (operator.equals(Binary.GE))
return CAstOperator.OP_GE;
if (operator.equals(Binary.GT))
return CAstOperator.OP_GT;
if (operator.equals(Binary.LE))
return CAstOperator.OP_LE;
if (operator.equals(Binary.LT))
return CAstOperator.OP_LT;
if (operator.equals(Binary.MOD))
return CAstOperator.OP_MOD;
if (operator.equals(Binary.MUL))
return CAstOperator.OP_MUL;
if (operator.equals(Binary.NE))
return CAstOperator.OP_NE;
if (operator.equals(Binary.SHL))
return CAstOperator.OP_LSH;
if (operator.equals(Binary.SHR))
return CAstOperator.OP_RSH;
if (operator.equals(Binary.SUB))
return CAstOperator.OP_SUB;
if (operator.equals(Binary.USHR))
return CAstOperator.OP_URSH;
Assertions.UNREACHABLE("Java2CAstTranslator.JavaTranslatingVisitorImpl.mapBinaryOpcode(): unrecognized binary operator.");
return null;
}
protected class JavaTranslatingVisitorImpl implements TranslatingVisitor {
public CAstNode visit(MethodDecl m, MethodContext mc) {
if (m.body() == null || m.body().statements().size() == 0)
return makeNode(mc, fFactory, m, CAstNode.RETURN);
else
return walkNodes(m.body(), mc);
}
public CAstNode visit(ConstructorDecl cd, MethodContext mc) {
// Needs to examine the initializers in the ClassContext
// and glue that code into the right place relative to the
// constructor method body ("wherever that may turn out to be").
List/*<FieldDecl|Initializer>*/ inits= mc.getInitializers();
Block body= cd.body();
if (hasSuperCall(body)) {
// Split at call to super:
// super();
// field initializer code
// remainder of ctor body
CAstNode[] bodyNodes= new CAstNode[inits.size()+body.statements().size()];
int idx= 0;
for(Iterator iter= body.statements().iterator(); iter.hasNext(); ) {
Stmt s= (Stmt) iter.next();
bodyNodes[idx++]= walkNodes(s, mc);
if (idx == 1) {
Assertions._assert(isSpecialCallStmt(s, ConstructorCall.SUPER));
idx= insertInitializers(mc, bodyNodes, idx);
}
}
return makeNode(mc, fFactory, body, CAstNode.BLOCK_STMT, bodyNodes);
} else if (hasThisCall(body)) {
return walkNodes(body, mc);
} else {
// add explicit call to default super()
// TODO following superClass lookup of default ctor won't work if we process Object in source...
ClassType superClass= (ClassType) cd.constructorInstance().container().superType();
ProcedureInstance defaultSuperCtor= findDefaultCtor(superClass);
CAstNode[] bodyNodes= new CAstNode[inits.size()+body.statements().size()+1];
CallSiteReference callSiteRef= CallSiteReference.make(0, referenceForMethod(defaultSuperCtor), IInvokeInstruction.Dispatch.SPECIAL);
CAstNode superCall= makeNode(mc, fFactory, cd, CAstNode.CALL, makeNode(mc, fFactory, cd, CAstNode.SUPER),
fFactory.makeConstant(callSiteRef));
bodyNodes[0]= superCall;
insertInitializers(mc, bodyNodes, 1);
int idx= inits.size() + 1;
for(Iterator iter= body.statements().iterator(); iter.hasNext(); idx++) {
Stmt s= (Stmt) iter.next();
bodyNodes[idx]= walkNodes(s, mc);
}
return makeNode(mc, fFactory, body, CAstNode.BLOCK_STMT, bodyNodes);
}
}
private ProcedureInstance findDefaultCtor(ClassType superClass) {
List/*<ProcedureInstance>*/ ctors= superClass.constructors();
for(Iterator iter= ctors.iterator(); iter.hasNext();) {
ConstructorInstance ctor= (ConstructorInstance) iter.next();
if (ctor.formalTypes().isEmpty())
return ctor;
}
Assertions.UNREACHABLE("Couldn't find default ctor");
return null;
}
public CAstNode visit(FieldDecl f, MethodContext ctorContext) {
// Generate CAST node for the initializer (init())
Type targetType= f.memberInstance().container();
Type fieldType= f.type().type();
TypeReference targetTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType));
TypeReference fieldTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType));
Atom fieldName= Atom.findOrCreateUnicodeAtom(f.name());
FieldReference fieldRef= FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef);
// We use null to indicate an OBJECT_REF to a static field, as the FieldReference doesn't
// hold enough info to determine this. In this case, (unlike field ref) we don't have a
// target expr to evaluate.
CAstNode thisNode= f.flags().isStatic() ? null : makeNode(ctorContext, fFactory, f, CAstNode.THIS);
CAstNode lhsNode= makeNode(ctorContext, fFactory, f, CAstNode.OBJECT_REF, thisNode, fFactory.makeConstant(fieldRef));
Expr init= f.init();
CAstNode rhsNode= walkNodes(init, ctorContext);
CAstNode assNode= makeNode(ctorContext, fFactory, f, CAstNode.ASSIGN, lhsNode, rhsNode);
return assNode;
}
public CAstNode visit(Import i, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(Import)");
return null;
}
public CAstNode visit(PackageNode p, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(PackageNode)");
return null;
}
public CAstNode visit(CanonicalTypeNode ctn, WalkContext wc) {
// We'll take care of this in its surrounding context...
return makeNode(wc, fFactory, null, CAstNode.EMPTY);
}
public CAstNode visit(ArrayTypeNode ctn, WalkContext wc) {
// We'll take care of this in its surrounding context...
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(CanonicalTypeNode)");
return null;
}
public CAstNode visit(ArrayInit ai, WalkContext wc) {
if (((ArrayType)ai.type()).base().isNull()) {
Assertions._assert(false,
"bad type " + ai.type() + " for " + ai + " at " + ai.position());
}
TypeName newTypeName =
TypeName.string2TypeName(typeToTypeID(ai.type()));
TypeReference newTypeRef =
TypeReference.findOrCreate(fClassLoaderRef, newTypeName);
CAstNode[] eltNodes= new CAstNode[ai.elements().size() + 1];
int idx=0;
eltNodes[idx++] =
makeNode(wc, fFactory, ai, CAstNode.NEW,
fFactory.makeConstant( newTypeRef ),
fFactory.makeConstant( ai.elements().size() ));
for(Iterator iter= ai.elements().iterator(); iter.hasNext(); idx++) {
Expr element= (Expr) iter.next();
eltNodes[idx]= walkNodes(element, wc);
if (eltNodes[idx] == null) {
Assertions._assert(eltNodes[idx] != null, element.toString());
}
}
return makeNode(wc, fFactory, ai, CAstNode.ARRAY_LITERAL, eltNodes);
}
public CAstNode visit(ArrayAccessAssign aaa, WalkContext wc) {
return processAssign(aaa, wc);
}
public CAstNode visit(FieldAssign fa, WalkContext wc) {
return processAssign(fa, wc);
}
public CAstNode visit(LocalAssign la, WalkContext wc) {
return processAssign(la, wc);
}
private CAstNode processAssign(Assign la, WalkContext wc) {
if (la.operator() == Assign.ASSIGN)
return makeNode(wc, fFactory, la, CAstNode.ASSIGN, walkNodes(la.left(), wc), walkNodes(la.right(), wc));
else
return makeNode(wc, fFactory, la, CAstNode.ASSIGN_PRE_OP, walkNodes(la.left(), wc), walkNodes(la.right(), wc), mapAssignOperator(la.operator()));
}
protected CAstOperator mapAssignOperator(Assign.Operator op) {
if (op == Assign.ADD_ASSIGN) return CAstOperator.OP_ADD;
else if (op == Assign.BIT_AND_ASSIGN) return CAstOperator.OP_BIT_AND;
else if (op == Assign.BIT_OR_ASSIGN) return CAstOperator.OP_BIT_OR;
else if (op == Assign.BIT_XOR_ASSIGN) return CAstOperator.OP_BIT_XOR;
else if (op == Assign.DIV_ASSIGN) return CAstOperator.OP_DIV;
else if (op == Assign.MOD_ASSIGN) return CAstOperator.OP_MOD;
else if (op == Assign.MUL_ASSIGN) return CAstOperator.OP_MUL;
else if (op == Assign.SHL_ASSIGN) return CAstOperator.OP_LSH;
else if (op == Assign.SHR_ASSIGN) return CAstOperator.OP_RSH;
else if (op == Assign.SUB_ASSIGN) return CAstOperator.OP_SUB;
else if (op == Assign.USHR_ASSIGN) return CAstOperator.OP_URSH;
Assertions.UNREACHABLE("Unknown assignment operator");
return null;
}
public CAstNode visit(Binary b, WalkContext wc) {
Expr left= b.left();
Expr right= b.right();
Operator operator= b.operator();
if (operator.equals(Binary.COND_AND))
return makeNode(wc, fFactory, b, CAstNode.IF_EXPR, walkNodes(left, wc), walkNodes(right, wc), fFactory.makeConstant(false));
else if (operator.equals(Binary.COND_OR))
return makeNode(wc, fFactory, b, CAstNode.IF_EXPR, walkNodes(left, wc), fFactory.makeConstant(true), walkNodes(right, wc));
else
return makeNode(wc, fFactory, b, CAstNode.BINARY_EXPR, mapBinaryOpcode(operator), walkNodes(left, wc), walkNodes(right, wc));
}
private void handleThrowsFromCall(ProcedureInstance procedureInstance,
Node callAstNode,
WalkContext wc)
{
List/*<Type>*/ throwTypes= procedureInstance.throwTypes();
for(Iterator iter =
new IteratorPlusOne(throwTypes.iterator(), fREType);
iter.hasNext(); )
{
Type thrownType= (Type) iter.next();
Collection/*<Pair<Type,Node>>*/ catchTargets =
wc.getCatchTargets(thrownType);
for(Iterator targetIter= catchTargets.iterator();
targetIter.hasNext(); )
{
Pair/*<Type,Node>*/ catchTarget=
(Pair/*<Type,Node>*/) targetIter.next();
wc.cfg().add(callAstNode, catchTarget.snd, catchTarget.fst);
}
}
}
public CAstNode visit(Call c, WalkContext wc) {
MethodInstance methodInstance= c.methodInstance();
boolean isStatic= methodInstance.flags().isStatic();
ReferenceType methodOwner= methodInstance.container();
if (methodOwner.isArray()) {
List realOne = methodInstance.overrides();
Assertions._assert(realOne.size() == 2, "bad array method");
methodInstance = (MethodInstance)realOne.get(1);
methodOwner= methodInstance.container();
}
if (! methodOwner.isClass()) {
Assertions._assert(false, "owner " + methodOwner + " of " + methodInstance + " is not a class");
}
boolean isIntf= ((ClassType) methodOwner).flags().isInterface();
Receiver target= c.target();
boolean isSpecial= methodInstance.flags().isPrivate() || (target instanceof Special && ((Special) target).kind() == Special.SUPER);
CAstNode[] children= new CAstNode[2 + methodInstance.formalTypes().size()]; // including the MethodReference
int i=0;
if (!isStatic)
children[i++]= walkNodes(target, wc);
else
children[i++]= makeNode(wc, fFactory, null, CAstNode.VOID);
if (children[0] == null) {
Assertions._assert(children[0] != null,
"no receiver for " + methodInstance + " in " +
wc.getEnclosingMethodName());
}
MethodReference methodRef= referenceForMethod(methodInstance);
int dummyPC= 0; // Just want to wrap the kind of call; the "rear end" won't care about anything else...
CallSiteReference callSiteRef;
if (isStatic)
callSiteRef= CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.STATIC);
else if (isIntf)
callSiteRef= CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.INTERFACE);
else if (isSpecial)
callSiteRef= CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.SPECIAL);
else
callSiteRef= CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.VIRTUAL);
children[i++]= fFactory.makeConstant(callSiteRef);
for(Iterator iter= c.arguments().iterator(); iter.hasNext(); ) {
Expr arg= (Expr) iter.next();
children[i++]= walkNodes(arg, wc);
}
handleThrowsFromCall(methodInstance, c, wc);
CAstNode result= makeNode(wc, fFactory, c, CAstNode.CALL, children);
wc.cfg().map(c, result);
return result;
}
public CAstNode visit(ConstructorCall cc, WalkContext wc) {
ConstructorInstance ctorInstance= cc.constructorInstance();
ReferenceType methodOwner= ctorInstance.container();
Assertions._assert(methodOwner.isClass());
MethodReference methodRef= referenceForMethod(ctorInstance);
int dummyPC= 0; // Just want to wrap the kind of call; the "rear end" won't care about anything else...
CallSiteReference callSiteRef= CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] children= new CAstNode[1 + 1 + ctorInstance.formalTypes().size()]; // including the MethodReference
int i=0;
CAstNode targetNode;
targetNode= (cc.kind() == ConstructorCall.THIS) ?
makeNode(wc, fFactory, cc, CAstNode.THIS) :
makeNode(wc, fFactory, cc, CAstNode.SUPER);
children[i++]= targetNode;
children[i++]= fFactory.makeConstant(callSiteRef);
for(Iterator iter= cc.arguments().iterator(); iter.hasNext(); ) {
Expr arg= (Expr) iter.next();
children[i++]= walkNodes(arg, wc);
}
handleThrowsFromCall(ctorInstance, cc, wc);
CAstNode result = makeNode(wc, fFactory, cc, CAstNode.CALL, children);
wc.cfg().map(cc, result);
return result;
}
public CAstNode visit(Cast c, WalkContext wc) {
Expr arg= c.expr();
Type castedTo= c.castType().type();
// TODO maybe use a TypeReference below instead of a CAstType
return makeNode(wc, fFactory, c, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(castedTo)), walkNodes(arg, wc));
}
public CAstNode visit(Conditional c, WalkContext wc) {
return makeNode(wc, fFactory, c, CAstNode.IF_EXPR, walkNodes(c.cond(), wc), walkNodes(c.consequent(), wc), walkNodes(c.alternative(), wc));
}
public CAstNode visit(Instanceof io, WalkContext wc) {
return makeNode(wc, fFactory, io, CAstNode.INSTANCEOF, fFactory.makeConstant(getTypeDict().getCAstTypeFor(io.compareType().type())), walkNodes(io.expr(), wc));
}
public CAstNode visit(BooleanLit bl, WalkContext wc) {
return fFactory.makeConstant(bl.value());
}
public CAstNode visit(ClassLit cl, WalkContext wc) {
Type litType = cl.typeNode().type();
String typeName = typeToTypeID(litType);
return makeNode(wc, fFactory, cl, CAstNode.TYPE_LITERAL_EXPR,
fFactory.makeConstant(typeName));
}
public CAstNode visit(FloatLit fl, WalkContext wc) {
return (fl.kind() == FloatLit.FLOAT) ?
fFactory.makeConstant((float) fl.value()) :
fFactory.makeConstant(fl.value());
}
public CAstNode visit(NullLit nl, WalkContext wc) {
return fFactory.makeConstant(null);
}
public CAstNode visit(CharLit cl, WalkContext wc) {
return fFactory.makeConstant(cl.value());
}
public CAstNode visit(IntLit il, WalkContext wc) {
return makeNode(wc, fFactory, il, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(il.type())), fFactory.makeConstant((int)il.value()));
}
public CAstNode visit(StringLit sl, WalkContext wc) {
return fFactory.makeConstant(sl.value());
}
public CAstNode visit(New n, WalkContext wc) {
String newTypeNameStr;
CAstEntity anonClass= null;
if (n.body() != null) {
fLocalTypeMap.put(n.type(), wc.getEnclosingMethodName());
anonClass= walkEntity(n, wc);
newTypeNameStr= anonClass.getType().getName();
} else {
newTypeNameStr= typeToTypeID(n.type());
}
TypeName newTypeName= TypeName.string2TypeName(newTypeNameStr);
TypeReference newTypeRef= TypeReference.findOrCreate(fClassLoaderRef, newTypeName);
ConstructorInstance ctorInst= n.constructorInstance();
MethodReference ctorRef = referenceForMethod(newTypeRef, ctorInst);
List/*<Expr>*/ args= n.arguments();
String tmpName= "ctor temp"; // this name is an illegal Java identifier
CAstNode newNode= makeNode(wc, fFactory, n, CAstNode.NEW, fFactory.makeConstant(newTypeRef));
if (n.body() != null)
wc.addScopedEntity(newNode, anonClass);
int dummyPC= 0; // Just want to wrap the kind of call; the "rear end" won't care about anything else...
CallSiteReference callSiteRef= CallSiteReference.make(dummyPC, ctorRef, IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] argNodes= new CAstNode[args.size() + 2]; // args + recvr + ctor ref
int idx= 0;
argNodes[idx++]= makeNode(wc, fFactory, n, CAstNode.VAR, fFactory.makeConstant(tmpName));
argNodes[idx++]= fFactory.makeConstant(callSiteRef);
for(Iterator iter= args.iterator(); iter.hasNext(); ) {
Expr arg= (Expr) iter.next();
argNodes[idx++]= walkNodes(arg, wc);
}
CAstNode callNode= makeNode(wc, fFactory, n, CAstNode.CALL, argNodes);
wc.cfg().map(n, callNode);
handleThrowsFromCall(ctorInst, n, wc);
return makeNode(wc, fFactory, n, CAstNode.LOCAL_SCOPE,
makeNode(wc, fFactory, n, CAstNode.BLOCK_EXPR,
makeNode(wc, fFactory, n, CAstNode.DECL_STMT,
makeNode(wc, fFactory, n, CAstNode.VAR, fFactory.makeConstant(tmpName)),
fFactory.makeConstant(true),
fFactory.makeConstant(false),
newNode),
callNode,
makeNode(wc, fFactory, n, CAstNode.VAR, fFactory.makeConstant(tmpName))));
}
public CAstNode visit(NewArray na, WalkContext wc) {
Type newType= na.type();
ArrayInit ai= na.init();
Assertions._assert(newType.isArray());
if (ai != null) {
return visit(ai, wc);
} else {
ArrayType arrayType= (ArrayType) newType;
TypeName arrayTypeName= TypeName.string2TypeName(typeToTypeID(arrayType));
TypeReference arrayTypeRef= TypeReference.findOrCreate(fClassLoaderRef, arrayTypeName);
List/*<Expr>*/ dims= na.dims();
CAstNode[] args= new CAstNode[dims.size() + 1];
int idx= 0;
args[idx++]= fFactory.makeConstant(arrayTypeRef);
for(Iterator iter= dims.iterator(); iter.hasNext(); ) {
Expr dimExpr= (Expr) iter.next();
args[idx++]= walkNodes(dimExpr, wc);
}
return makeNode(wc, fFactory, na, CAstNode.NEW, args);
}
}
public CAstNode visit(Special s, WalkContext wc) {
if (s.qualifier() != null) {
Type owningType= s.qualifier().type();
TypeName owningTypeName =
TypeName.string2TypeName(typeToTypeID(owningType));
TypeReference owningTypeRef =
TypeReference.findOrCreate(fClassLoaderRef, owningTypeName);
return makeNode(wc, fFactory, s,
s.kind() == Special.THIS ? CAstNode.THIS: CAstNode.SUPER,
fFactory.makeConstant(owningTypeRef));
} else {
return makeNode(wc, fFactory, s,
s.kind() == Special.THIS ? CAstNode.THIS : CAstNode.SUPER);
}
}
public CAstNode visit(Unary u, WalkContext wc) {
if (isAssignOp(u.operator())) {
if (u.operator().isPrefix())
return makeNode(wc, fFactory, u, CAstNode.ASSIGN_PRE_OP, walkNodes(u.expr(), wc), fFactory.makeConstant(1), mapUnaryOpcode(u.operator()));
else
return makeNode(wc, fFactory, u, CAstNode.ASSIGN_POST_OP, walkNodes(u.expr(), wc), fFactory.makeConstant(1), mapUnaryOpcode(u.operator()));
} else if (u.operator() == Unary.POS) // drop useless unary plus operator
return walkNodes(u.expr(), wc);
else if (u.operator() == Unary.NEG) {
CAstNode zero;
if (u.expr().type().isLongOrLess())
zero= fFactory.makeConstant(0L);
else
zero= fFactory.makeConstant(0.0);
return makeNode(wc, fFactory, u, CAstNode.BINARY_EXPR, CAstOperator.OP_SUB, zero, walkNodes(u.expr(), wc));
} else
return makeNode(wc, fFactory, u, CAstNode.UNARY_EXPR, mapUnaryOpcode(u.operator()), walkNodes(u.expr(), wc));
}
protected boolean isAssignOp(Unary.Operator operator) {
return operator == Unary.POST_DEC || operator == Unary.POST_INC ||
operator == Unary.PRE_DEC || operator == Unary.PRE_INC;
}
public CAstNode visit(ArrayAccess aa, WalkContext wc) {
TypeName eltTypeName= TypeName.string2TypeName(typeToTypeID(aa.type()));
TypeReference eltTypeRef= TypeReference.findOrCreate(fClassLoaderRef, eltTypeName);
return makeNode(wc, fFactory, aa, CAstNode.ARRAY_REF, walkNodes(aa.array(), wc),
fFactory.makeConstant(eltTypeRef),
walkNodes(aa.index(), wc));
}
public CAstNode visit(Field f, WalkContext wc) {
Receiver target= f.target();
Type targetType= target.type();
Type fieldType= f.type();
if (targetType.isArray()) {
Assertions._assert(f.name().equals("length"));
return makeNode(wc, fFactory, f, CAstNode.ARRAY_LENGTH, walkNodes(target, wc));
}
TypeReference targetTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType));
TypeReference fieldTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType));
Atom fieldName= Atom.findOrCreateUnicodeAtom(f.name());
FieldReference fieldRef= FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef);
CAstNode targetNode= walkNodes(target, wc);
if (f.fieldInstance().flags().isStatic()) {
// JLS says: evaluate the target of the field ref and throw it away.
// Hence the following block expr, whose 2 children are the target evaluation
// followed by the OBJECT_REF with a null target child (which the "back-end"
// CAst -> IR translator interprets as a static ref).
return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR,
targetNode,
makeNode(wc, fFactory, f, CAstNode.OBJECT_REF, makeNode(wc, fFactory, null, CAstNode.VOID), fFactory.makeConstant(fieldRef)));
} else {
Collection excTargets= wc.getCatchTargets(fNPEType);
if (!excTargets.isEmpty()) {
// connect NPE exception edge to relevant catch targets (presumably only one)
for(Iterator iterator= excTargets.iterator(); iterator.hasNext(); ) {
Pair catchPair = (Pair)iterator.next();
wc.cfg().add(f, catchPair.snd, fNPEType);
}
} else {
// connect exception edge to exit
wc.cfg().add(f, CAstControlFlowMap.EXCEPTION_TO_EXIT, fNPEType);
}
CAstNode refNode= makeNode(wc, fFactory, f, CAstNode.OBJECT_REF, targetNode, fFactory.makeConstant(fieldRef));
wc.cfg().map(f, refNode);
return refNode;
}
}
public CAstNode visit(Local l, WalkContext wc) {
return makeNode(wc, fFactory, l, CAstNode.VAR, fFactory.makeConstant(l.name()));
}
public CAstNode visit(ClassBody cb, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(ClassBody)");
return null;
}
public CAstNode visit(ClassDecl cd, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(ClassDecl)");
return null;
}
public CAstNode visit(Initializer i, WalkContext wc) {
// Perhaps this is invoked from within the ConstructorDecl visit() method...
return walkNodes(i.body(), wc);
}
public CAstNode visit(Assert a, WalkContext wc) {
return PolyglotJava2CAstTranslator.this.makeNode(wc, fFactory, a, CAstNode.ASSERT, walkNodes(a.cond(), wc));
}
public CAstNode visit(Branch b, WalkContext wc) {
Node target = null;
if (b.kind() == Branch.BREAK) {
target = wc.getBreakFor(b.label());
} else {
target = wc.getContinueFor(b.label());
}
Assertions._assert(target != null);
CAstNode result = makeNode(wc, fFactory, b, CAstNode.GOTO);
wc.cfg().map(b, result);
wc.cfg().add(b, target, null);
return result;
}
public CAstNode visit(Block b, WalkContext wc) {
CAstNode[] stmtNodes= new CAstNode[b.statements().size()];
int idx= 0;
for(Iterator iter= b.statements().iterator(); iter.hasNext(); idx++) {
Stmt s= (Stmt) iter.next();
stmtNodes[idx]= walkNodes(s, wc);
}
return makeNode(wc, fFactory, b, CAstNode.LOCAL_SCOPE,
makeNode(wc, fFactory, b, CAstNode.BLOCK_STMT, stmtNodes));
}
public CAstNode visit(SwitchBlock sb, WalkContext wc) {
CAstNode[] stmtNodes= new CAstNode[sb.statements().size()];
int idx= 0;
for(Iterator iter= sb.statements().iterator(); iter.hasNext(); idx++) {
Stmt s= (Stmt) iter.next();
stmtNodes[idx]= walkNodes(s, wc);
}
return makeNode(wc, fFactory, sb, CAstNode.BLOCK_STMT, stmtNodes);
}
public CAstNode visit(Catch c, WalkContext wc) {
Block body= c.body();
Formal f= c.formal();
CAstNode excDecl = makeNode(wc, fFactory, c, CAstNode.CATCH,
fFactory.makeConstant(f.name()),
walkNodes(body, wc));
CAstNode localScope=
makeNode(wc, fFactory, c, CAstNode.LOCAL_SCOPE, excDecl);
wc.cfg().map(c, excDecl);
wc.getNodeTypeMap().add(excDecl, wc.getTypeDictionary().getCAstTypeFor(c.catchType()));
return localScope;
}
public CAstNode visit(If i, WalkContext wc) {
return makeNode(wc, fFactory, i, CAstNode.IF_STMT, walkNodes(i.cond(), wc), walkNodes(i.consequent(), wc), walkNodes(i.alternative(), wc));
}
public CAstNode visit(Labeled l, WalkContext wc) {
Node stmt = l.statement();
while (stmt instanceof Block) {
stmt = (Node)((Block)stmt).statements().iterator().next();
}
wc.getLabelMap().put(stmt, l.label());
CAstNode result =
makeNode(wc, fFactory, l, CAstNode.LABEL_STMT,
fFactory.makeConstant(l.label()),
walkNodes(l.statement(), wc));
wc.cfg().map(l, result);
wc.getLabelMap().remove(stmt);
return result;
}
public CAstNode visit(LocalClassDecl lcd, WalkContext wc) {
fLocalTypeMap.put(lcd.decl().type(), wc.getEnclosingMethodName());
CAstEntity classEntity= walkEntity(lcd.decl(), wc);
final CAstNode lcdNode= makeNode(wc, fFactory, lcd, CAstNode.EMPTY);
wc.addScopedEntity(lcdNode, classEntity);
return lcdNode;
}
private Node makeBreakTarget(Node loop) {
return
fNodeFactory.Labeled(
Position.COMPILER_GENERATED,
"breakLabel"+loop.position().toString(),
fNodeFactory.Empty(Position.COMPILER_GENERATED));
}
private Node makeContinueTarget(Node loop) {
return
fNodeFactory.Labeled(
Position.COMPILER_GENERATED,
"continueLabel"+loop.position().toString(),
fNodeFactory.Empty(Position.COMPILER_GENERATED));
}
public CAstNode visit(Do d, WalkContext wc) {
Node header = fNodeFactory.Empty(Position.COMPILER_GENERATED);
Node breakTarget = makeBreakTarget(d);
Node continueTarget = makeContinueTarget(d);
CAstNode loopGoto =
makeNode(wc, fFactory, d, CAstNode.IFGOTO, walkNodes( d.cond(), wc ));
wc.cfg().map(loopGoto, loopGoto);
wc.cfg().add(loopGoto, header, Boolean.TRUE);
String loopLabel = (String) wc.getLabelMap().get(d);
WalkContext lc =
new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode continueNode = walkNodes(continueTarget, wc);
return makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
walkNodes(header, wc),
makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
walkNodes(d.body(),lc),
continueNode),
loopGoto,
walkNodes(breakTarget, wc));
}
public CAstNode visit(For f, WalkContext wc) {
Node breakTarget = makeBreakTarget(f);
Node continueTarget = makeContinueTarget(f);
String loopLabel = (String) wc.getLabelMap().get(f);
WalkContext lc =
new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode[] inits = new CAstNode[f.inits().size()];
for(int i = 0; i < inits.length; i++){
inits[i] = walkNodes((Node)f.inits().get(i), wc);
}
CAstNode[] iters = new CAstNode[f.iters().size()];
for(int i = 0; i < iters.length; i++){
iters[i] = walkNodes((Node)f.iters().get(i), wc);
}
CAstNode initsBlock = makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, inits);
CAstNode itersBlock = makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, iters);
return makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT,
initsBlock,
makeNode(wc, fFactory, f, CAstNode.LOOP,
walkNodes(f.cond(), wc),
makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT,
walkNodes( f.body(), lc ),
walkNodes(continueTarget, wc),
itersBlock)),
walkNodes(breakTarget, wc));
}
public CAstNode visit(While w, WalkContext wc) {
Expr c = w.cond();
Stmt b = w.body();
Node breakTarget = makeBreakTarget(w);
Node continueTarget = makeContinueTarget(w);
String loopLabel = (String) wc.getLabelMap().get(w);
LoopContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
/*
* The following loop is created sligtly differently than in jscore.
* It doesn't have a specific target for continue.
*/
return makeNode(wc, fFactory, w, CAstNode.BLOCK_STMT,
makeNode(wc, fFactory, w, CAstNode.LOOP,
walkNodes(c, wc ),
makeNode(wc, fFactory, w, CAstNode.BLOCK_STMT,
walkNodes(b, lc ),
walkNodes(continueTarget, wc))),
walkNodes(breakTarget, wc));
}
public CAstNode visit(Switch s, WalkContext wc) {
Node breakLabel= fNodeFactory.Labeled(Position.COMPILER_GENERATED, "break"+s.position().toString(), null);
CAstNode breakAst= walkNodes(breakLabel, wc);
String loopLabel = (String) wc.getLabelMap().get(s);
WalkContext child= new SwitchContext(wc, loopLabel, breakLabel);
Expr cond= s.expr();
List cases= s.elements();
// First compute the control flow edges for the various case labels
for(int i = 0; i < cases.size(); i++) {
SwitchElement se= (SwitchElement) cases.get(i);
if (se instanceof Case) {
Case c= (Case) se;
if (c.isDefault())
wc.cfg().add(s, c, CAstControlFlowMap.SWITCH_DEFAULT);
else
wc.cfg().add(s, c, fFactory.makeConstant(c.value()));
}
}
CAstNode[] caseNodes= new CAstNode[cases.size()];
// Now produce the CAst representation for each case
int idx=0;
for(Iterator iter= cases.iterator(); iter.hasNext(); idx++) {
SwitchElement se= (SwitchElement) iter.next();
caseNodes[idx]= walkNodes(se, child);
}
// Now produce the switch stmt itself
CAstNode switchAst =
makeNode(wc, fFactory, s, CAstNode.SWITCH, walkNodes(cond, wc),
makeNode(wc, fFactory, s, CAstNode.BLOCK_STMT, caseNodes));
wc.cfg().map(s, switchAst);
wc.cfg().map(breakLabel, breakAst);
// Finally, wrap the entire switch in a block so that we have a
// well-defined place to 'break' to.
return makeNode(wc, fFactory, s, CAstNode.BLOCK_STMT, switchAst, breakAst);
}
public CAstNode visit(Synchronized s, WalkContext wc) {
CAstNode exprNode= walkNodes(s.expr(), wc);
String exprName= fFactory.makeUnique();
CAstNode declStmt= makeNode(wc, fFactory, s, CAstNode.DECL_STMT,
makeNode(wc, fFactory, s, CAstNode.VAR, fFactory.makeConstant(exprName)),
fFactory.makeConstant(true),
fFactory.makeConstant(false),
exprNode);
CAstNode monitorEnterNode= makeNode(wc, fFactory, s, CAstNode.MONITOR_ENTER, makeNode(wc, fFactory, s, CAstNode.VAR, fFactory.makeConstant(exprName)));
CAstNode bodyNodes= walkNodes(s.body(), wc);
CAstNode monitorExitNode= makeNode(wc, fFactory, s, CAstNode.MONITOR_EXIT, makeNode(wc, fFactory, s, CAstNode.VAR, fFactory.makeConstant(exprName)));
CAstNode tryBody= makeNode(wc, fFactory, s, CAstNode.BLOCK_STMT, monitorEnterNode, bodyNodes);
CAstNode bigBody= makeNode(wc, fFactory, s, CAstNode.UNWIND, tryBody, monitorExitNode);
return makeNode(wc, fFactory, s, CAstNode.BLOCK_STMT, declStmt, bigBody);
}
public CAstNode visit(Try t, WalkContext wc) {
List catchBlocks= t.catchBlocks();
Block finallyBlock= t.finallyBlock();
Block tryBlock= t.tryBlock();
// try/finally
if (catchBlocks.isEmpty()) {
return makeNode(wc, fFactory, t, CAstNode.UNWIND,
walkNodes(tryBlock, wc),
walkNodes(finallyBlock, wc));
// try/catch/[finally]
} else {
TryCatchContext tc= new TryCatchContext(wc, t);
CAstNode tryNode = walkNodes(tryBlock, tc);
for(Iterator iter= catchBlocks.iterator(); iter.hasNext();) {
tryNode = makeNode(wc, fFactory, t, CAstNode.TRY,
tryNode,
walkNodes((Catch)iter.next(), wc));
}
// try/catch
if (finallyBlock == null) {
return tryNode;
// try/catch/finally
} else {
return makeNode(wc, fFactory, t, CAstNode.UNWIND,
tryNode,
walkNodes(finallyBlock, wc));
}
}
}
public CAstNode visit(Empty e, WalkContext wc) {
CAstNode result = makeNode(wc, fFactory, e, CAstNode.EMPTY);
wc.cfg().map(e, result);
return result;
}
public CAstNode visit(Eval e, WalkContext wc) {
return walkNodes(e.expr(), wc);
}
public CAstNode visit(LocalDecl ld, WalkContext wc) {
Expr init= ld.init();
Type type= ld.declType();
CAstNode initNode;
if (init == null) {
if (type.isLongOrLess())
initNode= fFactory.makeConstant(0);
else if (type.isDouble() || type.isFloat())
initNode= fFactory.makeConstant(0.0);
else
initNode= fFactory.makeConstant(null);
} else
initNode= walkNodes(init, wc);
boolean isFinal = ld.flags().isFinal();
return makeNode(wc, fFactory, ld, CAstNode.DECL_STMT,
makeNode(wc, fFactory, ld, CAstNode.VAR, fFactory.makeConstant(ld.name())),
fFactory.makeConstant( isFinal ),
fFactory.makeConstant(false),
initNode);
}
public CAstNode visit(Return r, WalkContext wc) {
Expr retExpr= r.expr();
if (retExpr == null)
return makeNode(wc, fFactory, r, CAstNode.RETURN);
else
return makeNode(wc, fFactory, r, CAstNode.RETURN, walkNodes(retExpr, wc));
}
public CAstNode visit(Case c, WalkContext wc) {
CAstNode label =
makeNode(wc, fFactory, c, CAstNode.LABEL_STMT,
fFactory.makeConstant( c.value() ));
wc.cfg().map(c, label);
return label;
}
public CAstNode visit(Throw t, WalkContext wc) {
CAstNode result= makeNode(wc, fFactory, t, CAstNode.THROW, walkNodes(t.expr(), wc));
Type label= t.expr().type();
wc.cfg().map(t, result);
Collection/*<Pair<Type,Node>>*/ catchNodes= wc.getCatchTargets(label);
for(Iterator iter= catchNodes.iterator(); iter.hasNext(); ) {
Pair/*<Type,Node>*/ catchNode= (Pair/*<Type,Node>*/) iter.next();
wc.cfg().add(t, catchNode.snd, catchNode.fst);
}
return result;
}
public CAstNode visit(Formal f, WalkContext wc) {
return makeNode(wc, fFactory, f, CAstNode.VAR, fFactory.makeConstant(f.name()));
}
}
protected static final class CompilationUnitEntity implements CAstEntity {
private final SourceFile fFile;
private final List/*<CAstEntity>*/ fTopLevelDecls;
public CompilationUnitEntity(SourceFile file, List/*<CAstEntity>*/ topLevelDecls) {
fFile= file;
fTopLevelDecls= topLevelDecls;
}
public int getKind() {
return FILE_ENTITY;
}
public String getName() {
return (fFile.package_() == null) ? "" : fFile.package_().package_().fullName().replace('.', '/');
// return fFile.source().path();
}
public String getSignature() {
Assertions.UNREACHABLE();
return null;
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public Map getAllScopedEntities() {
return Collections.singletonMap(null, fTopLevelDecls);
}
public Iterator getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("CompilationUnitEntity asked for AST-related entities, but it has no AST.");
return null;
}
public CAstNode getAST() {
return null;
}
public CAstControlFlowMap getControlFlow() {
Assertions.UNREACHABLE("CompilationUnitEntity.getControlFlow()");
return null;
}
public CAstSourcePositionMap getSourceMap() {
Assertions.UNREACHABLE("CompilationUnitEntity.getSourceMap()");
return null;
}
public CAstSourcePositionMap.Position getPosition() {
Assertions.UNREACHABLE("CompilationUnitEntity.getPosition()");
return null;
}
public CAstNodeTypeMap getNodeTypeMap() {
Assertions.UNREACHABLE("CompilationUnitEntity.getNodeTypeMap()");
return null;
}
public Collection getQualifiers() {
return Collections.EMPTY_LIST;
}
public CAstType getType() {
Assertions.UNREACHABLE("CompilationUnitEntity.getType()");
return null;
}
}
public final class PolyglotJavaType implements JavaType {
private final CAstTypeDictionary fDict;
private final TypeSystem fSystem;
private final ClassType fType;
private Collection/* <CAstType> */fSuperTypes= null;
public PolyglotJavaType(ClassType type, CAstTypeDictionary dict, TypeSystem system) {
super();
fDict= dict;
fSystem= system;
fType= type;
}
public String getName() {
if (fType.isLocal() || fType.isAnonymous()) {
return anonLocalTypeToTypeID(fType);
} else
return composeDOMOTypeDescriptor(fType);
}
public Collection getSupertypes() {
if (fSuperTypes == null) {
buildSuperTypes();
}
return fSuperTypes;
}
private void buildSuperTypes() {
// TODO this is a source entity, but it might actually be the root type (Object), so assume # intfs + 1
Type superType;
try {
superType= (fType.superType() == null) ? fSystem.typeForName("java.lang.Object") : fType.superType();
} catch (SemanticException e) {
Assertions.UNREACHABLE("Can't find java.lang.Object???");
return;
}
int N= fType.interfaces().size() + 1;
fSuperTypes= new ArrayList(N);
// Following assumes that noone can call getSupertypes() before we have
// created CAstType's for every type in the program being analyzed.
fSuperTypes.add(fDict.getCAstTypeFor(superType));
for(Iterator iter= fType.interfaces().iterator(); iter.hasNext();) {
Type t= (Type) iter.next();
fSuperTypes.add(fDict.getCAstTypeFor(t));
}
}
public boolean isInterface() {
return fType.flags().isInterface();
}
}
protected abstract static class CodeBodyEntity implements CAstEntity {
private final Map/*<CAstNode,CAstEntity>*/ fEntities;
public CodeBodyEntity(Map/*<CAstNode,CAstEntity>*/ entities) {
fEntities = new LinkedHashMap();
for(Iterator keys = entities.keySet().iterator(); keys.hasNext(); ) {
CAstNode key = (CAstNode)keys.next();
fEntities.put(key, Collections.singleton(entities.get(key)));
}
}
public Map getAllScopedEntities() {
return Collections.unmodifiableMap(fEntities);
}
public Iterator getScopedEntities(CAstNode construct) {
if (fEntities.containsKey(construct)) {
return ((Set)fEntities.get(construct)).iterator();
} else {
return EmptyIterator.instance();
}
}
public String getSignature() {
return Util.methodEntityToSelector(this).toString();
}
}
protected final class ClassEntity implements CAstEntity {
private final ClassContext fContext;
private final ClassType fCT;
private final String fName;
private final List/*<CAstEntity>*/ fEntities;
private final CAstSourcePositionMap.Position sourcePosition;
private ClassEntity(ClassContext context, List/*<CAstEntity>*/ entities, ClassDecl cd, Position p) {
this(context, entities, cd.type(), cd.name(), p);
}
private ClassEntity(ClassContext context, List/*<CAstEntity>*/ entities, ClassType ct, String name, Position p) {
fContext= context;
this.fEntities= entities;
fCT= ct;
fName= name;
sourcePosition = makePosition( p );
}
public int getKind() {
return TYPE_ENTITY;
}
public String getName() {
return fName; // unqualified?
}
public String getSignature() {
return "L" + fName.replace('.','/') + ";";
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public CAstNode getAST() {
// This entity has no AST nodes, really.
return null;
}
public Map getAllScopedEntities() {
return Collections.singletonMap(null, fEntities);
}
public Iterator getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("Non-AST-bearing entity (ClassEntity) asked for scoped entities related to a given AST node");
return null;
}
public CAstControlFlowMap getControlFlow() {
// This entity has no AST nodes, really.
return null;
}
public CAstSourcePositionMap getSourceMap() {
// This entity has no AST nodes, really.
return null;
}
public CAstSourcePositionMap.Position getPosition() {
return sourcePosition;
}
public CAstNodeTypeMap getNodeTypeMap() {
// This entity has no AST nodes, really.
return new CAstNodeTypeMap() {
public CAstType getNodeType(CAstNode node) {
throw new UnsupportedOperationException();
}
};
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(fCT.flags());
}
public CAstType getType() {
return new PolyglotJavaType(fCT, getTypeDict(), fTypeSystem);
}
}
protected final class ProcedureEntity extends CodeBodyEntity implements JavaProcedureEntity {
private final CAstNode fPdast;
private final TypeSystem fSystem;
private final Type declaringType;
private final ProcedureInstance fPd;
private final MethodContext fMc;
private final String[] argumentNames;
private ProcedureEntity(CAstNode pdast,
TypeSystem system,
ProcedureInstance pd,
Type declaringType,
String[] argumentNames,
Map/*<CAstNode,CAstEntity>*/ entities,
MethodContext mc) {
super(entities);
fPdast= pdast;
fSystem= system;
fPd= pd;
this.declaringType = declaringType;
this.argumentNames = argumentNames;
fMc= mc;
}
private ProcedureEntity(CAstNode pdast,
TypeSystem system,
ProcedureInstance pd,
String[] argumentNames,
Map/*<CAstNode,CAstEntity>*/ entities,
MethodContext mc) {
this(pdast, system, pd, pd.container(), argumentNames, entities, mc);
}
public String toString() {
return fPd.toString();
}
public int getKind() {
return CAstEntity.FUNCTION_ENTITY;
}
public String getName() {
if (fPd instanceof ConstructorInstance) {
return MethodReference.initAtom.toString();
} else {
Assertions._assert(fPd instanceof MethodInstance);
return ((MethodInstance)fPd).name();
}
}
public String[] getArgumentNames() {
return argumentNames;
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return fPd.flags().isStatic() ? fPd.formalTypes().size() : fPd.formalTypes().size() + 1;
}
public CAstNode getAST() {
return fPdast;
}
public CAstControlFlowMap getControlFlow() {
return fMc.cfg();
}
public CAstSourcePositionMap getSourceMap() {
return fMc.pos();
}
public CAstSourcePositionMap.Position getPosition() {
return makePosition( fPd.position() );
}
public CAstNodeTypeMap getNodeTypeMap() {
return fMc.getNodeTypeMap();
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(fPd.flags());
}
public CAstType getType() {
return new CAstType.Method() {
private Collection/*<CAstType>*/ fExceptionTypes= null;
private List/*<CAstType>*/ fParameterTypes= null;
public CAstType getReturnType() {
return fMc.getTypeDictionary().getCAstTypeFor(
(fPd instanceof MethodInstance) ?
((MethodInstance) fPd).returnType() :
fSystem.Void());
}
public List getArgumentTypes() {
if (fParameterTypes == null) {
final List formalTypes = fPd.formalTypes();
fParameterTypes= new ArrayList(formalTypes.size());
for(Iterator iter= formalTypes.iterator();
iter.hasNext(); )
{
fParameterTypes.add(fMc.getTypeDictionary().getCAstTypeFor((Type)iter.next()));
}
}
return fParameterTypes;
}
public String getName() {
Assertions.UNREACHABLE("CAstType.FunctionImpl#getName() called???");
return "?";
}
public Collection getSupertypes() {
Assertions.UNREACHABLE("CAstType.FunctionImpl#getSupertypes() called???");
return null;
}
public Collection/*<CAstType>*/ getExceptionTypes() {
if (fExceptionTypes == null) {
fExceptionTypes= new LinkedHashSet();
List exceptions= fPd.throwTypes();
if (exceptions != null) {
for(Iterator iterator= exceptions.iterator(); iterator.hasNext(); ) {
Type type= (Type) iterator.next();
fExceptionTypes.add(fMc.getTypeDictionary().getCAstTypeFor(type));
}
}
}
return fExceptionTypes;
}
public int getArgumentCount() {
return fPd.formalTypes().size();
}
public CAstType getDeclaringType() {
return getTypeDict().getCAstTypeFor(declaringType);
}
};
}
}
protected final class FieldEntity implements CAstEntity {
private final FieldDecl fFd;
private final WalkContext fContext;
private FieldEntity(FieldDecl fd, WalkContext context) {
super();
fFd= fd;
fContext= context;
}
public int getKind() {
return CAstEntity.FIELD_ENTITY;
}
public String getName() {
return fFd.name();
}
public String getSignature() {
return fFd.name() + typeToTypeID(fFd.type().type());
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public Iterator getScopedEntities(CAstNode construct) {
return EmptyIterator.instance();
}
public Map getAllScopedEntities() {
return Collections.EMPTY_MAP;
}
public CAstNode getAST() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstControlFlowMap getControlFlow() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstSourcePositionMap getSourceMap() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstSourcePositionMap.Position getPosition() {
return makePosition( fFd.position() );
}
public CAstNodeTypeMap getNodeTypeMap() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(fFd.flags());
}
public CAstType getType() {
return fContext.getTypeDictionary().getCAstTypeFor(fFd.type().type());
}
}
public interface WalkContext {
void addScopedEntity(CAstNode node, CAstEntity e);
// Map/*<CAstNode,CAstEntity>*/ getScopedEntities();
CAstControlFlowRecorder cfg();
CAstSourcePositionRecorder pos();
CAstNodeTypeMapRecorder getNodeTypeMap();
Collection/*<Pair<Type,Node>>*/ getCatchTargets(Type label);
Node getContinueFor(String label);
Node getBreakFor(String label);
Node getFinally();
String getEnclosingMethodName();
Type getEnclosingType();
CAstTypeDictionary getTypeDictionary();
List getStaticInitializers();
List getInitializers();
Map getLabelMap();
}
protected static class DelegatingContext implements WalkContext {
private final WalkContext parent;
public WalkContext getParent() {
return parent;
}
protected DelegatingContext(WalkContext parent) {
this.parent= parent;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
parent.addScopedEntity(node, e);
}
// public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
// return parent.getScopedEntities();
// }
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
}
public Collection/*<Pair<Type,Node>>*/ getCatchTargets(Type label) {
return parent.getCatchTargets(label);
}
public Node getContinueFor(String label) {
return parent.getContinueFor(label);
}
public Node getBreakFor(String label) {
return parent.getBreakFor(label);
}
public Node getFinally() {
return parent.getFinally();
}
public String getEnclosingMethodName() {
return parent.getEnclosingMethodName();
}
public Type getEnclosingType() {
return parent.getEnclosingType();
}
public CAstTypeDictionary getTypeDictionary() {
return parent.getTypeDictionary();
}
public List getStaticInitializers() {
return parent.getStaticInitializers();
}
public List getInitializers() {
return parent.getInitializers();
}
public Map getLabelMap() {
return parent.getLabelMap();
}
}
public class ClassContext extends DelegatingContext {
// private final ClassDecl cd;
private final Type type;
private List/*<Initializer+FieldDecl>*/ fInitializers= new ArrayList();
private List/*<Initializer+FieldDecl>*/ fStaticInitializers= new ArrayList();
private List/*<CAstEntity>*/ fChildren;
public ClassContext(Type type, List entities, WalkContext parent) {
super(parent);
this.type = type;
fChildren= entities;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
Assertions._assert(node == null);
fChildren.add(e);
}
// public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
// return null; // fChildren;
// }
public Type getEnclosingType() {
return type;
}
public List getInitializers() {
return fInitializers;
}
public List getStaticInitializers() {
return fStaticInitializers;
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("ClassContext.cfg()");
return null;
}
public Iterator/*<Pair<Type,Node>>*/ getCatchTarget(Type label) {
Assertions.UNREACHABLE("ClassContext.getCatchTarget()");
return null;
}
public Node getFinally() {
Assertions.UNREACHABLE("ClassContext.getFinally()");
return null;
}
public String getEnclosingMethodName() {
// No one outside a method defining a local class can see it,
// so it clearly can't escape through to the method's enclosing
// type...
Assertions.UNREACHABLE("ClassContext.getEnclosingMethodName()");
return null;
}
public CAstSourcePositionRecorder pos() {
// No AST, so no AST map
Assertions.UNREACHABLE("ClassContext.pos()");
return null;
}
public Node getContinueFor(String label) {
Assertions.UNREACHABLE(
"ClassContext.getContinueFor() with label "+label+" in "+type);
return null;
}
public Node getBreakFor(String label) {
System.err.println("Cannot find break target for " + label + " in " + type);
Assertions.UNREACHABLE("ClassContext.getBreakFor()");
return null;
}
public Map getLabelMap() {
Assertions.UNREACHABLE("ClassContext.getLabelMap()");
return null;
}
}
public class CodeBodyContext extends DelegatingContext {
final CAstSourcePositionRecorder fSourceMap= new CAstSourcePositionRecorder();
final CAstControlFlowRecorder fCFG= new CAstControlFlowRecorder();
final CAstNodeTypeMapRecorder fNodeTypeMap=
new CAstNodeTypeMapRecorder();
private final Map labelMap = new HashMap(2);
private final Map/*<CAstNode,CAstEntity>*/ fEntities;
public CodeBodyContext(WalkContext parent, Map/*<CAstNode,CAstEntity>*/ entities) {
super(parent);
fEntities= entities;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return fNodeTypeMap;
}
public CAstSourcePositionRecorder pos() {
return fSourceMap;
}
public CAstControlFlowRecorder cfg() {
return fCFG;
}
public void addScopedEntity(CAstNode node, CAstEntity entity) {
fEntities.put(node, entity);
}
public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
return fEntities;
}
public Map getLabelMap() {
return labelMap;
}
}
public class MethodContext extends CodeBodyContext {
final String methodName;
public MethodContext(String methodName, Map/*<CAstNode,CAstEntity>*/ entities, WalkContext parent) {
super(parent, entities);
this.methodName = methodName;
}
public MethodContext(ProcedureInstance pd, Map/*<CAstNode,CAstEntity>*/ entities, WalkContext parent) {
this(selectorForMethod(pd).toString(), entities, parent);
}
public Collection/*<Pair<Type,Node>>*/ getCatchTargets(Type label) {
return
Collections.singleton(
new Pair/*<Type,Node>*/(
fREType,
CAstControlFlowMap.EXCEPTION_TO_EXIT));
}
public String getEnclosingMethodName() {
return methodName;
}
}
private static class TryCatchContext extends DelegatingContext {
private final Try tryNode;
Collection/*<Pair<Type,Node>>*/ fCatchNodes= new ArrayList();
TryCatchContext(WalkContext parent, Try tryNode) {
super(parent);
this.tryNode = tryNode;
for(Iterator catchIter= tryNode.catchBlocks().iterator(); catchIter.hasNext(); ) {
Catch c= (Catch) catchIter.next();
Pair/*<Type,Node>*/ p= new Pair(c.catchType(), c);
fCatchNodes.add(p);
}
}
public Collection/*<Pair<Type,Node>>*/ getCatchTargets(Type label) {
// Look for all matching targets for this thrown type:
// if supertpe match, then return only matches at this catch
// if subtype match, then matches here and parent matches
Collection/*<Pair<Type,Node>>*/ catchNodes= new ArrayList();
for(Iterator iter= fCatchNodes.iterator(); iter.hasNext(); ) {
Pair/*<Type,Node>*/ p= (Pair/*<Type,Node>*/) iter.next();
Type catchType= (Type) p.fst;
// _must_ be caught
if (label.descendsFrom(catchType) || label.equals(catchType)) {
catchNodes.add(p);
return catchNodes;
// _might_ get caught
} else if (catchType.descendsFrom(label)) {
catchNodes.add(p);
continue;
}
}
catchNodes.addAll(getParent().getCatchTargets(label));
return catchNodes;
}
public List getStaticInitializers() {
return null;
}
public List getInitializers() {
return null;
}
}
protected static class RootContext implements WalkContext {
final CAstTypeDictionary fTypeDict;
public RootContext(CAstTypeDictionary typeDict) {
fTypeDict= typeDict;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
Assertions.UNREACHABLE("Attempt to call addScopedEntity() on a RootContext.");
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("RootContext.cfg()");
return null;
}
public Collection/*<Pair<Type,Node>>*/ getCatchTargets(Type label) {
Assertions.UNREACHABLE("RootContext.getCatchTargets()");
return null;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
Assertions.UNREACHABLE("RootContext.getNodeTypeMap()");
return null;
}
public Node getFinally() {
Assertions.UNREACHABLE("RootContext.getFinally()");
return null;
}
public CAstSourcePositionRecorder pos() {
// No AST, so no AST map
Assertions.UNREACHABLE("RootContext.pos()");
return null;
}
public Node getContinueFor(String label) {
Assertions.UNREACHABLE("RootContext.getContinueFor()");
return null;
}
public Node getBreakFor(String label) {
Assertions.UNREACHABLE("RootContext.getBreakFor()");
return null;
}
public String getEnclosingMethodName() {
Assertions.UNREACHABLE("RootContext.getEnclosingMethodName()");
return null;
}
public Type getEnclosingType() {
Assertions.UNREACHABLE("RootContext.getEnclosingType()");
return null;
}
public CAstTypeDictionary getTypeDictionary() {
return fTypeDict;
}
public List getStaticInitializers() {
Assertions.UNREACHABLE("RootContext.getStaticInitializers()");
return null;
}
public List getInitializers() {
Assertions.UNREACHABLE("RootContext.getInitializers()");
return null;
}
public Map getLabelMap() {
Assertions.UNREACHABLE("RootContext.getLabelMap()");
return null;
}
}
private class SwitchContext extends DelegatingContext {
protected final String label;
private final Node breakTo;
SwitchContext(WalkContext parent, String label, Node breakTo) {
super(parent);
this.label = label;
this.breakTo = breakTo;
}
public Node getBreakFor(String label) {
return (label == null || label.equals(this.label))?
breakTo:
super.getBreakFor(label);
}
public List getStaticInitializers() {
return null;
}
public List getInitializers() {
return null;
}
}
private class LoopContext extends SwitchContext {
private final Node continueTo;
protected LoopContext(WalkContext parent, String label, Node breakTo, Node continueTo) {
super(parent, label, breakTo);
this.continueTo = continueTo;
}
public Node getContinueFor(String label) {
return (label == null || label.equals(this.label))?
continueTo:
super.getContinueFor(label);
}
}
public PolyglotJava2CAstTranslator(ClassLoaderReference clr, NodeFactory nf, TypeSystem ts) {
fClassLoaderRef= clr;
fTypeSystem= ts;
fNodeFactory= nf;
try {
fNPEType= fTypeSystem.typeForName("java.lang.NullPointerException");
fREType= fTypeSystem.typeForName("java.lang.RuntimeException");
} catch (SemanticException e) {
Assertions.UNREACHABLE("Couldn't find Polyglot type for NPE/RE!");
}
}
private static class PolyglotSourcePosition extends AbstractSourcePosition
{
private final Position p;
PolyglotSourcePosition(Position p) {
this.p = p;
}
public int getFirstLine() { return p.line(); }
public int getLastLine() { return p.endLine(); }
public int getFirstCol() { return p.column(); }
public int getLastCol() { return p.endColumn(); }
public URL getURL() {
try {
return new URL("file:" + p.path());
} catch (MalformedURLException e) {
Assertions.UNREACHABLE( e.toString() );
return null;
}
}
public InputStream getInputStream() throws IOException {
return getURL().openConnection().getInputStream();
}
}
protected CAstSourcePositionMap.Position makePosition(Position p) {
return new PolyglotSourcePosition(p);
}
private void setPos(WalkContext wc, CAstNode cn, Node pn) {
if (pn != null) {
wc.pos().setPosition(cn, makePosition(pn.position()));
}
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind) {
CAstNode cn = Ast.makeNode(kind);
setPos(wc, cn, n);
return cn;
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c[]) {
CAstNode cn = Ast.makeNode(kind, c);
setPos(wc, cn, n);
return cn;
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c) {
CAstNode cn = Ast.makeNode(kind, c);
setPos(wc, cn, n);
return cn;
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2) {
CAstNode cn = Ast.makeNode(kind, c1, c2);
setPos(wc, cn, n);
return cn;
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3) {
CAstNode cn = Ast.makeNode(kind, c1, c2, c3);
setPos(wc, cn, n);
return cn;
}
private CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) {
CAstNode cn = Ast.makeNode(kind, c1, c2, c3, c4);
setPos(wc, cn, n);
return cn;
}
/**
* Translates the given Polyglot type to a name suitable for use in a DOMO TypeReference
* (i.e. a bytecode-compliant type name).
*/
public String typeToTypeID(Type type) {
if (type.isPrimitive()) {
PrimitiveType ptype= (PrimitiveType) type;
return JavaPrimitiveTypeMap.getShortName(ptype.name());
} else if (type.isArray()) {
ArrayType atype= (ArrayType) type;
return "[" + typeToTypeID(atype.base());
} else if (type.isNull()) {
Assertions.UNREACHABLE("typeToTypeID() encountered a null type!");
return null;
}
Assertions._assert(type.isClass(), "typeToTypeID() encountered type that is neither primitive, array, nor class!");
ClassType ctype= (ClassType) type;
return (ctype.isLocal() || ctype.isAnonymous()) ? anonLocalTypeToTypeID(ctype) : composeDOMOTypeDescriptor(ctype);
}
public String anonLocalTypeToTypeID(ClassType ctype) {
String enclosingName = (String) fLocalTypeMap.get(ctype);
String outerTypeID= typeToTypeID(ctype.outer());
String shortName= (ctype.isAnonymous()) ? anonTypeName(ctype) : ctype.fullName();
return outerTypeID + '/' + enclosingName + '/' + shortName;
}
public CAstEntity translate(Object ast, String fileName) {
return walkEntity((Node)ast, new RootContext(getTypeDict()));
}
public String composeDOMOTypeDescriptor(ClassType ctype) {
return "L" + composeDOMOTypeName(ctype);
}
public String composeDOMOTypeName(ClassType ctype) {
if (ctype.package_() != null) {
String packageName = ctype.package_().fullName();
Assertions._assert( ctype.fullName().startsWith( packageName ) );
return packageName.replace('.','/') + "/" + ctype.fullName().substring( packageName.length()+1 ).replace('.','$');
} else {
return ctype.fullName().replace('.', '$');
}
}
private Selector selectorForMethod(ProcedureInstance procInstance) {
Atom name= (procInstance instanceof ConstructorInstance) ?
MethodReference.initAtom :
Atom.findOrCreateUnicodeAtom(((MethodInstance) procInstance).name());
int numArgs= procInstance.formalTypes().size();
TypeName[] argTypeNames= (numArgs == 0) ? null : new TypeName[numArgs]; // Descriptor prefers null to an empty array
int i= 0;
for(Iterator iter= procInstance.formalTypes().iterator(); iter.hasNext(); i++) {
Type argType= (Type) iter.next();
argTypeNames[i]= TypeName.string2TypeName(typeToTypeID(argType));
}
Type retType= (procInstance instanceof ConstructorInstance) ?
fTypeSystem.Void() :
((MethodInstance) procInstance).returnType();
TypeName retTypeName= TypeName.string2TypeName(typeToTypeID(retType));
Descriptor desc= Descriptor.findOrCreate(argTypeNames, retTypeName);
return new Selector(name, desc);
}
private MethodReference referenceForMethod(ProcedureInstance procInstance)
{
TypeName ownerType= TypeName.string2TypeName(typeToTypeID(procInstance.container()));
TypeReference ownerTypeRef= TypeReference.findOrCreate(PolyglotJava2CAstTranslator.this.fClassLoaderRef, ownerType);
return referenceForMethod(ownerTypeRef, procInstance);
}
private MethodReference referenceForMethod(TypeReference ownerTypeRef, ProcedureInstance procInstance) {
// Handles both ConstructorInstance's and MethodInstance's
MethodReference methodRef= MethodReference.findOrCreate(ownerTypeRef, selectorForMethod(procInstance));
return methodRef;
}
protected static Collection mapFlagsToQualifiers(Flags flags) {
Set/*<CAstQualifier>*/ quals= new LinkedHashSet();
if (flags.isAbstract()) quals.add(CAstQualifier.ABSTRACT);
if (flags.isFinal()) quals.add(CAstQualifier.FINAL);
if (flags.isInterface()) quals.add(CAstQualifier.INTERFACE);
if (flags.isNative()) quals.add(CAstQualifier.NATIVE);
// if (flags.isPackage()) quals.add(CAstQualifier.PACKAGE);
if (flags.isPrivate()) quals.add(CAstQualifier.PRIVATE);
if (flags.isProtected()) quals.add(CAstQualifier.PROTECTED);
if (flags.isPublic()) quals.add(CAstQualifier.PUBLIC);
if (flags.isStatic()) quals.add(CAstQualifier.STATIC);
if (flags.isStrictFP()) quals.add(CAstQualifier.STRICTFP);
if (flags.isSynchronized()) quals.add(CAstQualifier.SYNCHRONIZED);
if (flags.isTransient()) quals.add(CAstQualifier.TRANSIENT);
if (flags.isVolatile()) quals.add(CAstQualifier.VOLATILE);
return quals;
}
protected void processClassMembers(List/*<ClassMember>*/ members, DelegatingContext classContext, List/*<CAstEntity>*/ memberEntities) {
// Collect all initializer-related gorp
for(Iterator memberIter= members.iterator(); memberIter.hasNext(); ) {
ClassMember member= (ClassMember) memberIter.next();
if (member instanceof Initializer) {
Initializer initializer= (Initializer) member;
if (initializer.flags().isStatic())
classContext.getStaticInitializers().add(initializer);
else
classContext.getInitializers().add(initializer);
} else if (member instanceof FieldDecl) {
FieldDecl fd= (FieldDecl) member;
if (fd.init() != null) {
if (fd.flags().isStatic())
classContext.getStaticInitializers().add(fd);
else
classContext.getInitializers().add(fd);
}
}
}
// Now process
for(Iterator memberIter= members.iterator(); memberIter.hasNext();) {
ClassMember member= (ClassMember) memberIter.next();
if (!(member instanceof Initializer)) {
CAstEntity memberEntity= walkEntity(member, classContext);
memberEntities.add(memberEntity);
}
}
}
protected void
addConstructorsToAnonymousClass(New n,
ParsedClassType anonType,
ClassContext classContext,
List memberEntities)
{
List superConstructors =
((ClassType)anonType.superType()).constructors();
for(Iterator iter = superConstructors.iterator(); iter.hasNext();) {
ConstructorInstance superCtor = (ConstructorInstance) iter.next();
Map childEntities = new HashMap();
final MethodContext mc =
new MethodContext(superCtor, childEntities, classContext);
String[] fakeArguments = new String[superCtor.formalTypes().size()+1];
for(int i = 0; i < fakeArguments.length; i++) {
fakeArguments[i] = (i==0)? "this": ("argument" + i);
}
List inits = classContext.getInitializers();
CAstNode[] bodyNodes = new CAstNode[inits.size()+1];
CallSiteReference callSiteRef = CallSiteReference.make(0, referenceForMethod(superCtor), IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] children = new CAstNode[ fakeArguments.length + 1 ];
children[0] = makeNode(mc, fFactory, n, CAstNode.SUPER);
children[1] = fFactory.makeConstant(callSiteRef);
for(int i = 1; i < fakeArguments.length; i++) {
children[i+1] = makeNode(mc, fFactory, n, CAstNode.VAR,
fFactory.makeConstant( fakeArguments[i] ));
}
bodyNodes[0] = makeNode(mc, fFactory, n, CAstNode.CALL, children);
insertInitializers(mc, bodyNodes, 1);
CAstNode ast =
makeNode(mc, fFactory, n, CAstNode.BLOCK_STMT, bodyNodes);
memberEntities.add(new ProcedureEntity(ast, fTypeSystem, superCtor, anonType, fakeArguments, childEntities, mc));
}
}
private String anonTypeName(ClassType ct) {
Position pos= ct.position();
return ct.fullName() + "$" + pos.line() + "$" + pos.column();
}
protected CAstEntity walkEntity(Node rootNode, final WalkContext context) {
if (rootNode instanceof SourceFile) {
SourceFile file= (SourceFile) rootNode;
List/*<CAstEntity>*/ declEntities= new ArrayList();
for(Iterator iter= file.decls().iterator(); iter.hasNext();) {
TopLevelDecl decl= (TopLevelDecl) iter.next();
declEntities.add(walkEntity(decl, context));
}
return new CompilationUnitEntity(file, declEntities);
} else if (rootNode instanceof ClassDecl) {
final ClassDecl cd= (ClassDecl) rootNode;
final List/*<CAstEntity>*/ memberEntities= new ArrayList();
final ClassContext classContext= new ClassContext(cd.type(), memberEntities, context);
processClassMembers(cd.body().members(), classContext, memberEntities);
return new ClassEntity(classContext, memberEntities, cd, cd.position());
} else if (rootNode instanceof New) {
final New n= (New) rootNode;
final List/*<CAstEntity>*/ memberEntities= new ArrayList();
ParsedClassType anonType= n.anonType();
String anonTypeName= anonTypeName(anonType);
final ClassContext classContext= new ClassContext(anonType, memberEntities, context);
processClassMembers(n.body().members(), classContext, memberEntities);
addConstructorsToAnonymousClass(n, anonType, classContext, memberEntities);
return new ClassEntity(classContext, memberEntities, anonType, anonTypeName, n.position());
} else if (rootNode instanceof ProcedureDecl) {
final ProcedureDecl pd= (ProcedureDecl) rootNode;
final Map/*<CAstNode,CAstEntity>*/ memberEntities= new LinkedHashMap();
final MethodContext mc =
new MethodContext(pd.procedureInstance(),
memberEntities,
context);
CAstNode pdAST= null;
if (!pd.flags().isAbstract()) {
// Presumably the MethodContext's parent is a ClassContext,
// and he has the list of initializers. Hopefully the following
// will glue that stuff in the right place in any constructor body.
pdAST= walkNodes(pd, mc);
}
List/* <Formal> */formals= pd.formals();
String[] argNames;
int i= 0;
if (!pd.flags().isStatic()) {
argNames = new String[formals.size()+1];
argNames[i++]= "this";
} else {
argNames = new String[formals.size()];
}
for(Iterator iter= formals.iterator(); iter.hasNext(); i++) {
Formal formal= (Formal) iter.next();
argNames[i]= formal.name();
}
return new ProcedureEntity(pdAST, fTypeSystem, pd.procedureInstance(), argNames, memberEntities, mc);
} else if (rootNode instanceof FieldDecl) {
final FieldDecl fd= (FieldDecl) rootNode;
return new FieldEntity(fd, context);
} else {
Assertions.UNREACHABLE("Unknown node type for walkEntity():" + rootNode.getClass().getName());
return null;
}
}
private boolean isSpecialCallStmt(Stmt maybeSuper, Kind kind) {
if (maybeSuper instanceof ConstructorCall) {
ConstructorCall cc= (ConstructorCall) maybeSuper;
return cc.kind() == kind;
}
return false;
}
private boolean hasSpecialCall(Block body, Kind kind) {
if (body.statements().size() <= 0) return false;
Stmt maybeSuper= (Stmt) body.statements().get(0);
return isSpecialCallStmt(maybeSuper, kind);
}
private boolean hasSuperCall(Block body) {
return hasSpecialCall(body, ConstructorCall.SUPER);
}
private boolean hasThisCall(Block body) {
return hasSpecialCall(body, ConstructorCall.THIS);
}
private int insertInitializers(WalkContext wc, CAstNode[] initCode, int offset) {
List/*<FieldDecl|Initializer>*/ inits= wc.getInitializers();
for(Iterator iter= inits.iterator(); iter.hasNext(); offset++) {
ClassMember init= (ClassMember) iter.next();
CAstNode initNode= walkNodes(init, wc);
initCode[offset]= initNode;
}
return offset;
}
protected CAstNode walkNodes(Node n, final WalkContext context) {
if (n == null) return makeNode(context, fFactory, null, CAstNode.EMPTY);
return ASTTraverser.visit(n, getTranslator(), context);
}
}