private StateQueue replicateStateSequence(StateQueue state) { HashMap<Long, State> stateMap = new HashMap<Long, State>(); replicateStateSequenceBranch(stateMap, state.head, state.head, state.last); State head = stateMap.get(state.head.name); StateQueue newQueue = new StateQueue(head); newQueue.last = stateMap.get(state.last.name); return newQueue; }
private void handleStepOutOfLoop( @NotNull final Instruction prevInstruction, @NotNull Instruction nextInstruction, @NotNull final int[] loopNumber, @NotNull MultiMap<BranchingInstruction, DfaMemoryState> processedStates, @NotNull MultiMap<BranchingInstruction, DfaMemoryState> incomingStates, @NotNull List<DfaInstructionState> inFlightStates, @NotNull DfaInstructionState[] afterStates, @NotNull StateQueue queue) { if (loopNumber[prevInstruction.getIndex()] == 0 || inSameLoop(prevInstruction, nextInstruction, loopNumber)) { return; } // stepped out of loop. destroy all memory states from the loop, we don't need them anymore // but do not touch yet states being handled right now for (DfaInstructionState state : inFlightStates) { Instruction instruction = state.getInstruction(); if (inSameLoop(prevInstruction, instruction, loopNumber)) { return; } } for (DfaInstructionState state : afterStates) { Instruction instruction = state.getInstruction(); if (inSameLoop(prevInstruction, instruction, loopNumber)) { return; } } // and still in queue if (!queue.processAll( new Processor<DfaInstructionState>() { @Override public boolean process(DfaInstructionState state) { Instruction instruction = state.getInstruction(); return !inSameLoop(prevInstruction, instruction, loopNumber); } })) return; // now remove obsolete memory states final Set<BranchingInstruction> mayRemoveStatesFor = new THashSet<BranchingInstruction>(); for (Instruction instruction : myInstructions) { if (inSameLoop(prevInstruction, instruction, loopNumber) && instruction instanceof BranchingInstruction) { mayRemoveStatesFor.add((BranchingInstruction) instruction); } } for (Instruction instruction : mayRemoveStatesFor) { processedStates.remove((BranchingInstruction) instruction); incomingStates.remove((BranchingInstruction) instruction); } }
public State iterate(SimpleNode root) throws ParseException { SimpleNode nodeChild = null; StateQueue cur = stateQueue.element(); if (cur == null) return null; for (int i = 0; i < root.jjtGetNumChildren(); i++) { nodeChild = (SimpleNode) root.jjtGetChild(i); if (nodeChild == null) continue; analysis(nodeChild); if (nodeChild.jjtGetNumChildren() > 0) { boolean isOR = nodeChild.toString().equals("OR"); if (isOR) { cur.orQueue.add(cur.last); cur.last.isFinal = true; // State newS = new State(); // cur.head.connect(newS, null, false); // stateQueue.addFirst(new StateQueue(newS)); stateQueue.addFirst(new StateQueue(cur.head)); } else { StateQueue sq = new StateQueue(cur.last); if (cur.toConnect.size() > 0) { sq.toConnect.addAll(cur.toConnect); cur.toConnect.clear(); } stateQueue.addFirst(sq); } cur.last = iterate(nodeChild); // if( cur.toConnect.size() > 0 ) // { // for(State s: cur.toConnect) // s.connect(cur.last, null, false); // // cur.toConnect.clear(); // } // if( isOR ) // { // cur.last.isFinal = true; // cur.orQueue.add(cur.last); // } StateQueue last = stateQueue.remove(); if (last != null) { if (last.orQueue.size() > 0) cur.toConnect.addAll(last.orQueue); if (last.toConnect.size() > 0) cur.toConnect.addAll(last.toConnect); } } } return cur.last; }
private void analysis(SimpleNode node) throws ParseException { if (node == null || node.jjtGetValue() == null) return; String name = node.toString(); StateQueue queue = stateQueue.element(); if (name.equals("Chars")) { // System.out.println(level + " Chars"); State s = new State(); _connectAll(queue, s, node.jjtGetValue().toString()); queue.last.connect(s, node.jjtGetValue().toString(), false); queue.last = s; } // else // if( name.equals("Expression") ) // { // State s = new State(); // // // // queue.last.connect(s, "aa", false); // queue.last = s; // } else if (name.equals("CharTypes")) { if (node.jjtGetValue().toString().equals(".")) { State s = new State(); _connectAll(queue, s, node.jjtGetValue().toString()); Connection nC = queue.last.connect(s, "<ANY>", false); nC.isAnyChar = true; queue.last = s; } else throw new ParseException("Invalid character received"); } else if (name.equals("Quantifier")) { // System.out.println(level + " Quantifier"); QuantifierState quantifier = (QuantifierState) node.jjtGetValue(); long start = -1; long end = -1; switch (quantifier.type) { case ZERO_OR_MORE: queue.head.connect(queue.last, null, true); queue.last.connect(queue.head, null, true); return; case ONE_OR_MORE: queue.last.connect(queue.head, null, true); return; case ZERO_OR_ONE: queue.head.connect(queue.last, null, true); return; case EXACTLY_X: if (quantifier.value != null && quantifier.value < 1L) throw new ParseException("Quantifier repetition cannot be zero"); start = quantifier.value; end = quantifier.value; break; case RANGED: if (quantifier.max != null && quantifier.max < 1L) throw new ParseException("Quantifier repetition cannot be zero"); if (quantifier.value > quantifier.max) throw new ParseException( "Quantifier minimum repetitions cannot be greater than max repetition"); start = quantifier.value; end = quantifier.max; break; } State newQueueLast = queue.last; ArrayList<State> ttttoConnect = new ArrayList<State>(); if (start == 0) ttttoConnect.add(queue.head); for (long i = 1; i < end; i++) { StateQueue newQueue = replicateStateSequence(queue); if (i >= start && i < end) ttttoConnect.add(newQueue.head); newQueueLast.connect(newQueue.head, null, false); newQueueLast = newQueue.last; } queue.last = newQueueLast; for (State s : ttttoConnect) { if (queue.last != null) s.connect(queue.last, null, true); } } }
@NotNull final RunnerResult analyzeMethod( @NotNull PsiElement psiBlock, @NotNull InstructionVisitor visitor, boolean ignoreAssertions, @NotNull Collection<DfaMemoryState> initialStates) { if (PsiTreeUtil.findChildOfType(psiBlock, OuterLanguageElement.class) != null) return RunnerResult.NOT_APPLICABLE; try { final ControlFlow flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, ignoreAssertions).buildControlFlow(); if (flow == null) return RunnerResult.NOT_APPLICABLE; int[] loopNumber = LoopAnalyzer.calcInLoop(flow); int endOffset = flow.getInstructionCount(); myInstructions = flow.getInstructions(); myNestedClosures.clear(); Set<Instruction> joinInstructions = ContainerUtil.newHashSet(); for (int index = 0; index < myInstructions.length; index++) { Instruction instruction = myInstructions[index]; if (instruction instanceof GotoInstruction) { joinInstructions.add(myInstructions[((GotoInstruction) instruction).getOffset()]); } else if (instruction instanceof ConditionalGotoInstruction) { joinInstructions.add( myInstructions[((ConditionalGotoInstruction) instruction).getOffset()]); } else if (instruction instanceof MethodCallInstruction && !((MethodCallInstruction) instruction).getContracts().isEmpty()) { joinInstructions.add(myInstructions[index + 1]); } } if (LOG.isDebugEnabled()) { LOG.debug("Analyzing code block: " + psiBlock.getText()); for (int i = 0; i < myInstructions.length; i++) { LOG.debug(i + ": " + myInstructions[i]); } } // for (int i = 0; i < myInstructions.length; i++) System.out.println(i + ": " + // myInstructions[i].toString()); Integer tooExpensiveHash = psiBlock.getUserData(TOO_EXPENSIVE_HASH); if (tooExpensiveHash != null && tooExpensiveHash == psiBlock.getText().hashCode()) { LOG.debug("Too complex because hasn't changed since being too complex already"); return RunnerResult.TOO_COMPLEX; } final StateQueue queue = new StateQueue(); for (final DfaMemoryState initialState : initialStates) { queue.offer(new DfaInstructionState(myInstructions[0], initialState)); } MultiMap<BranchingInstruction, DfaMemoryState> processedStates = MultiMap.createSet(); MultiMap<BranchingInstruction, DfaMemoryState> incomingStates = MultiMap.createSet(); long msLimit = shouldCheckTimeLimit() ? Registry.intValue("ide.dfa.time.limit.online") : Registry.intValue("ide.dfa.time.limit.offline"); WorkingTimeMeasurer measurer = new WorkingTimeMeasurer(msLimit * 1000 * 1000); int count = 0; while (!queue.isEmpty()) { List<DfaInstructionState> states = queue.getNextInstructionStates(joinInstructions); for (DfaInstructionState instructionState : states) { if (count++ % 1024 == 0 && measurer.isTimeOver()) { LOG.debug("Too complex because the analysis took too long"); psiBlock.putUserData(TOO_EXPENSIVE_HASH, psiBlock.getText().hashCode()); return RunnerResult.TOO_COMPLEX; } ProgressManager.checkCanceled(); if (LOG.isDebugEnabled()) { LOG.debug(instructionState.toString()); } // System.out.println(instructionState.toString()); Instruction instruction = instructionState.getInstruction(); if (instruction instanceof BranchingInstruction) { BranchingInstruction branching = (BranchingInstruction) instruction; Collection<DfaMemoryState> processed = processedStates.get(branching); if (processed.contains(instructionState.getMemoryState())) { continue; } if (processed.size() > MAX_STATES_PER_BRANCH) { LOG.debug("Too complex because too many different possible states"); return RunnerResult.TOO_COMPLEX; // Too complex :( } if (loopNumber[branching.getIndex()] != 0) { processedStates.putValue(branching, instructionState.getMemoryState().createCopy()); } } DfaInstructionState[] after = acceptInstruction(visitor, instructionState); for (DfaInstructionState state : after) { Instruction nextInstruction = state.getInstruction(); if (nextInstruction.getIndex() >= endOffset) { continue; } handleStepOutOfLoop( instruction, nextInstruction, loopNumber, processedStates, incomingStates, states, after, queue); if (nextInstruction instanceof BranchingInstruction) { BranchingInstruction branching = (BranchingInstruction) nextInstruction; if (processedStates.get(branching).contains(state.getMemoryState()) || incomingStates.get(branching).contains(state.getMemoryState())) { continue; } if (loopNumber[branching.getIndex()] != 0) { incomingStates.putValue(branching, state.getMemoryState().createCopy()); } } queue.offer(state); } } } psiBlock.putUserData(TOO_EXPENSIVE_HASH, null); LOG.debug("Analysis ok"); return RunnerResult.OK; } catch (ArrayIndexOutOfBoundsException e) { LOG.error(psiBlock.getText(), e); return RunnerResult.ABORTED; } catch (EmptyStackException e) { LOG.error(psiBlock.getText(), e); return RunnerResult.ABORTED; } }