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)
+}