diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java new file mode 100644 index 000000000000..0f5141a7aa52 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java @@ -0,0 +1,336 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.decompiler.modules.decompiler; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.modules.decompiler.exps.*; +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; + +import java.util.List; + +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 && + 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.hasModifier(CodeConstants.ACC_STATIC); + + 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 && + 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 && + 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; + } +} |