diff --git a/com.ibm.wala.cast.java.polyglot/.classpath b/com.ibm.wala.cast.java.polyglot/.classpath new file mode 100644 index 000000000..1089f59ab --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/com.ibm.wala.cast.java.polyglot/.project b/com.ibm.wala.cast.java.polyglot/.project new file mode 100644 index 000000000..1c403c0dd --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/.project @@ -0,0 +1,28 @@ + + + com.ibm.wala.cast.java.polyglot + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/com.ibm.wala.cast.java.polyglot/META-INF/MANIFEST.MF b/com.ibm.wala.cast.java.polyglot/META-INF/MANIFEST.MF new file mode 100644 index 000000000..c2f09d3e5 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/META-INF/MANIFEST.MF @@ -0,0 +1,82 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: WALA CAst Java Polyglot Plug-in +Bundle-SymbolicName: com.ibm.wala.cast.java.polyglot +Bundle-Version: 1.0.0 +Bundle-Activator: com.ibm.wala.cast.java.polyglot.Activator +Bundle-Vendor: IBM +Require-Bundle: com.ibm.wala.cast.java;bundle-version="1.0.0", + com.ibm.wala.cast;bundle-version="1.0.0", + com.ibm.wala.core;bundle-version="1.1.3", + org.eclipse.core.runtime +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-ActivationPolicy: lazy +Export-Package: com.ibm.wala.cast.java.polyglot;uses:="org.osgi.framework,org.eclipse.core.runtime", + com.ibm.wala.cast.java.translator.polyglot; + uses:="com.ibm.wala.types, + polyglot.types, + polyglot.util, + polyglot.ast, + com.ibm.wala.ipa.cha, + com.ibm.wala.cast.java.client, + com.ibm.wala.classLoader, + com.ibm.wala.cast.tree, + com.ibm.wala.cast.java.loader, + com.ibm.wala.ipa.callgraph.impl, + com.ibm.wala.ipa.callgraph, + polyglot.frontend.goals, + com.ibm.wala.cast.tree.impl, + com.ibm.wala.cast.java.translator, + polyglot.frontend, + com.ibm.wala.cast.java.types", + java_cup;uses:="java_cup.runtime", + java_cup.runtime, + polyglot.ast; + uses:="polyglot.visit, + polyglot.types, + polyglot.util, + polyglot.frontend", + polyglot.ext.param;uses:="polyglot.frontend", + polyglot.ext.param.types;uses:="polyglot.util,polyglot.types,polyglot.frontend", + polyglot.frontend, + polyglot.frontend.goals; + uses:="polyglot.visit, + polyglot.types, + polyglot.ast, + polyglot.frontend", + polyglot.frontend.passes; + uses:="polyglot.visit, + polyglot.types, + polyglot.frontend.goals, + polyglot.frontend", + polyglot.lex;uses:="polyglot.util,java_cup.runtime", + polyglot.main;uses:="polyglot.util,polyglot.frontend", + polyglot.parse; + uses:="polyglot.util, + polyglot.types, + polyglot.ast, + java_cup.runtime, + polyglot.lex, + polyglot.frontend", + polyglot.qq; + uses:="polyglot.util, + polyglot.types, + polyglot.ast, + polyglot.parse, + java_cup.runtime, + polyglot.lex, + polyglot.frontend", + polyglot.types; + uses:="polyglot.util, + polyglot.main, + polyglot.types.reflect, + polyglot.frontend", + polyglot.types.reflect;uses:="polyglot.util,polyglot.types,polyglot.frontend", + polyglot.util;uses:="polyglot.types", + polyglot.util.typedump;uses:="polyglot.util,polyglot.types", + polyglot.visit; + uses:="polyglot.util, + polyglot.types, + polyglot.main, + polyglot.ast, + polyglot.frontend" diff --git a/com.ibm.wala.cast.java.polyglot/build.properties b/com.ibm.wala.cast.java.polyglot/build.properties new file mode 100644 index 000000000..c820afa01 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/build.properties @@ -0,0 +1,4 @@ +source.. = source/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/polyglot/Activator.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/polyglot/Activator.java new file mode 100644 index 000000000..61fbdca1c --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/polyglot/Activator.java @@ -0,0 +1,50 @@ +package com.ibm.wala.cast.java.polyglot; + +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends Plugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.ibm.wala.cast.java.polyglot"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/ASTTraverser.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/ASTTraverser.java new file mode 100644 index 000000000..f5cdabf53 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/ASTTraverser.java @@ -0,0 +1,202 @@ +/****************************************************************************** + * 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 Sep 1, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.ast.ArrayAccess; +import polyglot.ast.ArrayAccessAssign; +import polyglot.ast.ArrayInit; +import polyglot.ast.ArrayTypeNode; +import polyglot.ast.Assert; +import polyglot.ast.Binary; +import polyglot.ast.Block; +import polyglot.ast.BooleanLit; +import polyglot.ast.Branch; +import polyglot.ast.Call; +import polyglot.ast.CanonicalTypeNode; +import polyglot.ast.Case; +import polyglot.ast.Cast; +import polyglot.ast.Catch; +import polyglot.ast.CharLit; +import polyglot.ast.ClassBody; +import polyglot.ast.ClassDecl; +import polyglot.ast.ClassLit; +import polyglot.ast.Conditional; +import polyglot.ast.ConstructorCall; +import polyglot.ast.ConstructorDecl; +import polyglot.ast.Do; +import polyglot.ast.Empty; +import polyglot.ast.Eval; +import polyglot.ast.Field; +import polyglot.ast.FieldAssign; +import polyglot.ast.FieldDecl; +import polyglot.ast.FloatLit; +import polyglot.ast.For; +import polyglot.ast.Formal; +import polyglot.ast.If; +import polyglot.ast.Import; +import polyglot.ast.Initializer; +import polyglot.ast.Instanceof; +import polyglot.ast.IntLit; +import polyglot.ast.Labeled; +import polyglot.ast.Local; +import polyglot.ast.LocalAssign; +import polyglot.ast.LocalClassDecl; +import polyglot.ast.LocalDecl; +import polyglot.ast.MethodDecl; +import polyglot.ast.New; +import polyglot.ast.NewArray; +import polyglot.ast.Node; +import polyglot.ast.NullLit; +import polyglot.ast.PackageNode; +import polyglot.ast.Return; +import polyglot.ast.Special; +import polyglot.ast.StringLit; +import polyglot.ast.Switch; +import polyglot.ast.SwitchBlock; +import polyglot.ast.Synchronized; +import polyglot.ast.Throw; +import polyglot.ast.Try; +import polyglot.ast.Unary; +import polyglot.ast.While; + +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.MethodContext; +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.WalkContext; +import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.util.debug.Assertions; + +/** + * Wrapper for the logic (nasty cascaded instanceof tests) necessary to visit a Polyglot AST + * and dispatch to the appropriate TranslatingVisitor methods for each AST node type. + * @author rfuhrer + */ +public class ASTTraverser { + protected ASTTraverser() { } + + public static CAstNode visit(Node n, TranslatingVisitor tv, WalkContext wc) { + if (n instanceof MethodDecl) { + return tv.visit((MethodDecl) n, (MethodContext) wc); + } else if (n instanceof ConstructorDecl) { + return tv.visit((ConstructorDecl) n, (MethodContext) wc); + } else if (n instanceof FieldDecl) { + return tv.visit((FieldDecl) n, (MethodContext) wc); + } else if (n instanceof Import) { + return tv.visit((Import) n, wc); + } else if (n instanceof PackageNode) { + return tv.visit((PackageNode) n, wc); + } else if (n instanceof CanonicalTypeNode) { + return tv.visit((CanonicalTypeNode) n, wc); + } else if (n instanceof ArrayTypeNode) { + return tv.visit((ArrayTypeNode) n, wc); + } else if (n instanceof ArrayInit) { + return tv.visit((ArrayInit) n, wc); + } else if (n instanceof ArrayAccessAssign) { + return tv.visit((ArrayAccessAssign) n, wc); + } else if (n instanceof FieldAssign) { + return tv.visit((FieldAssign) n, wc); + } else if (n instanceof LocalAssign) { + return tv.visit((LocalAssign) n, wc); + } else if (n instanceof Binary) { + return tv.visit((Binary) n, wc); + } else if (n instanceof Call) { + return tv.visit((Call) n, wc); + } else if (n instanceof ConstructorCall) { + return tv.visit((ConstructorCall) n, wc); + } else if (n instanceof Cast) { + return tv.visit((Cast) n, wc); + } else if (n instanceof Conditional) { + return tv.visit((Conditional) n, wc); + } else if (n instanceof Instanceof) { + return tv.visit((Instanceof) n, wc); + } else if (n instanceof BooleanLit) { + return tv.visit((BooleanLit) n, wc); + } else if (n instanceof ClassLit) { + return tv.visit((ClassLit) n, wc); + } else if (n instanceof FloatLit) { + return tv.visit((FloatLit) n, wc); + } else if (n instanceof NullLit) { + return tv.visit((NullLit) n, wc); + } else if (n instanceof CharLit) { + return tv.visit((CharLit) n, wc); + } else if (n instanceof IntLit) { + return tv.visit((IntLit) n, wc); + } else if (n instanceof StringLit) { + return tv.visit((StringLit) n, wc); + } else if (n instanceof New) { + return tv.visit((New) n, wc); + } else if (n instanceof NewArray) { + return tv.visit((NewArray) n, wc); + } else if (n instanceof Special) { + return tv.visit((Special) n, wc); + } else if (n instanceof Unary) { + return tv.visit((Unary) n, wc); + } else if (n instanceof ArrayAccess) { + return tv.visit((ArrayAccess) n, wc); + } else if (n instanceof Field) { + return tv.visit((Field) n, wc); + } else if (n instanceof Local) { + return tv.visit((Local) n, wc); + } else if (n instanceof ClassBody) { + return tv.visit((ClassBody) n, wc); + } else if (n instanceof ClassDecl) { + return tv.visit((ClassDecl) n, wc); + } else if (n instanceof Initializer) { + return tv.visit((Initializer) n, wc); + } else if (n instanceof Assert) { + return tv.visit((Assert) n, wc); + } else if (n instanceof Branch) { + return tv.visit((Branch) n, wc); + } else if (n instanceof SwitchBlock) { // must test for this one before Block + return tv.visit((SwitchBlock) n, wc); + } else if (n instanceof Block) { // must test for this one before Block + return tv.visit((Block) n, wc); + } else if (n instanceof Catch) { + return tv.visit((Catch) n, wc); + } else if (n instanceof If) { + return tv.visit((If) n, wc); + } else if (n instanceof Labeled) { + return tv.visit((Labeled) n, wc); + } else if (n instanceof LocalClassDecl) { + return tv.visit((LocalClassDecl) n, wc); + } else if (n instanceof Do) { + return tv.visit((Do) n, wc); + } else if (n instanceof For) { + return tv.visit((For) n, wc); + } else if (n instanceof While) { + return tv.visit((While) n, wc); + } else if (n instanceof Switch) { + return tv.visit((Switch) n, wc); + } else if (n instanceof Synchronized) { + return tv.visit((Synchronized) n, wc); + } else if (n instanceof Try) { + return tv.visit((Try) n, wc); + } else if (n instanceof Empty) { + return tv.visit((Empty) n, wc); + } else if (n instanceof Eval) { + return tv.visit((Eval) n, wc); + } else if (n instanceof LocalDecl) { + return tv.visit((LocalDecl) n, wc); + } else if (n instanceof Return) { + return tv.visit((Return) n, wc); + } else if (n instanceof Case) { + return tv.visit((Case) n, wc); + } else if (n instanceof Throw) { + return tv.visit((Throw) n, wc); + } else if (n instanceof Formal) { + return tv.visit((Formal) n, wc); + } else { + Assertions.UNREACHABLE("Unhandled node " + n + " of type " + n.getClass().getName() + " in ASTTraverser.visit()."); + return null; + } + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/AscriptionGoal.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/AscriptionGoal.java new file mode 100644 index 000000000..957e955b7 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/AscriptionGoal.java @@ -0,0 +1,55 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.ast.ArrayInit; +import polyglot.ast.Expr; +import polyglot.frontend.CyclicDependencyException; +import polyglot.frontend.ExtensionInfo; +import polyglot.frontend.Job; +import polyglot.frontend.Pass; +import polyglot.frontend.Scheduler; +import polyglot.frontend.VisitorPass; +import polyglot.frontend.goals.AbstractGoal; +import polyglot.types.SemanticException; +import polyglot.types.Type; +import polyglot.util.ErrorInfo; +import polyglot.visit.AscriptionVisitor; + +/** + * Runs an AscriptionVisitor to make sure that empty array literals actually get a type. + * @author rfuhrer + */ +public class AscriptionGoal extends AbstractGoal { + public AscriptionGoal(Job job) { + super(job); + try { + Scheduler scheduler= job.extensionInfo().scheduler(); + + addPrerequisiteGoal(scheduler.TypeChecked(job), scheduler); + } catch (CyclicDependencyException e) { + job.compiler().errorQueue().enqueue(ErrorInfo.INTERNAL_ERROR, "Cycle encountered in goal graph?"); + throw new IllegalStateException(e.getMessage()); + } + } + + public Pass createPass(ExtensionInfo extInfo) { + return new VisitorPass(this, + new AscriptionVisitor(job(), extInfo.typeSystem(), extInfo.nodeFactory()) { + public Expr ascribe(Expr e, Type toType) throws SemanticException { + if (e instanceof ArrayInit && e.type().isNull()) { + return e.type(toType); + } + return super.ascribe(e, toType); + } + }); + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRGoal.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRGoal.java new file mode 100644 index 000000000..9fb116f71 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRGoal.java @@ -0,0 +1,66 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.frontend.CyclicDependencyException; +import polyglot.frontend.Job; +import polyglot.frontend.Pass; +import polyglot.frontend.Scheduler; +import polyglot.frontend.goals.AbstractGoal; +import polyglot.frontend.goals.EndGoal; +import polyglot.util.ErrorInfo; + +import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl; +import com.ibm.wala.cast.java.translator.Java2IRTranslator; + +/** + * A kind of EndGoal that indicates that DOMO IR has been generated for the given compilation unit. + * @author rfuhrer + */ +public class IRGoal extends AbstractGoal implements EndGoal { + private JavaSourceLoaderImpl fSourceLoader; + + public IRGoal(Job job, JavaSourceLoaderImpl sourceLoader) { + super(job); + fSourceLoader = sourceLoader; + try { + Scheduler scheduler= job.extensionInfo().scheduler(); + + addPrerequisiteGoal(scheduler.TypeChecked(job), scheduler); + // Need ConstantsChecked in order to make sure that case statements have non-zero labels. + addPrerequisiteGoal(scheduler.ConstantsChecked(job), scheduler); + // Need to add an AscriptionGoal as a prereq to make sure that empty array initializers get a type ascribed. + addPrerequisiteGoal(new AscriptionGoal(job), scheduler); + } catch (CyclicDependencyException e) { + job.compiler().errorQueue().enqueue(ErrorInfo.INTERNAL_ERROR, "Cycle encountered in goal graph?"); + throw new IllegalStateException(e.getMessage()); + } + } + + public Pass createPass(polyglot.frontend.ExtensionInfo extInfo) { + return new JavaIRPass(this, job(), + new Java2IRTranslator( + new PolyglotJava2CAstTranslator( + fSourceLoader.getReference(), + extInfo.nodeFactory(), + extInfo.typeSystem(), + new PolyglotIdentityMapper(fSourceLoader.getReference(), this.job.extensionInfo().typeSystem())), + fSourceLoader, + ((IRTranslatorExtension)extInfo).getCAstRewriterFactory())); + } + + public String name() { + return ""; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRTranslatorExtension.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRTranslatorExtension.java new file mode 100644 index 000000000..47ea06810 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/IRTranslatorExtension.java @@ -0,0 +1,32 @@ +/****************************************************************************** + * 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 Oct 21, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import com.ibm.wala.cast.tree.impl.CAstRewriterFactory; + +public interface IRTranslatorExtension { + void setSourceLoader(PolyglotSourceLoaderImpl jsli); + + /** + * @return the identity mapper, for mapping AST nodes to WALA TypeReferences, + * MethodReferences and FieldReferences. Helps clients to correlate analysis + * results to AST nodes. + */ + PolyglotIdentityMapper getIdentityMapper(); + + /** + * @return the CAstRewriterFactory. + */ + CAstRewriterFactory getCAstRewriterFactory(); +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRPass.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRPass.java new file mode 100644 index 000000000..7c5121ec4 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRPass.java @@ -0,0 +1,40 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.frontend.AbstractPass; +import polyglot.frontend.Job; +import polyglot.frontend.goals.Goal; + +import com.ibm.wala.cast.java.translator.Java2IRTranslator; + +/** + * A Pass that creates DOMO IR for the given Java compilation unit. + * @author rfuhrer + */ +public final class JavaIRPass extends AbstractPass { + private final Job fJob; + private final Java2IRTranslator fTranslator; + + public JavaIRPass(Goal goal, Job job, Java2IRTranslator translator) { + super(goal); + this.fJob= job; + this.fTranslator= translator; + } + + public boolean run() { + fTranslator.translate(fJob.ast(), fJob.source().name()); + return true; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRTranslatorExtension.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRTranslatorExtension.java new file mode 100644 index 000000000..dd2ebf4ef --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/JavaIRTranslatorExtension.java @@ -0,0 +1,52 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.frontend.JLExtensionInfo; +import polyglot.frontend.Job; +import polyglot.frontend.goals.Goal; + +import com.ibm.wala.cast.tree.impl.CAstRewriterFactory; + +/** + * A Polyglot extension descriptor for a test harness extension that generates DOMO IR for + * the sources and class files in the classpath. + * @author rfuhrer + */ +public class JavaIRTranslatorExtension extends JLExtensionInfo implements IRTranslatorExtension { + protected PolyglotSourceLoaderImpl fSourceLoader; + protected PolyglotIdentityMapper fMapper; + protected CAstRewriterFactory rewriterFactory; + + public void setSourceLoader(PolyglotSourceLoaderImpl sourceLoader) { + fSourceLoader= sourceLoader; + fMapper= new PolyglotIdentityMapper(sourceLoader.getReference(), typeSystem()); + } + + public Goal getCompileGoal(Job job) { + return new IRGoal(job, fSourceLoader); + } + + public PolyglotIdentityMapper getIdentityMapper() { + return fMapper; + } + + public void setCAstRewriterFactory(CAstRewriterFactory factory) { + rewriterFactory = factory; + } + + public CAstRewriterFactory getCAstRewriterFactory() { + return rewriterFactory; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotClassLoaderFactory.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotClassLoaderFactory.java new file mode 100644 index 000000000..8b763eab3 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotClassLoaderFactory.java @@ -0,0 +1,56 @@ +/****************************************************************************** + * 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 Oct 7, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; +import com.ibm.wala.classLoader.ClassLoaderImpl; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.eclipse.util.EclipseProjectPath; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; + +public class PolyglotClassLoaderFactory extends ClassLoaderFactoryImpl { + + /** + * A map from ClassLoaderReference to IRTranslatorExtension, so that source files + * in different languages are processed by the right kind of IRTranslatorExtension. + */ + final protected Map fExtensionMap= new HashMap(); + + public PolyglotClassLoaderFactory(SetOfClasses exclusions, IRTranslatorExtension javaExtInfo) { + super(exclusions); + fExtensionMap.put(EclipseProjectPath.SOURCE_REF, javaExtInfo); + } + + protected IRTranslatorExtension getExtensionFor(ClassLoaderReference clr) { + return fExtensionMap.get(clr); + } + + protected IClassLoader makeNewClassLoader(ClassLoaderReference classLoaderReference, IClassHierarchy cha, IClassLoader parent, + AnalysisScope scope) throws IOException { + if (classLoaderReference.equals(EclipseProjectPath.SOURCE_REF)) { + ClassLoaderImpl cl = new PolyglotSourceLoaderImpl(classLoaderReference, parent, getExclusions(), cha, getExtensionFor(classLoaderReference)); + cl.init(scope.getModules(classLoaderReference)); + return cl; + } else { + return super.makeNewClassLoader(classLoaderReference, cha, parent, scope); + } + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotFrontEnd.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotFrontEnd.java new file mode 100644 index 000000000..2f873d66b --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotFrontEnd.java @@ -0,0 +1,97 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import polyglot.frontend.Compiler; +import polyglot.frontend.ExtensionInfo; +import polyglot.frontend.Job; +import polyglot.frontend.Scheduler; +import polyglot.util.ErrorInfo; +import polyglot.util.ErrorLimitError; +import polyglot.util.ErrorQueue; +import polyglot.util.InternalCompilerError; +import polyglot.util.Position; +import polyglot.util.StdErrorQueue; + +/** + * Enhancement of core Polyglot compiler that takes as input a Collection of StreamSources. + * Identical to Compiler in all other respects. + * @author rfuhrer + */ +public final class PolyglotFrontEnd extends Compiler { + public PolyglotFrontEnd(ExtensionInfo info, ErrorQueue eq) { + super(info, eq); + } + public PolyglotFrontEnd(ExtensionInfo info) { + this(info, new StdErrorQueue(System.err, 1000 * 1000, info.compilerName())); + } + + public boolean compile(Collection/**/sources) { + boolean okay= false; + + try { + try { + Scheduler scheduler= sourceExtension().scheduler(); + List jobs= new ArrayList(); + + // First, create a goal to compile every source file. + for(Iterator i= sources.iterator(); i.hasNext(); ) { + StreamSource source= (StreamSource) i.next(); + + // mark this source as being explicitly specified by the user. + source.setUserSpecified(true); + + // Add a new SourceJob for the given source. If a Job for the source + // already exists, then we will be given the existing job. + Job job= scheduler.addJob(source); + jobs.add(job); + + // Now, add a goal for completing the job. + scheduler.addGoal(sourceExtension().getCompileGoal(job)); + } + + scheduler.setCommandLineJobs(jobs); + + // Then, compile the files to completion. + okay= scheduler.runToCompletion(); + } catch (InternalCompilerError e) { + // Report it like other errors, but rethrow to get the stack trace. + try { + errorQueue().enqueue(ErrorInfo.INTERNAL_ERROR, e.message(), e.position()); + } catch (ErrorLimitError e2) { + } + errorQueue().flush(); + throw e; + } catch (RuntimeException e) { + // Flush the error queue, then rethrow to get the stack trace. + errorQueue().enqueue(ErrorInfo.INTERNAL_ERROR, "Internal polyglot compiler error: " + e.getMessage(), Position.COMPILER_GENERATED); + errorQueue().flush(); + throw e; + } + } catch (ErrorLimitError e) { + } + errorQueue().flush(); + + for(Iterator i= allExtensions().iterator(); i.hasNext(); ) { + ExtensionInfo ext= (ExtensionInfo) i.next(); + ext.getStats().report(); + } + return okay; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java new file mode 100644 index 000000000..20d70712b --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotIdentityMapper.java @@ -0,0 +1,230 @@ +/** + * + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import polyglot.types.ArrayType; +import polyglot.types.ClassType; +import polyglot.types.CodeInstance; +import polyglot.types.ConstructorInstance; +import polyglot.types.FieldInstance; +import polyglot.types.InitializerInstance; +import polyglot.types.MemberInstance; +import polyglot.types.MethodInstance; +import polyglot.types.PrimitiveType; +import polyglot.types.ProcedureInstance; +import polyglot.types.Type; +import polyglot.types.TypeSystem; + +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.IdentityMapper; +import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap; +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.collections.HashMapFactory; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.strings.Atom; + +/** + * Class responsible for mapping Polyglot type system objects representing types, + * methods and fields to the corresponding WALA TypeReferences, MethodReferences + * and FieldReferences. Used during translation and by clients to help correlate + * WALA analysis results to the various AST nodes. + * @author rfuhrer + */ +public class PolyglotIdentityMapper implements IdentityMapper { + private final Map fTypeMap= HashMapFactory.make(); + private final Map fFieldMap= HashMapFactory.make(); + private final Map fMethodMap= HashMapFactory.make(); + + /** + * Map from Polyglot local ClassTypes to their enclosing methods. Used by localTypeToTypeID().
+ * 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(); + + private final ClassLoaderReference fClassLoaderRef; + private final TypeSystem fTypeSystem; + + public PolyglotIdentityMapper(ClassLoaderReference clr, TypeSystem ts) { + fClassLoaderRef= clr; + fTypeSystem= ts; + } + + public FieldReference getFieldRef(FieldInstance field) { + if (!fFieldMap.containsKey(field)) { + FieldReference ref= referenceForField(field); + fFieldMap.put(field, ref); + return ref; + } + return fFieldMap.get(field); + } + + public TypeReference getTypeRef(Type type) { + if (!fTypeMap.containsKey(type)) { + TypeReference ref= referenceForType(type); + fTypeMap.put(type, ref); + return ref; + } + return fTypeMap.get(type); + } + + public MethodReference getMethodRef(CodeInstance method) { + if (!fMethodMap.containsKey(method)) { + MethodReference sel= referenceForMethod(method); + fMethodMap.put(method, sel); + return sel; + } + return fMethodMap.get(method); + } + + public void mapLocalAnonTypeToMethod(ClassType anonLocalType, CodeInstance owningProc) { + fLocalTypeMap.put(anonLocalType, owningProc); + } + + /** + * Create a FieldReference for the given Polyglot FieldInstance.
+ * N.B.: This method does not canonicalize the FieldReferences, + * but rather creates a new one for each call. + * You more likely want to call getFieldRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having FieldInstances collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public FieldReference referenceForField(FieldInstance field) { + Type targetType= field.container(); + Type fieldType= field.type(); + TypeReference targetTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType)); + TypeReference fieldTypeRef= TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType)); + Atom fieldName= Atom.findOrCreateUnicodeAtom(field.name()); + FieldReference fieldRef= FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef); + + return fieldRef; + } + + /** + * Create a TypeReference for the given Polyglot Type.
+ * N.B.: This method does not canonicalize the TypeReferences, + * but rather creates a new one for each call. + * You more likely want to call getTypeRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having Types collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public TypeReference referenceForType(Type type) { + TypeName typeName= TypeName.string2TypeName(typeToTypeID(type)); + TypeReference typeRef= TypeReference.findOrCreate(fClassLoaderRef, typeName); + + return typeRef; + } + + private Selector selectorForMethod(CodeInstance procInstance) { + Atom name= + (procInstance instanceof ConstructorInstance) ? + MethodReference.initAtom : + (procInstance instanceof InitializerInstance) ? + MethodReference.clinitName : + Atom.findOrCreateUnicodeAtom(((MethodInstance) procInstance).name()); + + TypeName[] argTypeNames = null; + if (! (procInstance instanceof InitializerInstance)) { + List formalTypes = ((ProcedureInstance)procInstance).formalTypes(); + int numArgs = formalTypes.size(); + // Descriptor prefers null to an empty array + if (numArgs > 0) { + argTypeNames = new TypeName[numArgs]; + + int i = 0; + for(Iterator iter = formalTypes.iterator(); iter.hasNext(); i++) { + Type argType= (Type) iter.next(); + argTypeNames[i]= TypeName.string2TypeName(typeToTypeID(argType)); + } + } + } + + Type retType= + (procInstance instanceof MethodInstance) ? ((MethodInstance) procInstance).returnType() : fTypeSystem.Void(); + TypeName retTypeName= TypeName.string2TypeName(typeToTypeID(retType)); + + Descriptor desc= Descriptor.findOrCreate(argTypeNames, retTypeName); + + return new Selector(name, desc); + } + + /** + * Create a MethodReference for the given Polyglot MethodInstance.
+ * N.B.: This method does not canonicalize the MethodReferences, + * but rather creates a new one for each call. + * You more likely want to call getMethodRef(). This method is exposed + * so that multiple Polyglot instances can use the translation services + * without having MethodInstances collide (producing the dreaded "we are + * TypeSystem_c but type Foo is from TypeSystem_c" exception). + */ + public MethodReference referenceForMethod(CodeInstance procInstance) { + // Handles both ConstructorInstance's and MethodInstance's + TypeName ownerType= TypeName.string2TypeName(typeToTypeID(((MemberInstance)procInstance).container())); + TypeReference ownerTypeRef= TypeReference.findOrCreate(fClassLoaderRef, ownerType); + MethodReference methodRef= MethodReference.findOrCreate(ownerTypeRef, selectorForMethod(procInstance)); + + return methodRef; + } + + /** + * 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 the type " + 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) { + CodeInstance procInstance= (CodeInstance) fLocalTypeMap.get(ctype); + + String outerTypeID= typeToTypeID(ctype.outer()); + String shortName= (ctype.isAnonymous()) ? PolyglotJava2CAstTranslator.anonTypeName(ctype) : ctype.fullName(); + + return outerTypeID + '/' + getMethodRef(procInstance).getSelector() + '/' + shortName; + } + + 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('.', '$'); + } + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJava2CAstTranslator.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJava2CAstTranslator.java new file mode 100644 index 000000000..2291e2a49 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJava2CAstTranslator.java @@ -0,0 +1,2716 @@ +/****************************************************************************** + * 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 java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import polyglot.ast.ArrayAccess; +import polyglot.ast.ArrayAccessAssign; +import polyglot.ast.ArrayInit; +import polyglot.ast.ArrayTypeNode; +import polyglot.ast.Assert; +import polyglot.ast.Assign; +import polyglot.ast.Binary; +import polyglot.ast.Block; +import polyglot.ast.BooleanLit; +import polyglot.ast.Branch; +import polyglot.ast.Call; +import polyglot.ast.CanonicalTypeNode; +import polyglot.ast.Case; +import polyglot.ast.Cast; +import polyglot.ast.Catch; +import polyglot.ast.CharLit; +import polyglot.ast.ClassBody; +import polyglot.ast.ClassDecl; +import polyglot.ast.ClassLit; +import polyglot.ast.ClassMember; +import polyglot.ast.Conditional; +import polyglot.ast.ConstructorCall; +import polyglot.ast.ConstructorDecl; +import polyglot.ast.Do; +import polyglot.ast.Empty; +import polyglot.ast.Eval; +import polyglot.ast.Expr; +import polyglot.ast.Field; +import polyglot.ast.FieldAssign; +import polyglot.ast.FieldDecl; +import polyglot.ast.FloatLit; +import polyglot.ast.For; +import polyglot.ast.Formal; +import polyglot.ast.If; +import polyglot.ast.Import; +import polyglot.ast.Initializer; +import polyglot.ast.Instanceof; +import polyglot.ast.IntLit; +import polyglot.ast.Labeled; +import polyglot.ast.Local; +import polyglot.ast.LocalAssign; +import polyglot.ast.LocalClassDecl; +import polyglot.ast.LocalDecl; +import polyglot.ast.MethodDecl; +import polyglot.ast.New; +import polyglot.ast.NewArray; +import polyglot.ast.Node; +import polyglot.ast.NodeFactory; +import polyglot.ast.NullLit; +import polyglot.ast.PackageNode; +import polyglot.ast.ProcedureDecl; +import polyglot.ast.Receiver; +import polyglot.ast.Return; +import polyglot.ast.SourceFile; +import polyglot.ast.Special; +import polyglot.ast.Stmt; +import polyglot.ast.StringLit; +import polyglot.ast.Switch; +import polyglot.ast.SwitchBlock; +import polyglot.ast.SwitchElement; +import polyglot.ast.Synchronized; +import polyglot.ast.Throw; +import polyglot.ast.TopLevelDecl; +import polyglot.ast.Try; +import polyglot.ast.Unary; +import polyglot.ast.While; +import polyglot.ast.Binary.Operator; +import polyglot.ast.ConstructorCall.Kind; +import polyglot.types.ArrayType; +import polyglot.types.ClassType; +import polyglot.types.CodeInstance; +import polyglot.types.ConstructorInstance; +import polyglot.types.FieldInstance; +import polyglot.types.Flags; +import polyglot.types.InitializerInstance; +import polyglot.types.InitializerInstance_c; +import polyglot.types.MemberInstance; +import polyglot.types.MethodInstance; +import polyglot.types.ParsedClassType; +import polyglot.types.ProcedureInstance; +import polyglot.types.ReferenceType; +import polyglot.types.SemanticException; +import polyglot.types.Type; +import polyglot.types.TypeSystem; +import polyglot.util.Position; + +import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol; +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.JavaType; +import com.ibm.wala.cast.tree.CAst; +import com.ibm.wala.cast.tree.CAstControlFlowMap; +import com.ibm.wala.cast.tree.CAstEntity; +import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.cast.tree.CAstNodeTypeMap; +import com.ibm.wala.cast.tree.CAstQualifier; +import com.ibm.wala.cast.tree.CAstSourcePositionMap; +import com.ibm.wala.cast.tree.CAstSymbol; +import com.ibm.wala.cast.tree.CAstType; +import com.ibm.wala.cast.tree.CAstTypeDictionary; +import com.ibm.wala.cast.tree.impl.AbstractSourcePosition; +import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder; +import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder; +import com.ibm.wala.cast.tree.impl.CAstOperator; +import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder; +import com.ibm.wala.cast.tree.impl.CAstSymbolImpl; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.shrikeBT.IInvokeInstruction; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.MemberReference; +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.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.IteratorPlusOne; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; + +public class PolyglotJava2CAstTranslator implements TranslatorToCAst { + protected final CAst fFactory = new CAstImpl(); + + protected final NodeFactory fNodeFactory; + + protected final TypeSystem fTypeSystem; + + protected Type fNPEType; + + protected Type fCCEType; + + protected Type fREType; // RuntimeException + + protected Type fDivByZeroType; + + protected final ClassLoaderReference fClassLoaderRef; + + private CAstTypeDictionary fTypeDict; + + private TranslatingVisitor fTranslator; + + protected PolyglotIdentityMapper fIdentityMapper; + + protected final boolean DEBUG = true; + + 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 CAstNode translateConstant(Object constant) { + return fFactory.makeConstant(constant); + } + + 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/* */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, false, 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, fIdentityMapper.getMethodRef(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, false, 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/* */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(); + FieldReference fieldRef = fIdentityMapper.getFieldRef(f.fieldInstance()); + // 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() ? makeNode(ctorContext, fFactory, null, CAstNode.VOID) : 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; + if ( init instanceof ArrayInit ) { + rhsNode = visit((ArrayInit)init,ctorContext,f.declType()); + } else { + 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; + } + + /* + * If we've handled all the parent cases, this should never be called -- + * visit(ArrayInit,WalkContext,Type) should be instead. + */ + 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()); + } + + TypeReference newTypeRef = fIdentityMapper.getTypeRef(ai.type()); + 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(); + if ( element instanceof ArrayInit ) { + eltNodes[idx] = visit((ArrayInit)element, wc, ((ArrayType)ai.type()).base()); + } else { + 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); + } + + /* + * Workaround for the null array init bug: just in case ai.type().base() is null (e.g. + * "new Object[] {null}") we get the type from the parent (in this example, a + * NewArray of type Object[]) + */ + public CAstNode visit(ArrayInit ai, WalkContext wc, Type t) { + TypeReference newTypeRef = fIdentityMapper.getTypeRef(t); + 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(); + if ( element instanceof ArrayInit ) { + eltNodes[idx] = visit((ArrayInit)element, wc, ((ArrayType)t).base()); + } else { + 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) { + WalkContext lvc = new AssignmentContext(wc); + if (la.operator() == Assign.ASSIGN) { + return makeNode(wc, fFactory, la, CAstNode.ASSIGN, walkNodes(la.left(), lvc), walkNodes(la.right(), wc)); + } else { + CAstNode op = + makeNode(wc, + fFactory, + la, + CAstNode.ASSIGN_PRE_OP, + walkNodes(la.left(), lvc), + walkNodes(la.right(), wc), + mapAssignOperator(la.operator())); + + + if (la.type().isLongOrLess() && + (mapAssignOperator(la.operator())==CAstOperator.OP_DIV || + mapAssignOperator(la.operator())==CAstOperator.OP_MOD)) + { + Collection excTargets = wc.getCatchTargets(fDivByZeroType); + if (!excTargets.isEmpty()) { + for (Iterator iterator = excTargets.iterator(); + iterator.hasNext();) + { + Pair catchPair = (Pair) iterator.next(); + wc.cfg().add(op, catchPair.snd, fDivByZeroType); + } + } else { + wc.cfg().add(op, + CAstControlFlowMap.EXCEPTION_TO_EXIT, + fDivByZeroType); + } + } + + return op; + } + } + + 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 { + Type leftType = left.type(); + Type rightType = right.type(); + if (leftType.isPrimitive() && rightType.isPrimitive()) { + CAstNode leftNode = walkNodes(left, wc); + CAstNode rightNode = walkNodes(right, wc); + + try { + Type result = fTypeSystem.promote(leftType, rightType); + + if (! result.equals(leftType)) { + leftNode = makeNode(wc, fFactory, b, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(result)), leftNode, fFactory.makeConstant(getTypeDict().getCAstTypeFor(leftType))); + } + + if (! result.equals(rightType)) { + rightNode = makeNode(wc, fFactory, b, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(result)), rightNode, fFactory.makeConstant(getTypeDict().getCAstTypeFor(rightType))); + } + } catch (SemanticException e) { + + } + + CAstNode op = makeNode(wc, fFactory, b, CAstNode.BINARY_EXPR, mapBinaryOpcode(operator), leftNode, rightNode); + + if (leftType.isLongOrLess() && + rightType.isLongOrLess() && + (mapBinaryOpcode(operator)==CAstOperator.OP_DIV || + mapBinaryOpcode(operator)==CAstOperator.OP_MOD)) + { + Collection excTargets = wc.getCatchTargets(fDivByZeroType); + if (!excTargets.isEmpty()) { + for (Iterator iterator = excTargets.iterator(); + iterator.hasNext();) + { + Pair catchPair = (Pair) iterator.next(); + wc.cfg().add(op, catchPair.snd, fDivByZeroType); + } + } else { + wc.cfg().add(op, + CAstControlFlowMap.EXCEPTION_TO_EXIT, + fDivByZeroType); + } + } + + return op; + + } else { + return makeNode(wc, fFactory, b, CAstNode.BINARY_EXPR, mapBinaryOpcode(operator), walkNodes(left, wc), walkNodes(right, wc)); + } + } + } + + @SuppressWarnings("unchecked") + private void handleThrowsFromCall(ProcedureInstance procedureInstance, Node callAstNode, WalkContext wc) { + List throwTypes = procedureInstance.throwTypes(); + for (Iterator iter = IteratorPlusOne.make(throwTypes.iterator(), fREType); iter.hasNext();) { + Type thrownType = (Type) iter.next(); + Collection/* > */catchTargets = wc.getCatchTargets(thrownType); + + for (Iterator targetIter = catchTargets.iterator(); targetIter.hasNext();) { + Pair/* */catchTarget = (Pair/* */) 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.getEnclosingMethod()); + } + + MethodReference methodRef = fIdentityMapper.getMethodRef(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 = fIdentityMapper.getMethodRef(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 castedFrom = arg.type(); + Type castedTo = c.castType().type(); + + // null can go into anything (e.g. in "((Foobar) null)" null can be assumed to be of type Foobar already) + if ( castedFrom.isNull() ) + castedFrom = castedTo; + + CAstNode ast = makeNode(wc, fFactory, c, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(castedTo)), + walkNodes(arg, wc), + fFactory.makeConstant(getTypeDict().getCAstTypeFor(castedFrom))); + + Collection excTargets = wc.getCatchTargets(fCCEType); + if (!excTargets.isEmpty()) { + // connect ClassCastException exception edge to relevant catch targets + // (presumably only one) + for (Iterator iterator = excTargets.iterator(); iterator.hasNext();) { + Pair catchPair = (Pair) iterator.next(); + wc.cfg().add(c, catchPair.snd, fCCEType); + } + } else { + // connect exception edge to exit + wc.cfg().add(c, CAstControlFlowMap.EXCEPTION_TO_EXIT, fCCEType); + } + + wc.cfg().map(c, ast); + return ast; + } + + 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 = fIdentityMapper.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 fFactory.makeConstant((int) il.value()); + } + + public CAstNode visit(StringLit sl, WalkContext wc) { + return fFactory.makeConstant(sl.value()); + } + + public CAstNode visit(New n, WalkContext wc) { + CAstEntity anonClass = null; + String newTypeNameStr; + TypeReference newTypeRef; + ConstructorInstance ctorInst = n.constructorInstance(); + MethodReference ctorRef = fIdentityMapper.getMethodRef(ctorInst); + + if (n.body() != null) { + fIdentityMapper.mapLocalAnonTypeToMethod((ClassType) n.type(), wc.getEnclosingMethod()); + + anonClass = walkEntity(n, wc); + + newTypeNameStr = anonClass.getType().getName(); + TypeName newTypeName = TypeName.string2TypeName(newTypeNameStr); + Selector ctorSel = ctorRef.getSelector(); + newTypeRef = TypeReference.findOrCreate(fClassLoaderRef, newTypeName); + ctorRef = MethodReference.findOrCreate(newTypeRef, ctorSel); + } else { + newTypeRef = fIdentityMapper.getTypeRef(n.type()); + } + + List/* */args = n.arguments(); + String tmpName = "ctor temp"; // this name is an illegal Java + // identifier + + // new nodes with an explicit enclosing argument, e.g. "outer.new Inner()". They are mostly treated the same, except in JavaCAst2IRTranslator.doNewObject + CAstNode newNode; + Expr enclosing = n.qualifier(); + if ( enclosing != null ) { + CAstNode encNode = walkNodes(enclosing, wc); + newNode = makeNode(wc, fFactory, n, CAstNode.NEW_ENCLOSING, fFactory.makeConstant(newTypeRef), encNode); + } + else + newNode = makeNode(wc, fFactory, n, CAstNode.NEW, fFactory.makeConstant(newTypeRef)); + // end enclosing new stuff + + 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, fFactory.makeConstant(new InternalCAstSymbol(tmpName, true)), 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, newType); + } else { + ArrayType arrayType = (ArrayType) newType; + TypeReference arrayTypeRef = fIdentityMapper.getTypeRef(arrayType); + + List/* */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(); + TypeReference owningTypeRef = fIdentityMapper.getTypeRef(owningType); + + 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())) { + WalkContext lvc = new AssignmentContext(wc); + if (u.operator().isPrefix()) + return makeNode(wc, fFactory, u, CAstNode.ASSIGN_PRE_OP, walkNodes(u.expr(), lvc), fFactory.makeConstant(1), + mapUnaryOpcode(u.operator())); + else + return makeNode(wc, fFactory, u, CAstNode.ASSIGN_POST_OP, walkNodes(u.expr(), lvc), 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) { + TypeReference eltTypeRef = fIdentityMapper.getTypeRef(aa.type()); + + 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(aa, catchPair.snd, fNPEType); + } + } else { + // connect exception edge to exit + wc.cfg().add(aa, CAstControlFlowMap.EXCEPTION_TO_EXIT, fNPEType); + } + + CAstNode n = makeNode(wc, fFactory, aa, CAstNode.ARRAY_REF, walkNodes(aa.array(), wc), fFactory.makeConstant(eltTypeRef), + walkNodes(aa.index(), wc)); + + wc.cfg().map(aa, n); + + return n; + } + + 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)); + } + FieldReference fieldRef = fIdentityMapper.getFieldRef(f.fieldInstance()); + CAstNode targetNode = walkNodes(target, wc); + FieldInstance fi = f.fieldInstance(); + + if (fi.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). + if (fi.isConstant()) { + return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR, targetNode, // can + // have + // side + // effects! + translateConstant(fi.constantValue())); + } else { + 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); + + if (fi.isConstant()) { + return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR, refNode, // can + // have + // side + // effects! + translateConstant(fi.constantValue())); + } else { + 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 breakTarget = makeBreakTarget(l); + + Node stmt = l.statement(); + while (stmt instanceof Block) { + stmt = (Node) ((Block) stmt).statements().iterator().next(); + } + + wc.getLabelMap().put(stmt, l.label()); + + CAstNode result; + if (! (l.statement() instanceof Empty)) { + WalkContext child = new BreakContext(wc, l.label(), breakTarget); + + result = + makeNode(wc, fFactory, l, CAstNode.BLOCK_STMT, + makeNode(wc, fFactory, l, CAstNode.LABEL_STMT, fFactory.makeConstant(l.label()), walkNodes(l.statement(), child)), + walkNodes(breakTarget, wc)); + } else { + 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) { + fIdentityMapper.mapLocalAnonTypeToMethod(lcd.decl().type(), wc.getEnclosingMethod()); + + CAstEntity classEntity = walkEntity(lcd.decl(), wc); + + final CAstNode lcdNode = makeNode(wc, fFactory, lcd, CAstNode.EMPTY); + + wc.addScopedEntity(lcdNode, classEntity); + return lcdNode; + } + + protected Node makeBreakTarget(Node loop) { + return fNodeFactory.Labeled(Position.COMPILER_GENERATED, "breakLabel" + loop.position().toString().replace('.', '_'), + fNodeFactory.Empty(Position.COMPILER_GENERATED)); + } + + protected Node makeContinueTarget(Node loop) { + return fNodeFactory.Labeled(Position.COMPILER_GENERATED, "continueLabel" + loop.position().toString().replace('.', '_'), + 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(s.position(), "switchBreakLabel" + + s.position().toString().replace('.', '_'), fNodeFactory.Empty(s.position())); + CAstNode breakAst = walkNodes(breakLabel, wc); + String loopLabel = (String) wc.getLabelMap().get(s); + WalkContext child = new BreakContext(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); + + // 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, fFactory.makeConstant(new CAstSymbolImpl(exprName, true)), + 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 if (init instanceof ArrayInit) + initNode = visit((ArrayInit) init, wc, type); + else + initNode = walkNodes(init, wc); + + Object defaultValue; + if (type.isLongOrLess()) + defaultValue = new Integer(0); + else if (type.isDouble() || type.isFloat()) + defaultValue = new Double(0.0); + else + defaultValue = CAstSymbol.NULL_DEFAULT_VALUE; + + boolean isFinal = ld.flags().isFinal(); + + return makeNode(wc, fFactory, ld, CAstNode.DECL_STMT, fFactory.makeConstant(new CAstSymbolImpl(ld.name(), isFinal, + defaultValue)), 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/* > */catchNodes = wc.getCatchTargets(label); + + for (Iterator iter = catchNodes.iterator(); iter.hasNext();) { + Pair/* */catchNode = (Pair/* */) 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 String fName; + + private final Collection fTopLevelDecls; + + public CompilationUnitEntity(SourceFile file, List topLevelDecls) { + fName = (file.package_() == null) ? "" : file.package_().package_().fullName().replace('.', '/'); + fTopLevelDecls = topLevelDecls; + } + + public int getKind() { + return FILE_ENTITY; + } + + public String getName() { + return fName; + } + + 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 fSuperTypes = null; + + public PolyglotJavaType(ClassType type, CAstTypeDictionary dict, TypeSystem system) { + super(); + fDict = dict; + fSystem = system; + fType = type; + } + + public String getName() { + // TODO Will the IdentityMapper do the right thing for anonymous + // classes? + // If so, we can delete most of the following logic... + if (fType.isLocal() || fType.isAnonymous()) { + return fIdentityMapper.anonLocalTypeToTypeID(fType); + } else + return fIdentityMapper.getTypeRef(fType).getName().toString(); + } + + 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 Collection getQualifiers() { + return mapFlagsToQualifiers(fType.flags()); + } + + public boolean isInterface() { + return fType.flags().isInterface(); + } + } + + protected abstract static class CodeBodyEntity implements CAstEntity { + private final Map> fEntities; + + public CodeBodyEntity(Map 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 (fEntities.get(construct)).iterator(); + } else { + return EmptyIterator.instance(); + } + } + + public String getSignature() { + return Util.methodEntityToSelector(this).toString(); + } + } + + protected final class ClassEntity implements CAstEntity { + @SuppressWarnings("unused") + private final ClassContext fContext; + + private final ClassType fCT; + + private final String fName; + + private final Collection fEntities; + + private final CAstSourcePositionMap.Position sourcePosition; + + private ClassEntity(ClassContext context, List entities, ClassDecl cd, Position p) { + this(context, entities, cd.type(), cd.name(), p); + } + + private ClassEntity(ClassContext context, List 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 CodeInstance fPd; + + private final MethodContext fMc; + + private final String[] argumentNames; + + private ProcedureEntity(CAstNode pdast, TypeSystem system, CodeInstance pd, Type declaringType, String[] argumentNames, + Map 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, CodeInstance pd, String[] argumentNames, + Map entities, MethodContext mc) { + this(pdast, system, pd, ((MemberInstance) pd).container(), argumentNames, entities, mc); + } + + private List formalTypes() { + if (fPd instanceof ProcedureInstance) { + return ((ProcedureInstance) fPd).formalTypes(); + } else { + return Collections.EMPTY_LIST; + } + } + + 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 { + if (fPd instanceof InitializerInstance) { + return MethodReference.clinitName.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() ? formalTypes().size() : 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 getSourceMap().getPosition(fPdast); + } + + public CAstNodeTypeMap getNodeTypeMap() { + return fMc.getNodeTypeMap(); + } + + public Collection getQualifiers() { + return mapFlagsToQualifiers(fPd.flags()); + } + + public CAstType getType() { + return new CAstType.Method() { + private Collection fExceptionTypes = null; + + private List 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 = 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/* */getExceptionTypes() { + if (fExceptionTypes == null) { + fExceptionTypes = new LinkedHashSet(); + + if (fPd instanceof ProcedureInstance) { + List exceptions = ((ProcedureInstance) 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 formalTypes().size(); + } + + public CAstType getDeclaringType() { + return getTypeDict().getCAstTypeFor(declaringType); + } + }; + } + } + + protected final class FieldEntity implements CAstEntity { + private final FieldInstance fFI; + + private final WalkContext fContext; + + private FieldEntity(FieldDecl fd, WalkContext context) { + super(); + fFI = fd.fieldInstance(); + fContext = context; + } + + public int getKind() { + return CAstEntity.FIELD_ENTITY; + } + + public String getName() { + return fFI.name(); + } + + public String getSignature() { + return fFI.name() + fIdentityMapper.typeToTypeID(fFI.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.emptyMap(); + } + + 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(fFI.position()); + } + + public CAstNodeTypeMap getNodeTypeMap() { + // No AST for a field decl; initializers folded into + // constructor processing... + return null; + } + + public Collection getQualifiers() { + return mapFlagsToQualifiers(fFI.flags()); + } + + public CAstType getType() { + return fContext.getTypeDictionary().getCAstTypeFor(fFI.type()); + } + } + + public interface WalkContext { + void addScopedEntity(CAstNode node, CAstEntity e); + + CAstControlFlowRecorder cfg(); + + CAstSourcePositionRecorder pos(); + + CAstNodeTypeMapRecorder getNodeTypeMap(); + + Collection> getCatchTargets(Type label); + + Node getContinueFor(String label); + + Node getBreakFor(String label); + + Node getFinally(); + + CodeInstance getEnclosingMethod(); + + Type getEnclosingType(); + + CAstTypeDictionary getTypeDictionary(); + + List getStaticInitializers(); + + List getInitializers(); + + Map getLabelMap(); + + boolean needLVal(); + } + + 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/**/ getScopedEntities() { + // return parent.getScopedEntities(); + // } + + public CAstControlFlowRecorder cfg() { + return parent.cfg(); + } + + public CAstSourcePositionRecorder pos() { + return parent.pos(); + } + + public CAstNodeTypeMapRecorder getNodeTypeMap() { + return parent.getNodeTypeMap(); + } + + public Collection> 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 CodeInstance getEnclosingMethod() { + return parent.getEnclosingMethod(); + } + + 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 boolean needLVal() { + return parent.needLVal(); + } + } + + public class ClassContext extends DelegatingContext { + // private final ClassDecl cd; + private final Type type; + + private List/* */fInitializers = new ArrayList(); + + private List/* */fStaticInitializers = new ArrayList(); + + private List 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/**/ 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/* > */getCatchTarget(Type label) { + Assertions.UNREACHABLE("ClassContext.getCatchTarget()"); + return null; + } + + public Node getFinally() { + Assertions.UNREACHABLE("ClassContext.getFinally()"); + return null; + } + + public CodeInstance getEnclosingMethod() { + // 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.getEnclosingMethod()"); + 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 boolean needLVal() { + Assertions.UNREACHABLE("ClassContext.needLVal()"); + return false; + } + } + + public class CodeBodyContext extends DelegatingContext { + final CAstSourcePositionRecorder fSourceMap = new CAstSourcePositionRecorder(); + + final CAstControlFlowRecorder fCFG = new CAstControlFlowRecorder(fSourceMap); + + final CAstNodeTypeMapRecorder fNodeTypeMap = new CAstNodeTypeMapRecorder(); + + private final Map labelMap = HashMapFactory.make(2); + + private final Map fEntities; + + public CodeBodyContext(WalkContext parent, Map 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/* */getScopedEntities() { + return fEntities; + } + + public Map getLabelMap() { + return labelMap; + } + + public boolean needLVal() { + return false; + } + } + + public class MethodContext extends CodeBodyContext { + final CodeInstance fPI; + + public MethodContext(CodeInstance pi, Map entities, WalkContext parent) { + super(parent, entities); + fPI = pi; + } + + public Collection> getCatchTargets(Type label) { + Collection> result = Collections.singleton(Pair.make(fREType, CAstControlFlowMap.EXCEPTION_TO_EXIT)); + return result; + } + + public CodeInstance getEnclosingMethod() { + return fPI; + } + } + + private static class TryCatchContext extends DelegatingContext { + @SuppressWarnings("unused") + private final Try tryNode; + + Collection> 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 p = Pair.make(c.catchType(), (Object)c); + + fCatchNodes.add(p); + } + } + + public Collection> 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> catchNodes = new ArrayList>(); + + for (Iterator> iter = fCatchNodes.iterator(); iter.hasNext();) { + Pair p = (Pair) 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> 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 CodeInstance getEnclosingMethod() { + Assertions.UNREACHABLE("RootContext.getEnclosingMethod()"); + 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; + } + + public boolean needLVal() { + Assertions.UNREACHABLE("ClassContext.needLVal()"); + return false; + } + } + + public class BreakContext extends DelegatingContext { + protected final String label; + + private final Node breakTo; + + BreakContext(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; + } + } + + public class LoopContext extends BreakContext { + private final Node continueTo; + + public 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); + } + } + + private class AssignmentContext extends DelegatingContext { + + protected AssignmentContext(WalkContext parent) { + super(parent); + } + + public boolean needLVal() { + return true; + } + } + + public PolyglotJava2CAstTranslator(ClassLoaderReference clr, NodeFactory nf, TypeSystem ts, PolyglotIdentityMapper identityMapper) { + fClassLoaderRef = clr; + fTypeSystem = ts; + fNodeFactory = nf; + fIdentityMapper = identityMapper; + try { + fNPEType = fTypeSystem.typeForName("java.lang.NullPointerException"); + fCCEType = fTypeSystem.typeForName("java.lang.ClassCastException"); + fREType = fTypeSystem.typeForName("java.lang.RuntimeException"); + fDivByZeroType = fTypeSystem.typeForName("java.lang.ArithmeticException"); + } catch (SemanticException e) { + Assertions.UNREACHABLE("Couldn't find Polyglot type for NPE/RE!"); + } + } + + protected static class PolyglotSourcePosition extends AbstractSourcePosition { + private final Position p; + + public 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 int getFirstOffset() { + return p.offset(); + } + + public int getLastOffset() { + return p.endOffset(); + } + + public URL getURL() { + try { + String path = p.path(); + return new URL("file:" + (path.length() == 0 ? p.file() : 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 void setPos(WalkContext wc, CAstNode cn, Position p) { + if (p != null) { + wc.pos().setPosition(cn, makePosition(p)); + } + } + + protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind) { + CAstNode cn = Ast.makeNode(kind); + setPos(wc, cn, n); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c[]) { + CAstNode cn = Ast.makeNode(kind, c); + setPos(wc, cn, n); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c) { + CAstNode cn = Ast.makeNode(kind, c); + setPos(wc, cn, n); + return cn; + } + + protected 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; + } + + protected 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; + } + + protected 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; + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind) { + return makeNode(wc, fFactory, n, kind); + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c[]) { + return makeNode(wc, fFactory, n, kind, c); + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c) { + return makeNode(wc, fFactory, n, kind, c); + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2) { + return makeNode(wc, fFactory, n, kind, c1, c2); + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3) { + return makeNode(wc, fFactory, n, kind, c1, c2, c3); + } + + protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) { + return makeNode(wc, fFactory, n, kind, c1, c2, c3, c4); + } + + protected CAstNode makeNode(WalkContext wc, int kind, Position p) { + CAstNode cn = fFactory.makeNode(kind); + setPos(wc, cn, p); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1) { + CAstNode cn = fFactory.makeNode(kind, c1); + setPos(wc, cn, p); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode[] rest) { + CAstNode cn = fFactory.makeNode(kind, c1, rest); + setPos(wc, cn, p); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2) { + CAstNode cn = fFactory.makeNode(kind, c1, c2); + setPos(wc, cn, p); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2, CAstNode c3) { + CAstNode cn = fFactory.makeNode(kind, c1, c2, c3); + setPos(wc, cn, p); + return cn; + } + + protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) { + CAstNode cn = fFactory.makeNode(kind, c1, c2, c3, c4); + setPos(wc, cn, p); + return cn; + } + + public CAstEntity translate(Object ast, String fileName) { + return walkEntity((Node) ast, new RootContext(getTypeDict())); + } + + /** + * Maps front-end-specific representations into WALA references of the appropriate kind. + * @author rfuhrer + * + * @param The front-end-specific representation of a type (e.g., for Polyglot, a Type) + * @param The front-end-specific representation of a procedure/method (e.g., for Polyglot, a CodeInstance) + * @param The front-end-specific representation of a field (e.g., for Polyglot, a FieldInstance) + */ + public interface IdentityMapper { + MemberReference getMethodRef(MethodRep method); + + TypeReference getTypeRef(TypeRep type); + + FieldReference getFieldRef(FieldRep field); + } + + protected static Collection mapFlagsToQualifiers(Flags flags) { + Set 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(Node n, ClassType classType, List members, DelegatingContext classContext, + List 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); + } + } + + // add class initializer, if needed + if (!classContext.getStaticInitializers().isEmpty()) { + InitializerInstance initInstance = new InitializerInstance_c(fTypeSystem, n.position(), classType, Flags.STATIC); + + Map childEntities = HashMapFactory.make(); + final MethodContext mc = new MethodContext(initInstance, childEntities, classContext); + + List inits = classContext.getStaticInitializers(); + CAstNode[] bodyNodes = new CAstNode[inits.size()]; + insertInitializers(mc, bodyNodes, true, 0); + + CAstNode ast = makeNode(mc, fFactory, n, CAstNode.BLOCK_STMT, bodyNodes); + + memberEntities.add(new ProcedureEntity(ast, fTypeSystem, initInstance, new String[0], childEntities, mc)); + + } + } + + 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 = HashMapFactory.make(); + 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, fIdentityMapper.getMethodRef(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, false, 1); + + CAstNode ast = makeNode(mc, fFactory, n, CAstNode.BLOCK_STMT, bodyNodes); + + memberEntities.add(new ProcedureEntity(ast, fTypeSystem, superCtor, anonType, fakeArguments, childEntities, mc)); + } + } + + static String anonTypeName(ClassType ct) { + Position pos = ct.position(); + + return ct.fullName() + "$" + pos.line() + "$" + pos.column(); + } + + @SuppressWarnings("unchecked") + protected CAstEntity walkEntity(Node rootNode, final WalkContext context) { + if (rootNode instanceof SourceFile) { + SourceFile file = (SourceFile) rootNode; + List 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 memberEntities = new ArrayList(); + final ClassContext classContext = new ClassContext(cd.type(), memberEntities, context); + + processClassMembers(rootNode, cd.type(), 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 memberEntities = new ArrayList(); + ParsedClassType anonType = n.anonType(); + String anonTypeName = anonTypeName(anonType); + final ClassContext classContext = new ClassContext(anonType, memberEntities, context); + + processClassMembers(rootNode, anonType, 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 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/* */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, boolean wantStatic, int offset) { + List inits = wantStatic ? wc.getStaticInitializers() : wc.getInitializers(); + + for (Iterator iter = inits.iterator(); iter.hasNext(); offset++) { + ClassMember init = (ClassMember) iter.next(); + CAstNode initNode = walkNodes(init, wc); + + if (initNode != null) { + initCode[offset] = initNode; + } else { + initCode[offset] = makeNode(wc, fFactory, null, CAstNode.EMPTY); + } + } + 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); + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJavaSourceAnalysisEngine.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJavaSourceAnalysisEngine.java new file mode 100644 index 000000000..5ae68fb9e --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotJavaSourceAnalysisEngine.java @@ -0,0 +1,17 @@ +package com.ibm.wala.cast.java.translator.polyglot; + +import com.ibm.wala.cast.java.client.JavaSourceAnalysisEngine; +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; + +public class PolyglotJavaSourceAnalysisEngine extends JavaSourceAnalysisEngine { + + public IRTranslatorExtension getTranslatorExtension() { + return new JavaIRTranslatorExtension(); + } + + protected ClassLoaderFactory getClassLoaderFactory(SetOfClasses exclusions) { + return new PolyglotClassLoaderFactory(exclusions, getTranslatorExtension()); + } + +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceLoaderImpl.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceLoaderImpl.java new file mode 100644 index 000000000..4b1393526 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceLoaderImpl.java @@ -0,0 +1,41 @@ +/****************************************************************************** + * 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 Oct 7, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.io.IOException; + +import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl; +import com.ibm.wala.cast.java.translator.SourceModuleTranslator; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.ipa.callgraph.impl.SetOfClasses; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; + +public class PolyglotSourceLoaderImpl extends JavaSourceLoaderImpl { + private final IRTranslatorExtension fExtInfo; + + public PolyglotSourceLoaderImpl(ClassLoaderReference loaderRef, IClassLoader parent, SetOfClasses exclusions, + IClassHierarchy cha, IRTranslatorExtension extInfo) throws IOException { + super(loaderRef, parent, exclusions, cha); + this.fExtInfo = extInfo; + } + + public IRTranslatorExtension getTranslatorExtension() { + return fExtInfo; + } + + protected SourceModuleTranslator getTranslator() { + return new PolyglotSourceModuleTranslator(cha.getScope(), fExtInfo, this); + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceModuleTranslator.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceModuleTranslator.java new file mode 100644 index 000000000..1a09ad754 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotSourceModuleTranslator.java @@ -0,0 +1,146 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import polyglot.frontend.Compiler; +import polyglot.frontend.ExtensionInfo; +import polyglot.main.Options; +import polyglot.main.UsageError; +import polyglot.util.ErrorInfo; +import polyglot.util.Position; + +import com.ibm.wala.cast.java.translator.SourceModuleTranslator; +import com.ibm.wala.classLoader.DirectoryTreeModule; +import com.ibm.wala.classLoader.FileModule; +import com.ibm.wala.classLoader.JarFileModule; +import com.ibm.wala.classLoader.Module; +import com.ibm.wala.classLoader.SourceFileModule; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.debug.Assertions; + +/** + * A SourceModuleTranslator whose implementation of loadAllSources() uses the PolyglotFrontEnd + * pseudo-compiler to generate DOMO IR for the sources in the compile-time classpath. + * @author rfuhrer + */ +public class PolyglotSourceModuleTranslator implements SourceModuleTranslator { + private final ExtensionInfo fExtInfo; + + private String fClassPath; + + public PolyglotSourceModuleTranslator(AnalysisScope scope, IRTranslatorExtension extInfo, PolyglotSourceLoaderImpl sourceLoader) { + fExtInfo= (ExtensionInfo) extInfo; + computeClassPath(scope); + extInfo.setSourceLoader(sourceLoader); + } + + private void computeClassPath(AnalysisScope scope) { + StringBuffer buf= new StringBuffer(); + + ClassLoaderReference cl= findInnermostClassLoader(scope); + + while (cl != null) { + List modules= scope.getModules(cl); + + for(Iterator iter= modules.iterator(); iter.hasNext(); ) { + Module m= (Module) iter.next(); + + if (buf.length() > 0) + buf.append(File.pathSeparator); + if (m instanceof JarFileModule) { + JarFileModule jarFileModule= (JarFileModule) m; + + buf.append(jarFileModule.getAbsolutePath()); + } else if (m instanceof DirectoryTreeModule) { + DirectoryTreeModule directoryTreeModule= (DirectoryTreeModule) m; + + buf.append(directoryTreeModule.getPath()); + } else if (m instanceof FileModule) { + // do nothing + } else + Assertions.UNREACHABLE("Module entry is neither jar file nor directory"); + } + cl= cl.getParent(); + } + fClassPath= buf.toString(); + } + + private ClassLoaderReference findInnermostClassLoader(AnalysisScope scope) { + Set parentLoaders= new HashSet(); + + for(ClassLoaderReference loader: scope.getLoaders()) { + parentLoaders.add(loader.getParent()); + } + for (ClassLoaderReference child : scope.getLoaders()) { + if (!parentLoaders.contains(child)) { + return child; + } + } + throw new IllegalStateException("No innermost class loader???"); + } + + public void loadAllSources(Set modules) { + Options opts= fExtInfo.getOptions(); + opts.assertions = true; + Options.global = opts; + try { + opts.parseCommandLine(new String[] { "-cp", fClassPath }, new HashSet()); + } catch (UsageError e) { + // Assertions.UNREACHABLE("Error parsing classpath spec???"); + } + + Compiler compiler= new PolyglotFrontEnd(fExtInfo); + List streams= new ArrayList(); + + // N.B.: 'modules' is a flat set of source file ModuleEntry's. + for(Iterator it= modules.iterator(); it.hasNext(); ) { + SourceFileModule entry= (SourceFileModule) it.next(); + + Assertions._assert(entry.isSourceFile()); + + if (skipSourceFile(entry)) { + continue; + } + + String filePath= entry.getAbsolutePath(); + + try { + StreamSource srcStream= new StreamSource(entry.getInputStream(), filePath); + + streams.add(srcStream); + } catch (IOException e) { + compiler.errorQueue().enqueue(new ErrorInfo(ErrorInfo.IO_ERROR, "Unable to open source file '" + entry.getName() + "'", Position.COMPILER_GENERATED)); + } + } + compiler.compile(streams); + // At this point, DOMO now "knows" about all the source-originated stuff + } + + /** + * @return true if the given source file module should not be processed, + * e.g. because it is generated on behalf of some upstream source. + */ + protected boolean skipSourceFile(SourceFileModule entry) { + return false; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotTypeDictionary.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotTypeDictionary.java new file mode 100644 index 000000000..3a8d3ab39 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/PolyglotTypeDictionary.java @@ -0,0 +1,102 @@ +/****************************************************************************** + * 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 Sep 28, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import polyglot.types.ArrayType; +import polyglot.types.ClassType; +import polyglot.types.PrimitiveType; +import polyglot.types.ReferenceType; +import polyglot.types.Type; +import polyglot.types.TypeSystem; + +import com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap; +import com.ibm.wala.cast.tree.CAstType; +import com.ibm.wala.cast.tree.impl.CAstTypeDictionaryImpl; +import com.ibm.wala.util.debug.Assertions; + +public class PolyglotTypeDictionary extends CAstTypeDictionaryImpl { + private final class PolyglotJavaArrayType implements CAstType.Array { + private final Type fEltPolyglotType; + + private final CAstType fEltCAstType; + + private PolyglotJavaArrayType(ArrayType arrayType) { + super(); + fEltPolyglotType = arrayType.base(); + fEltCAstType = getCAstTypeFor(fEltPolyglotType); + } + + public int getNumDimensions() { + return 1; // always 1 for Java + } + + public CAstType getElementType() { + return fEltCAstType; + } + + public String getName() { + return "[" + fEltCAstType.getName(); + } + + public Collection getSupertypes() { + if (fEltPolyglotType.isPrimitive()) + return Collections.singleton(getCAstTypeFor(fTypeSystem.Object())); + Assertions._assert(fEltPolyglotType.isReference(), "Non-primitive, non-reference array element type!"); + ReferenceType baseRefType = (ReferenceType) fEltPolyglotType; + Collection supers = new ArrayList(); + for (Iterator superIter = baseRefType.interfaces().iterator(); superIter.hasNext();) { + supers.add(getCAstTypeFor(superIter.next())); + } + if (baseRefType.superType() != null) + supers.add(getCAstTypeFor(baseRefType.superType())); + return supers; + } + } + + protected final TypeSystem fTypeSystem; + + private final PolyglotJava2CAstTranslator fTranslator; + + public PolyglotTypeDictionary(TypeSystem typeSystem, PolyglotJava2CAstTranslator translator) { + fTypeSystem = typeSystem; + fTranslator = translator; + } + + public CAstType getCAstTypeFor(Object astType) { + CAstType type = super.getCAstTypeFor(astType); + // Handle the case where we haven't seen an AST decl for some type before + // processing a reference. This can certainly happen with classes in byte- + // code libraries, for which we never see an AST decl. + // In this case, just create a new type and return that. + if (type == null) { + final Type polyglotType = (Type) astType; + + if (polyglotType.isClass()) + type = fTranslator.new PolyglotJavaType((ClassType) astType, this, fTypeSystem); + else if (polyglotType.isPrimitive()) { + type = JavaPrimitiveTypeMap.lookupType(((PrimitiveType) polyglotType).name()); + } else if (polyglotType.isArray()) { + type = new PolyglotJavaArrayType((ArrayType) polyglotType); + } else + Assertions.UNREACHABLE("getCAstTypeFor() passed type that is not primitive, array, or class?"); + super.map(astType, type); + } + return type; + } +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/StreamSource.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/StreamSource.java new file mode 100644 index 000000000..93f9c7511 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/StreamSource.java @@ -0,0 +1,45 @@ +/****************************************************************************** + * 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 Oct 6, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import polyglot.frontend.FileSource; + +/** + * A Polyglot Source whose input comes from an InputStream.
+ * Currently extends FileSource since that's all that the Polyglot Compiler class + * will accept. + * @author rfuhrer + */ +public class StreamSource extends FileSource { + private InputStream fStream; + + public StreamSource(InputStream s, String fullPath) throws IOException { + super(new File(fullPath), true); + fStream= s; + } + + public Reader open() throws IOException { + if (reader == null) { + reader = createReader(fStream); + } + + return reader; + } + +} diff --git a/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/TranslatingVisitor.java b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/TranslatingVisitor.java new file mode 100644 index 000000000..0c81601f6 --- /dev/null +++ b/com.ibm.wala.cast.java.polyglot/source/com/ibm/wala/cast/java/translator/polyglot/TranslatingVisitor.java @@ -0,0 +1,136 @@ +/****************************************************************************** + * 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 Sep 1, 2005 + */ +package com.ibm.wala.cast.java.translator.polyglot; + +import polyglot.ast.ArrayAccess; +import polyglot.ast.ArrayAccessAssign; +import polyglot.ast.ArrayInit; +import polyglot.ast.ArrayTypeNode; +import polyglot.ast.Assert; +import polyglot.ast.Binary; +import polyglot.ast.Block; +import polyglot.ast.BooleanLit; +import polyglot.ast.Branch; +import polyglot.ast.Call; +import polyglot.ast.CanonicalTypeNode; +import polyglot.ast.Case; +import polyglot.ast.Cast; +import polyglot.ast.Catch; +import polyglot.ast.CharLit; +import polyglot.ast.ClassBody; +import polyglot.ast.ClassDecl; +import polyglot.ast.ClassLit; +import polyglot.ast.Conditional; +import polyglot.ast.ConstructorCall; +import polyglot.ast.ConstructorDecl; +import polyglot.ast.Do; +import polyglot.ast.Empty; +import polyglot.ast.Eval; +import polyglot.ast.Field; +import polyglot.ast.FieldAssign; +import polyglot.ast.FieldDecl; +import polyglot.ast.FloatLit; +import polyglot.ast.For; +import polyglot.ast.Formal; +import polyglot.ast.If; +import polyglot.ast.Import; +import polyglot.ast.Initializer; +import polyglot.ast.Instanceof; +import polyglot.ast.IntLit; +import polyglot.ast.Labeled; +import polyglot.ast.Local; +import polyglot.ast.LocalAssign; +import polyglot.ast.LocalClassDecl; +import polyglot.ast.LocalDecl; +import polyglot.ast.MethodDecl; +import polyglot.ast.New; +import polyglot.ast.NewArray; +import polyglot.ast.NullLit; +import polyglot.ast.PackageNode; +import polyglot.ast.Return; +import polyglot.ast.Special; +import polyglot.ast.StringLit; +import polyglot.ast.Switch; +import polyglot.ast.SwitchBlock; +import polyglot.ast.Synchronized; +import polyglot.ast.Throw; +import polyglot.ast.Try; +import polyglot.ast.Unary; +import polyglot.ast.While; + +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.MethodContext; +import com.ibm.wala.cast.java.translator.polyglot.PolyglotJava2CAstTranslator.WalkContext; +import com.ibm.wala.cast.tree.CAstNode; + +/** + * An alternative visitor API for Polyglot, whose API is somewhat brain-damaged... + * @author rfuhrer + */ +public interface TranslatingVisitor { + CAstNode visit(MethodDecl m, MethodContext context); + CAstNode visit(ConstructorDecl cd, MethodContext cc); + CAstNode visit(FieldDecl f, MethodContext mc); // yes, a MethodContext; we process FieldDecl's only to add their initializers to each constructor + CAstNode visit(Import i, WalkContext wc); + CAstNode visit(PackageNode p, WalkContext wc); + CAstNode visit(CanonicalTypeNode ctn, WalkContext wc); + CAstNode visit(ArrayTypeNode ctn, WalkContext wc); + CAstNode visit(ArrayInit ai, WalkContext wc); + CAstNode visit(ArrayAccessAssign aaa, WalkContext wc); + CAstNode visit(FieldAssign fa, WalkContext wc); + CAstNode visit(LocalAssign la, WalkContext wc); + CAstNode visit(Binary b, WalkContext wc); + CAstNode visit(Call c, WalkContext wc); + CAstNode visit(ConstructorCall cc, WalkContext wc); + CAstNode visit(Cast c, WalkContext wc); + CAstNode visit(Conditional c, WalkContext wc); + CAstNode visit(Instanceof io, WalkContext wc); + CAstNode visit(BooleanLit bl, WalkContext wc); + CAstNode visit(ClassLit cl, WalkContext wc); + CAstNode visit(FloatLit fl, WalkContext wc); + CAstNode visit(NullLit nl, WalkContext wc); + CAstNode visit(CharLit cl, WalkContext wc); + CAstNode visit(IntLit il, WalkContext wc); + CAstNode visit(StringLit sl, WalkContext wc); + CAstNode visit(New n, WalkContext wc); + CAstNode visit(NewArray na, WalkContext wc); + CAstNode visit(Special s, WalkContext wc); + CAstNode visit(Unary u, WalkContext wc); + CAstNode visit(ArrayAccess aa, WalkContext wc); + CAstNode visit(Field f, WalkContext wc); + CAstNode visit(Local l, WalkContext wc); + CAstNode visit(ClassBody cb, WalkContext wc); // should never see this when producing CAstNodes + CAstNode visit(ClassDecl cd, WalkContext wc); // should never see this when producing CAstNodes + CAstNode visit(Initializer i, WalkContext wc); // should never see this when producing CAstNodes + CAstNode visit(Assert a, WalkContext wc); + CAstNode visit(Branch b, WalkContext wc); + CAstNode visit(Block b, WalkContext wc); + CAstNode visit(SwitchBlock sb, WalkContext wc); + CAstNode visit(Catch c, WalkContext wc); + CAstNode visit(If i, WalkContext wc); + CAstNode visit(Labeled l, WalkContext wc); + CAstNode visit(LocalClassDecl lcd, WalkContext wc); + CAstNode visit(Do d, WalkContext wc); + CAstNode visit(For f, WalkContext wc); + CAstNode visit(While w, WalkContext wc); + CAstNode visit(Switch s, WalkContext wc); + CAstNode visit(Synchronized s, WalkContext wc); + CAstNode visit(Try t, WalkContext wc); + CAstNode visit(Empty e, WalkContext wc); + CAstNode visit(Eval e, WalkContext wc); + CAstNode visit(LocalDecl ld, WalkContext wc); + CAstNode visit(Return r, WalkContext wc); + CAstNode visit(Case c, WalkContext wc); + CAstNode visit(Throw t, WalkContext wc); + CAstNode visit(Formal f, WalkContext wc); // may not see these (might be handled by parent) +}