ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / dataFlow / DataFlowRunner.java
blobdcff2bfdee15fc1526f4e5f225181076db4bbad0
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Created by IntelliJ IDEA.
19 * User: max
20 * Date: Jan 28, 2002
21 * Time: 10:16:39 PM
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com.intellij.codeInspection.dataFlow;
27 import com.intellij.codeInspection.dataFlow.instructions.BranchingInstruction;
28 import com.intellij.codeInspection.dataFlow.instructions.Instruction;
29 import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
30 import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
31 import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
32 import com.intellij.openapi.application.ApplicationManager;
33 import com.intellij.openapi.diagnostic.Logger;
34 import com.intellij.openapi.progress.ProgressManager;
35 import com.intellij.openapi.util.Pair;
36 import com.intellij.psi.*;
37 import gnu.trove.THashSet;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
41 import java.util.*;
43 public class DataFlowRunner {
44 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowRunner");
45 private static final long ourTimeLimit = 10000;
47 private Instruction[] myInstructions;
48 private DfaVariableValue[] myFields;
49 private final DfaValueFactory myValueFactory = new DfaValueFactory();
51 // Maximum allowed attempts to process instruction. Fail as too complex to process if certain instruction
52 // is executed more than this limit times.
53 public static final int MAX_STATES_PER_BRANCH = 300;
55 public Instruction getInstruction(int index) {
56 return myInstructions[index];
59 protected DataFlowRunner() {
62 public DfaValueFactory getFactory() {
63 return myValueFactory;
66 @Nullable
67 protected Collection<DfaMemoryState> createInitialStates(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
68 if (psiBlock.getParent() instanceof PsiMethod) {
69 final PsiClass containingClass = ((PsiMethod)psiBlock.getParent()).getContainingClass();
70 if (containingClass instanceof PsiAnonymousClass) {
71 final PsiElement newExpression = containingClass.getParent();
72 final PsiCodeBlock block = DfaUtil.getTopmostBlockInSameClass(newExpression);
73 if (newExpression instanceof PsiNewExpression && block != null) {
74 final EnvironmentalInstructionVisitor envVisitor = new EnvironmentalInstructionVisitor(visitor, (PsiNewExpression)newExpression);
75 final RunnerResult result = analyzeMethod(block, envVisitor);
76 if (result == RunnerResult.OK) {
77 final Collection<DfaMemoryState> closureStates = envVisitor.getClosureStates();
78 if (!closureStates.isEmpty()) {
79 return closureStates;
82 return null;
88 return Arrays.asList(createMemoryState());
91 public final RunnerResult analyzeMethod(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
92 try {
93 final Collection<DfaMemoryState> initialStates = createInitialStates(psiBlock, visitor);
94 if (initialStates == null) return RunnerResult.NOT_APPLICABLE;
96 final ControlFlow flow = createControlFlowAnalyzer().buildControlFlow(psiBlock);
97 if (flow == null) return RunnerResult.NOT_APPLICABLE;
99 int endOffset = flow.getInstructionCount();
100 myInstructions = flow.getInstructions();
101 myFields = flow.getFields();
103 if (LOG.isDebugEnabled()) {
104 for (int i = 0; i < myInstructions.length; i++) {
105 Instruction instruction = myInstructions[i];
106 LOG.debug(i + ": " + instruction.toString());
110 int branchCount = 0;
111 for (Instruction instruction : myInstructions) {
112 if (instruction instanceof BranchingInstruction) branchCount++;
115 if (branchCount > 80) return RunnerResult.TOO_COMPLEX; // Do not even try. Definitely will out of time.
117 final ArrayList<DfaInstructionState> queue = new ArrayList<DfaInstructionState>();
118 for (final DfaMemoryState initialState : initialStates) {
119 queue.add(new DfaInstructionState(myInstructions[0], initialState));
122 long timeLimit = ourTimeLimit;
123 final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode();
124 final long before = System.currentTimeMillis();
125 while (!queue.isEmpty()) {
126 if (!unitTestMode && System.currentTimeMillis() - before > timeLimit) return RunnerResult.TOO_COMPLEX;
127 ProgressManager.checkCanceled();
129 DfaInstructionState instructionState = queue.remove(0);
130 if (LOG.isDebugEnabled()) {
131 LOG.debug(instructionState.toString());
134 Instruction instruction = instructionState.getInstruction();
135 long distance = instructionState.getDistanceFromStart();
137 if (instruction instanceof BranchingInstruction) {
138 if (!instruction.setMemoryStateProcessed(instructionState.getMemoryState().createCopy())) {
139 return RunnerResult.TOO_COMPLEX; // Too complex :(
143 DfaInstructionState[] after = instruction.accept(this, instructionState.getMemoryState(), visitor);
144 if (after != null) {
145 for (DfaInstructionState state : after) {
146 Instruction nextInstruction = state.getInstruction();
147 if ((!(nextInstruction instanceof BranchingInstruction) || !nextInstruction.isMemoryStateProcessed(state.getMemoryState())) && instruction.getIndex() < endOffset) {
148 state.setDistanceFromStart(distance + 1);
149 queue.add(state);
155 return RunnerResult.OK;
157 catch (ArrayIndexOutOfBoundsException e) {
158 LOG.error(psiBlock.getText(), e); /* TODO[max] !!! hack (of 18186). Please fix in better times. */
159 return RunnerResult.ABORTED;
161 catch (EmptyStackException e) /* TODO[max] !!! hack (of 18186). Please fix in better times. */ {
162 return RunnerResult.ABORTED;
166 protected ControlFlowAnalyzer createControlFlowAnalyzer() {
167 return new ControlFlowAnalyzer(myValueFactory);
170 protected DfaMemoryState createMemoryState() {
171 return new DfaMemoryStateImpl(myValueFactory);
174 public Instruction[] getInstructions() {
175 return myInstructions;
178 public DfaVariableValue[] getFields() {
179 return myFields;
182 public Pair<Set<Instruction>,Set<Instruction>> getConstConditionalExpressions() {
183 Set<Instruction> trueSet = new HashSet<Instruction>();
184 Set<Instruction> falseSet = new HashSet<Instruction>();
186 for (Instruction instruction : myInstructions) {
187 if (instruction instanceof BranchingInstruction) {
188 BranchingInstruction branchingInstruction = (BranchingInstruction)instruction;
189 if (branchingInstruction.getPsiAnchor() != null && branchingInstruction.isConditionConst()) {
190 if (!branchingInstruction.isTrueReachable()) {
191 falseSet.add(branchingInstruction);
194 if (!branchingInstruction.isFalseReachable()) {
195 trueSet.add(branchingInstruction);
201 for (Instruction instruction : myInstructions) {
202 if (instruction instanceof BranchingInstruction) {
203 BranchingInstruction branchingInstruction = (BranchingInstruction)instruction;
204 if (branchingInstruction.isTrueReachable()) {
205 falseSet.remove(branchingInstruction);
207 if (branchingInstruction.isFalseReachable()) {
208 trueSet.remove(branchingInstruction);
213 return Pair.create(trueSet, falseSet);
216 private static class EnvironmentalInstructionVisitor extends DelegatingInstructionVisitor {
217 private final PsiNewExpression myNewExpression;
218 private final Set<DfaMemoryState> myClosureStates = new THashSet<DfaMemoryState>();
220 public EnvironmentalInstructionVisitor(@NotNull InstructionVisitor delegate, @NotNull PsiNewExpression newExpression) {
221 super(delegate);
222 myNewExpression = newExpression;
225 @Override
226 public DfaInstructionState[] visitMethodCall(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
227 if (myNewExpression == instruction.getCallExpression()) {
228 myClosureStates.add(memState.createCopy());
230 return super.visitMethodCall(instruction, runner, memState);
233 @NotNull
234 public Collection<DfaMemoryState> getClosureStates() {
235 return myClosureStates;