f2321ac47bfb32346fa8b17f9b7030479651e51b
[idea/community.git] / plugins / java-decompiler / engine / src / org / jetbrains / java / decompiler / modules / decompiler / stats / CatchAllStatement.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.java.decompiler.modules.decompiler.stats;
17
18 import org.jetbrains.java.decompiler.code.CodeConstants;
19 import org.jetbrains.java.decompiler.main.DecompilerContext;
20 import org.jetbrains.java.decompiler.main.TextBuffer;
21 import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
22 import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
23 import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
24 import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
25 import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
26 import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
27 import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
28 import org.jetbrains.java.decompiler.struct.gen.VarType;
29 import org.jetbrains.java.decompiler.util.InterpreterUtil;
30
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.HashSet;
34 import java.util.List;
35
36 public class CatchAllStatement extends Statement {
37
38   private Statement handler;
39
40   private boolean isFinally;
41
42   private VarExprent monitor;
43
44   private List<VarExprent> vars = new ArrayList<VarExprent>();
45
46   // *****************************************************************************
47   // constructors
48   // *****************************************************************************
49
50   private CatchAllStatement() {
51     type = Statement.TYPE_CATCHALL;
52   }
53
54   private CatchAllStatement(Statement head, Statement handler) {
55
56     this();
57
58     first = head;
59     stats.addWithKey(head, head.id);
60
61     this.handler = handler;
62     stats.addWithKey(handler, handler.id);
63
64     List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
65     if (!lstSuccs.isEmpty()) {
66       StatEdge edge = lstSuccs.get(0);
67       if (edge.getType() == StatEdge.TYPE_REGULAR) {
68         post = edge.getDestination();
69       }
70     }
71
72     vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
73                             new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
74                             (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
75   }
76
77
78   // *****************************************************************************
79   // public methods
80   // *****************************************************************************
81
82   public static Statement isHead(Statement head) {
83
84     if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
85       return null;
86     }
87
88     HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
89
90     if (setHandlers.size() != 1) {
91       return null;
92     }
93
94     for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
95       Statement exc = edge.getDestination();
96
97       if (edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) {
98         List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL);
99         if (lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
100
101           if (head.isMonitorEnter() || exc.isMonitorEnter()) {
102             return null;
103           }
104
105           if (DecHelper.checkStatementExceptions(Arrays.asList(head, exc))) {
106             return new CatchAllStatement(head, exc);
107           }
108         }
109       }
110     }
111
112     return null;
113   }
114
115   public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) {
116     String indstr = InterpreterUtil.getIndentString(indent);
117     String indstr1 = null;
118
119     String new_line_separator = DecompilerContext.getNewLineSeparator();
120
121     TextBuffer buf = new TextBuffer();
122
123     buf.append(ExprProcessor.listToJava(varDefinitions, indent, tracer));
124
125     boolean labeled = isLabeled();
126     if (labeled) {
127       buf.append(indstr).append("label").append(this.id.toString()).append(":").append(new_line_separator);
128       tracer.incrementCurrentSourceLine();
129     }
130
131     List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
132     if (first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally &&
133         !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) {
134       TextBuffer content = ExprProcessor.jmpWrapper(first, indent, true, tracer);
135       content.setLength(content.length() - new_line_separator.length());
136       buf.append(content);
137     }
138     else {
139       buf.append(indstr).append("try {").append(new_line_separator);
140       tracer.incrementCurrentSourceLine();
141       buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer));
142       buf.append(indstr).append("}");
143     }
144
145     buf.append(isFinally ? " finally" :
146                " catch (" + vars.get(0).toJava(indent, tracer) + ")").append(" {").append(new_line_separator);
147     tracer.incrementCurrentSourceLine();
148
149     if (monitor != null) {
150       indstr1 = InterpreterUtil.getIndentString(indent + 1);
151       buf.append(indstr1).append("if(").append(monitor.toJava(indent, tracer)).append(") {").append(new_line_separator);
152       tracer.incrementCurrentSourceLine();
153     }
154
155     buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true, tracer));
156
157     if (monitor != null) {
158       buf.append(indstr1).append("}").append(new_line_separator);
159       tracer.incrementCurrentSourceLine();
160     }
161
162     buf.append(indstr).append("}").append(new_line_separator);
163     tracer.incrementCurrentSourceLine();
164
165     return buf;
166   }
167
168   public void replaceStatement(Statement oldstat, Statement newstat) {
169
170     if (handler == oldstat) {
171       handler = newstat;
172     }
173
174     super.replaceStatement(oldstat, newstat);
175   }
176
177   public Statement getSimpleCopy() {
178
179     CatchAllStatement cas = new CatchAllStatement();
180
181     cas.isFinally = this.isFinally;
182
183     if (this.monitor != null) {
184       cas.monitor = new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
185                                    VarType.VARTYPE_INT,
186                                    (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR));
187     }
188
189     if (!this.vars.isEmpty()) {
190       // FIXME: WTF??? vars?!
191       vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
192                               new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
193                               (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
194     }
195
196     return cas;
197   }
198
199   public void initSimpleCopy() {
200     first = stats.get(0);
201     handler = stats.get(1);
202   }
203
204   // *****************************************************************************
205   // getter and setter methods
206   // *****************************************************************************
207
208   public Statement getHandler() {
209     return handler;
210   }
211
212
213   public void setHandler(Statement handler) {
214     this.handler = handler;
215   }
216
217
218   public boolean isFinally() {
219     return isFinally;
220   }
221
222
223   public void setFinally(boolean isFinally) {
224     this.isFinally = isFinally;
225   }
226
227
228   public VarExprent getMonitor() {
229     return monitor;
230   }
231
232
233   public void setMonitor(VarExprent monitor) {
234     this.monitor = monitor;
235   }
236
237   public List<VarExprent> getVars() {
238     return vars;
239   }
240 }