diff options
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.java | 174 |
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; + } +} + |