Search in sources :

Example 16 with IntArrayList

use of com.intellij.util.containers.IntArrayList in project intellij-community by JetBrains.

the class LineWrapperTest method doTest.

private void doTest(String text, boolean atLineStart, double clipWidth, int... expectedBreaks) {
    IntArrayList actualBreaks = LineWrapper.calcBreakOffsets(text.toCharArray(), 0, text.length(), atLineStart, 0, clipWidth, myWidthProvider);
    assertArrayEquals(expectedBreaks, actualBreaks.toArray());
}
Also used : IntArrayList(com.intellij.util.containers.IntArrayList)

Example 17 with IntArrayList

use of com.intellij.util.containers.IntArrayList in project intellij-community by JetBrains.

the class ControlFlowUtil method internalDepthFirstSearch.

private static void internalDepthFirstSearch(final List<Instruction> instructions, final InstructionClientVisitor clientVisitor, int startOffset, int endOffset) {
    final WalkThroughStack walkThroughStack = new WalkThroughStack(instructions.size() / 2);
    walkThroughStack.push(startOffset);
    // we can change instruction internal state here (e.g. CallInstruction.stack)
    synchronized (instructions) {
        final IntArrayList currentProcedureReturnOffsets = new IntArrayList();
        ControlFlowInstructionVisitor getNextOffsetVisitor = new ControlFlowInstructionVisitor() {

            @Override
            public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) {
                instruction.execute(offset + 1);
                int newOffset = instruction.offset;
                // 'procedure' pointed by call instruction should be processed regardless of whether it was already visited or not
                // clear procedure text and return instructions aftewards
                int i;
                for (i = instruction.procBegin; i < clientVisitor.processedInstructions.length && (i < instruction.procEnd || i < instructions.size() && instructions.get(i) instanceof ReturnInstruction); i++) {
                    clientVisitor.processedInstructions[i] = false;
                }
                clientVisitor.procedureEntered(instruction.procBegin, i);
                walkThroughStack.push(offset, newOffset);
                walkThroughStack.push(newOffset);
                currentProcedureReturnOffsets.add(offset + 1);
            }

            @Override
            public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) {
                int newOffset = instruction.execute(false);
                if (newOffset != -1) {
                    walkThroughStack.push(offset, newOffset);
                    walkThroughStack.push(newOffset);
                }
            }

            @Override
            public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) {
                int newOffset = instruction.offset;
                walkThroughStack.push(offset, newOffset);
                walkThroughStack.push(newOffset);
            }

            @Override
            public void visitConditionalBranchingInstruction(ConditionalBranchingInstruction instruction, int offset, int nextOffset) {
                int newOffset = instruction.offset;
                walkThroughStack.push(offset, newOffset);
                walkThroughStack.push(offset, offset + 1);
                walkThroughStack.push(newOffset);
                walkThroughStack.push(offset + 1);
            }

            @Override
            public void visitInstruction(Instruction instruction, int offset, int nextOffset) {
                int newOffset = offset + 1;
                walkThroughStack.push(offset, newOffset);
                walkThroughStack.push(newOffset);
            }
        };
        while (!walkThroughStack.isEmpty()) {
            final int offset = walkThroughStack.peekOldOffset();
            final int newOffset = walkThroughStack.popNewOffset();
            if (offset >= endOffset) {
                continue;
            }
            Instruction instruction = instructions.get(offset);
            if (clientVisitor.processedInstructions[offset]) {
                if (newOffset != -1) {
                    instruction.accept(clientVisitor, offset, newOffset);
                }
                // when traversing call instruction, we have traversed all procedure control flows, so pop return address
                if (!currentProcedureReturnOffsets.isEmpty() && currentProcedureReturnOffsets.get(currentProcedureReturnOffsets.size() - 1) - 1 == offset) {
                    currentProcedureReturnOffsets.remove(currentProcedureReturnOffsets.size() - 1);
                }
                continue;
            }
            if (!currentProcedureReturnOffsets.isEmpty()) {
                int returnOffset = currentProcedureReturnOffsets.get(currentProcedureReturnOffsets.size() - 1);
                CallInstruction callInstruction = (CallInstruction) instructions.get(returnOffset - 1);
                // we should push back to 'return offset' stack
                synchronized (callInstruction.stack) {
                    if (callInstruction.procBegin <= offset && offset < callInstruction.procEnd + 2 && (callInstruction.stack.size() == 0 || callInstruction.stack.peekReturnOffset() != returnOffset)) {
                        callInstruction.stack.push(returnOffset, callInstruction);
                    }
                }
            }
            clientVisitor.processedInstructions[offset] = true;
            instruction.accept(getNextOffsetVisitor, offset, newOffset);
        }
    }
}
Also used : IntArrayList(com.intellij.util.containers.IntArrayList)

Example 18 with IntArrayList

use of com.intellij.util.containers.IntArrayList in project intellij-community by JetBrains.

the class ControlFlowUtil method hasObservableThrowExitPoints.

/**
   * Detect throw instructions which might affect observable control flow via side effects with local variables.
   *
   * The side effect of exception thrown occurs when a local variable is written in the try block, and then accessed
   * in the finally section or in/after a catch section.
   *
   * Example:
   * <pre>
   * { // --- start of theOuterBlock ---
   *   Status status = STARTED;
   *   try { // --- start of theTryBlock ---
   *     status = PREPARING;
   *     doPrepare(); // may throw exception
   *     status = WORKING;
   *     doWork(); // may throw exception
   *     status = FINISHED;
   *   } // --- end of theTryBlock ---
   *   catch (Exception e) {
   *      LOG.error("Failed when " + status, e); // can get PREPARING or WORKING here
   *   }
   *   if (status == FINISHED) LOG.info("Finished"); // can get PREPARING or WORKING here in the case of exception
   * } // --- end of theOuterBlock ---
   * </pre>
   * In the example above {@code hasObservableThrowExitPoints(theTryBlock) == true},
   * because the resulting value of the "status" variable depends on the exceptions being thrown.
   * In the same example {@code hasObservableThrowExitPoints(theOuterBlock) == false},
   * because no outgoing variables here depend on the exceptions being thrown.
   */
public static boolean hasObservableThrowExitPoints(@NotNull final ControlFlow flow, final int flowStart, final int flowEnd, @NotNull PsiElement[] elements, @NotNull PsiElement enclosingCodeFragment) {
    final List<Instruction> instructions = flow.getInstructions();
    class Worker {

        @NotNull
        private Map<PsiVariable, IntArrayList> getWritesOffsets() {
            final Map<PsiVariable, IntArrayList> writeOffsets = new THashMap<>();
            for (int i = flowStart; i < flowEnd; i++) {
                Instruction instruction = instructions.get(i);
                if (instruction instanceof WriteVariableInstruction) {
                    final PsiVariable variable = ((WriteVariableInstruction) instruction).variable;
                    if (variable instanceof PsiLocalVariable || variable instanceof PsiParameter) {
                        IntArrayList offsets = writeOffsets.get(variable);
                        if (offsets == null)
                            writeOffsets.put(variable, offsets = new IntArrayList());
                        offsets.add(i);
                    }
                }
            }
            LOG.debug("writeOffsets:", writeOffsets);
            return writeOffsets;
        }

        @NotNull
        private Map<PsiVariable, IntArrayList> getVisibleReadsOffsets(Map<PsiVariable, IntArrayList> writeOffsets, PsiCodeBlock tryBlock) {
            final Map<PsiVariable, IntArrayList> visibleReadOffsets = new THashMap<>();
            for (PsiVariable variable : writeOffsets.keySet()) {
                if (!PsiTreeUtil.isAncestor(tryBlock, variable, true)) {
                    visibleReadOffsets.put(variable, new IntArrayList());
                }
            }
            if (visibleReadOffsets.isEmpty())
                return visibleReadOffsets;
            for (int i = 0; i < instructions.size(); i++) {
                final Instruction instruction = instructions.get(i);
                if (instruction instanceof ReadVariableInstruction) {
                    final PsiVariable variable = ((ReadVariableInstruction) instruction).variable;
                    final IntArrayList readOffsets = visibleReadOffsets.get(variable);
                    if (readOffsets != null) {
                        readOffsets.add(i);
                    }
                }
            }
            LOG.debug("visibleReadOffsets:", visibleReadOffsets);
            return visibleReadOffsets;
        }

        @NotNull
        private Map<PsiVariable, Set<PsiElement>> getReachableAfterWrite(Map<PsiVariable, IntArrayList> writeOffsets, Map<PsiVariable, IntArrayList> visibleReadOffsets) {
            final Map<PsiVariable, Set<PsiElement>> afterWrite = new THashMap<>();
            for (PsiVariable variable : visibleReadOffsets.keySet()) {
                final Function<Integer, BitSet> calculator = getReachableInstructionsCalculator();
                final BitSet collectedOffsets = new BitSet(flowEnd);
                for (final int writeOffset : writeOffsets.get(variable).toArray()) {
                    LOG.assertTrue(writeOffset >= flowStart, "writeOffset");
                    final BitSet reachableOffsets = calculator.fun(writeOffset);
                    collectedOffsets.or(reachableOffsets);
                }
                Set<PsiElement> throwSources = afterWrite.get(variable);
                if (throwSources == null)
                    afterWrite.put(variable, throwSources = new THashSet<>());
                for (int i = flowStart; i < flowEnd; i++) {
                    if (collectedOffsets.get(i)) {
                        throwSources.add(flow.getElement(i));
                    }
                }
                final List<PsiElement> subordinates = new ArrayList<>();
                for (PsiElement element : throwSources) {
                    if (throwSources.contains(element.getParent())) {
                        subordinates.add(element);
                    }
                }
                throwSources.removeAll(subordinates);
            }
            LOG.debug("afterWrite:", afterWrite);
            return afterWrite;
        }

        @NotNull
        private IntArrayList getCatchOrFinallyOffsets(List<PsiTryStatement> tryStatements, List<PsiClassType> thrownExceptions) {
            final IntArrayList catchOrFinallyOffsets = new IntArrayList();
            for (PsiTryStatement tryStatement : tryStatements) {
                final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
                if (finallyBlock != null) {
                    int offset = flow.getStartOffset(finallyBlock);
                    if (offset >= 0) {
                        // -2 is an adjustment for rethrow-after-finally
                        catchOrFinallyOffsets.add(offset - 2);
                    }
                }
                for (PsiCatchSection catchSection : tryStatement.getCatchSections()) {
                    final PsiCodeBlock catchBlock = catchSection.getCatchBlock();
                    final PsiParameter parameter = catchSection.getParameter();
                    if (catchBlock != null && parameter != null) {
                        for (PsiClassType throwType : thrownExceptions) {
                            if (isCaughtExceptionType(throwType, parameter.getType())) {
                                int offset = flow.getStartOffset(catchBlock);
                                if (offset >= 0) {
                                    // -1 is an adjustment for catch block initialization
                                    catchOrFinallyOffsets.add(offset - 1);
                                }
                            }
                        }
                    }
                }
            }
            return catchOrFinallyOffsets;
        }

        private boolean isAnyReadOffsetReachableFrom(IntArrayList readOffsets, IntArrayList fromOffsets) {
            if (readOffsets != null && !readOffsets.isEmpty()) {
                final int[] readOffsetsArray = readOffsets.toArray();
                for (int j = 0; j < fromOffsets.size(); j++) {
                    int fromOffset = fromOffsets.get(j);
                    if (areInstructionsReachable(flow, readOffsetsArray, fromOffset)) {
                        LOG.debug("reachableFromOffset:", fromOffset);
                        return true;
                    }
                }
            }
            return false;
        }

        private Function<Integer, BitSet> getReachableInstructionsCalculator() {
            final ControlFlowGraph graph = new ControlFlowGraph(flow.getSize()) {

                @Override
                void addArc(int offset, int nextOffset) {
                    nextOffset = promoteThroughGotoChain(flow, nextOffset);
                    if (nextOffset >= flowStart && nextOffset < flowEnd) {
                        super.addArc(offset, nextOffset);
                    }
                }
            };
            graph.buildFrom(flow);
            return startOffset -> {
                BitSet visitedOffsets = new BitSet(flowEnd);
                graph.depthFirstSearch(startOffset, visitedOffsets);
                return visitedOffsets;
            };
        }
    }
    final Worker worker = new Worker();
    final Map<PsiVariable, IntArrayList> writeOffsets = worker.getWritesOffsets();
    if (writeOffsets.isEmpty())
        return false;
    final PsiElement commonParent = elements.length != 1 ? PsiTreeUtil.findCommonParent(elements) : elements[0].getParent();
    final List<PsiTryStatement> tryStatements = collectTryStatementStack(commonParent, enclosingCodeFragment);
    if (tryStatements.isEmpty())
        return false;
    final PsiCodeBlock tryBlock = tryStatements.get(0).getTryBlock();
    if (tryBlock == null)
        return false;
    final Map<PsiVariable, IntArrayList> visibleReadOffsets = worker.getVisibleReadsOffsets(writeOffsets, tryBlock);
    if (visibleReadOffsets.isEmpty())
        return false;
    final Map<PsiVariable, Set<PsiElement>> afterWrite = worker.getReachableAfterWrite(writeOffsets, visibleReadOffsets);
    if (afterWrite.isEmpty())
        return false;
    for (Map.Entry<PsiVariable, Set<PsiElement>> entry : afterWrite.entrySet()) {
        final PsiVariable variable = entry.getKey();
        final PsiElement[] psiElements = entry.getValue().toArray(PsiElement.EMPTY_ARRAY);
        final List<PsiClassType> thrownExceptions = ExceptionUtil.getThrownExceptions(psiElements);
        if (!thrownExceptions.isEmpty()) {
            final IntArrayList catchOrFinallyOffsets = worker.getCatchOrFinallyOffsets(tryStatements, thrownExceptions);
            if (worker.isAnyReadOffsetReachableFrom(visibleReadOffsets.get(variable), catchOrFinallyOffsets)) {
                return true;
            }
        }
    }
    return false;
}
Also used : TIntHashSet(gnu.trove.TIntHashSet) java.util(java.util) ArrayUtil(com.intellij.util.ArrayUtil) ReflectionUtil(com.intellij.util.ReflectionUtil) IncorrectOperationException(com.intellij.util.IncorrectOperationException) THashSet(gnu.trove.THashSet) DummyHolder(com.intellij.psi.impl.source.DummyHolder) THashMap(gnu.trove.THashMap) IntArrayList(com.intellij.util.containers.IntArrayList) Nullable(org.jetbrains.annotations.Nullable) PsiTreeUtil(com.intellij.psi.util.PsiTreeUtil) Function(com.intellij.util.Function) IntStack(com.intellij.util.containers.IntStack) PsiUtil(com.intellij.psi.util.PsiUtil) com.intellij.psi(com.intellij.psi) ExceptionUtil(com.intellij.codeInsight.ExceptionUtil) Logger(com.intellij.openapi.diagnostic.Logger) NotNull(org.jetbrains.annotations.NotNull) TIntHashSet(gnu.trove.TIntHashSet) THashSet(gnu.trove.THashSet) IntArrayList(com.intellij.util.containers.IntArrayList) THashMap(gnu.trove.THashMap) IntArrayList(com.intellij.util.containers.IntArrayList) IntArrayList(com.intellij.util.containers.IntArrayList) THashMap(gnu.trove.THashMap)

Example 19 with IntArrayList

use of com.intellij.util.containers.IntArrayList in project intellij-community by JetBrains.

the class TextPainter method drawString.

private boolean drawString(Graphics2D g, char[] text, int end, boolean lineStart, Point2D position, Rectangle2D clip, Color backColor, Color underscoredColor) {
    boolean toContinue = true;
    if (end >= mySegmentEnd) {
        end = mySegmentEnd;
        toContinue = false;
    }
    if (myOffset >= end)
        return toContinue;
    boolean isInClip = (getLineHeight(g) + position.getY() >= clip.getY()) && (position.getY() <= clip.getY() + clip.getHeight());
    if (!isInClip)
        return toContinue;
    if (myPrintSettings.WRAP) {
        double w = getTextSegmentWidth(text, myOffset, end - myOffset, position.getX(), g);
        if (position.getX() + w > clip.getWidth()) {
            IntArrayList breakOffsets = LineWrapper.calcBreakOffsets(text, myOffset, end, lineStart, position.getX(), clip.getWidth(), (t, start, count, x) -> getTextSegmentWidth(t, start, count, x, g));
            for (int i = 0; i < breakOffsets.size(); i++) {
                int breakOffset = breakOffsets.get(i);
                drawTabbedString(g, text, breakOffset - myOffset, position, backColor, underscoredColor);
                position.setLocation(0, position.getY() + getLineHeight(g));
                if (position.getY() > clip.getY() + clip.getHeight() - getLineHeight(g)) {
                    return false;
                }
            }
        }
    }
    drawTabbedString(g, text, end - myOffset, position, backColor, underscoredColor);
    return toContinue;
}
Also used : IntArrayList(com.intellij.util.containers.IntArrayList)

Example 20 with IntArrayList

use of com.intellij.util.containers.IntArrayList in project intellij-community by JetBrains.

the class TerminalBlock method findExitPoints.

Collection<PsiStatement> findExitPoints(ControlFlow controlFlow) {
    int startOffset = controlFlow.getStartOffset(myStatements[0]);
    int endOffset = controlFlow.getEndOffset(myStatements[myStatements.length - 1]);
    if (startOffset < 0 || endOffset < 0)
        return null;
    return ControlFlowUtil.findExitPointsAndStatements(controlFlow, startOffset, endOffset, new IntArrayList(), PsiContinueStatement.class, PsiBreakStatement.class, PsiReturnStatement.class, PsiThrowStatement.class);
}
Also used : IntArrayList(com.intellij.util.containers.IntArrayList)

Aggregations

IntArrayList (com.intellij.util.containers.IntArrayList)31 ArrayList (java.util.ArrayList)5 PsiFile (com.intellij.psi.PsiFile)3 NotNull (org.jetbrains.annotations.NotNull)3 TextRange (com.intellij.openapi.util.TextRange)2 Nullable (org.jetbrains.annotations.Nullable)2 ExceptionUtil (com.intellij.codeInsight.ExceptionUtil)1 RadComponent (com.intellij.designer.model.RadComponent)1 LighterASTNode (com.intellij.lang.LighterASTNode)1 Logger (com.intellij.openapi.diagnostic.Logger)1 RangeMarker (com.intellij.openapi.editor.RangeMarker)1 Project (com.intellij.openapi.project.Project)1 com.intellij.psi (com.intellij.psi)1 PsiCodeBlock (com.intellij.psi.PsiCodeBlock)1 PsiElement (com.intellij.psi.PsiElement)1 PsiJavaFile (com.intellij.psi.PsiJavaFile)1 DummyHolder (com.intellij.psi.impl.source.DummyHolder)1 MethodSignature (com.intellij.psi.util.MethodSignature)1 PsiTreeUtil (com.intellij.psi.util.PsiTreeUtil)1 PsiUtil (com.intellij.psi.util.PsiUtil)1