mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java control flow: Detecting redundant assignment when the control flow includes a try-finally statement, fixed handling calls, tests added (IDEA-155836)
This commit is contained in:
@@ -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<PsiVariable> myVariablesUseArmed;
|
||||
private final int myInstructionIdx;
|
||||
private final IntArrayList myBackwardTraces;
|
||||
private static class InstructionState implements Comparable<InstructionState> {
|
||||
private Set<PsiVariable> myUsed;
|
||||
private final InstructionKey myInstructionKey;
|
||||
private final List<InstructionKey> 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<InstructionKey>(2);
|
||||
myUsed = null;
|
||||
}
|
||||
|
||||
public void addBackwardTrace(int i) {
|
||||
myBackwardTraces.add(i);
|
||||
public void addBackwardTrace(InstructionKey key) {
|
||||
myBackwardTraces.add(key);
|
||||
}
|
||||
|
||||
public IntArrayList getBackwardTraces() {
|
||||
public List<InstructionKey> 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<PsiVariable>();
|
||||
if (myUsed == null) myUsed = new THashSet<PsiVariable>();
|
||||
}
|
||||
|
||||
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<InstructionKey, InstructionState> 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<InstructionState> queue = new Queue<InstructionState>(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<InstructionKey> 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<Instruction> instructions) {
|
||||
final InstructionState[] states = new InstructionState[instructions.size()];
|
||||
private static IntArrayList[] getBackwardTraces(final List<Instruction> 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<InstructionKey, InstructionState> getStates(final List<Instruction> instructions) {
|
||||
class WalkThroughStack {
|
||||
private final com.intellij.util.containers.Stack<InstructionKey> myFrom;
|
||||
private final com.intellij.util.containers.Stack<InstructionKey> myNext;
|
||||
|
||||
WalkThroughStack(int size) {
|
||||
if (size < 2) size = 2;
|
||||
myFrom = new Stack<InstructionKey>(size);
|
||||
myNext = new Stack<InstructionKey>(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<InstructionKey, InstructionState> myStates;
|
||||
private final WalkThroughStack myWalkThroughStack;
|
||||
|
||||
Walker() {
|
||||
myStates = new THashMap<InstructionKey, InstructionState>(instructions.size());
|
||||
myWalkThroughStack = new WalkThroughStack(instructions.size() / 2);
|
||||
}
|
||||
|
||||
Map<InstructionKey, InstructionState> walk() {
|
||||
InstructionKey startKey = InstructionKey.create(0);
|
||||
myStates.put(startKey, new InstructionState(startKey));
|
||||
myWalkThroughStack.push(InstructionKey.create(-1), startKey);
|
||||
|
||||
Set<InstructionKey> visited = new THashSet<InstructionKey>(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) {
|
||||
|
||||
@@ -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<InstructionKey> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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<J, N> h, B b) {
|
||||
return new E();
|
||||
}
|
||||
|
||||
public String s() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void f(C c, M m) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Q<J, M> {
|
||||
|
||||
}
|
||||
|
||||
private static class N {
|
||||
}
|
||||
|
||||
|
||||
private static class H<J, M> {
|
||||
public void p(Q<J, M> q) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
private static class HB<J, M> extends H<J, M> {
|
||||
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<N> ns() {
|
||||
return new ArrayList<N>();
|
||||
}
|
||||
|
||||
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<String> 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<L> ls(G g) {
|
||||
return new ArrayList<L>();
|
||||
}
|
||||
}
|
||||
|
||||
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<J, N> h = new HB<J, N>(c) {
|
||||
@Override
|
||||
public void p(Q<J, N> q) throws IOException {
|
||||
m5(c, m, q);
|
||||
}
|
||||
};
|
||||
if (!m4(c)) {
|
||||
final Map<N, Set<File>> map = m2(c, h);
|
||||
for (Map.Entry<N, Set<File>> e : map.entrySet()) {
|
||||
final N n = e.getKey();
|
||||
final Set<File> files = e.getValue();
|
||||
if (!files.isEmpty()) {
|
||||
final S mapping = c.d().dm.s(n);
|
||||
for (File srcFile : files) {
|
||||
mapping.s(srcFile.getPath(), new ArrayList<String>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
L:
|
||||
for (G g : G.gs()) {
|
||||
final List<L> 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<N, Set<File>> m2(C c, H<J, N> h) {
|
||||
return new HashMap<N, Set<File>>();
|
||||
}
|
||||
|
||||
private static boolean m3(C c, H<J, N> 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<J, N> q) {
|
||||
}
|
||||
|
||||
private void m6(C c, float v) {
|
||||
}
|
||||
|
||||
private void m7(L l1, long l, int i) {
|
||||
}
|
||||
|
||||
private void m8(C c, List<N> ns) {
|
||||
}
|
||||
|
||||
private void m9(B b) {
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
if (b) {
|
||||
i = 1;
|
||||
}
|
||||
else {
|
||||
i = 2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i;
|
||||
if (b) {
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
}
|
||||
else {
|
||||
<warning descr="The value 2 assigned to 'i' is never used">i</warning> = 2;
|
||||
}
|
||||
i = 3;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
class C {
|
||||
int f(boolean b, boolean c) {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
if (b) {
|
||||
if (c) {
|
||||
i = 1;
|
||||
}
|
||||
else {
|
||||
i = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = 3;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
int f() {
|
||||
int i = 0;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
i = 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
class C {
|
||||
int f() {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
try {
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
}
|
||||
finally {
|
||||
<warning descr="The value 2 assigned to 'i' is never used">i</warning> = 2;
|
||||
try {
|
||||
<warning descr="The value 3 assigned to 'i' is never used">i</warning> = 3;
|
||||
}
|
||||
finally {
|
||||
<warning descr="The value 4 assigned to 'i' is never used">i</warning> = 4;
|
||||
}
|
||||
i = 5;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class C {
|
||||
int f() {
|
||||
int i;
|
||||
try {
|
||||
} finally {
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
try {
|
||||
i = 2;
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class C {
|
||||
int f() {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
i = 2;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i;
|
||||
try {
|
||||
<warning descr="The value 0 assigned to 'i' is never used">i</warning> = 0;
|
||||
} finally {
|
||||
if (b) throw new RuntimeException();
|
||||
i = 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
try {
|
||||
if (b) throw new RuntimeException();
|
||||
} finally {
|
||||
i = 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
try {
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
}
|
||||
finally {
|
||||
i = 2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class C {
|
||||
int f(boolean b) {
|
||||
int i = <warning descr="Variable 'i' initializer '0' is redundant">0</warning>;
|
||||
try {
|
||||
<warning descr="The value 1 assigned to 'i' is never used">i</warning> = 1;
|
||||
if (b) throw new RuntimeException();
|
||||
}
|
||||
finally {
|
||||
i = 2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class C {
|
||||
boolean test(boolean b) {
|
||||
boolean f = <warning descr="Variable 'f' initializer 'false' is redundant">false</warning>;
|
||||
try {
|
||||
if (b) throw new RuntimeException();
|
||||
f = true;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user