Beispiel #1
0
  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);
    }
  }
Beispiel #3
0
  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;
  }
Beispiel #4
0
  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;
    }
  }