new special parent scope for cases where JavaScript redefines a variable using a reference to the existing definition

This commit is contained in:
Julian Dolby 2014-06-26 11:05:43 -04:00
parent 32f8672068
commit e58ec4dba8
5 changed files with 82 additions and 9 deletions

View File

@ -106,6 +106,9 @@ import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
import com.ibm.wala.cast.tree.visit.CAstVisitor;
import com.ibm.wala.cast.tree.visit.CAstVisitor.Context;
import com.ibm.wala.cast.util.CAstPattern;
import com.ibm.wala.classLoader.SourceModule;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
@ -511,8 +514,11 @@ public class RhinoToAstTranslator {
// new first statement will be a block declaring all names.
CAstNode[] newStmts = new CAstNode[stmts.length + 1];
newStmts[0] = Ast.makeNode(CAstNode.BLOCK_STMT, child.getNameDecls().toArray(new CAstNode[child.getNameDecls().size()]));
if (child.getNameDecls().size() == 1) {
newStmts[0] = child.getNameDecls().iterator().next();
} else {
newStmts[0] = Ast.makeNode(CAstNode.BLOCK_STMT, child.getNameDecls().toArray(new CAstNode[child.getNameDecls().size()]));
}
System.arraycopy(stmts, 0, newStmts, 1, stmts.length);
stmts = newStmts;
@ -1385,14 +1391,37 @@ public class RhinoToAstTranslator {
if (init.getInitializer() == null) {
children[i++] = Ast.makeNode(CAstNode.EMPTY);
} else {
CAstNode initCode = visit(init, arg);
CAstPattern nameVarPattern = CAstPattern.parse("VAR(\"" + init.getTarget().getString() + "\")");
if (! nameVarPattern.new Matcher() {
@Override
protected boolean enterEntity(CAstEntity n, Context context, CAstVisitor<Context> visitor) {
return true;
}
@Override
protected boolean doVisit(CAstNode n, Context context, CAstVisitor<Context> visitor) {
return true;
}
}.findAll(null, initCode).isEmpty()) {
initCode =
Ast.makeNode(CAstNode.SPECIAL_PARENT_SCOPE,
Ast.makeConstant(init.getTarget().getString()),
initCode);
}
children[i++] =
Ast.makeNode(CAstNode.ASSIGN,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(init.getTarget().getString())),
visit(init, arg));
Ast.makeNode(CAstNode.ASSIGN, readName(arg, null, init.getTarget().getString()),initCode);
}
}
return Ast.makeNode(CAstNode.BLOCK_STMT, children);
if (i == 1) {
return children[0];
} else {
return Ast.makeNode(CAstNode.BLOCK_STMT, children);
}
}
@Override

View File

@ -163,6 +163,7 @@ public interface CAstNode {
// explicit lexical scopes
public static final int LOCAL_SCOPE = 200;
public static final int SPECIAL_PARENT_SCOPE = 201;
// literal expression kinds
public static final int CONSTANT = 300;

View File

@ -416,7 +416,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
*/
public final void visit(final CAstNode n, C context, CAstVisitor<C> visitor) {
Position restore = currentPosition;
if (context.getSourceMap() != null) {
if (context != null && context.getSourceMap() != null) {
Position p = context.getSourceMap().getPosition(n);
if (p != null) {
currentPosition = p;
@ -451,6 +451,15 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
break;
}
case CAstNode.SPECIAL_PARENT_SCOPE: {
if (visitor.visitSpecialParentScope(n, context, visitor))
break;
C localContext = visitor.makeSpecialParentContext(context, n);
visitor.visit(n.getChild(1), localContext, visitor);
visitor.leaveSpecialParentScope(n, context, visitor);
break;
}
case CAstNode.BLOCK_EXPR: {
if (visitor.visitBlockExpr(n, context, visitor))
break;
@ -818,7 +827,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
visitor.leaveTypeLiteralExpr(n, context, visitor);
break;
}
case CAstNode.IS_DEFINED_EXPR: {
if (visitor.visitIsDefinedExpr(n, context, visitor)) {
break;
@ -875,6 +884,18 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
currentPosition = restore;
}
protected void leaveSpecialParentScope(CAstNode n, C context, CAstVisitor<C> visitor) {
visitor.leaveNode(n, context, visitor);
}
protected C makeSpecialParentContext(C context, CAstNode n) {
return context;
}
protected boolean visitSpecialParentScope(CAstNode n, C context, CAstVisitor<C> visitor) {
return visitor.visitNode(n, context, visitor);
}
/**
* Process the given array reference node. Factored out so that derived languages can reuse this
* code for specially-marked types of array references (as in X10, for which different instruction

View File

@ -1314,4 +1314,25 @@ public abstract class DelegatingCAstVisitor<C extends CAstVisitor.Context> exten
protected void leaveInstanceOf(CAstNode n, C c, CAstVisitor<C> visitor) {
delegate.leaveInstanceOf(n, c, visitor);
}
/**
* Visit a LocalScope node.
* @param n the node to process
* @param c a visitor-specific context
* @return true if no further processing is needed
*/
@Override
protected boolean visitSpecialParentScope(CAstNode n, C c, CAstVisitor<C> visitor) {
return delegate.visitSpecialParentScope(n, c, visitor);
}
/**
* Leave a LocalScope node.
* @param n the node to process
* @param c a visitor-specific context
*/
@Override
protected void leaveSpecialParentScope(CAstNode n, C c, CAstVisitor<C> visitor) {
delegate.leaveSpecialParentScope(n, c, visitor);
}
}

View File

@ -94,7 +94,8 @@ public class CAstPrinter {
// explicit lexical scopes
case CAstNode.LOCAL_SCOPE: return "SCOPE";
case CAstNode.SPECIAL_PARENT_SCOPE: return "SPECIAL PARENT SCOPE";
// literal expression kinds
case CAstNode.CONSTANT: return "CONSTANT";
case CAstNode.OPERATOR: return "OPERATOR";