diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index 2fd3cc405bdd..b494e8eded30 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -23,13 +23,13 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.containers.IntArrayList; import com.intellij.util.containers.Queue; +import com.intellij.util.containers.Stack; +import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author max @@ -64,67 +64,71 @@ public class DefUseUtil { } } - private static class InstructionState { - private Set myVariablesUseArmed; - private final int myInstructionIdx; - private final IntArrayList myBackwardTraces; + private static class InstructionState implements Comparable { + private Set myUsed; + private final InstructionKey myInstructionKey; + private final List myBackwardTraces; private boolean myIsVisited; - public InstructionState(int instructionIdx) { - myInstructionIdx = instructionIdx; - myBackwardTraces = new IntArrayList(); - myVariablesUseArmed = null; + public InstructionState(@NotNull InstructionKey instructionKey) { + myInstructionKey = instructionKey; + myBackwardTraces = new ArrayList(2); + myUsed = null; } - public void addBackwardTrace(int i) { - myBackwardTraces.add(i); + public void addBackwardTrace(InstructionKey key) { + myBackwardTraces.add(key); } - public IntArrayList getBackwardTraces() { + public List getBackwardTraces() { return myBackwardTraces; } - public int getInstructionIdx() { - return myInstructionIdx; + public InstructionKey getInstructionKey() { + return myInstructionKey; } - void mergeUseArmed(PsiVariable psiVariable) { + void addUsed(PsiVariable psiVariable) { touch(); - myVariablesUseArmed.add(psiVariable); + myUsed.add(psiVariable); } - boolean mergeUseDisarmed(PsiVariable psiVariable) { + boolean removeUsed(PsiVariable psiVariable) { touch(); - - boolean result = myVariablesUseArmed.contains(psiVariable); - myVariablesUseArmed.remove(psiVariable); - - return result; + return myUsed.remove(psiVariable); } private void touch() { - if (myVariablesUseArmed == null) myVariablesUseArmed = new THashSet(); + if (myUsed == null) myUsed = new THashSet(); } - public void merge(InstructionState state) { + public void addUsedFrom(InstructionState state) { touch(); - myVariablesUseArmed.addAll(state.myVariablesUseArmed); + myUsed.addAll(state.myUsed); } public boolean contains(InstructionState state) { - return myVariablesUseArmed != null && state.myVariablesUseArmed != null && - myVariablesUseArmed.containsAll(state.myVariablesUseArmed); + return myUsed != null && state.myUsed != null && + myUsed.containsAll(state.myUsed); } - public boolean markVisited() { - boolean old = myIsVisited; + public void markVisited() { myIsVisited = true; - return old; } public boolean isVisited() { return myIsVisited; } + + @Override + public int compareTo(@NotNull InstructionState other) { + return myInstructionKey.compareTo(other.myInstructionKey); + } + + @Override + public String toString() { + return myInstructionKey + " " + myBackwardTraces + (myIsVisited ? "(v)" : "(n)") + " " + (myUsed != null ? myUsed : "-"); + } } @Nullable @@ -165,9 +169,11 @@ public class DefUseUtil { } } - InstructionState[] states = getStates(instructions); + Map stateMap = getStates(instructions); + InstructionState[] states = stateMap.values().toArray(new InstructionState[0]); + Arrays.sort(states); - boolean[] defsArmed = new boolean[instructions.size()]; + BitSet usefulWrites = new BitSet(instructions.size()); Queue queue = new Queue(8); @@ -178,7 +184,7 @@ public class DefUseUtil { for (PsiVariable psiVariable : assignedVariables) { if (psiVariable instanceof PsiField) { - outerState.mergeUseArmed(psiVariable); + outerState.addUsed(psiVariable); } } queue.addLast(outerState); @@ -188,21 +194,21 @@ public class DefUseUtil { InstructionState state = queue.pullFirst(); state.markVisited(); - int idx = state.getInstructionIdx(); - if (idx < instructions.size()) { - Instruction instruction = instructions.get(idx); + InstructionKey key = state.getInstructionKey(); + if (key.getOffset() < instructions.size()) { + Instruction instruction = instructions.get(key.getOffset()); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; PsiVariable psiVariable = writeInstruction.variable; outUsedVariables.add(psiVariable); - if (state.mergeUseDisarmed(psiVariable)) { - defsArmed[idx] = true; + if (state.removeUsed(psiVariable)) { + usefulWrites.set(key.getOffset()); } } else if (instruction instanceof ReadVariableInstruction) { ReadVariableInstruction readInstruction = (ReadVariableInstruction)instruction; - state.mergeUseArmed(readInstruction.variable); + state.addUsed(readInstruction.variable); outUsedVariables.add(readInstruction.variable); } else { @@ -210,12 +216,11 @@ public class DefUseUtil { } } - IntArrayList backwardTraces = state.getBackwardTraces(); - for (int j = 0; j < backwardTraces.size(); j++) { - int prevIdx = backwardTraces.get(j); - InstructionState prevState = states[prevIdx]; - if (!prevState.contains(state)) { - prevState.merge(state); + List backwardTraces = state.getBackwardTraces(); + for (InstructionKey prevKeys : backwardTraces) { + InstructionState prevState = stateMap.get(prevKeys); + if (prevState != null && !prevState.contains(state)) { + prevState.addUsedFrom(state); queue.addLast(prevState); } } @@ -228,7 +233,7 @@ public class DefUseUtil { Instruction instruction = instructions.get(i); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; - if (!defsArmed[i]) { + if (!usefulWrites.get(i)) { PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i), PsiStatement.class, PsiAssignmentExpression.class, PsiPostfixExpression.class, PsiPrefixExpression.class); @@ -254,16 +259,16 @@ public class DefUseUtil { public static PsiElement[] getDefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) { try { RefsDefs refsDefs = new RefsDefs(body) { - private final InstructionState[] states = getStates(instructions); + private final IntArrayList[] myBackwardTraces = getBackwardTraces(instructions); @Override protected int nNext(int index) { - return states[index].getBackwardTraces().size(); + return myBackwardTraces[index].size(); } @Override protected int getNext(int index, int no) { - return states[index].getBackwardTraces().get(no); + return myBackwardTraces[index].get(no); } @Override @@ -407,7 +412,7 @@ public class DefUseUtil { } } - // hack: ControlFlow doesnn't contains parameters initialization + // hack: ControlFlow doesn't contains parameters initialization if (index == 0 && def instanceof PsiParameter) { res.add(def.getNameIdentifier()); } @@ -442,10 +447,10 @@ public class DefUseUtil { } - private static InstructionState[] getStates(final List instructions) { - final InstructionState[] states = new InstructionState[instructions.size()]; + private static IntArrayList[] getBackwardTraces(final List instructions) { + final IntArrayList[] states = new IntArrayList[instructions.size()]; for (int i = 0; i < states.length; i++) { - states[i] = new InstructionState(i); + states[i] = new IntArrayList(); } for (int i = 0; i < instructions.size(); i++) { @@ -453,13 +458,106 @@ public class DefUseUtil { for (int j = 0; j != instruction.nNext(); ++ j) { final int next = instruction.getNext(i, j); if (next < states.length) { - states[next].addBackwardTrace(i); + states[next].add(i); } } } return states; } + private static Map getStates(final List instructions) { + class WalkThroughStack { + private final com.intellij.util.containers.Stack myFrom; + private final com.intellij.util.containers.Stack myNext; + + WalkThroughStack(int size) { + if (size < 2) size = 2; + myFrom = new Stack(size); + myNext = new Stack(size); + } + + void push(InstructionKey fromKey, InstructionKey nextKey) { + myFrom.push(fromKey); + myNext.push(nextKey); + } + + InstructionKey peekFrom() { + return myFrom.peek(); + } + + InstructionKey popNext() { + myFrom.pop(); + return myNext.pop(); + } + + boolean isEmpty() { + return myFrom.isEmpty(); + } + } + + class Walker { + private final Map myStates; + private final WalkThroughStack myWalkThroughStack; + + Walker() { + myStates = new THashMap(instructions.size()); + myWalkThroughStack = new WalkThroughStack(instructions.size() / 2); + } + + Map walk() { + InstructionKey startKey = InstructionKey.create(0); + myStates.put(startKey, new InstructionState(startKey)); + myWalkThroughStack.push(InstructionKey.create(-1), startKey); + + Set visited = new THashSet(instructions.size()); + while (!myWalkThroughStack.isEmpty()) { + InstructionKey fromKey = myWalkThroughStack.peekFrom(); + InstructionKey nextKey = myWalkThroughStack.popNext(); + addBackwardTrace(fromKey, nextKey); + if (!visited.contains(nextKey)) { + visit(nextKey); + visited.add(nextKey); + } + } + return myStates; + } + + private void visit(InstructionKey fromKey) { + if (fromKey.getOffset() >= instructions.size()) return; + final Instruction instruction = instructions.get(fromKey.getOffset()); + if (instruction instanceof CallInstruction) { + int nextOffset = ((CallInstruction)instruction).offset; + LOG.assertTrue(nextOffset != 0); + int returnOffset = fromKey.getOffset() + 1; + InstructionKey nextKey = fromKey.push(nextOffset, returnOffset); + myWalkThroughStack.push(fromKey, nextKey); + } + else if (instruction instanceof ReturnInstruction) { + int overriddenOffset = ((ReturnInstruction)instruction).offset; + InstructionKey nextKey = fromKey.pop(overriddenOffset); + myWalkThroughStack.push(fromKey, nextKey); + } + else { + for (int no = 0; no != instruction.nNext(); no++) { + final int nextOffset = instruction.getNext(fromKey.getOffset(), no); + InstructionKey nextKey = fromKey.next(nextOffset); + myWalkThroughStack.push(fromKey, nextKey); + } + } + } + + private void addBackwardTrace(InstructionKey fromKey, InstructionKey nextKey) { + if (fromKey.getOffset() >= 0 && nextKey.getOffset() < instructions.size()) { + InstructionState state = myStates.get(nextKey); + if (state == null) myStates.put(nextKey, state = new InstructionState(nextKey)); + state.addBackwardTrace(fromKey); + } + } + } + + return new Walker().walk(); + } + private static final ControlFlowPolicy ourPolicy = new ControlFlowPolicy() { @Override public PsiVariable getUsedVariable(@NotNull PsiReferenceExpression refExpr) { diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java new file mode 100644 index 000000000000..283e9dc182e1 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.controlFlow; + +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * @author Pavel.Dolgov + */ +class InstructionKey implements Comparable { + private final int myOffset; + private final int[] myCallStack; // shared between instructions on the same stack level + + private InstructionKey(int offset, @NotNull int[] callStack) { + myOffset = offset; + myCallStack = callStack; + } + + @NotNull + static InstructionKey create(int offset) { + return new InstructionKey(offset, ArrayUtil.EMPTY_INT_ARRAY); + } + + InstructionKey next(int nextOffset) { + return new InstructionKey(nextOffset, myCallStack); + } + + InstructionKey push(int nextOffset, int returnOffset) { + int[] nextStack = ArrayUtil.append(myCallStack, returnOffset); + return new InstructionKey(nextOffset, nextStack); + } + + InstructionKey pop(int overriddenOffset) { + int returnOffset = myCallStack[myCallStack.length - 1]; + int[] nextStack = ArrayUtil.realloc(myCallStack, myCallStack.length - 1); + int nextOffset = overriddenOffset != 0 ? overriddenOffset : returnOffset; + return new InstructionKey(nextOffset, nextStack); + } + + int getOffset() { + return myOffset; + } + + int[] getCallStack() { + return myCallStack; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InstructionKey key = (InstructionKey)o; + + if (myOffset != key.myOffset) return false; + if (!Arrays.equals(myCallStack, key.myCallStack)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myOffset; + result = 31 * result + Arrays.hashCode(myCallStack); + return result; + } + + @Override + public String toString() { + if (myCallStack.length == 0) { + return String.valueOf(myOffset); + } + StringBuilder s = new StringBuilder(); + for (int offset : myCallStack) { + if (s.length() != 0) s.append(','); + s.append(offset); + } + return myOffset + "(" + s + ")"; + } + + @Override + public int compareTo(@NotNull InstructionKey key) { + int c = myOffset - key.myOffset; + if (c != 0) return c; + for (int i = 0, len = Math.min(myCallStack.length, key.myCallStack.length); i < len; i++) { + c = myCallStack[i] - key.myCallStack[i]; + if (c != 0) return c; + } + c = myCallStack.length - key.myCallStack.length; + return c; + } +} diff --git a/java/java-tests/testData/inspection/defUse/ComplexDoubleTryFinally.java b/java/java-tests/testData/inspection/defUse/ComplexDoubleTryFinally.java new file mode 100644 index 000000000000..90f3e92fb45a --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/ComplexDoubleTryFinally.java @@ -0,0 +1,307 @@ +import java.io.File; +import java.io.IOException; +import java.util.*; + +class Z { + private float f1; + private float f2; + + private static class R { + public static final R N = new R(); + } + + private static class J { + } + + private static class E { + public static final E E1 = new E(); + public static final E E2 = new E(); + public static final E E3 = new E(); + public static final E E4 = new E(); + } + + private static class G { + public static final G G1 = new G(); + + public static G[] gs() { + return new G[]{new G()}; + } + } + + private static class C { + public void c() { + } + + public D d() { + return new D(); + } + } + + private static class B { + public B(C c) { + } + + public int n() { + return 0; + } + + public void c() { + } + + public void f() { + } + } + + private static class L { + public void s(C c, M m) { + } + + public E b(C c, M m, H h, B b) { + return new E(); + } + + public String s() { + return ""; + } + + public void f(C c, M m) { + } + } + + private static class Q { + + } + + private static class N { + } + + + private static class H { + public void p(Q q) throws IOException { + } + } + + private static class HB extends H { + public HB(C c) { + } + } + + private static class T { + public int s() { + return 0; + } + } + + private static class M { + + public T t() { + return new T(); + } + + public List ns() { + return new ArrayList(); + } + + public String s() { + return ""; + } + } + + private static class F { + public void b(C c, M m) { + } + + public void c(C c) { + } + } + + private static class S { + public void s(String s, List ls) { + } + } + + + private static class DM { + public S s(N n) { + return new S(); + } + } + + private static class D { + public F f = new F(); + public DM dm; + } + + private D d = new D(); + + private static class K { + public List ls(G g) { + return new ArrayList(); + } + } + + private K k = new K(); + + private static class Ex extends Exception { + public Ex(String s) { + super(s); + } + + public Ex(Exception e) { + super(e); + } + } + + + private boolean foo(final C c, final M m) throws Ex, IOException { + for (G g : G.gs()) { + for (L l : k.ls(g)) { + l.s(c, m); + } + } + + boolean b1 = false; + boolean b2 = false; + float c1 = f1; + final int s = m.t().s(); + int p = 0; + boolean b3; + B b = new B(c); + try { + do { + b3 = false; + d.f.b(c, m); + + H h = new HB(c) { + @Override + public void p(Q q) throws IOException { + m5(c, m, q); + } + }; + if (!m4(c)) { + final Map> map = m2(c, h); + for (Map.Entry> e : map.entrySet()) { + final N n = e.getKey(); + final Set files = e.getValue(); + if (!files.isEmpty()) { + final S mapping = c.d().dm.s(n); + for (File srcFile : files) { + mapping.s(srcFile.getPath(), new ArrayList()); + } + } + } + } + + L: + for (G g : G.gs()) { + final List ls = k.ls(g); + if (g == G.G1) { + m9(b); + } + if (ls.isEmpty()) { + continue; + } + + try { + for (L l : ls) { + m8(c, m.ns()); + long l1 = System.nanoTime(); + int n1 = b.n(); + final E e = l.b(c, m, h, b); + m7(l, System.nanoTime() - l1, b.n() - n1); + + b1 |= (e != E.E1); + + if (e == E.E2) { + throw new Ex("Fail " + l.s()); + } + c.c(); + if (e == E.E3) { + b3 = true; + } + else if (e == E.E4) { + if (!b2 && !m4(c)) { + System.out.println("1 " + l.s() + ":" + m.s()); + b2 = true; + try { + c.d().f.c(c); + m1(c, R.N, m, null); + f2 -= (p * s) / c1; + c1 = f1; + p = 0; + b3 = true; + b.c(); + break L; + } + catch (Exception ex) { + throw new Ex(ex); + } + } + else { + System.out.println("2 " + l.s()); + } + } + + p++; + m6(c, s / (c1)); + } + } + finally { + final boolean b4 = m3(c, h, m); + if (b4) { + b3 = true; + } + if (b3 && !b2) { + f2 -= (p * s) / c1; + c1 += f1; + f2 += (p * s) / c1; + } + } + } + } + while (b3); + } + finally { + m9(b); + b.f(); + b.c(); + for (G g : G.gs()) { + for (L l : k.ls(g)) { + l.f(c, m); + } + } + } + + return b1; + } + + private void m1(C c, R r, M m, Object o) { + } + + private static Map> m2(C c, H h) { + return new HashMap>(); + } + + private static boolean m3(C c, H h, M m) { + return c != null && h != null && m != null; + } + + private boolean m4(C c) { + return c != null && f1>1; + } + + private void m5(C c, M m, Q q) { + } + + private void m6(C c, float v) { + } + + private void m7(L l1, long l, int i) { + } + + private void m8(C c, List ns) { + } + + private void m9(B b) { + } +} diff --git a/java/java-tests/testData/inspection/defUse/ComplexTripleTryFinally.java b/java/java-tests/testData/inspection/defUse/ComplexTripleTryFinally.java new file mode 100644 index 000000000000..7935489f1e69 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/ComplexTripleTryFinally.java @@ -0,0 +1,143 @@ +import java.io.IOException; + +class Y { + private static class Ex extends Exception { + public Ex(Exception e) { + super(e); + } + } + + private static class P { + } + + private static class T { + } + + private static class R { + public T[] ts() { + return new T[]{new T()}; + } + } + + private static class M { + public S s() { + return new S(); + } + } + + private static class S { + public void c() throws IOException { + } + } + + private static class F { + public void c() { + } + } + + private static class D { + public M m; + public S s; + public F f; + + public R r() { + return new R(); + } + + public P p() { + return new P(); + } + } + + private static class C { + public D d() { + return new D(); + } + + public void c() { + } + + public Q q() { + return new Q(); + } + } + + private static class Q { + public boolean a(T t) { + return false; + } + } + + + private static class J { + public boolean c() { + return false; + } + } + + + private void foo(C c) throws Ex { + final D d = c.d(); + Ex ex = null; + try { + final J j = m2(d.p()); + final boolean b = j.c(); + if (b) { + m3(c); + } + else { + for (T t : d.r().ts()) { + c.c(); + if (c.q().a(t)) { + m1(c, t); + } + } + } + } + catch (Ex e) { + ex = e; + } + finally { + try { + d.m.s().c(); + } + catch (IOException e) { + if (ex == null) { + ex = new Ex(e); + } + else { + System.out.println("1" + e); + } + } + finally { + try { + d.s.c(); + } + catch (IOException e) { + if (ex == null) { + ex = new Ex(e); + } + else { + System.out.println("2 " + e); + } + } + finally { + d.f.c(); + if (ex != null) { + throw ex; + } + } + } + } + } + + private void m1(C c, T t) throws Ex { + } + + private static J m2(P p) throws Ex { + return new J(); + } + + private void m3(C c) throws Ex { + } +} diff --git a/java/java-tests/testData/inspection/defUse/IfAfter.java b/java/java-tests/testData/inspection/defUse/IfAfter.java new file mode 100644 index 000000000000..9c970e4b37c5 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/IfAfter.java @@ -0,0 +1,12 @@ +class C { + int f(boolean b) { + int i = 0; + if (b) { + i = 1; + } + else { + i = 2; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfBefore.java b/java/java-tests/testData/inspection/defUse/IfBefore.java new file mode 100644 index 000000000000..919d6f70001e --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/IfBefore.java @@ -0,0 +1,13 @@ +class C { + int f(boolean b) { + int i; + if (b) { + i = 1; + } + else { + i = 2; + } + i = 3; + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfInLoop.java b/java/java-tests/testData/inspection/defUse/IfInLoop.java new file mode 100644 index 000000000000..bffd06abb78e --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/IfInLoop.java @@ -0,0 +1,10 @@ +class C { + int f() { + int i = 0; + for (int j = 0; j < 2; j++) { + if (j == 2) return 1; + i = 1; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfNested.java b/java/java-tests/testData/inspection/defUse/IfNested.java new file mode 100644 index 000000000000..0c3a61ef6c94 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/IfNested.java @@ -0,0 +1,17 @@ +class C { + int f(boolean b, boolean c) { + int i = 0; + if (b) { + if (c) { + i = 1; + } + else { + i = 2; + } + } + else { + i = 3; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/InLoop.java b/java/java-tests/testData/inspection/defUse/InLoop.java new file mode 100644 index 000000000000..654f950ef224 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/InLoop.java @@ -0,0 +1,9 @@ +class C { + int f() { + int i = 0; + for (int j = 0; j < 2; j++) { + i = 1; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java b/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java new file mode 100644 index 000000000000..45dd359a2e03 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java @@ -0,0 +1,19 @@ +class C { + int f() { + int i = 0; + try { + i = 1; + } + finally { + i = 2; + try { + i = 3; + } + finally { + i = 4; + } + i = 5; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/NestedTryFinally.java b/java/java-tests/testData/inspection/defUse/NestedTryFinally.java new file mode 100644 index 000000000000..613e8222aa66 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/NestedTryFinally.java @@ -0,0 +1,14 @@ +class C { + int f() { + int i; + try { + } finally { + i = 1; + try { + i = 2; + } finally { + } + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/Sequence.java b/java/java-tests/testData/inspection/defUse/Sequence.java new file mode 100644 index 000000000000..5c8f3efd9d1c --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/Sequence.java @@ -0,0 +1,8 @@ +class C { + int f() { + int i = 0; + i = 1; + i = 2; + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/ThrowInFinally.java b/java/java-tests/testData/inspection/defUse/ThrowInFinally.java new file mode 100644 index 000000000000..db9d87e6695d --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/ThrowInFinally.java @@ -0,0 +1,12 @@ +class C { + int f(boolean b) { + int i; + try { + i = 0; + } finally { + if (b) throw new RuntimeException(); + i = 1; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/ThrowInTry.java b/java/java-tests/testData/inspection/defUse/ThrowInTry.java new file mode 100644 index 000000000000..c118d307dd31 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/ThrowInTry.java @@ -0,0 +1,11 @@ +class C { + int f(boolean b) { + int i = 0; + try { + if (b) throw new RuntimeException(); + } finally { + i = 1; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryFinally.java b/java/java-tests/testData/inspection/defUse/TryFinally.java new file mode 100644 index 000000000000..a8c743d39706 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/TryFinally.java @@ -0,0 +1,12 @@ +class C { + int f(boolean b) { + int i = 0; + try { + i = 1; + } + finally { + i = 2; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryThrowFinally.java b/java/java-tests/testData/inspection/defUse/TryThrowFinally.java new file mode 100644 index 000000000000..821bb7363323 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/TryThrowFinally.java @@ -0,0 +1,13 @@ +class C { + int f(boolean b) { + int i = 0; + try { + i = 1; + if (b) throw new RuntimeException(); + } + finally { + i = 2; + } + return i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java b/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java new file mode 100644 index 000000000000..15ca531cdbf7 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java @@ -0,0 +1,15 @@ +class C { + boolean test(boolean b) { + boolean f = false; + try { + if (b) throw new RuntimeException(); + f = true; + } + catch (RuntimeException e) { + throw e; + } + finally { + } + return f; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java index 62ddd52b6d8a..16170f387a8d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java @@ -38,9 +38,24 @@ public class DefUseTest extends LightCodeInsightFixtureTestCase { public void testUsedInArrayInitializer() { doTest(); } public void testHang() { doTest(); } public void testOperatorAssignment() { doTest(); } - @Bombed(user="roman.shevchenko@jetbrains.com", day=1, month=Calendar.AUGUST, year=2017) public void testTryWithFinally() { doTest(); } + public void testTryWithFinally() { doTest(); } public void testTryWithoutFinally() { doTest(); } + public void testSequence() { doTest(); } + public void testIfAfter() { doTest(); } + public void testIfBefore() { doTest(); } + public void testIfNested() { doTest(); } + public void testInLoop() { doTest(); } + public void testIfInLoop() { doTest(); } + public void testThrowInTry() { doTest(); } + public void testThrowInFinally() { doTest(); } + public void testTryThrowFinally() { doTest(); } + public void testNestedTryFinally() { doTest(); } + public void testNestedBigTryFinally() { doTest(); } + public void testTryWithFinallyRethrow() { doTest(); } + public void testComplexDoubleTryFinally() { doTest(); } + public void testComplexTripleTryFinally() { doTest(); } + private void doTest() { myFixture.enableInspections(new DefUseInspection()); myFixture.testHighlighting(getTestName(false) + ".java");