DefUseUtil: make the traversal non-recursive to avoid possible SOE for huge methods (EA-144050)

GitOrigin-RevId: 02df88e041af9be7a4259a734bbfe3b7b0e3cd93
This commit is contained in:
Tagir Valeev
2020-05-04 07:36:17 +00:00
committed by intellij-monorepo-bot
parent f433a0c263
commit 10c3276674
@@ -13,6 +13,7 @@ import com.intellij.util.containers.Queue;
import com.intellij.util.containers.Stack;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -391,7 +392,8 @@ public class DefUseUtil {
final boolean [] visited = new boolean[instructions.size() + 1];
visited [visited.length-1] = true; // stop on the code end
int elem = defs() ? flow.getStartOffset(refOrDef) : flow.getEndOffset(refOrDef);
final boolean defs = defs();
int elem = defs ? flow.getStartOffset(refOrDef) : flow.getEndOffset(refOrDef);
// hack: ControlFlow doesn't contains parameters initialization
if (elem == -1 && def instanceof PsiParameter) {
@@ -399,62 +401,65 @@ public class DefUseUtil {
}
if (elem != -1) {
if (!defs () && instructions.get(elem) instanceof ReadVariableInstruction) {
if (!defs && instructions.get(elem) instanceof ReadVariableInstruction) {
LOG.assertTrue(nNext(elem) == 1);
LOG.assertTrue(getNext(elem,0) == elem+1);
elem += 1;
}
final Set<@NotNull PsiElement> res = new THashSet<>();
class Inner {
private void traverse(int index) {
if (visited[index]) {
return;
}
visited [index] = true;
// hack: ControlFlow doesn't contains parameters initialization
int startIndex = elem;
if (defs ()) {
final Instruction instruction = instructions.get(index);
processInstruction(res, instruction, index);
if (instruction instanceof WriteVariableInstruction) {
WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction;
if (instructionW.variable == def) {
return;
}
}
TIntArrayList workQueue = new TIntArrayList();
workQueue.add(startIndex);
// hack: ControlFlow doesn't contains parameters initialization
if (index == 0 && def instanceof PsiParameter) {
PsiIdentifier identifier = def.getNameIdentifier();
if (identifier != null) {
res.add(identifier);
}
while (!workQueue.isEmpty()) {
int index = workQueue.remove(workQueue.size() - 1);
if (visited[index]) {
continue;
}
visited [index] = true;
if (defs) {
final Instruction instruction = instructions.get(index);
processInstruction(res, instruction, index);
if (instruction instanceof WriteVariableInstruction) {
WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction;
if (instructionW.variable == def) {
continue;
}
}
final int nNext = nNext (index);
for (int i = 0; i < nNext; i++) {
final int prev = getNext(index, i);
if (!visited [prev]) {
if (!defs ()) {
final Instruction instruction = instructions.get(prev);
if (instruction instanceof WriteVariableInstruction) {
WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction;
if (instructionW.variable == def) {
continue;
}
}
else {
processInstruction(res, instruction, prev);
}
}
traverse (prev);
// hack: ControlFlow doesn't contains parameters initialization
if (index == 0 && def instanceof PsiParameter) {
PsiIdentifier identifier = def.getNameIdentifier();
if (identifier != null) {
res.add(identifier);
}
}
}
final int nNext = nNext (index);
for (int i = 0; i < nNext; i++) {
final int prev = getNext(index, i);
if (!visited [prev]) {
if (!defs) {
final Instruction instruction = instructions.get(prev);
if (instruction instanceof WriteVariableInstruction) {
WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction;
if (instructionW.variable == def) {
continue;
}
}
else {
processInstruction(res, instruction, prev);
}
}
workQueue.add(prev);
}
}
}
new Inner ().traverse(elem);
return PsiUtilCore.toPsiElementArray(res);
}
return PsiElement.EMPTY_ARRAY;