0001: /*
0002: * Spoon - http://spoon.gforge.inria.fr/
0003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
0004: *
0005: * This software is governed by the CeCILL-C License under French law and
0006: * abiding by the rules of distribution of free software. You can use, modify
0007: * and/or redistribute the software under the terms of the CeCILL-C license as
0008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
0009: *
0010: * This program is distributed in the hope that it will be useful, but WITHOUT
0011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
0013: *
0014: * The fact that you are presently reading this means that you have had
0015: * knowledge of the CeCILL-C license and that you accept its terms.
0016: */
0017:
0018: package spoon.support.reflect.eval;
0019:
0020: import java.lang.annotation.Annotation;
0021: import java.util.ArrayList;
0022: import java.util.Arrays;
0023: import java.util.HashMap;
0024: import java.util.List;
0025: import java.util.Map;
0026: import java.util.Stack;
0027:
0028: import spoon.processing.Severity;
0029: import spoon.reflect.Factory;
0030: import spoon.reflect.code.CtAbstractInvocation;
0031: import spoon.reflect.code.CtArrayAccess;
0032: import spoon.reflect.code.CtAssert;
0033: import spoon.reflect.code.CtAssignment;
0034: import spoon.reflect.code.CtBinaryOperator;
0035: import spoon.reflect.code.CtBlock;
0036: import spoon.reflect.code.CtBreak;
0037: import spoon.reflect.code.CtCase;
0038: import spoon.reflect.code.CtCatch;
0039: import spoon.reflect.code.CtCodeSnippetExpression;
0040: import spoon.reflect.code.CtCodeSnippetStatement;
0041: import spoon.reflect.code.CtConditional;
0042: import spoon.reflect.code.CtContinue;
0043: import spoon.reflect.code.CtDo;
0044: import spoon.reflect.code.CtExpression;
0045: import spoon.reflect.code.CtFieldAccess;
0046: import spoon.reflect.code.CtFor;
0047: import spoon.reflect.code.CtForEach;
0048: import spoon.reflect.code.CtIf;
0049: import spoon.reflect.code.CtInvocation;
0050: import spoon.reflect.code.CtLiteral;
0051: import spoon.reflect.code.CtLocalVariable;
0052: import spoon.reflect.code.CtNewArray;
0053: import spoon.reflect.code.CtNewClass;
0054: import spoon.reflect.code.CtOperatorAssignment;
0055: import spoon.reflect.code.CtReturn;
0056: import spoon.reflect.code.CtStatement;
0057: import spoon.reflect.code.CtStatementList;
0058: import spoon.reflect.code.CtSwitch;
0059: import spoon.reflect.code.CtSynchronized;
0060: import spoon.reflect.code.CtThrow;
0061: import spoon.reflect.code.CtTry;
0062: import spoon.reflect.code.CtUnaryOperator;
0063: import spoon.reflect.code.CtVariableAccess;
0064: import spoon.reflect.code.CtWhile;
0065: import spoon.reflect.declaration.CtAnnotation;
0066: import spoon.reflect.declaration.CtAnnotationType;
0067: import spoon.reflect.declaration.CtAnonymousExecutable;
0068: import spoon.reflect.declaration.CtClass;
0069: import spoon.reflect.declaration.CtConstructor;
0070: import spoon.reflect.declaration.CtElement;
0071: import spoon.reflect.declaration.CtEnum;
0072: import spoon.reflect.declaration.CtExecutable;
0073: import spoon.reflect.declaration.CtField;
0074: import spoon.reflect.declaration.CtInterface;
0075: import spoon.reflect.declaration.CtMethod;
0076: import spoon.reflect.declaration.CtPackage;
0077: import spoon.reflect.declaration.CtParameter;
0078: import spoon.reflect.declaration.CtType;
0079: import spoon.reflect.declaration.CtTypeParameter;
0080: import spoon.reflect.declaration.CtVariable;
0081: import spoon.reflect.declaration.ModifierKind;
0082: import spoon.reflect.eval.StepKind;
0083: import spoon.reflect.eval.SymbolicEvaluationStack;
0084: import spoon.reflect.eval.SymbolicEvaluationStep;
0085: import spoon.reflect.eval.SymbolicEvaluator;
0086: import spoon.reflect.eval.SymbolicEvaluatorObserver;
0087: import spoon.reflect.eval.SymbolicHeap;
0088: import spoon.reflect.eval.SymbolicInstance;
0089: import spoon.reflect.eval.SymbolicStackFrame;
0090: import spoon.reflect.reference.CtArrayTypeReference;
0091: import spoon.reflect.reference.CtExecutableReference;
0092: import spoon.reflect.reference.CtFieldReference;
0093: import spoon.reflect.reference.CtLocalVariableReference;
0094: import spoon.reflect.reference.CtPackageReference;
0095: import spoon.reflect.reference.CtParameterReference;
0096: import spoon.reflect.reference.CtTypeParameterReference;
0097: import spoon.reflect.reference.CtTypeReference;
0098: import spoon.reflect.reference.CtVariableReference;
0099: import spoon.reflect.visitor.CtVisitor;
0100: import spoon.reflect.visitor.Query;
0101: import spoon.reflect.visitor.filter.TypeFilter;
0102:
0103: /**
0104: * This visitor implements an abstract evaluator for the program compile-time
0105: * metamodel.
0106: */
0107: public class VisitorSymbolicEvaluator implements CtVisitor,
0108: SymbolicEvaluator {
0109:
0110: List<CtTypeReference<?>> statefullExternals = new ArrayList<CtTypeReference<?>>();
0111:
0112: public List<CtTypeReference<?>> getStatefullExternals() {
0113: return statefullExternals;
0114: }
0115:
0116: /**
0117: * The default constructor.
0118: *
0119: * @param observers
0120: * observers to be notified of the progress of the evaluation
0121: */
0122: public VisitorSymbolicEvaluator(
0123: SymbolicEvaluatorObserver[] observers) {
0124: for (SymbolicEvaluatorObserver observer : observers) {
0125: addObserver(observer);
0126: }
0127: }
0128:
0129: // List<SymbolicEvaluationPath> paths = new
0130: // ArrayList<SymbolicEvaluationPath>();
0131:
0132: private void startPath() {
0133: // paths.add(new SymbolicEvaluationPath());
0134: notifyStartPath();
0135: }
0136:
0137: // public SymbolicEvaluationPath getCurrentPath() {
0138: // return paths.get(paths.size() - 1);
0139: // }
0140:
0141: // private void addToPath(AbstractStackFrame frame) {
0142: // paths.get(paths.size() - 1).add(frame);
0143: // }
0144:
0145: // public List<SymbolicEvaluationPath> getPaths() {
0146: // return paths;
0147: // }
0148: //
0149: // public void dumpPaths() {
0150: // int i = 1;
0151: // for (SymbolicEvaluationPath p : paths) {
0152: // System.out.println("-- path " + (i++));
0153: // p.dump();
0154: // }
0155: // }
0156:
0157: private void resetCurrentEvaluation() {
0158: stack = new SymbolicEvaluationStack();
0159: heap.clear();
0160: SymbolicInstance.resetIds();
0161: result = null;
0162: }
0163:
0164: public void reset() {
0165: resetCurrentEvaluation();
0166: branchingPoints.clear();
0167: // paths.clear();
0168: }
0169:
0170: private SymbolicInstance<?> result = null;
0171:
0172: void enterExecutable(CtAbstractInvocation<?> caller,
0173: CtExecutableReference<?> eref, SymbolicInstance<?> target,
0174: List<SymbolicInstance<?>> args) {
0175: Map<CtVariableReference<?>, SymbolicInstance<?>> variables = new HashMap<CtVariableReference<?>, SymbolicInstance<?>>();
0176: CtExecutable<?> e = eref.getDeclaration();
0177: if (e != null) {
0178: // initialize arguments
0179: int i = 0;
0180: for (CtVariable<?> v : e.getParameters()) {
0181: variables.put(v.getReference(), args.get(i++));
0182: }
0183: // initialize local variables
0184: for (CtVariable<?> v : Query.getElements(e.getBody(),
0185: new TypeFilter<CtVariable<?>>(CtVariable.class))) {
0186: variables.put(v.getReference(), null);
0187: }
0188: }
0189: stack.enterFrame(caller, target, eref, args, variables);
0190: notifyEnterStep(new SymbolicEvaluationStep(StepKind.ENTER,
0191: new SymbolicStackFrame(getStack().getFrameStack()
0192: .peek()), new SymbolicHeap(getHeap())));
0193: }
0194:
0195: void exitExecutable(CtExecutableReference<?> eref) {
0196: stack.setResult(result);
0197: notifyExitStep(new SymbolicEvaluationStep(StepKind.EXIT,
0198: new SymbolicStackFrame(getStack().getFrameStack()
0199: .peek()), new SymbolicHeap(getHeap())));
0200: stack.exitFrame();
0201: }
0202:
0203: protected Stack<BranchingPoint> branchingPoints = new Stack<BranchingPoint>();
0204:
0205: protected SymbolicEvaluationStack stack = new SymbolicEvaluationStack();
0206:
0207: protected SymbolicHeap heap = new SymbolicHeap();
0208:
0209: private List<SymbolicEvaluatorObserver> observers = new ArrayList<SymbolicEvaluatorObserver>();
0210:
0211: Number convert(CtTypeReference<?> type, Number n) {
0212: if ((type.getActualClass() == int.class)
0213: || (type.getActualClass() == Integer.class)) {
0214: return n.intValue();
0215: }
0216: if ((type.getActualClass() == byte.class)
0217: || (type.getActualClass() == Byte.class)) {
0218: return n.byteValue();
0219: }
0220: if ((type.getActualClass() == long.class)
0221: || (type.getActualClass() == Long.class)) {
0222: return n.longValue();
0223: }
0224: if ((type.getActualClass() == float.class)
0225: || (type.getActualClass() == Float.class)) {
0226: return n.floatValue();
0227: }
0228: if ((type.getActualClass() == short.class)
0229: || (type.getActualClass() == Short.class)) {
0230: return n.shortValue();
0231: }
0232: return n;
0233: }
0234:
0235: class BranchingPoint {
0236: public BranchingPoint(SymbolicEvaluationStack stack,
0237: CtElement... branches) {
0238: this .stack = new SymbolicEvaluationStack(stack);
0239: this .branches = Arrays.asList(branches);
0240: uncompletedBranches = new ArrayList<CtElement>(
0241: this .branches);
0242: }
0243:
0244: public List<CtElement> branches;
0245:
0246: public SymbolicEvaluationStack stack;
0247:
0248: public List<CtElement> uncompletedBranches;
0249:
0250: public List<CtElement> completedBranches = new ArrayList<CtElement>();
0251:
0252: public SymbolicInstance<?> evaluate(
0253: VisitorSymbolicEvaluator evaluator) {
0254: return evaluator.evaluate(uncompletedBranches.get(0));
0255: }
0256:
0257: public boolean nextBranch() {
0258: completedBranches.add(uncompletedBranches.get(0));
0259: uncompletedBranches.remove(0);
0260: if (uncompletedBranches.isEmpty()) {
0261: return false;
0262: }
0263: return true;
0264: }
0265:
0266: @Override
0267: public String toString() {
0268: return branches.toString();
0269: }
0270: }
0271:
0272: private BranchingPoint getBranchingPoint(CtElement... branches) {
0273: if (!branchingPoints.isEmpty()) {
0274: // look for the first uncompleted bp at the top of the stack
0275: boolean first = true;
0276: do {
0277: BranchingPoint bp = branchingPoints.peek();
0278: if (bp.stack.equals(stack)
0279: && bp.branches.equals(Arrays.asList(branches))) {
0280: bp.nextBranch();
0281: return bp;
0282: // if (!bp.nextBranch()) {
0283: // branchingPoints.pop();
0284: // } else {
0285: // return bp;
0286: // }
0287: }
0288: first = false;
0289: } while (!branchingPoints.isEmpty() && first);
0290: // look for any bp in the stack
0291: for (int i = branchingPoints.size() - 2; i >= 0; i--) {
0292: BranchingPoint bp = branchingPoints.get(i);
0293: if (bp.stack.equals(stack)
0294: && bp.branches.equals(Arrays.asList(branches))) {
0295: return bp;
0296: }
0297: }
0298: }
0299: // create a new branch
0300: BranchingPoint bp = new BranchingPoint(stack, branches);
0301: branchingPoints.push(bp);
0302: return bp;
0303: }
0304:
0305: @SuppressWarnings("unchecked")
0306: protected SymbolicInstance evaluateBranches(CtElement... branches) {
0307: // System.out.println("branches: "+Arrays.asList(branches));
0308: BranchingPoint bp = getBranchingPoint(branches);
0309: // System.out.println("bp: "+bp);
0310: result = bp.evaluate(this );
0311: // System.out.println("result: "+result);
0312: // remove completed bp
0313: if (branchingPoints.peek() == bp) {
0314: if (bp.uncompletedBranches.size() == 1) {
0315: branchingPoints.pop();
0316: }
0317: }
0318: return result;
0319: }
0320:
0321: public SymbolicInstance<?> evaluate(CtElement element) {
0322: if (element == null) {
0323: return null;
0324: }
0325: // System.out.println("[evaluating
0326: // "+element.getClass().getSimpleName()+"]");
0327: element.accept(this );
0328: if (result == null) {
0329: result = SymbolicInstance.NULL;
0330: }
0331: return result;
0332: }
0333:
0334: @SuppressWarnings("unchecked")
0335: public <T> SymbolicInstance<T> evaluate(CtExpression<T> expression) {
0336: if (expression == null) {
0337: return null;
0338: }
0339: // System.out.println("[evaluating
0340: // "+element.getClass().getSimpleName()+"]");
0341: expression.accept(this );
0342: if (result == null) {
0343: result = SymbolicInstance.NULL;
0344: }
0345: return (SymbolicInstance<T>) result;
0346: }
0347:
0348: // private boolean evaluationCompleted() {
0349: // return branchingPoints.size() == 1
0350: // && branchingPoints.peek().uncompletedBranches.size() == 1;
0351: // }
0352:
0353: public void invoke(CtExecutable<?> executable,
0354: SymbolicInstance<?>... args) {
0355: do {
0356: resetCurrentEvaluation();
0357: startPath();
0358: List<SymbolicInstance<?>> cargs = new ArrayList<SymbolicInstance<?>>();
0359: for (SymbolicInstance<?> i : args) {
0360: cargs.add(i == null ? null : i.getClone());
0361: }
0362: SymbolicInstance<?> target = heap.getType(this , executable
0363: .getDeclaringType().getReference());
0364: try {
0365: invoke(null, executable.getReference(), target, cargs);
0366: } catch (SymbolicWrappedException e) {
0367: // swallow it
0368: }
0369: notifyEndPath();
0370: } while (!branchingPoints.isEmpty());
0371: }
0372:
0373: public void invoke(SymbolicInstance<?> target,
0374: CtExecutable<?> executable, List<SymbolicInstance<?>> args) {
0375: do {
0376: resetCurrentEvaluation();
0377: // AbstractInstance.dumpHeap();
0378: startPath();
0379: List<SymbolicInstance<?>> cargs = null;
0380: if (args != null) {
0381: cargs = new ArrayList<SymbolicInstance<?>>();
0382: for (SymbolicInstance<?> i : args) {
0383: cargs.add(i == null ? null : i.getClone());
0384: }
0385: }
0386: try {
0387: invoke(null, executable.getReference(), target, cargs);
0388: } catch (SymbolicWrappedException e) {
0389: e.printStackTrace();
0390: // swallow it
0391: }
0392: notifyEndPath();
0393: // System.out.println("END");
0394: // dumpPaths();
0395: // heap.dump();
0396: } while (!branchingPoints.isEmpty());
0397: // dumpPaths();
0398:
0399: }
0400:
0401: /**
0402: * Tell if the given method follows the getter naming conventions.
0403: */
0404: boolean isGetter(CtExecutableReference<?> e) {
0405: return e.getSimpleName().startsWith("get")
0406: && (e.getParameterTypes().size() == 0);
0407: }
0408:
0409: /**
0410: * Tell if the given method follows the setter naming conventions.
0411: */
0412: boolean isSetter(CtExecutableReference<?> e) {
0413: return e.getSimpleName().startsWith("set")
0414: && (e.getParameterTypes().size() == 1);
0415: }
0416:
0417: boolean isStateFullExternal(CtTypeReference<?> type) {
0418: for (CtTypeReference<?> t : getStatefullExternals()) {
0419: if (t.isAssignableFrom(type)) {
0420: return true;
0421: }
0422: }
0423: return false;
0424: }
0425:
0426: @SuppressWarnings("unchecked")
0427: private <T> SymbolicInstance<T> invoke(
0428: CtAbstractInvocation<?> caller,
0429: CtExecutableReference<T> executable,
0430: SymbolicInstance<?> target, List<SymbolicInstance<?>> args) {
0431: enterExecutable(caller, executable, target, args);
0432: // System.out.println("[invoking " + caller + "]");
0433: // stack.dump();
0434: // heap.dump();
0435: try {
0436: CtExecutable<?> decl = executable.getDeclaration();
0437: if (decl != null) {
0438: if (decl.getBody() != null) {
0439: evaluate(decl.getBody());
0440: if (executable.isConstructor()) {
0441: result = target;
0442: } else {
0443: result = null;
0444: }
0445: } else {
0446: result = new SymbolicInstance(this , executable
0447: .getType(), false);
0448: }
0449: } else {
0450: // not accessible (set the result to the return type or to the
0451: // field value if a getter)
0452: CtFieldReference fref = null;
0453: if (isStateFullExternal(executable.getDeclaringType())) {
0454: if ((target != null) && isGetter(executable)) {
0455: // System.out.println(m);
0456: SymbolicInstance r = null;
0457: fref = executable.getFactory().Field()
0458: .createReference(
0459: target.getConcreteType(),
0460: executable.getType(),
0461: executable.getSimpleName()
0462: .substring(3));
0463: r = heap.get(target.getFieldValue(fref));
0464: if (r != null) {
0465: result = r;
0466: } else {
0467: result = new SymbolicInstance(this ,
0468: executable.getType(), false);
0469: }
0470: } else if ((target != null) && isSetter(executable)) {
0471: // System.out.println(m.toString()+"
0472: // "+caller.getPosition());
0473: fref = executable.getFactory().Field()
0474: .createReference(
0475: target.getConcreteType(),
0476: executable.getType(),
0477: executable.getSimpleName()
0478: .substring(3));
0479: target.setFieldValue(heap, fref, args.get(0));
0480: result = new SymbolicInstance(this , executable
0481: .getType(), false);
0482: // heap.dump();
0483: // stack.dump();
0484: } else {
0485: result = new SymbolicInstance(this , executable
0486: .getType(), false);
0487: }
0488: } else {
0489: if (!executable.isConstructor()) {
0490: result = new SymbolicInstance(this , executable
0491: .getType(), false);
0492: } else {
0493: // TODO: JJ - verify this
0494: result = target;
0495: }
0496: }
0497: }
0498: } catch (ReturnException e) {
0499: // normal return
0500: } finally {
0501: exitExecutable(executable);
0502: }
0503: return (SymbolicInstance<T>) result;
0504: }
0505:
0506: private void skip(CtElement e) {
0507: e.getFactory().getEnvironment().report(null, Severity.WARNING,
0508: e, "symbolic evaluator: ignoring unsupported element");
0509: }
0510:
0511: public <A extends Annotation> void visitCtAnnotation(
0512: CtAnnotation<A> annotation) {
0513: skip(annotation);
0514: }
0515:
0516: public <A extends Annotation> void visitCtAnnotationType(
0517: CtAnnotationType<A> annotationType) {
0518: throw new RuntimeException("Not evaluable");
0519: }
0520:
0521: public void visitCtAnonymousExecutable(CtAnonymousExecutable impl) {
0522: throw new RuntimeException("Not evaluable");
0523: }
0524:
0525: public <T, E extends CtExpression<?>> void visitCtArrayAccess(
0526: CtArrayAccess<T, E> arrayAccess) {
0527: skip(arrayAccess);
0528: }
0529:
0530: public <T> void visitCtArrayTypeReference(
0531: CtArrayTypeReference<T> reference) {
0532: throw new RuntimeException("Not evaluable");
0533: }
0534:
0535: public <T> void visitCtCodeSnippetExpression(
0536: CtCodeSnippetExpression<T> expression) {
0537: skip(expression);
0538: }
0539:
0540: public void visitCtCodeSnippetStatement(
0541: CtCodeSnippetStatement statement) {
0542: skip(statement);
0543: }
0544:
0545: public <T> void visitCtAssert(CtAssert<T> asserted) {
0546: skip(asserted);
0547: }
0548:
0549: public <T, A extends T> void visitCtAssignment(
0550: CtAssignment<T, A> assignment) {
0551:
0552: if (assignment.getAssigned() instanceof CtVariableAccess) {
0553: CtVariableReference<T> vref = ((CtVariableAccess<T>) assignment
0554: .getAssigned()).getVariable();
0555: SymbolicInstance<?> res = evaluate(assignment
0556: .getAssignment());
0557: if (vref instanceof CtFieldReference) {
0558: CtExpression<?> target = ((CtFieldAccess<?>) assignment
0559: .getAssigned()).getTarget();
0560: if (target == null) {
0561: stack.getThis().setFieldValue(heap, vref, res);
0562: } else {
0563: ((SymbolicInstance<?>) evaluate(target))
0564: .setFieldValue(heap, vref, res);
0565: }
0566: } else {
0567: stack.setVariableValue(vref, res);
0568: }
0569: result = res;
0570: }
0571: }
0572:
0573: @SuppressWarnings("unchecked")
0574: public <T> void visitCtBinaryOperator(CtBinaryOperator<T> operator) {
0575: SymbolicInstance left = evaluate(operator.getLeftHandOperand());
0576: SymbolicInstance right = evaluate(operator
0577: .getRightHandOperand());
0578: switch (operator.getKind()) {
0579: case AND:
0580: case OR:
0581: case EQ:
0582: if (left.equalsRef(right)) {
0583: result = SymbolicInstance.TRUE;
0584: } else {
0585: result = SymbolicInstance.FALSE;
0586: }
0587: return;
0588: case NE:
0589: if (!left.equalsRef(right)) {
0590: result = SymbolicInstance.TRUE;
0591: } else {
0592: result = SymbolicInstance.FALSE;
0593: }
0594: return;
0595: case GE:
0596: case LE:
0597: case GT:
0598: case LT:
0599: case INSTANCEOF:
0600: SymbolicInstance<Boolean> bool = new SymbolicInstance<Boolean>(
0601: this , operator.getFactory().Type().createReference(
0602: boolean.class), false);
0603: result = bool;
0604: return;
0605: case MINUS:
0606: case MUL:
0607: case DIV:
0608: SymbolicInstance<Number> number = new SymbolicInstance<Number>(
0609: this , operator.getFactory().Type().createReference(
0610: Number.class), false);
0611: result = number;
0612: return;
0613: case PLUS:
0614: if ((left.getConcreteType() != null)
0615: && ((left.getConcreteType().getActualClass() == String.class) || (right
0616: .getConcreteType().getActualClass() == String.class))) {
0617: SymbolicInstance<String> string = new SymbolicInstance<String>(
0618: this , operator.getFactory().Type()
0619: .createReference(String.class), false);
0620: result = string;
0621: return;
0622: }
0623: bool = new SymbolicInstance<Boolean>(this ,
0624: operator.getFactory().Type().createReference(
0625: boolean.class), false);
0626: result = bool;
0627: return;
0628: default:
0629: throw new RuntimeException("unsupported operator");
0630: }
0631: }
0632:
0633: public <R> void visitCtBlock(CtBlock<R> block) {
0634: for (CtStatement s : block.getStatements()) {
0635: evaluate(s);
0636: }
0637: }
0638:
0639: public void visitCtBreak(CtBreak breakStatement) {
0640: skip(breakStatement);
0641: }
0642:
0643: public <E> void visitCtCase(CtCase<E> caseStatement) {
0644: skip(caseStatement);
0645: }
0646:
0647: public void visitCtCatch(CtCatch catchBlock) {
0648: skip(catchBlock);
0649: }
0650:
0651: public <T> void visitCtClass(CtClass<T> ctClass) {
0652: throw new RuntimeException("Not evaluable");
0653: }
0654:
0655: public <T> void visitCtConstructor(CtConstructor<T> c) {
0656: throw new RuntimeException("Not evaluable");
0657: }
0658:
0659: public void visitCtContinue(CtContinue continueStatement) {
0660: skip(continueStatement);
0661: }
0662:
0663: public void visitCtDo(CtDo doLoop) {
0664: evaluate(doLoop.getBody());
0665: evaluate(doLoop.getLoopingExpression());
0666: }
0667:
0668: public <T extends Enum<?>> void visitCtEnum(CtEnum<T> ctEnum) {
0669: throw new RuntimeException("Not evaluable");
0670: }
0671:
0672: public <T> void visitCtExecutableReference(
0673: CtExecutableReference<T> reference) {
0674: throw new RuntimeException("Not evaluable");
0675: }
0676:
0677: public <T> void visitCtField(CtField<T> f) {
0678: skip(f);
0679: }
0680:
0681: boolean isAccessible(CtFieldReference<?> field) {
0682: return field.getDeclaringType().isAssignableFrom(
0683: stack.getThis().getConcreteType());
0684: }
0685:
0686: public <T> void visitCtFieldAccess(CtFieldAccess<T> fieldAccess) {
0687: if (fieldAccess.getVariable().getSimpleName().equals("this")) {
0688: result = stack.getThis();
0689: return;
0690: }
0691: if (fieldAccess.getVariable().getSimpleName().equals("class")) {
0692: SymbolicInstance<?> type = heap.getType(this , fieldAccess
0693: .getType());
0694: result = type;
0695: return;
0696: }
0697: SymbolicInstance<?> target = evaluate(fieldAccess.getTarget());
0698: if (target == null) {
0699: if (isAccessible(fieldAccess.getVariable())) {
0700: target = stack.getThis();
0701: }
0702: }
0703: if ((target != null) && !target.isExternal()) {
0704: result = heap.get(target.getFieldValue(fieldAccess
0705: .getVariable()));
0706: } else {
0707: // set the type to the declared one
0708: SymbolicInstance<T> i = new SymbolicInstance<T>(this ,
0709: fieldAccess.getType(), false);
0710: // this instance is not put on the heap because it will be put if
0711: // assigned to an object's field
0712: result = i;
0713: }
0714: }
0715:
0716: public <T> void visitCtFieldReference(CtFieldReference<T> reference) {
0717: throw new RuntimeException("Not evaluable");
0718: }
0719:
0720: public void visitCtFor(CtFor forLoop) {
0721: for (CtStatement s : forLoop.getForInit()) {
0722: evaluate(s);
0723: }
0724: evaluate(forLoop.getExpression());
0725: evaluate(forLoop.getBody());
0726: for (CtStatement s : forLoop.getForUpdate()) {
0727: evaluate(s);
0728: }
0729: }
0730:
0731: public void visitCtForEach(CtForEach foreach) {
0732: evaluate(foreach.getBody());
0733: }
0734:
0735: public void visitCtIf(CtIf ifElement) {
0736: SymbolicInstance<?> result = evaluate(ifElement.getCondition());
0737: if (result == SymbolicInstance.TRUE) {
0738: evaluate(ifElement.getThenStatement());
0739: return;
0740: }
0741: if (result == SymbolicInstance.FALSE) {
0742: evaluate(ifElement.getElseStatement());
0743: return;
0744: }
0745: evaluateBranches(ifElement.getThenStatement(), ifElement
0746: .getElseStatement());
0747: }
0748:
0749: public <T> void visitCtInterface(CtInterface<T> intrface) {
0750: throw new RuntimeException("Not evaluable");
0751: }
0752:
0753: public <T> void visitCtInvocation(CtInvocation<T> invocation) {
0754: CtExecutableReference<T> eref = invocation.getExecutable();
0755: // if (eref.getSimpleName().equals("<init>"))
0756: // return;
0757: List<SymbolicInstance<?>> arguments = new ArrayList<SymbolicInstance<?>>();
0758: for (CtExpression<?> expr : invocation.getArguments()) {
0759: SymbolicInstance<?> o = evaluate(expr);
0760: arguments.add(o);
0761: }
0762: SymbolicInstance<?> target = evaluate(invocation.getTarget());
0763: // redirect ref to the overloading method if any
0764: if (target != null) {
0765: CtExecutableReference<T> override = eref
0766: .getOverridingExecutable(target.getConcreteType());
0767: if (override != null) {
0768: eref = override;
0769: }
0770: }
0771: if (target == null) {
0772: if (eref.isStatic()) {
0773: target = heap.getType(this , eref.getDeclaringType());
0774: } else {
0775: target = stack.getThis();
0776: }
0777: }
0778: // CtExecutable<T> e = eref.getDeclaration();
0779: // if (e != null) {
0780: invoke(invocation, eref, target, arguments);
0781: // } else {
0782: // // method is not accessible
0783: // // set the result to the declared type
0784: // Method m = invocation.getExecutable().getActualMethod();
0785: // stack.setResult(heap.get(this, invocation.getFactory().Type()
0786: // .createReference(m.getReturnType())));
0787: // }
0788: }
0789:
0790: public <T> void visitCtLiteral(CtLiteral<T> literal) {
0791: if (literal.getValue() == null) {
0792: result = SymbolicInstance.NULL;
0793: } else if (literal.getValue().equals(true)) {
0794: result = SymbolicInstance.TRUE;
0795: } else if (literal.getValue().equals(false)) {
0796: result = SymbolicInstance.FALSE;
0797: } else if ((literal.getValue() instanceof Number)) {
0798: if (((Number) literal.getValue()).intValue() == 0) {
0799: result = SymbolicInstance.ZERO;
0800: }
0801: } else {
0802: result = new SymbolicInstance<T>(this , literal.getType(),
0803: false);
0804: }
0805: }
0806:
0807: public <T> void visitCtLocalVariable(
0808: final CtLocalVariable<T> localVariable) {
0809: stack.setVariableValue(localVariable.getReference(),
0810: evaluate(localVariable.getDefaultExpression()));
0811: }
0812:
0813: public <T> void visitCtLocalVariableReference(
0814: CtLocalVariableReference<T> reference) {
0815: throw new RuntimeException("Not evaluable");
0816: }
0817:
0818: public <T> void visitCtMethod(CtMethod<T> m) {
0819: throw new RuntimeException("Not evaluable");
0820: }
0821:
0822: public <T> void visitCtNewArray(CtNewArray<T> newArray) {
0823: skip(newArray);
0824: }
0825:
0826: public <T> void visitCtNewClass(CtNewClass<T> newClass) {
0827: // CtExecutable<T> e = eref.getDeclaration();
0828: List<SymbolicInstance<?>> arguments = new ArrayList<SymbolicInstance<?>>();
0829: for (CtExpression<?> expr : newClass.getArguments()) {
0830: SymbolicInstance<?> o = evaluate(expr);
0831: arguments.add(o);
0832: }
0833: SymbolicInstance<T> i = new SymbolicInstance<T>(this , newClass
0834: .getType(), false);
0835: heap.store(i);
0836: // evaluate the constructor
0837: invoke(newClass, newClass.getExecutable(), i, arguments);
0838: // TODO: something better for externals
0839: result = i;
0840: }
0841:
0842: public <T, A extends T> void visitCtOperatorAssignement(
0843: CtOperatorAssignment<T, A> assignment) {
0844: skip(assignment);
0845: }
0846:
0847: public void visitCtPackage(CtPackage ctPackage) {
0848: throw new RuntimeException("Not evaluable");
0849: }
0850:
0851: public void visitCtPackageReference(CtPackageReference reference) {
0852: throw new RuntimeException("Not evaluable");
0853: }
0854:
0855: public <T> void visitCtParameter(CtParameter<T> parameter) {
0856: throw new RuntimeException("Not evaluable");
0857: }
0858:
0859: public <R> void visitCtStatementList(CtStatementList<R> statements) {
0860: skip(statements);
0861: }
0862:
0863: public <T> void visitCtParameterReference(
0864: CtParameterReference<T> reference) {
0865: throw new RuntimeException("Not evaluable");
0866: }
0867:
0868: public <R> void visitCtReturn(CtReturn<R> returnStatement) {
0869: result = evaluate(returnStatement.getReturnedExpression());
0870: throw new ReturnException(returnStatement);
0871: }
0872:
0873: public <E> void visitCtSwitch(CtSwitch<E> switchStatement) {
0874: skip(switchStatement);
0875: }
0876:
0877: public void visitCtSynchronized(CtSynchronized synchro) {
0878: skip(synchro);
0879: }
0880:
0881: @SuppressWarnings("unchecked")
0882: public void visitCtThrow(CtThrow throwStatement) {
0883: throw new SymbolicWrappedException(evaluate(throwStatement
0884: .getThrownExpression()), throwStatement, getStack());
0885: }
0886:
0887: public void visitCtTry(CtTry tryBlock) {
0888: try {
0889: evaluate(tryBlock.getBody());
0890: } catch (ReturnException r) {
0891: // normal return
0892: } catch (SymbolicWrappedException e) {
0893: for (CtCatch c : tryBlock.getCatchers()) {
0894: if (c.getParameter().getType().isAssignableFrom(
0895: e.getAbstractCause().getConcreteType())) {
0896: getStack().setVariableValue(
0897: c.getParameter().getReference(),
0898: e.getAbstractCause());
0899: evaluate(c.getBody());
0900: return;
0901: }
0902: }
0903: // re-throw unhandled exception
0904: throw e;
0905: } finally {
0906: evaluate(tryBlock.getFinalizer());
0907: }
0908: }
0909:
0910: public void visitCtTypeParameter(CtTypeParameter typeParameter) {
0911: throw new RuntimeException("Not evaluable");
0912: }
0913:
0914: public void visitCtTypeParameterReference(
0915: CtTypeParameterReference ref) {
0916: throw new RuntimeException("Not evaluable");
0917: }
0918:
0919: public <T> void visitCtTypeReference(CtTypeReference<T> reference) {
0920: throw new RuntimeException("Not evaluable");
0921: }
0922:
0923: public <T> void visitCtUnaryOperator(CtUnaryOperator<T> operator) {
0924: evaluate(operator.getOperand());
0925: // switch (operator.getKind()) {
0926: // case POSTINC:
0927: // case POSTDEC:
0928: // case PREINC:
0929: // case PREDEC:
0930: // case NEG:
0931: // AbstractInstance<Number>
0932: // number=AbstractInstance.get(this,operator.getFactory().Type().createReference(Number.class));
0933: // setResult(number);
0934: // return;
0935: // case NOT:
0936: // AbstractInstance<Boolean>
0937: // bool=AbstractInstance.get(this,operator.getFactory().Type().createReference(Boolean.class));
0938: // setResult(bool);
0939: // return;
0940: // default:
0941: // throw new RuntimeException("unsupported operator");
0942: // }
0943: }
0944:
0945: public <T> void visitCtVariableAccess(
0946: CtVariableAccess<T> variableAccess) {
0947: CtVariableReference<?> vref = variableAccess.getVariable();
0948: result = stack.getVariableValue(vref);
0949: }
0950:
0951: public void visitCtWhile(CtWhile whileLoop) {
0952: evaluate(whileLoop.getLoopingExpression());
0953: evaluate(whileLoop.getBody());
0954: }
0955:
0956: public <T> void visitCtConditional(CtConditional<T> conditional) {
0957: evaluate(conditional.getCondition());
0958: evaluate(conditional.getThenExpression());
0959: evaluate(conditional.getElseExpression());
0960: }
0961:
0962: public SymbolicHeap getHeap() {
0963: return heap;
0964: }
0965:
0966: public SymbolicEvaluationStack getStack() {
0967: return stack;
0968: }
0969:
0970: protected void notifyExitStep(SymbolicEvaluationStep step) {
0971: for (SymbolicEvaluatorObserver o : observers) {
0972: o.onExitStep(this , step);
0973: }
0974:
0975: }
0976:
0977: protected void notifyEnterStep(SymbolicEvaluationStep step) {
0978: for (SymbolicEvaluatorObserver o : observers) {
0979: o.onEnterStep(this , step);
0980: }
0981: }
0982:
0983: protected void notifyStartPath() {
0984: for (SymbolicEvaluatorObserver o : observers) {
0985: o.onStartPath(this );
0986: }
0987: }
0988:
0989: protected void notifyEndPath() {
0990: for (SymbolicEvaluatorObserver o : observers) {
0991: o.onEndPath(this );
0992: }
0993: }
0994:
0995: public void addObserver(SymbolicEvaluatorObserver observer) {
0996: observers.add(observer);
0997: }
0998:
0999: public void addObservers(
1000: List<SymbolicEvaluatorObserver> evaluatorObservers) {
1001: observers.addAll(evaluatorObservers);
1002: }
1003:
1004: public void invoke(CtExecutable<?> executable) {
1005: Factory f = executable.getFactory();
1006: List<SymbolicInstance<?>> args = new ArrayList<SymbolicInstance<?>>();
1007: for (CtParameter<?> p : executable.getParameters()) {
1008: SymbolicInstance<?> arg = f.Eval().createSymbolicInstance(
1009: this , p.getType(), false);
1010: getHeap().store(arg);
1011: args.add(arg);
1012: }
1013: // Create target(this) for the invocation
1014: SymbolicInstance<?> target = f.Eval()
1015: .createSymbolicInstance(
1016: this ,
1017: executable.getDeclaringType().getReference(),
1018: executable.getModifiers().contains(
1019: ModifierKind.STATIC));
1020: // Seed the fields of the class
1021: CtType<?> targetType = executable.getDeclaringType();
1022: for (CtField<?> field : targetType.getFields()) {
1023: if (!field.getModifiers().contains(ModifierKind.STATIC)
1024: && executable.getModifiers().contains(
1025: ModifierKind.STATIC)) {
1026: continue;
1027: }
1028:
1029: CtVariableReference<?> fref = field.getReference();
1030: SymbolicInstance<?> si = f.Eval().createSymbolicInstance(
1031: this , fref.getType(), false);
1032: target.setFieldValue(getHeap(), fref, si);
1033: }
1034:
1035: getHeap().store(target);
1036: invoke(target, executable, args);
1037:
1038: }
1039: }
|