package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters; import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.*; import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers.InfiniteAssertRewriter; import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers.PreconditionAssertRewriter; import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers.StructuredStatementTransformer; import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.util.MiscStatementTools; import org.benf.cfr.reader.bytecode.analysis.parse.Expression; import org.benf.cfr.reader.bytecode.analysis.parse.expression.*; import org.benf.cfr.reader.bytecode.analysis.parse.literal.TypedLiteral; import org.benf.cfr.reader.bytecode.analysis.parse.lvalue.StaticVariable; import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier; import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch; import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; import org.benf.cfr.reader.bytecode.analysis.structured.expression.StructuredStatementExpression; import org.benf.cfr.reader.bytecode.analysis.structured.statement.*; import org.benf.cfr.reader.bytecode.analysis.structured.statement.placeholder.BeginBlock; import org.benf.cfr.reader.bytecode.analysis.structured.statement.placeholder.EndBlock; import org.benf.cfr.reader.bytecode.analysis.types.InnerClassInfo; import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; import org.benf.cfr.reader.bytecode.analysis.types.TypeConstants; import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; import org.benf.cfr.reader.entities.*; import org.benf.cfr.reader.util.collections.ListFactory; import org.benf.cfr.reader.util.collections.MapFactory; import org.benf.cfr.reader.util.getopt.Options; import org.benf.cfr.reader.util.getopt.OptionsImpl; import java.util.List; import java.util.Map; public class AssertRewriter { private final ClassFile classFile; private StaticVariable assertionStatic = null; private final boolean switchExpressions; private InferredJavaType boolIjt = new InferredJavaType(RawJavaType.BOOLEAN, InferredJavaType.Source.EXPRESSION); public AssertRewriter(ClassFile classFile, Options options) { this.classFile = classFile; this.switchExpressions = options.getOption(OptionsImpl.SWITCH_EXPRESSION, classFile.getClassFileVersion()); } public void sugarAsserts(Method staticInit) { /* * Determine if the static init has a line like * * CLASSX.y = !(CLASSX.class.desiredAssertionStatus()); * * where y is static final boolean. */ if (!staticInit.hasCodeAttribute()) return; List<StructuredStatement> statements = MiscStatementTools.linearise(staticInit.getAnalysis()); if (statements == null) return; MatchIterator<StructuredStatement> mi = new MatchIterator<StructuredStatement>(statements); WildcardMatch wcm1 = new WildcardMatch(); final JavaTypeInstance topClassType = classFile.getClassType(); InnerClassInfo innerClassInfo = topClassType.getInnerClassHereInfo(); JavaTypeInstance classType = topClassType; while (innerClassInfo != InnerClassInfo.NOT) { JavaTypeInstance nextClass = innerClassInfo.getOuterClass(); if (nextClass == null || nextClass.equals(classType)) break; classType = nextClass; innerClassInfo = classType.getInnerClassHereInfo(); } Matcher<StructuredStatement> m = new ResetAfterTest(wcm1, new CollectMatch("ass1", new StructuredAssignment( wcm1.getStaticVariable("assertbool", topClassType, new InferredJavaType(RawJavaType.BOOLEAN, InferredJavaType.Source.TEST)), new NotOperation(new BooleanExpression( wcm1.getMemberFunction("assertmeth", "desiredAssertionStatus", new Literal(TypedLiteral.getClass(classType)) ) )) )) ); AssertVarCollector matchResultCollector = new AssertVarCollector(wcm1); while (mi.hasNext()) { mi.advance(); matchResultCollector.clear(); if (m.match(mi, matchResultCollector)) { // This really should only match once. If it matches multiple times, something else // is being identically initialised, which is probably wrong! if (matchResultCollector.matched()) break; mi.rewind1(); } } if (!matchResultCollector.matched()) return; assertionStatic = matchResultCollector.assertStatic; /* * Ok, now we know what the assertion field is. Let's search all conditionals for it - if we find one, * we can transform that conditional into an assert * * if (!assertionsDisabledField && (x)) --> assert(!x)) */ rewriteMethods(); } private class AssertVarCollector extends AbstractMatchResultIterator { private final WildcardMatch wcm; ClassFileField assertField = null; StaticVariable assertStatic = null; private AssertVarCollector(WildcardMatch wcm) { this.wcm = wcm; } @Override public void clear() { assertField = null; assertStatic = null; } @Override public void collectStatement(String name, StructuredStatement statement) { StaticVariable staticVariable = wcm.getStaticVariable("assertbool").getMatch(); ClassFileField field; try { field = classFile.getFieldByName(staticVariable.getFieldName(), staticVariable.getInferredJavaType().getJavaTypeInstance()); } catch (NoSuchFieldException e) { return; } if (!field.getField().testAccessFlag(AccessFlag.ACC_SYNTHETIC)) return; assertField = field; statement.getContainer().nopOut(); assertField.markHidden(); assertStatic = staticVariable; } boolean matched() { return (assertField != null); } } private void rewriteMethods() { List<Method> methods = classFile.getMethods(); WildcardMatch wcm1 = new WildcardMatch(); Matcher<StructuredStatement> standardAssertMatcher = buildStandardAssertMatcher(wcm1); AssertUseCollector collector = new AssertUseCollector(wcm1); Matcher<StructuredStatement> switchAssertMatcher = buildSwitchAssertMatcher(wcm1); SwitchAssertUseCollector swcollector = new SwitchAssertUseCollector(); for (Method method : methods) { if (!method.hasCodeAttribute()) continue; Op04StructuredStatement top = method.getAnalysis(); if (top == null) continue; handlePreConditionedAsserts(top); /* * Pre-transform a couple of particularly horrible samples. * (where the assertion gets moved into a while block test). * See InfiniteAssert tests. */ handleInfiniteAsserts(top); List<StructuredStatement> statements = MiscStatementTools.linearise(top); if (statements == null) continue; MatchIterator<StructuredStatement> mi = new MatchIterator<StructuredStatement>(statements); while (mi.hasNext()) { mi.advance(); if (standardAssertMatcher.match(mi, collector)) { mi.rewind1(); } } // If we're looking for switch expression assertions, things get more interesting. // We can't search for a simple pattern any more, but we can find possible entry points. if (switchExpressions) { mi = new MatchIterator<StructuredStatement>(statements); while (mi.hasNext()) { mi.advance(); if (switchAssertMatcher.match(mi, swcollector)) { mi.rewind1(); } } } } } private Matcher<StructuredStatement> buildSwitchAssertMatcher(WildcardMatch wcm1) { return new ResetAfterTest(wcm1, new CollectMatch("ass1", new MatchSequence( new BeginBlock(null), new StructuredIf( new NotOperation(new BooleanExpression(new LValueExpression(assertionStatic))), null ), new BeginBlock(null), new StructuredSwitch(wcm1.getExpressionWildCard("switchExpression"), null, wcm1.getBlockIdentifier("switchblock")) )) ); } private Matcher<StructuredStatement> buildStandardAssertMatcher(WildcardMatch wcm1) { return new ResetAfterTest(wcm1, new MatchOneOf( new CollectMatch("ass1", new MatchSequence( new StructuredIf( new BooleanOperation( new NotOperation(new BooleanExpression(new LValueExpression(assertionStatic))), wcm1.getConditionalExpressionWildcard("condition"), BoolOp.AND), null ), new BeginBlock(null), new StructuredThrow(wcm1.getConstructorSimpleWildcard("exception", TypeConstants.ASSERTION_ERROR)), new EndBlock(null) )), // obviated by demorgan pass? new CollectMatch("ass1b", new MatchSequence( new StructuredIf( new NotOperation( new BooleanOperation(new BooleanExpression(new LValueExpression(assertionStatic)), wcm1.getConditionalExpressionWildcard("condition"), BoolOp.OR)), null ), new BeginBlock(null), new StructuredThrow(wcm1.getConstructorSimpleWildcard("exception", TypeConstants.ASSERTION_ERROR)), new EndBlock(null) )), new CollectMatch("ass1c", new MatchSequence( new StructuredIf(new NotOperation(new BooleanExpression(new LValueExpression(assertionStatic))), null ), new BeginBlock(null), new StructuredIf(wcm1.getConditionalExpressionWildcard("condition"), null ), new BeginBlock(null), new StructuredThrow(wcm1.getConstructorSimpleWildcard("exception", TypeConstants.ASSERTION_ERROR)), new EndBlock(null) , new EndBlock(null) )), new CollectMatch("ass2", new MatchSequence( new MatchOneOf( new StructuredIf( new BooleanOperation( new BooleanExpression(new LValueExpression(assertionStatic)), wcm1.getConditionalExpressionWildcard("condition2"), BoolOp.OR), null), new StructuredIf( new BooleanExpression(new LValueExpression(assertionStatic)), null) ), new BeginBlock(wcm1.getBlockWildcard("condBlock")), new MatchOneOf( new StructuredReturn(null, null), new StructuredReturn(wcm1.getExpressionWildCard("retval"), null), new StructuredBreak(wcm1.getBlockIdentifier("breakblock"), false) ), new EndBlock(wcm1.getBlockWildcard("condBlock")), new CollectMatch("ass2throw", new StructuredThrow(wcm1.getConstructorSimpleWildcard("exception2", TypeConstants.ASSERTION_ERROR))) )), new CollectMatch("assonly", new MatchSequence( new StructuredIf( new NotOperation(new BooleanExpression(new LValueExpression(assertionStatic))), null ), new BeginBlock(null), new StructuredThrow(wcm1.getConstructorSimpleWildcard("exception", TypeConstants.ASSERTION_ERROR)), new EndBlock(null) )) ) ); } /* * Consider AssertTest19: * public static void f(Integer x) { * if (x > 1) { * assert (x!=3); * } * } * * The first test happens regardless, the second inside the assert * * reasonable : if (x>1&& !assertionsDisabled && x==3) throw(); * totally wrong : assert(x>1 && x!=3) * * but correct is as above ;) */ private void handlePreConditionedAsserts(Op04StructuredStatement statements) { PreconditionAssertRewriter rewriter = new PreconditionAssertRewriter(assertionStatic); rewriter.transform(statements); } private void handleInfiniteAsserts(Op04StructuredStatement statements) { InfiniteAssertRewriter rewriter = new InfiniteAssertRewriter(assertionStatic); rewriter.transform(statements); } private class SwitchAssertUseCollector extends AbstractMatchResultIterator { private SwitchAssertUseCollector() { } @Override public void clear() { } @Override public void collectStatement(String name, StructuredStatement statement) { /* We expect this statement to be a block, containing our test, and starting a switch. * We don't know if the switch is the only statement in the block (exception has been rolled up) * or if there's ONE throw after it. * * If neither, bail! */ if (!(statement instanceof BeginBlock)) return; Block block = ((BeginBlock)statement).getBlock(); Pair<Boolean, Op04StructuredStatement> content = block.getOneStatementIfPresent(); if (content.getFirst()) return; StructuredStatement ifStm = content.getSecond().getStatement(); if (!(ifStm instanceof StructuredIf)) return; Op04StructuredStatement taken = ((StructuredIf) ifStm).getIfTaken(); StructuredStatement takenBody = taken.getStatement(); if (takenBody.getClass() != Block.class) return; Block takenBlock = (Block)takenBody; // This will either have a switch ONLY, or a switch and a throw. List<Op04StructuredStatement> switchAndThrow = takenBlock.getFilteredBlockStatements(); if (switchAndThrow.isEmpty()) return; BlockIdentifier outerBlock = block.getBreakableBlockOrNull(); StructuredStatement switchS = switchAndThrow.get(0).getStatement(); if (!(switchS instanceof StructuredSwitch)) return; StructuredSwitch struSwi = (StructuredSwitch)switchS; BlockIdentifier switchBlock = struSwi.getBlockIdentifier(); Op04StructuredStatement swBody = struSwi.getBody(); if (!(swBody.getStatement() instanceof Block)) { return; } Block swBodyBlock = (Block)(swBody.getStatement()); if (switchAndThrow.size() > 2) { // It's possible that this is a switch with no content, because we've extracted all the content // after the default. // if so, we could aggressively roll it up, and try that. // (test SwitchExpressionAssert1d) switchAndThrow = tryCombineSwitch(switchAndThrow, outerBlock, switchBlock, swBodyBlock); if (switchAndThrow.size() != 1) return; takenBlock.replaceBlockStatements(switchAndThrow); } StructuredStatement newAssert = null; switch (switchAndThrow.size()) { case 1: // switch, with throw rolled up into last case. newAssert = processSwitchEmbeddedThrow(ifStm, outerBlock, swBodyBlock, swBody, struSwi); break; case 2: // switch, followed by throw. // In this version, if it ends up leaving the if, it's true. // if it ends up leaving the switch (so into the throw), it's false. newAssert = processSwitchAndThrow(ifStm, outerBlock, switchBlock, swBodyBlock, struSwi, switchAndThrow.get(1)); break; default: // switch, with logic dropping off the last case. break; } if (newAssert != null) { content.getSecond().replaceStatement(newAssert); } } // We know the first statement is a switch - if it doesn't have any breaks in it, then we're safe to // roll outer statements in. private List<Op04StructuredStatement> tryCombineSwitch(List<Op04StructuredStatement> content, BlockIdentifier outer, BlockIdentifier swiBlockIdentifier, Block swBodyBlock) { Map<Op04StructuredStatement, StructuredExpressionYield> replacements = MapFactory.newOrderedMap(); ControlFlowSwitchExpressionTransformer cfset = new ControlFlowSwitchExpressionTransformer(outer, swiBlockIdentifier, replacements); content.get(0).transform(cfset, new StructuredScope()); if (cfset.failed) return content; if (cfset.falseFound != 0) return content; List<Op04StructuredStatement> cases = swBodyBlock.getFilteredBlockStatements(); Op04StructuredStatement lastCase = cases.get(cases.size()-1); StructuredStatement ss = lastCase.getStatement(); if (!(ss instanceof StructuredCase)) return content; Op04StructuredStatement body = ((StructuredCase) ss).getBody(); StructuredStatement bodySS = body.getStatement(); Block block; if (bodySS instanceof Block) { block = (Block)bodySS; } else { block = new Block(body); } block.setIndenting(true); block.getBlockStatements().addAll(content.subList(1, content.size())); body.replaceStatement(block); return ListFactory.newList(content.get(0)); } private Pair<Boolean, Expression> getThrowExpression(StructuredStatement throwS) { WildcardMatch wcm2 = new WildcardMatch(); WildcardMatch.ConstructorInvokationSimpleWildcard constructor = wcm2.getConstructorSimpleWildcard("exception", TypeConstants.ASSERTION_ERROR); StructuredStatement test = new StructuredThrow(constructor); if (!test.equals(throwS)) return Pair.make(false, null);; Expression exceptArg = null; List<Expression> consArg = constructor.getMatch().getArgs(); if (consArg.size() == 1) { exceptArg = consArg.get(0); } else if (consArg.size() > 1) { return Pair.make(false, null); } return Pair.make(true, exceptArg); } private StructuredStatement processSwitchAndThrow(StructuredStatement ifStm, BlockIdentifier outer, BlockIdentifier swiBlockIdentifier, Block swBodyBlock, StructuredSwitch struSwi, Op04StructuredStatement throwStm) { // First, we need to verify that the throw expression really is one Pair<Boolean, Expression> excepTest = getThrowExpression(throwStm.getStatement()); if (!excepTest.getFirst()) return null; Expression exceptArg = excepTest.getSecond(); // The switch should have only BREAK immediate, BREAK outer, or THROW exits. // break immediate -> yield false // break outer -> yield true // However, the switch could itself have complex content in it. List<SwitchExpression.Branch> branches = ListFactory.newList(); Map<Op04StructuredStatement, StructuredExpressionYield> replacements = MapFactory.newOrderedMap(); if (!getBranches(outer, swiBlockIdentifier, swBodyBlock, branches, replacements, false)) return null; SwitchExpression sw = new SwitchExpression(boolIjt, struSwi.getSwitchOn(), branches); return ((StructuredIf)ifStm).convertToAssertion(StructuredAssert.mkStructuredAssert(new BooleanExpression(sw), exceptArg)); } @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean getBranches(BlockIdentifier outer, BlockIdentifier swiBlockIdentifier, Block swBodyBlock, List<SwitchExpression.Branch> branches, Map<Op04StructuredStatement, StructuredExpressionYield> replacements, boolean addYieldTrue) { for (Op04StructuredStatement statement : swBodyBlock.getBlockStatements()) { SwitchExpression.Branch branch = getBranch(outer, swiBlockIdentifier, replacements, statement, addYieldTrue); if (branch == null) return false; branches.add(branch); } for (Map.Entry<Op04StructuredStatement, StructuredExpressionYield> replacement : replacements.entrySet()) { Op04StructuredStatement first = replacement.getKey(); StructuredStatement statement = first.getStatement(); if (statement instanceof StructuredBreak) { StructuredBreak sb = (StructuredBreak) statement; if (!sb.isLocalBreak()) sb.getBreakBlock().releaseForeignRef(); } first.replaceStatement(replacement.getValue()); } return true; } private SwitchExpression.Branch getBranch(BlockIdentifier outer, BlockIdentifier swiBlockIdentifier, Map<Op04StructuredStatement, StructuredExpressionYield> replacements, Op04StructuredStatement statement, boolean addYieldTrue) { StructuredStatement cstm = statement.getStatement(); if (!(cstm instanceof StructuredCase)) return null; StructuredCase caseStm = (StructuredCase)cstm; ControlFlowSwitchExpressionTransformer cfset = new ControlFlowSwitchExpressionTransformer(outer, swiBlockIdentifier, replacements); Op04StructuredStatement body = caseStm.getBody(); body.transform(cfset, new StructuredScope()); if (cfset.failed) return null; if (addYieldTrue) { StructuredStatement stm = body.getStatement(); if (stm instanceof Block) { Block block = (Block) stm; Op04StructuredStatement last = block.getLast(); StructuredStatement lastStm = replacements.get(last); if (lastStm == null) { lastStm = last.getStatement(); } if (!(lastStm instanceof StructuredExpressionYield)) { cfset.totalStatements++; block.getBlockStatements().add(new Op04StructuredStatement(new StructuredExpressionYield(Literal.TRUE))); } } } Expression value = cfset.totalStatements == 0 ? cfset.single : new StructuredStatementExpression(boolIjt, body.getStatement()); return new SwitchExpression.Branch(caseStm.getValues(), value); } private StructuredStatement processSwitchEmbeddedThrow(StructuredStatement ifStm, BlockIdentifier outer, Block swBodyBlock, Op04StructuredStatement switchStm, StructuredSwitch struSwi) { // Soooo - if there's only ONE Assertion error that gets thrown, we can be pretty confident that // that's the assertion. // If there are multiple? // If they're identical, then we COULD consider them the same. If not, give up, go home. // Also, don't forget to add a 'yield true' at the end of the last block, if there's not a yield or a throw there already! Map<Op04StructuredStatement, StructuredExpressionYield> replacements = MapFactory.newOrderedMap(); BlockIdentifier swiBlockIdentifier = struSwi.getBlockIdentifier(); AssertionTrackingControlFlowSwitchExpressionTransformer track = new AssertionTrackingControlFlowSwitchExpressionTransformer(swiBlockIdentifier, outer, replacements); switchStm.transform(track, new StructuredScope()); if (track.failed) return null; if (track.throwSS.size() > 1) { return null; } replacements.clear(); Expression exceptArg = null; if (track.throwSS.size() == 1) { StructuredStatement throwStm = track.throwSS.get(0); Pair<Boolean, Expression> excepTest = getThrowExpression(throwStm); if (!excepTest.getFirst()) return null; exceptArg = excepTest.getSecond(); replacements.put(throwStm.getContainer(), new StructuredExpressionYield(Literal.FALSE)); } List<SwitchExpression.Branch> branches = ListFactory.newList(); if (!getBranches(swiBlockIdentifier, swiBlockIdentifier, swBodyBlock, branches, replacements, true)) return null; // And add yield true to the end of every branch that could roll off. SwitchExpression sw = new SwitchExpression(boolIjt, struSwi.getSwitchOn(), branches); return ((StructuredIf)ifStm).convertToAssertion(StructuredAssert.mkStructuredAssert(new BooleanExpression(sw), exceptArg)); } } static class AssertionTrackingControlFlowSwitchExpressionTransformer extends ControlFlowSwitchExpressionTransformer { List<StructuredStatement> throwSS = ListFactory.newList(); AssertionTrackingControlFlowSwitchExpressionTransformer(BlockIdentifier trueBlock, BlockIdentifier falseBlock, Map<Op04StructuredStatement, StructuredExpressionYield> replacements) { super(trueBlock, falseBlock, replacements); } @Override void additionalHandling(StructuredStatement in) { if (in instanceof StructuredThrow) { if (((StructuredThrow) in).getValue().getInferredJavaType().getJavaTypeInstance().equals(TypeConstants.ASSERTION_ERROR)) { throwSS.add(in); } } } } static class ControlFlowSwitchExpressionTransformer implements StructuredStatementTransformer { private Map<Op04StructuredStatement, StructuredExpressionYield> replacements; protected boolean failed; int totalStatements; Expression single; int trueFound = 0; int falseFound = 0; private BlockIdentifier trueBlock; private BlockIdentifier falseBlock; private ControlFlowSwitchExpressionTransformer(BlockIdentifier trueBlock, BlockIdentifier falseBlock, Map<Op04StructuredStatement, StructuredExpressionYield> replacements) { this.trueBlock = trueBlock; this.falseBlock = falseBlock; this.replacements = replacements; } void additionalHandling(StructuredStatement in) { } @Override public StructuredStatement transform(StructuredStatement in, StructuredScope scope) { if (failed) return in; if (in.isEffectivelyNOP()) return in; if (!(in instanceof Block)) { StructuredExpressionYield y = (StructuredExpressionYield)replacements.get(in.getContainer()); if (y == null) { totalStatements++; } else { single = y.getValue(); } } if (in instanceof StructuredBreak) { BreakClassification bk = classifyBreak((StructuredBreak)in, scope); switch (bk) { case TRUE_BLOCK: totalStatements--; trueFound++; single = Literal.TRUE; replacements.put(in.getContainer(), new StructuredExpressionYield(single)); return in; case FALSE_BLOCK: totalStatements--; falseFound++; single = Literal.FALSE; replacements.put(in.getContainer(), new StructuredExpressionYield(single)); return in; case INNER: break; case TOO_FAR: failed = true; return in; } } if (in instanceof StructuredReturn) { failed = true; return in; } additionalHandling(in); in.transformStructuredChildren(this, scope); return in; } BreakClassification classifyBreak(StructuredBreak in, StructuredScope scope) { BlockIdentifier breakBlock = in.getBreakBlock(); if (breakBlock == trueBlock) return BreakClassification.TRUE_BLOCK; if (breakBlock == falseBlock) return BreakClassification.FALSE_BLOCK; for (StructuredStatement stm : scope.getAll()) { BlockIdentifier block = stm.getBreakableBlockOrNull(); if (block == breakBlock) return BreakClassification.INNER; } return BreakClassification.TOO_FAR; } enum BreakClassification { TRUE_BLOCK, FALSE_BLOCK, TOO_FAR, INNER } } private class AssertUseCollector extends AbstractMatchResultIterator { private StructuredStatement ass2throw; private final WildcardMatch wcm; private AssertUseCollector(WildcardMatch wcm) { this.wcm = wcm; } @Override public void clear() { ass2throw = null; } @Override public void collectStatement(String name, StructuredStatement statement) { WildcardMatch.ConstructorInvokationSimpleWildcard constructor = wcm.getConstructorSimpleWildcard("exception"); List<Expression> args = constructor.getMatch().getArgs(); Expression arg = args.size() > 0 ? args.get(0) : null; if (arg != null) { // We can remove a spurious cast to Object. if (arg instanceof CastExpression && arg.getInferredJavaType().getJavaTypeInstance() == TypeConstants.OBJECT) { arg = ((CastExpression) arg).getChild(); } } if (name.equals("ass1") || name.equals("ass1b") || name.equals("ass1c")) { StructuredIf ifStatement = (StructuredIf) statement; ConditionalExpression condition = wcm.getConditionalExpressionWildcard("condition").getMatch(); if (name.equals("ass1") || name.equals("ass1c")) condition = new NotOperation(condition); condition = condition.simplify(); StructuredStatement structuredAssert = ifStatement.convertToAssertion(StructuredAssert.mkStructuredAssert(condition,arg)); ifStatement.getContainer().replaceStatement(structuredAssert); } else if (name.equals("ass2")) { if (ass2throw == null) throw new IllegalStateException(); StructuredIf ifStatement = (StructuredIf) statement; // If there's a condition, it's in condition 2, otherwise it's an assert literal. WildcardMatch.ConditionalExpressionWildcard wcard = wcm.getConditionalExpressionWildcard("condition2"); ConditionalExpression conditionalExpression = wcard.getMatch(); if (conditionalExpression == null) conditionalExpression = new BooleanExpression(new Literal(TypedLiteral.getBoolean(0))); // The if statement becomes an assert conditjon, the throw statement becomes the content of the if block. StructuredStatement structuredAssert = StructuredAssert.mkStructuredAssert(conditionalExpression,arg); ifStatement.getContainer().replaceStatement(structuredAssert); ass2throw.getContainer().replaceStatement(ifStatement.getIfTaken().getStatement()); } else if (name.equals("ass2throw")) { ass2throw = statement; } else if (name.equals("assonly")) { StructuredIf ifStatement = (StructuredIf) statement; StructuredStatement structuredAssert = ifStatement.convertToAssertion(StructuredAssert.mkStructuredAssert(new BooleanExpression(Literal.FALSE),arg)); ifStatement.getContainer().replaceStatement(structuredAssert); } } } }