RunnerResult (@NotNull List<? extends DfaInstructionState> startingStates) { int endOffset = myFlow.getInstructionCount(); DfaInstructionState lastInstructionState = null; myNestedClosures.clear(); myWasForciblyMerged = false; myValueFactory.setContext(myPsiAnchor); final StateQueue queue = new StateQueue(); for (DfaInstructionState state : startingStates) { queue.offer(state); } MultiMap<Instruction, DfaMemoryState> processedStates = MultiMap.createSet(); MultiMap<Instruction, DfaMemoryState> incomingStates = MultiMap.createSet(); try { Set<Instruction> joinInstructions = getJoinInstructions(); int[] loopNumber = myFlow.getLoopNumbers(); int stateLimit = Registry.intValue("ide.dfa.state.limit"); int count = 0; while (!queue.isEmpty()) { List<DfaInstructionState> states = queue.getNextInstructionStates(joinInstructions); if (states.size() > getComplexityLimit()) { LOG.trace("Too complex because too many different possible states"); return RunnerResult.TOO_COMPLEX; } assert !states.isEmpty(); Instruction instruction = states.get(0).getInstruction(); beforeInstruction(instruction); for (DfaInstructionState instructionState : states) { lastInstructionState = instructionState; if (count++ > stateLimit) { LOG.trace("Too complex data flow: too many instruction states processed"); return RunnerResult.TOO_COMPLEX; } ProgressManager.checkCanceled(); if (LOG.isTraceEnabled()) { LOG.trace(instructionState.toString()); } if (!instruction.isLinear()) { Collection<DfaMemoryState> processed = processedStates.get(instruction); if (containsState(processed, instructionState)) { continue; } if (processed.size() > getComplexityLimit() / 6) { instructionState = mergeBackBranches(instructionState, processed); if (containsState(processed, instructionState)) { continue; } } if (processed.size() > getComplexityLimit()) { LOG.trace("Too complex because too many different possible states"); return RunnerResult.TOO_COMPLEX; } if (loopNumber[instruction.getIndex()] != 0) { processedStates.putValue(instruction, instructionState.getMemoryState().createCopy()); } } DfaInstructionState[] after = acceptInstruction(instructionState); if (LOG.isDebugEnabled() && instruction instanceof ControlTransferInstruction && after.length == 0) { DfaMemoryState memoryState = instructionState.getMemoryState(); if (!memoryState.isEmptyStack()) { // can pop safely as this memory state is unnecessary anymore (after is empty) DfaValue topValue = memoryState.pop(); if (!(topValue instanceof DfaControlTransferValue || myPsiAnchor instanceof PsiCodeFragment && memoryState.isEmptyStack())) { // push back so error report includes this entry memoryState.push(topValue); reportDfaProblem(instructionState, new RuntimeException("Stack is corrupted")); } } } for (DfaInstructionState state : after) { Instruction nextInstruction = state.getInstruction(); if (nextInstruction.getIndex() >= endOffset) { continue; } handleStepOutOfLoop(instruction, nextInstruction, loopNumber, processedStates, incomingStates, states, after, queue); if (!nextInstruction.isLinear()) { if (containsState(processedStates.get(nextInstruction), state) || containsState(incomingStates.get(nextInstruction), state)) { continue; } if (loopNumber[nextInstruction.getIndex()] != 0) { incomingStates.putValue(nextInstruction, state.getMemoryState().createCopy()); } } if (nextInstruction.getIndex() < instruction.getIndex() && (!(instruction instanceof GotoInstruction) || ((GotoInstruction)instruction).shouldWidenBackBranch())) { state.getMemoryState().widen(); } queue.offer(state); } } afterInstruction(instruction); if (myCancelled) { return RunnerResult.CANCELLED; } } myWasForciblyMerged |= queue.wasForciblyMerged(); return RunnerResult.OK; } catch (ProcessCanceledException ex) { throw ex; } catch (RuntimeException | AssertionError e) { reportDfaProblem(lastInstructionState, e); return RunnerResult.ABORTED; } }