diff options
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java')
-rw-r--r-- | src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java new file mode 100644 index 0000000..d11753e --- /dev/null +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java @@ -0,0 +1,320 @@ +/* + * Fernflower - The Analytical Java Decompiler + * http://www.reversed-java.com + * + * (C) 2008 - 2010, Stiver + * + * This software is NEITHER public domain NOR free software + * as per GNU License. See license.txt for more details. + * + * This software is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +package org.jetbrains.java.decompiler.modules.decompiler; + +import java.util.List; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; +import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; +import org.jetbrains.java.decompiler.struct.StructMethod; +import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; +import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; +import org.jetbrains.java.decompiler.util.VBStyleCollection; + +public class IdeaNotNullHelper { + + + public static boolean removeHardcodedChecks(Statement root, StructMethod mt) { + + boolean checks_removed = false; + + // parameter @NotNull annotations + while(findAndRemoveParameterCheck(root, mt)) { // iterate until nothing found. Each invocation removes one parameter check. + checks_removed = true; + } + + // method @NotNull annotation + while(findAndRemoveReturnCheck(root, mt)) { // iterate until nothing found. Each invocation handles one method exit check. + checks_removed = true; + } + + return checks_removed; + } + + private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod mt) { + + Statement st = stat.getFirst(); + while(st.type == Statement.TYPE_SEQUENCE) { + st = st.getFirst(); + } + + if(st.type == Statement.TYPE_IF) { + + IfStatement ifstat = (IfStatement)st; + Statement ifbranch = ifstat.getIfstat(); + + Exprent if_condition = ifstat.getHeadexprent().getCondition(); + + boolean is_notnull_check = false; + + // TODO: FUNCTION_NE also possible if reversed order (in theory) + if(ifbranch != null && if_condition.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ && + ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) { + + FunctionExprent func = (FunctionExprent)if_condition; + Exprent first_param = func.getLstOperands().get(0); + Exprent second_param = func.getLstOperands().get(1); + + if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order + if(first_param.type == Exprent.EXPRENT_VAR) { + VarExprent var = (VarExprent)first_param; + + boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + + MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); + VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes(); + + // parameter annotations + StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); + if(param_annotations != null) { + + List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations(); + int method_param_number = md.params.length; + + int index = thisvar ? 1 : 0; + for (int i = 0; i < method_param_number; i++) { + + if(index == var.getIndex()) { + if(param_annotations_lists.size() >= method_param_number - i) { + int shift = method_param_number - param_annotations_lists.size(); // NOTE: workaround for compiler bug, count annotations starting with the last parameter + + List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift); + + for(AnnotationExprent ann : annotations) { + if(ann.getClassname().equals("org/jetbrains/annotations/NotNull")) { + is_notnull_check = true; + } + } + } + + break; + } + + index+=md.params[i].stack_size; + } + } + } + } + } + + if(!is_notnull_check) { + return false; + } + + removeParameterCheck(stat, mt); + + return true; + } + + return false; + } + + private static void removeParameterCheck(Statement stat, StructMethod mt) { + + Statement st = stat.getFirst(); + while(st.type == Statement.TYPE_SEQUENCE) { + st = st.getFirst(); + } + + IfStatement ifstat = (IfStatement)st; + + if(ifstat.getElsestat() == null) { // if + // TODO: + } else { // if - else + + StatEdge ifedge = ifstat.getIfEdge(); + StatEdge elseedge = ifstat.getElseEdge(); + + Statement ifbranch = ifstat.getIfstat(); + Statement elsebranch = ifstat.getElsestat(); + + ifstat.getFirst().removeSuccessor(ifedge); + ifstat.getFirst().removeSuccessor(elseedge); + + ifstat.getStats().removeWithKey(ifbranch.id); + ifstat.getStats().removeWithKey(elsebranch.id); + + if(!ifbranch.getAllSuccessorEdges().isEmpty()) { + ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0)); + } + + ifstat.getParent().replaceStatement(ifstat, elsebranch); + ifstat.getParent().setAllParent(); + } + + } + + private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) { + + VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes(); + + boolean is_notnull_check = false; + + // method annotation, refers to the return value + StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS); + if(attr != null) { + List<AnnotationExprent> annotations = attr.getAnnotations(); + + for(AnnotationExprent ann : annotations) { + if(ann.getClassname().equals("org/jetbrains/annotations/NotNull")) { + is_notnull_check = true; + } + } + } + + if(is_notnull_check) { + return removeReturnCheck(stat, mt); + } + + return false; + } + + + private static boolean removeReturnCheck(Statement stat, StructMethod mt) { + + Statement parent = stat.getParent(); + + if(parent != null && parent.type == Statement.TYPE_IF && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) { + Exprent exprent = stat.getExprents().get(0); + if(exprent.type == Exprent.EXPRENT_EXIT) { + ExitExprent exit_exprent = (ExitExprent)exprent; + if(exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) { + Exprent exprent_value = exit_exprent.getValue(); + //if(exprent_value.type == Exprent.EXPRENT_VAR) { + // VarExprent var_value = (VarExprent)exprent_value; + + IfStatement ifparent = (IfStatement)parent; + Exprent if_condition = ifparent.getHeadexprent().getCondition(); + + if(ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION && + ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory) + + FunctionExprent func = (FunctionExprent)if_condition; + Exprent first_param = func.getLstOperands().get(0); + Exprent second_param = func.getLstOperands().get(1); + + StatEdge ifedge = ifparent.getIfEdge(); + StatEdge elseedge = ifparent.getElseEdge(); + + Statement ifbranch = ifparent.getIfstat(); + Statement elsebranch = ifparent.getElsestat(); + + if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order + //if(first_param.type == Exprent.EXPRENT_VAR && ((VarExprent)first_param).getIndex() == var_value.getIndex()) { + if(first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc. + if(ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && // TODO: special check for IllegalStateException + ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) { + + ifparent.getFirst().removeSuccessor(ifedge); + ifparent.getFirst().removeSuccessor(elseedge); + + ifparent.getStats().removeWithKey(ifbranch.id); + ifparent.getStats().removeWithKey(elsebranch.id); + + if(!ifbranch.getAllSuccessorEdges().isEmpty()) { + ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0)); + } + + if(!ifparent.getFirst().getExprents().isEmpty()) { + elsebranch.getExprents().addAll(0, ifparent.getFirst().getExprents()); + } + + ifparent.getParent().replaceStatement(ifparent, elsebranch); + ifparent.getParent().setAllParent(); + + return true; + } + } + } + } + //} + } + } + } else if (parent != null && parent.type == Statement.TYPE_SEQUENCE && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) { + Exprent exprent = stat.getExprents().get(0); + if(exprent.type == Exprent.EXPRENT_EXIT) { + ExitExprent exit_exprent = (ExitExprent)exprent; + if(exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) { + Exprent exprent_value = exit_exprent.getValue(); + + SequenceStatement sequence = (SequenceStatement)parent; + int sequence_stats_number = sequence.getStats().size(); + + if(sequence_stats_number > 1 && sequence.getStats().getLast() == stat && sequence.getStats().get(sequence_stats_number - 2).type == Statement.TYPE_IF) { + + IfStatement ifstat = (IfStatement)sequence.getStats().get(sequence_stats_number - 2); + Exprent if_condition = ifstat.getHeadexprent().getCondition(); + + if(ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION && + ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory) + + FunctionExprent func = (FunctionExprent)if_condition; + Exprent first_param = func.getLstOperands().get(0); + Exprent second_param = func.getLstOperands().get(1); + + Statement ifbranch = ifstat.getIfstat(); + + if(second_param.type == Exprent.EXPRENT_CONST && ((ConstExprent)second_param).getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order + if(first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc. + if(ifbranch.type == Statement.TYPE_BASICBLOCK && ifbranch.getExprents().size() == 1 && // TODO: special check for IllegalStateException + ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) { + + ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0)); // remove 'else' edge + + if(!ifstat.getFirst().getExprents().isEmpty()) { + stat.getExprents().addAll(0, ifstat.getFirst().getExprents()); + } + + for(StatEdge edge : ifstat.getAllPredecessorEdges()) { + + ifstat.removePredecessor(edge); + edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat); + stat.addPredecessor(edge); + } + + sequence.getStats().removeWithKey(ifstat.id); + sequence.setFirst(sequence.getStats().get(0)); + + return true; + } + } + } + } + } + } + } + } + + + for(Statement st: stat.getStats()) { + if(removeReturnCheck(st, mt)) { + return true; + } + } + + return false; + } + +} |