summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java')
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java355
1 files changed, 355 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
new file mode 100644
index 000000000000..fdd6cd5015f8
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
@@ -0,0 +1,355 @@
+/*
+ * 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.vars;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class VarDefinitionHelper {
+
+ private HashMap<Integer, Statement> mapVarDefStatements;
+
+ // statement.id, defined vars
+ private HashMap<Integer, HashSet<Integer>> mapStatementVars;
+
+ private HashSet<Integer> implDefVars;
+
+ private VarProcessor varproc;
+
+ public VarDefinitionHelper(Statement root, StructMethod mt, VarProcessor varproc) {
+
+ mapVarDefStatements = new HashMap<Integer, Statement>();
+ mapStatementVars = new HashMap<Integer, HashSet<Integer>>();
+ implDefVars = new HashSet<Integer>();
+
+ this.varproc = varproc;
+
+ VarNamesCollector vc = DecompilerContext.getVarNamesCollector();
+
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = 0;
+ if (thisvar) {
+ paramcount = 1;
+ }
+ paramcount += md.params.length;
+
+
+ // method parameters are implicitly defined
+ int varindex = 0;
+ for (int i = 0; i < paramcount; i++) {
+ implDefVars.add(varindex);
+ varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ if (thisvar) {
+ StructClass current_class = (StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS);
+
+ varproc.getThisvars().put(new VarVersionPaar(0, 0), current_class.qualifiedName);
+ varproc.setVarName(new VarVersionPaar(0, 0), "this");
+ vc.addName("this");
+ }
+
+ // catch variables are implicitly defined
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.removeFirst();
+
+ List<VarExprent> lstVars = null;
+ if (st.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)st).getVars();
+ }
+ else if (st.type == Statement.TYPE_TRYCATCH) {
+ lstVars = ((CatchStatement)st).getVars();
+ }
+
+ if (lstVars != null) {
+ for (VarExprent var : lstVars) {
+ implDefVars.add(var.getIndex());
+ varproc.setVarName(new VarVersionPaar(var), vc.getFreeName(var.getIndex()));
+ var.setDefinition(true);
+ }
+ }
+
+ stack.addAll(st.getStats());
+ }
+
+ initStatement(root);
+ }
+
+
+ public void setVarDefinitions() {
+
+ VarNamesCollector vc = DecompilerContext.getVarNamesCollector();
+
+ for (Entry<Integer, Statement> en : mapVarDefStatements.entrySet()) {
+ Statement stat = en.getValue();
+ Integer index = en.getKey();
+
+ if (implDefVars.contains(index)) {
+ // already implicitly defined
+ continue;
+ }
+
+ varproc.setVarName(new VarVersionPaar(index.intValue(), 0), vc.getFreeName(index));
+
+ // special case for
+ if (stat.type == Statement.TYPE_DO) {
+ DoStatement dstat = (DoStatement)stat;
+ if (dstat.getLooptype() == DoStatement.LOOP_FOR) {
+
+ if (dstat.getInitExprent() != null && setDefinition(dstat.getInitExprent(), index)) {
+ continue;
+ }
+ else {
+ List<Exprent> lstSpecial = Arrays.asList(dstat.getConditionExprent(), dstat.getIncExprent());
+ for (VarExprent var : getAllVars(lstSpecial)) {
+ if (var.getIndex() == index.intValue()) {
+ stat = stat.getParent();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ Statement first = findFirstBlock(stat, index);
+
+ List<Exprent> lst;
+ if (first == null) {
+ lst = stat.getVarDefinitions();
+ }
+ else if (first.getExprents() == null) {
+ lst = first.getVarDefinitions();
+ }
+ else {
+ lst = first.getExprents();
+ }
+
+
+ boolean defset = false;
+
+ // search for the first assignement to var [index]
+ int addindex = 0;
+ for (Exprent expr : lst) {
+ if (setDefinition(expr, index)) {
+ defset = true;
+ break;
+ }
+ else {
+ boolean foundvar = false;
+ for (Exprent exp : expr.getAllExprents(true)) {
+ if (exp.type == Exprent.EXPRENT_VAR && ((VarExprent)exp).getIndex() == index) {
+ foundvar = true;
+ break;
+ }
+ }
+ if (foundvar) {
+ break;
+ }
+ }
+ addindex++;
+ }
+
+ if (!defset) {
+ VarExprent var = new VarExprent(index.intValue(), varproc.getVarType(new VarVersionPaar(index.intValue(), 0)), varproc);
+ var.setDefinition(true);
+
+ lst.add(addindex, var);
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private Statement findFirstBlock(Statement stat, Integer varindex) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(stat);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.remove(0);
+
+ if (stack.isEmpty() || mapStatementVars.get(st.id).contains(varindex)) {
+
+ if (st.isLabeled() && !stack.isEmpty()) {
+ return st;
+ }
+
+ if (st.getExprents() != null) {
+ return st;
+ }
+ else {
+ stack.clear();
+
+ switch (st.type) {
+ case Statement.TYPE_SEQUENCE:
+ stack.addAll(0, st.getStats());
+ break;
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ stack.add(st.getFirst());
+ break;
+ default:
+ return st;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Set<Integer> initStatement(Statement stat) {
+
+ HashMap<Integer, Integer> mapCount = new HashMap<Integer, Integer>();
+
+ List<VarExprent> condlst;
+
+ if (stat.getExprents() == null) {
+
+ // recurse on children statements
+ List<Integer> childVars = new ArrayList<Integer>();
+ List<Exprent> currVars = new ArrayList<Exprent>();
+
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ Statement st = (Statement)obj;
+ childVars.addAll(initStatement(st));
+
+ if (st.type == DoStatement.TYPE_DO) {
+ DoStatement dost = (DoStatement)st;
+ if (dost.getLooptype() != DoStatement.LOOP_FOR &&
+ dost.getLooptype() != DoStatement.LOOP_DO) {
+ currVars.add(dost.getConditionExprent());
+ }
+ }
+ else if (st.type == DoStatement.TYPE_CATCHALL) {
+ CatchAllStatement fin = (CatchAllStatement)st;
+ if (fin.isFinally() && fin.getMonitor() != null) {
+ currVars.add(fin.getMonitor());
+ }
+ }
+ }
+ else if (obj instanceof Exprent) {
+ currVars.add((Exprent)obj);
+ }
+ }
+
+ // children statements
+ for (Integer index : childVars) {
+ Integer count = mapCount.get(index);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ mapCount.put(index, new Integer(count.intValue() + 1));
+ }
+
+ condlst = getAllVars(currVars);
+ }
+ else {
+ condlst = getAllVars(stat.getExprents());
+ }
+
+ // this statement
+ for (VarExprent var : condlst) {
+ mapCount.put(new Integer(var.getIndex()), new Integer(2));
+ }
+
+
+ HashSet<Integer> set = new HashSet<Integer>(mapCount.keySet());
+
+ // put all variables defined in this statement into the set
+ for (Entry<Integer, Integer> en : mapCount.entrySet()) {
+ if (en.getValue().intValue() > 1) {
+ mapVarDefStatements.put(en.getKey(), stat);
+ }
+ }
+
+ mapStatementVars.put(stat.id, set);
+
+ return set;
+ }
+
+ private static List<VarExprent> getAllVars(List<Exprent> lst) {
+
+ List<VarExprent> res = new ArrayList<VarExprent>();
+ List<Exprent> listTemp = new ArrayList<Exprent>();
+
+ for (Exprent expr : lst) {
+ listTemp.addAll(expr.getAllExprents(true));
+ listTemp.add(expr);
+ }
+
+ for (Exprent exprent : listTemp) {
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ res.add((VarExprent)exprent);
+ }
+ }
+
+ return res;
+ }
+
+ private static boolean setDefinition(Exprent expr, Integer index) {
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ Exprent left = ((AssignmentExprent)expr).getLeft();
+ if (left.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)left;
+ if (var.getIndex() == index.intValue()) {
+ var.setDefinition(true);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}