refactoring of CAst front end machinery to allow more reuse
This commit is contained in:
parent
8796653292
commit
cd944a8f12
|
@ -11,3 +11,4 @@ javacProjectSettings = true
|
||||||
bin.excludes = dat/core-modules/.eslintrc,\
|
bin.excludes = dat/core-modules/.eslintrc,\
|
||||||
dat/core-modules/.gitignore,\
|
dat/core-modules/.gitignore,\
|
||||||
dat/core-modules/.gitkeep
|
dat/core-modules/.gitkeep
|
||||||
|
javacDefaultEncoding.. = UTF-8
|
||||||
|
|
|
@ -38,15 +38,15 @@ public class FieldBasedCGGamesTest extends AbstractFieldBasedTest {
|
||||||
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/solitaire1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC);
|
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/solitaire1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CancelException.class)
|
@Test // (expected = CancelException.class)
|
||||||
public void testWorldOfSolitaire() throws IOException, WalaException, Error, CancelException {
|
public void testWorldOfSolitaire() throws IOException, WalaException, Error, CancelException {
|
||||||
runTestExceptOnTravis(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC);
|
runTestExceptOnTravis(new URL("http://worldofsolitaire.com/"), new Object[][]{}, BuilderType.OPTIMISTIC);
|
||||||
if (System.getenv("TRAVIS") != null) {
|
if (System.getenv("TRAVIS") != null) {
|
||||||
// fake it
|
// fake it
|
||||||
throw new CancelException(null);
|
// throw new CancelException(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMinesweeper() throws IOException, WalaException, Error, CancelException {
|
public void testMinesweeper() throws IOException, WalaException, Error, CancelException {
|
||||||
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
|
runTestExceptOnTravis(new URL("http://www.inmensia.com/files/minesweeper1.0.html"), new Object[][]{}, BuilderType.OPTIMISTIC_WORKLIST);
|
||||||
|
|
|
@ -15,8 +15,8 @@ compilers.p.discouraged-class=0
|
||||||
compilers.p.internal=0
|
compilers.p.internal=0
|
||||||
compilers.p.missing-packages=0
|
compilers.p.missing-packages=0
|
||||||
compilers.p.missing-version-export-package=2
|
compilers.p.missing-version-export-package=2
|
||||||
compilers.p.missing-version-import-package=0
|
compilers.p.missing-version-import-package=2
|
||||||
compilers.p.missing-version-require-bundle=0
|
compilers.p.missing-version-require-bundle=2
|
||||||
compilers.p.no-required-att=0
|
compilers.p.no-required-att=0
|
||||||
compilers.p.not-externalized-att=0
|
compilers.p.not-externalized-att=0
|
||||||
compilers.p.unknown-attribute=0
|
compilers.p.unknown-attribute=0
|
||||||
|
|
|
@ -4,9 +4,10 @@ Bundle-Name: %Bundle-Name
|
||||||
Bundle-SymbolicName: com.ibm.wala.cast.js.rhino
|
Bundle-SymbolicName: com.ibm.wala.cast.js.rhino
|
||||||
Bundle-Version: 1.4.4.qualifier
|
Bundle-Version: 1.4.4.qualifier
|
||||||
Bundle-Vendor: %Bundle-Vendor
|
Bundle-Vendor: %Bundle-Vendor
|
||||||
Require-Bundle: com.ibm.wala.cast;bundle-version="1.0.0",
|
Require-Bundle: com.ibm.wala.cast;bundle-version="1.4.4",
|
||||||
com.ibm.wala.cast.js;bundle-version="1.0.0",
|
com.ibm.wala.cast.js;bundle-version="1.4.4",
|
||||||
com.ibm.wala.core;bundle-version="1.1.3"
|
com.ibm.wala.core;bundle-version="1.4.4",
|
||||||
|
com.ibm.wala.util;bundle-version="1.4.4"
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Export-Package: com.ibm.wala.cast.js.translator,
|
Export-Package: com.ibm.wala.cast.js.translator,
|
||||||
|
|
|
@ -159,10 +159,9 @@ public class RhinoToAstTranslator implements TranslatorToCAst {
|
||||||
*/
|
*/
|
||||||
private static class FunctionContext extends JavaScriptTranslatorToCAst.FunctionContext<WalkContext,Node> implements WalkContext {
|
private static class FunctionContext extends JavaScriptTranslatorToCAst.FunctionContext<WalkContext,Node> implements WalkContext {
|
||||||
FunctionContext(WalkContext parent, Node s) {
|
FunctionContext(WalkContext parent, Node s) {
|
||||||
super(parent, s);
|
super(parent, s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* context used for top-level script declarations
|
* context used for top-level script declarations
|
||||||
|
@ -191,26 +190,41 @@ public class RhinoToAstTranslator implements TranslatorToCAst {
|
||||||
|
|
||||||
private static class BreakContext extends JavaScriptTranslatorToCAst.BreakContext<WalkContext, Node> implements WalkContext {
|
private static class BreakContext extends JavaScriptTranslatorToCAst.BreakContext<WalkContext, Node> implements WalkContext {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext getParent() {
|
||||||
|
return (WalkContext) super.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
BreakContext(WalkContext parent, Node breakTo, String label) {
|
BreakContext(WalkContext parent, Node breakTo, String label) {
|
||||||
super(parent, breakTo, label);
|
super(parent, breakTo, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LoopContext extends JavaScriptTranslatorToCAst.LoopContext<WalkContext, Node> implements WalkContext {
|
private static class LoopContext extends TranslatorToCAst.LoopContext<WalkContext, Node> implements WalkContext {
|
||||||
|
|
||||||
LoopContext(WalkContext parent, Node breakTo, Node continueTo, String label) {
|
LoopContext(WalkContext parent, Node breakTo, Node continueTo, String label) {
|
||||||
super(parent, breakTo, continueTo, label);
|
super(parent, breakTo, continueTo, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext getParent() {
|
||||||
|
return (WalkContext) super.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TryCatchContext extends JavaScriptTranslatorToCAst.TryCatchContext<WalkContext, Node> implements WalkContext {
|
}
|
||||||
|
|
||||||
|
private static class TryCatchContext extends TranslatorToCAst.TryCatchContext<WalkContext, Node> implements WalkContext {
|
||||||
|
|
||||||
TryCatchContext(WalkContext parent, CAstNode catchNode) {
|
TryCatchContext(WalkContext parent, CAstNode catchNode) {
|
||||||
super(parent, catchNode);
|
super(parent, catchNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext getParent() {
|
||||||
|
return (WalkContext) super.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String operationReceiverName(int operationIndex) {
|
private static String operationReceiverName(int operationIndex) {
|
||||||
|
|
|
@ -12,26 +12,24 @@ package com.ibm.wala.cast.js.translator;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
|
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
|
||||||
import com.ibm.wala.cast.tree.CAstControlFlowMap;
|
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.CAstNode;
|
||||||
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
|
|
||||||
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
|
|
||||||
import com.ibm.wala.util.collections.HashMapFactory;
|
|
||||||
import com.ibm.wala.util.debug.Assertions;
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
|
|
||||||
interface WalkContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.WalkContext<C, T> {
|
interface WalkContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.WalkContext<C, T> {
|
||||||
|
|
||||||
String script();
|
@Override
|
||||||
|
WalkContext<C, T> getParent();
|
||||||
|
|
||||||
T top();
|
default String script() {
|
||||||
|
return getParent().script();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a name declaration to this context. For variables or constants, n
|
* Add a name declaration to this context. For variables or constants, n
|
||||||
|
@ -39,22 +37,35 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
* variable (if any) may occur in a separate assignment. For functions, n
|
* variable (if any) may occur in a separate assignment. For functions, n
|
||||||
* should be a {@link CAstNode#FUNCTION_STMT}, including the function body.
|
* should be a {@link CAstNode#FUNCTION_STMT}, including the function body.
|
||||||
*/
|
*/
|
||||||
void addNameDecl(CAstNode n);
|
default void addNameDecl(CAstNode n) {
|
||||||
|
getParent().addNameDecl(n);
|
||||||
|
}
|
||||||
|
|
||||||
Collection<CAstNode> getNameDecls();
|
default Collection<CAstNode> getNameDecls() {
|
||||||
|
return getParent().getNameDecls();
|
||||||
|
}
|
||||||
|
|
||||||
CAstNode getCatchTarget();
|
default int setOperation(T node) {
|
||||||
|
return getParent().setOperation(node);
|
||||||
|
}
|
||||||
|
|
||||||
int setOperation(T node);
|
default boolean foundMemberOperation(T node) {
|
||||||
|
return getParent().foundMemberOperation(node);
|
||||||
boolean foundMemberOperation(T node);
|
}
|
||||||
|
|
||||||
void copyOperation(T from, T to);
|
|
||||||
|
|
||||||
|
default void copyOperation(T from, T to) {
|
||||||
|
getParent().copyOperation(from, to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RootContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.RootContext<C, T> implements WalkContext<C,T> {
|
public static class RootContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.RootContext<C, T> implements WalkContext<C,T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext<C, T> getParent() {
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String script() { return null; }
|
public String script() { return null; }
|
||||||
|
|
||||||
|
@ -98,35 +109,34 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DelegatingContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.DelegatingContext<C, T> implements WalkContext<C,T> {
|
public static class FunctionContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.FunctionContext<C, T> implements WalkContext<C,T> {
|
||||||
|
|
||||||
protected DelegatingContext(C parent) {
|
private final Vector<CAstNode> initializers = new Vector<>();
|
||||||
super(parent);
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext<C, T> getParent() {
|
||||||
|
return (WalkContext<C, T>) super.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FunctionContext(C parent, T s) {
|
||||||
|
super(parent, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNameDecl(CAstNode v) { initializers.add(v); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<CAstNode> getNameDecls() { return initializers; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String script() {
|
public String script() {
|
||||||
return parent.script();
|
return parent.script();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public T top() {
|
|
||||||
return parent.top();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addNameDecl(CAstNode n) {
|
|
||||||
parent.addNameDecl(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<CAstNode> getNameDecls() {
|
|
||||||
return parent.getNameDecls();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CAstNode getCatchTarget() {
|
public CAstNode getCatchTarget() {
|
||||||
return parent.getCatchTarget();
|
return CAstControlFlowMap.EXCEPTION_TO_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -143,51 +153,6 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
public void copyOperation(T from, T to) {
|
public void copyOperation(T from, T to) {
|
||||||
parent.copyOperation(from, to);
|
parent.copyOperation(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FunctionContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
|
||||||
private final T topNode;
|
|
||||||
private final CAstSourcePositionRecorder pos = new CAstSourcePositionRecorder();
|
|
||||||
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder(pos);
|
|
||||||
private final Map<CAstNode, Collection<CAstEntity>> scopedEntities = HashMapFactory.make();
|
|
||||||
private final Vector<CAstNode> initializers = new Vector<>();
|
|
||||||
|
|
||||||
protected FunctionContext(C parent, T s) {
|
|
||||||
super(parent);
|
|
||||||
this.topNode = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T top() { return topNode; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CAstNode getCatchTarget() { return CAstControlFlowMap.EXCEPTION_TO_EXIT; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addScopedEntity(CAstNode construct, CAstEntity e) {
|
|
||||||
if (! scopedEntities.containsKey(construct)) {
|
|
||||||
scopedEntities.put(construct, new HashSet<CAstEntity>(1));
|
|
||||||
}
|
|
||||||
scopedEntities.get(construct).add(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
|
|
||||||
return scopedEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addNameDecl(CAstNode v) { initializers.add(v); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<CAstNode> getNameDecls() { return initializers; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CAstControlFlowRecorder cfg() { return cfg; }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CAstSourcePositionRecorder pos() { return pos; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ScriptContext<C extends WalkContext<C, T>, T> extends FunctionContext<C,T> {
|
public static class ScriptContext<C extends WalkContext<C, T>, T> extends FunctionContext<C,T> {
|
||||||
|
@ -202,48 +167,6 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
public String script() { return script; }
|
public String script() { return script; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TryCatchContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
|
||||||
private final CAstNode catchNode;
|
|
||||||
|
|
||||||
protected TryCatchContext(C parent, CAstNode catchNode) {
|
|
||||||
super(parent);
|
|
||||||
this.catchNode = catchNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CAstNode getCatchTarget() { return catchNode; }
|
|
||||||
}
|
|
||||||
|
|
||||||
class BreakContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
|
||||||
private final T breakTarget;
|
|
||||||
protected final String label;
|
|
||||||
|
|
||||||
protected BreakContext(C parent, T breakTarget, String label) {
|
|
||||||
super(parent);
|
|
||||||
this.breakTarget = breakTarget;
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getBreakFor(String l) {
|
|
||||||
return (l == null || l.equals(label))? breakTarget: super.getBreakFor(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoopContext<C extends WalkContext<C, T>, T> extends BreakContext<C,T> {
|
|
||||||
private final T continueTo;
|
|
||||||
|
|
||||||
protected LoopContext(C parent, T breakTo, T continueTo, String label) {
|
|
||||||
super(parent, breakTo, label);
|
|
||||||
this.continueTo = continueTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getContinueFor(String l) {
|
|
||||||
return (l == null || l.equals(label))? continueTo: super.getContinueFor(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to determine the value to be passed as the 'this' argument for a
|
* Used to determine the value to be passed as the 'this' argument for a
|
||||||
* function call. This is needed since in JavaScript, you can write a call
|
* function call. This is needed since in JavaScript, you can write a call
|
||||||
|
@ -255,7 +178,8 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
* 'this' parameter in baseVar, and then to use baseVar as the actual argument
|
* 'this' parameter in baseVar, and then to use baseVar as the actual argument
|
||||||
* sub-node for the CAst call node
|
* sub-node for the CAst call node
|
||||||
*/
|
*/
|
||||||
public class MemberDestructuringContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
public class MemberDestructuringContext<C extends WalkContext<C, T>, T> implements WalkContext<C,T> {
|
||||||
|
private final WalkContext<C, T> parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* node for which we actually care about what the base pointer is. this
|
* node for which we actually care about what the base pointer is. this
|
||||||
|
@ -272,7 +196,7 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
private boolean foundBase = false;
|
private boolean foundBase = false;
|
||||||
|
|
||||||
protected MemberDestructuringContext(C parent, T initialBaseFor, int operationIndex) {
|
protected MemberDestructuringContext(C parent, T initialBaseFor, int operationIndex) {
|
||||||
super(parent);
|
this.parent = parent;
|
||||||
baseFor.add( initialBaseFor );
|
baseFor.add( initialBaseFor );
|
||||||
this.operationIndex = operationIndex;
|
this.operationIndex = operationIndex;
|
||||||
}
|
}
|
||||||
|
@ -296,6 +220,11 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
|
||||||
public void copyOperation(T from, T to) {
|
public void copyOperation(T from, T to) {
|
||||||
if (baseFor.contains(from)) baseFor.add(to);
|
if (baseFor.contains(from)) baseFor.add(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext<C, T> getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ package com.ibm.wala.cast.ir.translator;
|
||||||
|
|
||||||
import com.ibm.wala.cast.tree.CAstControlFlowMap;
|
import com.ibm.wala.cast.tree.CAstControlFlowMap;
|
||||||
import com.ibm.wala.cast.tree.CAstNode;
|
import com.ibm.wala.cast.tree.CAstNode;
|
||||||
import com.ibm.wala.cast.tree.CAstNodeTypeMap;
|
|
||||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
||||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
||||||
import com.ibm.wala.cast.tree.CAstType;
|
import com.ibm.wala.cast.tree.CAstType;
|
||||||
|
@ -60,7 +59,7 @@ public abstract class AbstractCodeEntity extends AbstractEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CAstNodeTypeMap getNodeTypeMap() {
|
public CAstNodeTypeMapRecorder getNodeTypeMap() {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import com.ibm.wala.cast.tree.CAstQualifier;
|
||||||
import com.ibm.wala.cast.tree.CAstType;
|
import com.ibm.wala.cast.tree.CAstType;
|
||||||
import com.ibm.wala.util.debug.Assertions;
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
class AbstractFieldEntity extends AbstractDataEntity {
|
public class AbstractFieldEntity extends AbstractDataEntity {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final Set<CAstQualifier> modifiers;
|
private final Set<CAstQualifier> modifiers;
|
||||||
|
|
|
@ -13,6 +13,7 @@ package com.ibm.wala.cast.ir.translator;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ import com.ibm.wala.cast.tree.rewrite.CAstRewriter.CopyKey;
|
||||||
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.RewriteContext;
|
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.RewriteContext;
|
||||||
import com.ibm.wala.cast.tree.rewrite.CAstRewriterFactory;
|
import com.ibm.wala.cast.tree.rewrite.CAstRewriterFactory;
|
||||||
import com.ibm.wala.util.WalaException;
|
import com.ibm.wala.util.WalaException;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
import com.ibm.wala.util.warnings.Warning;
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
|
||||||
public interface TranslatorToCAst {
|
public interface TranslatorToCAst {
|
||||||
|
@ -48,42 +50,70 @@ public interface TranslatorToCAst {
|
||||||
|
|
||||||
public interface WalkContext<C extends WalkContext<C, T>, T> {
|
public interface WalkContext<C extends WalkContext<C, T>, T> {
|
||||||
|
|
||||||
|
WalkContext<C, T> getParent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a mapping from CAstNodes to the scoped entities (e.g. functions or
|
* get a mapping from CAstNodes to the scoped entities (e.g. functions or
|
||||||
* local classes) introduced by those nodes. Also maps <code>null</code> to
|
* local classes) introduced by those nodes. Also maps <code>null</code> to
|
||||||
* those entities not corresponding to any node (e.g nested classes)
|
* those entities not corresponding to any node (e.g nested classes)
|
||||||
*/
|
*/
|
||||||
Map<CAstNode, Collection<CAstEntity>> getScopedEntities();
|
default Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
|
||||||
|
return getParent().getScopedEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
default CAstNode getCatchTarget() {
|
||||||
|
return getParent().getCatchTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
default CAstNode getCatchTarget(String s) {
|
||||||
|
return getParent().getCatchTarget(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
default T top() {
|
||||||
|
return getParent().top();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* associate a child entity with a given CAstNode, e.g. for a function declaration
|
* associate a child entity with a given CAstNode, e.g. for a function declaration
|
||||||
*/
|
*/
|
||||||
void addScopedEntity(CAstNode newNode, CAstEntity visit);
|
default void addScopedEntity(CAstNode newNode, CAstEntity visit) {
|
||||||
|
getParent().addScopedEntity(newNode, visit);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for recording control-flow relationships among the CAst nodes
|
* for recording control-flow relationships among the CAst nodes
|
||||||
*/
|
*/
|
||||||
CAstControlFlowRecorder cfg();
|
default CAstControlFlowRecorder cfg() {
|
||||||
|
return getParent().cfg();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for recording source positions
|
* for recording source positions
|
||||||
*/
|
*/
|
||||||
CAstSourcePositionRecorder pos();
|
default CAstSourcePositionRecorder pos() {
|
||||||
|
return getParent().pos();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for recording types of nodes
|
* for recording types of nodes
|
||||||
*/
|
*/
|
||||||
CAstNodeTypeMapRecorder getNodeTypeMap();
|
default CAstNodeTypeMapRecorder getNodeTypeMap() {
|
||||||
|
return getParent().getNodeTypeMap();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for a 'continue' style goto, return the control flow target
|
* for a 'continue' style goto, return the control flow target
|
||||||
*/
|
*/
|
||||||
T getContinueFor(String label);
|
default T getContinueFor(String label) {
|
||||||
|
return getParent().getContinueFor(label);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for a 'break' style goto, return the control flow target
|
* for a 'break' style goto, return the control flow target
|
||||||
*/
|
*/
|
||||||
T getBreakFor(String label);
|
default T getBreakFor(String label) {
|
||||||
|
return getParent().getBreakFor(label);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +158,18 @@ public interface TranslatorToCAst {
|
||||||
assert false;
|
assert false;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T top() {
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext<C, T> getParent() {
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,42 +181,106 @@ public interface TranslatorToCAst {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CAstControlFlowRecorder cfg() {
|
public T top() {
|
||||||
return parent.cfg();
|
return parent.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CAstSourcePositionRecorder pos() {
|
public WalkContext<C, T> getParent() {
|
||||||
return parent.pos();
|
return parent;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CAstNodeTypeMapRecorder getNodeTypeMap() {
|
|
||||||
return parent.getNodeTypeMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getContinueFor(String label) {
|
|
||||||
return parent.getContinueFor(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T getBreakFor(String label) {
|
|
||||||
return parent.getBreakFor(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
|
|
||||||
parent.addScopedEntity(newNode, visit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
|
|
||||||
return parent.getScopedEntities();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BreakContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
||||||
|
private final T breakTarget;
|
||||||
|
protected final String label;
|
||||||
|
|
||||||
|
protected BreakContext(C parent, T breakTarget, String label) {
|
||||||
|
super(parent);
|
||||||
|
this.breakTarget = breakTarget;
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getBreakFor(String l) {
|
||||||
|
return (l == null || l.equals(label))? breakTarget: super.getBreakFor(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LoopContext<C extends WalkContext<C, T>, T> extends BreakContext<C,T> {
|
||||||
|
private final T continueTo;
|
||||||
|
|
||||||
|
protected LoopContext(C parent, T breakTo, T continueTo, String label) {
|
||||||
|
super(parent, breakTo, label);
|
||||||
|
this.continueTo = continueTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getContinueFor(String l) {
|
||||||
|
return (l == null || l.equals(label))? continueTo: super.getContinueFor(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TryCatchContext<C extends WalkContext<C, T>, T> implements WalkContext<C,T> {
|
||||||
|
private final Map<String,CAstNode> catchNode;
|
||||||
|
private final WalkContext<C,T> parent;
|
||||||
|
|
||||||
|
protected TryCatchContext(C parent, CAstNode catchNode) {
|
||||||
|
this(parent, Collections.singletonMap(null, catchNode));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TryCatchContext(C parent, Map<String,CAstNode> catchNode) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.catchNode = catchNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CAstNode getCatchTarget() { return getCatchTarget(null); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CAstNode getCatchTarget(String s) { return catchNode.get(s); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalkContext<C, T> getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FunctionContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
|
||||||
|
private final T topNode;
|
||||||
|
private final CAstSourcePositionRecorder pos = new CAstSourcePositionRecorder();
|
||||||
|
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder(pos);
|
||||||
|
private final Map<CAstNode, Collection<CAstEntity>> scopedEntities = HashMapFactory.make();
|
||||||
|
|
||||||
|
protected FunctionContext(C parent, T s) {
|
||||||
|
super(parent);
|
||||||
|
this.topNode = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T top() { return topNode; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addScopedEntity(CAstNode construct, CAstEntity e) {
|
||||||
|
if (! scopedEntities.containsKey(construct)) {
|
||||||
|
scopedEntities.put(construct, new HashSet<CAstEntity>(1));
|
||||||
|
}
|
||||||
|
scopedEntities.get(construct).add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
|
||||||
|
return scopedEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CAstControlFlowRecorder cfg() { return cfg; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CAstSourcePositionRecorder pos() { return pos; }
|
||||||
|
}
|
||||||
|
|
||||||
public static class DoLoopTranslator {
|
public static class DoLoopTranslator {
|
||||||
private final boolean replicateForDoLoops;
|
private final boolean replicateForDoLoops;
|
||||||
|
|
||||||
|
|
|
@ -158,9 +158,9 @@ public interface CAstNode {
|
||||||
public static final int IS_DEFINED_EXPR = 128;
|
public static final int IS_DEFINED_EXPR = 128;
|
||||||
public static final int MACRO_VAR = 129;
|
public static final int MACRO_VAR = 129;
|
||||||
public static final int NARY_EXPR = 130;
|
public static final int NARY_EXPR = 130;
|
||||||
|
|
||||||
// new nodes with an explicit enclosing argument, e.g. "outer.new Inner()". They are mostly treated the same, except in JavaCAst2IRTranslator.doNewObject
|
// new nodes with an explicit enclosing argument, e.g. "outer.new Inner()". They are mostly treated the same, except in JavaCAst2IRTranslator.doNewObject
|
||||||
public static final int NEW_ENCLOSING = 131;
|
public static final int NEW_ENCLOSING = 131;
|
||||||
|
public static final int COMPREHENSION_EXPR = 132;
|
||||||
|
|
||||||
// explicit lexical scopes
|
// explicit lexical scopes
|
||||||
public static final int LOCAL_SCOPE = 200;
|
public static final int LOCAL_SCOPE = 200;
|
||||||
|
|
|
@ -79,7 +79,9 @@ public class CAstImpl implements CAst {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int code = getKind() * (getChildCount() + 13);
|
int code = getKind() * (getChildCount() + 13);
|
||||||
for (int i = 0; i < getChildCount() && i < 15; i++) {
|
for (int i = 0; i < getChildCount() && i < 15; i++) {
|
||||||
code *= getChild(i).getKind();
|
if (getChild(i) != null) {
|
||||||
|
code *= getChild(i).getKind();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
|
|
|
@ -87,5 +87,7 @@ public class CAstOperator implements CAstNode {
|
||||||
public final static CAstOperator OP_REL_OR = new CAstOperator("||");
|
public final static CAstOperator OP_REL_OR = new CAstOperator("||");
|
||||||
public final static CAstOperator OP_BIT_XOR = new CAstOperator("^");
|
public final static CAstOperator OP_BIT_XOR = new CAstOperator("^");
|
||||||
public final static CAstOperator OP_REL_XOR = new CAstOperator("^^");
|
public final static CAstOperator OP_REL_XOR = new CAstOperator("^^");
|
||||||
|
public final static CAstOperator OP_IN = new CAstOperator("in");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,13 +330,19 @@ public class ShrikeCFG extends AbstractCFG<IInstruction, ShrikeCFG.BasicBlock> i
|
||||||
} else {
|
} else {
|
||||||
TypeReference caughtException = null;
|
TypeReference caughtException = null;
|
||||||
if (element.getCatchClass() != null) {
|
if (element.getCatchClass() != null) {
|
||||||
ClassLoaderReference loader = ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader();
|
ClassLoaderReference loader =
|
||||||
|
element.getCatchClassLoader() == null?
|
||||||
|
ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader():
|
||||||
|
(ClassLoaderReference)element.getCatchClassLoader();
|
||||||
caughtException = ShrikeUtil.makeTypeReference(loader, element.getCatchClass());
|
caughtException = ShrikeUtil.makeTypeReference(loader, element.getCatchClass());
|
||||||
if (DEBUG) {
|
//if (DEBUG) {
|
||||||
System.err.println(" caughtException " + caughtException);
|
System.err.println(" caughtException " + caughtException);
|
||||||
}
|
//}
|
||||||
IClass caughtClass = cha.lookupClass(caughtException);
|
IClass caughtClass = cha.lookupClass(caughtException);
|
||||||
if (caughtClass == null) {
|
//if (DEBUG) {
|
||||||
|
System.err.println(" caughtException class " + caughtClass);
|
||||||
|
//}
|
||||||
|
if (caughtClass == null) {
|
||||||
// conservatively add the edge, and raise a warning
|
// conservatively add the edge, and raise a warning
|
||||||
addExceptionalEdgeTo(b);
|
addExceptionalEdgeTo(b);
|
||||||
Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
|
Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
|
||||||
|
|
|
@ -147,7 +147,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
|
|
||||||
klass = klass.getSuperclass();
|
klass = klass.getSuperclass();
|
||||||
|
|
||||||
while (klass != null) {
|
while (klass != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.err.println("got superclass " + klass);
|
System.err.println("got superclass " + klass);
|
||||||
}
|
}
|
||||||
|
@ -295,6 +295,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean addClass(IClass klass) {
|
public boolean addClass(IClass klass) {
|
||||||
|
|
||||||
if (klass == null) {
|
if (klass == null) {
|
||||||
throw new IllegalArgumentException("klass is null");
|
throw new IllegalArgumentException("klass is null");
|
||||||
}
|
}
|
||||||
|
@ -325,7 +326,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
|
|
||||||
if (klass.getReference().equals(this.rootTypeRef)) {
|
if (klass.getReference().equals(this.rootTypeRef)) {
|
||||||
// there is only one root
|
// there is only one root
|
||||||
assert root == null;
|
assert root == null || root == node;
|
||||||
root = node;
|
root = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +343,10 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
}
|
}
|
||||||
supernode.addChild(node);
|
supernode.addChild(node);
|
||||||
if (supernode.getJavaClass().getReference().equals(rootTypeRef)) {
|
if (supernode.getJavaClass().getReference().equals(rootTypeRef)) {
|
||||||
|
|
||||||
|
assert root == null || root == supernode;
|
||||||
|
root = supernode;
|
||||||
|
|
||||||
node = null;
|
node = null;
|
||||||
} else {
|
} else {
|
||||||
node = supernode;
|
node = supernode;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.ibm.wala.classLoader.IClassLoader;
|
||||||
import com.ibm.wala.classLoader.IMethod;
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
import com.ibm.wala.shrikeBT.ExceptionHandler;
|
import com.ibm.wala.shrikeBT.ExceptionHandler;
|
||||||
import com.ibm.wala.shrikeBT.IInstruction;
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
import com.ibm.wala.types.TypeReference;
|
import com.ibm.wala.types.TypeReference;
|
||||||
import com.ibm.wala.util.collections.EmptyIterator;
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
import com.ibm.wala.util.collections.HashMapFactory;
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
@ -168,6 +169,8 @@ public class SSACFG implements ControlFlowGraph<SSAInstruction, ISSABasicBlock>,
|
||||||
if (handler.getCatchClass() == null) {
|
if (handler.getCatchClass() == null) {
|
||||||
// by convention, in ShrikeCT this means catch everything
|
// by convention, in ShrikeCT this means catch everything
|
||||||
t = TypeReference.JavaLangThrowable;
|
t = TypeReference.JavaLangThrowable;
|
||||||
|
} else if (handler.getCatchClassLoader() instanceof ClassLoaderReference) {
|
||||||
|
t = ShrikeUtil.makeTypeReference((ClassLoaderReference)handler.getCatchClassLoader(), handler.getCatchClass());
|
||||||
} else {
|
} else {
|
||||||
TypeReference exceptionType = ShrikeUtil.makeTypeReference(loader.getReference(), handler.getCatchClass());
|
TypeReference exceptionType = ShrikeUtil.makeTypeReference(loader.getReference(), handler.getCatchClass());
|
||||||
IClass klass = null;
|
IClass klass = null;
|
||||||
|
|
|
@ -34,17 +34,24 @@ final public class ExceptionHandler {
|
||||||
int handler;
|
int handler;
|
||||||
|
|
||||||
final String catchClass;
|
final String catchClass;
|
||||||
|
|
||||||
|
final Object catchClassLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param handler the label for the handler code
|
* @param handler the label for the handler code
|
||||||
* @param catchClass the type of exception that should be caught (in JVM format), or null if all exceptions should be caught (as
|
* @param catchClass the type of exception that should be caught (in JVM format), or null if all exceptions should be caught (as
|
||||||
* with 'finally')
|
* with 'finally')
|
||||||
*/
|
*/
|
||||||
public ExceptionHandler(int handler, String catchClass) {
|
public ExceptionHandler(int handler, String catchClass, Object catchClassLoader) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.catchClass = catchClass;
|
this.catchClass = catchClass;
|
||||||
|
this.catchClassLoader = catchClassLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ExceptionHandler(int handler, String catchClass) {
|
||||||
|
this(handler, catchClass, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the label of the handler code
|
* @return the label of the handler code
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +59,10 @@ final public class ExceptionHandler {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getCatchClassLoader() {
|
||||||
|
return catchClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the type of exceptions to be caught, or null if all exceptions should be caught
|
* @return the type of exceptions to be caught, or null if all exceptions should be caught
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue