summaryrefslogtreecommitdiff
path: root/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java')
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java174
1 files changed, 174 insertions, 0 deletions
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java
new file mode 100644
index 000000000000..40a730190d2e
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/ControlFlowGraph.java
@@ -0,0 +1,174 @@
+/*
+ * 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 com.intellij.codeInspection.bytecodeAnalysis.asm;
+
+import com.intellij.codeInspection.bytecodeAnalysis.asm.ControlFlowGraph.Edge;
+import gnu.trove.TIntArrayList;
+import org.jetbrains.org.objectweb.asm.tree.MethodNode;
+import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author lambdamix
+ */
+public final class ControlFlowGraph {
+ public static final class Edge {
+ public final int from, to;
+
+ public Edge(int from, int to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Edge)) {
+ return false;
+ }
+ Edge edge = (Edge) o;
+ return from == edge.from && to == edge.to;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * from + to;
+ }
+ }
+
+ public final String className;
+ public final MethodNode methodNode;
+ public final int[][] transitions;
+ public final int edgeCount;
+ public final boolean[] errors;
+ public final Set<Edge> errorTransitions;
+
+ ControlFlowGraph(String className, MethodNode methodNode, int[][] transitions, int edgeCount, boolean[] errors, Set<Edge> errorTransitions) {
+ this.className = className;
+ this.methodNode = methodNode;
+ this.transitions = transitions;
+ this.edgeCount = edgeCount;
+ this.errors = errors;
+ this.errorTransitions = errorTransitions;
+ }
+
+ public static ControlFlowGraph build(String className, MethodNode methodNode, boolean jsr) throws AnalyzerException {
+ return jsr ? new ControlFlowBuilder(className, methodNode).buildCFG() : new LiteControlFlowBuilder(className, methodNode).buildCFG();
+ }
+}
+
+final class ControlFlowBuilder extends FramelessAnalyzer {
+ final String className;
+ final MethodNode methodNode;
+ final TIntArrayList[] transitions;
+ final Set<ControlFlowGraph.Edge> errorTransitions;
+ private final boolean[] errors;
+ private int edgeCount;
+
+ ControlFlowBuilder(String className, MethodNode methodNode) {
+ this.className = className;
+ this.methodNode = methodNode;
+ transitions = new TIntArrayList[methodNode.instructions.size()];
+ errors = new boolean[methodNode.instructions.size()];
+ for (int i = 0; i < transitions.length; i++) {
+ transitions[i] = new TIntArrayList();
+ }
+ errorTransitions = new HashSet<Edge>();
+ }
+
+ final ControlFlowGraph buildCFG() throws AnalyzerException {
+ if ((methodNode.access & (ACC_ABSTRACT | ACC_NATIVE)) == 0) {
+ analyze(methodNode);
+ }
+ int[][] resultTransitions = new int[transitions.length][];
+ for (int i = 0; i < resultTransitions.length; i++) {
+ resultTransitions[i] = transitions[i].toNativeArray();
+ }
+ return new ControlFlowGraph(className, methodNode, resultTransitions, edgeCount, errors, errorTransitions);
+ }
+
+ @Override
+ protected final void newControlFlowEdge(int insn, int successor) {
+ if (!transitions[insn].contains(successor)) {
+ transitions[insn].add(successor);
+ edgeCount++;
+ }
+ }
+
+ @Override
+ protected final boolean newControlFlowExceptionEdge(int insn, int successor) {
+ if (!transitions[insn].contains(successor)) {
+ transitions[insn].add(successor);
+ edgeCount++;
+ errorTransitions.add(new Edge(insn, successor));
+ errors[successor] = true;
+ }
+ return true;
+ }
+}
+
+final class LiteControlFlowBuilder extends LiteFramelessAnalyzer {
+ final String className;
+ final MethodNode methodNode;
+ final TIntArrayList[] transitions;
+ final Set<ControlFlowGraph.Edge> errorTransitions;
+ private final boolean[] errors;
+ private int edgeCount;
+
+ LiteControlFlowBuilder(String className, MethodNode methodNode) {
+ this.className = className;
+ this.methodNode = methodNode;
+ transitions = new TIntArrayList[methodNode.instructions.size()];
+ errors = new boolean[methodNode.instructions.size()];
+ for (int i = 0; i < transitions.length; i++) {
+ transitions[i] = new TIntArrayList();
+ }
+ errorTransitions = new HashSet<Edge>();
+ }
+
+ final ControlFlowGraph buildCFG() throws AnalyzerException {
+ if ((methodNode.access & (ACC_ABSTRACT | ACC_NATIVE)) == 0) {
+ analyze(methodNode);
+ }
+ int[][] resultTransitions = new int[transitions.length][];
+ for (int i = 0; i < resultTransitions.length; i++) {
+ resultTransitions[i] = transitions[i].toNativeArray();
+ }
+ return new ControlFlowGraph(className, methodNode, resultTransitions, edgeCount, errors, errorTransitions);
+ }
+
+ @Override
+ protected final void newControlFlowEdge(int insn, int successor) {
+ if (!transitions[insn].contains(successor)) {
+ transitions[insn].add(successor);
+ edgeCount++;
+ }
+ }
+
+ @Override
+ protected final boolean newControlFlowExceptionEdge(int insn, int successor) {
+ if (!transitions[insn].contains(successor)) {
+ transitions[insn].add(successor);
+ edgeCount++;
+ errorTransitions.add(new Edge(insn, successor));
+ errors[successor] = true;
+ }
+ return true;
+ }
+}
+