mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
wrap def-use structure into a bit more friendly DefinitionMap
This commit is contained in:
+4
-4
@@ -27,7 +27,6 @@ import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.Processor;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import gnu.trove.TObjectProcedure;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
@@ -48,6 +47,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.DefinitionMap;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsDfaInstance;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsSemilattice;
|
||||
|
||||
@@ -82,8 +82,8 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
final Instruction[] flow = owner.getControlFlow();
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<TIntObjectHashMap<TIntHashSet>> engine = new DFAEngine<TIntObjectHashMap<TIntHashSet>>(flow, dfaInstance, lattice);
|
||||
final List<TIntObjectHashMap<TIntHashSet>> dfaResult = engine.performDFAWithTimeout();
|
||||
final DFAEngine<DefinitionMap> engine = new DFAEngine<DefinitionMap>(flow, dfaInstance, lattice);
|
||||
final List<DefinitionMap> dfaResult = engine.performDFAWithTimeout();
|
||||
if (dfaResult == null) {
|
||||
return;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase {
|
||||
final ReadWriteVariableInstruction varInst = (ReadWriteVariableInstruction) instruction;
|
||||
if (!varInst.isWrite()) {
|
||||
final String varName = varInst.getVariableName();
|
||||
TIntObjectHashMap<TIntHashSet> e = dfaResult.get(i);
|
||||
DefinitionMap e = dfaResult.get(i);
|
||||
e.forEachValue(new TObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(TIntHashSet reaching) {
|
||||
reaching.forEach(new TIntProcedure() {
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs;
|
||||
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TIntObjectProcedure;
|
||||
import gnu.trove.TObjectProcedure;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class DefinitionMap {
|
||||
private final TIntObjectHashMap<TIntHashSet> myMap = new TIntObjectHashMap<TIntHashSet>();
|
||||
|
||||
public void registerDef(Instruction varInsn, int num) {
|
||||
TIntHashSet defs = myMap.get(num);
|
||||
if (defs == null) {
|
||||
myMap.put(num, defs = new TIntHashSet());
|
||||
} else {
|
||||
defs.clear();
|
||||
}
|
||||
defs.add(varInsn.num());
|
||||
}
|
||||
|
||||
public void merge(DefinitionMap map2) {
|
||||
map2.myMap.forEachEntry(new TIntObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(int num, TIntHashSet defs) {
|
||||
TIntHashSet defs2 = myMap.get(num);
|
||||
if (defs2 == null) {
|
||||
defs2 = new TIntHashSet(defs.toArray());
|
||||
myMap.put(num, defs2);
|
||||
}
|
||||
else {
|
||||
defs2.addAll(defs.toArray());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean eq(final DefinitionMap m2) {
|
||||
if (myMap.size() != m2.myMap.size()) return false;
|
||||
|
||||
return myMap.forEachEntry(new TIntObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(int num, TIntHashSet defs1) {
|
||||
final TIntHashSet defs2 = m2.myMap.get(num);
|
||||
return defs2 != null && defs2.equals(defs1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void copyFrom(DefinitionMap map, int fromIndex, int toIndex) {
|
||||
TIntHashSet defs = map.myMap.get(fromIndex);
|
||||
if (defs == null) defs = new TIntHashSet();
|
||||
myMap.put(toIndex, defs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public int[] getDefinitions(int atInstruction) {
|
||||
TIntHashSet set = myMap.get(atInstruction);
|
||||
return set == null ? null : set.toArray();
|
||||
}
|
||||
|
||||
public void forEachValue(TObjectProcedure<TIntHashSet> procedure) {
|
||||
myMap.forEachValue(procedure);
|
||||
}
|
||||
}
|
||||
+15
-20
@@ -66,8 +66,8 @@ public class ReachingDefinitionsCollector {
|
||||
final Instruction[] flow = flowOwner.getControlFlow();
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<TIntObjectHashMap<TIntHashSet>> engine = new DFAEngine<TIntObjectHashMap<TIntHashSet>>(flow, dfaInstance, lattice);
|
||||
final TIntObjectHashMap<TIntHashSet> dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance);
|
||||
final DFAEngine<DefinitionMap> engine = new DFAEngine<DefinitionMap>(flow, dfaInstance, lattice);
|
||||
final DefinitionMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance);
|
||||
|
||||
final LinkedHashSet<Integer> fragmentInstructions = getFragmentInstructions(first, last, flow);
|
||||
final int[] postorder = ControlFlowBuilderUtil.postorder(flow);
|
||||
@@ -82,7 +82,7 @@ public class ReachingDefinitionsCollector {
|
||||
for (final Integer ref : fragmentReads) {
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref];
|
||||
String name = rwInstruction.getVariableName();
|
||||
final int[] defs = dfaResult.get(ref).toArray();
|
||||
final int[] defs = dfaResult.getDefinitions(ref);
|
||||
if (!allDefsInFragment(defs, fragmentInstructions)) {
|
||||
addVariable(name, imap, manager, getType(rwInstruction.getElement()));
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class ReachingDefinitionsCollector {
|
||||
for (final Integer ref : reachableFromFragmentReads) {
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref];
|
||||
String name = rwInstruction.getVariableName();
|
||||
final int[] defs = dfaResult.get(ref).toArray();
|
||||
final int[] defs = dfaResult.getDefinitions(ref);
|
||||
if (anyDefInFragment(defs, fragmentInstructions)) {
|
||||
for (int def : defs) {
|
||||
if (fragmentInstructions.contains(def)) {
|
||||
@@ -277,24 +277,21 @@ public class ReachingDefinitionsCollector {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static LinkedHashSet<Integer> getReachable(final LinkedHashSet<Integer> fragmentInsns, final Instruction[] flow, TIntObjectHashMap<TIntHashSet> dfaResult, final int[] postorder) {
|
||||
private static LinkedHashSet<Integer> getReachable(final LinkedHashSet<Integer> fragmentInsns, final Instruction[] flow, DefinitionMap dfaResult, final int[] postorder) {
|
||||
final LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
|
||||
for (Instruction insn : flow) {
|
||||
if (insn instanceof ReadWriteVariableInstruction &&
|
||||
!((ReadWriteVariableInstruction) insn).isWrite()) {
|
||||
final int ref = insn.num();
|
||||
TIntHashSet defs = dfaResult.get(ref);
|
||||
defs.forEach(new TIntProcedure() {
|
||||
public boolean execute(int def) {
|
||||
if (fragmentInsns.contains(def)) {
|
||||
if (!fragmentInsns.contains(ref) || postorder[ref] < postorder[def]) {
|
||||
result.add(ref);
|
||||
return false;
|
||||
}
|
||||
for (int def : dfaResult.getDefinitions(ref)) {
|
||||
if (fragmentInsns.contains(def)) {
|
||||
if (!fragmentInsns.contains(ref) || postorder[ref] < postorder[def]) {
|
||||
result.add(ref);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,19 +364,17 @@ public class ReachingDefinitionsCollector {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TIntObjectHashMap<TIntHashSet> postprocess(@NotNull final ArrayList<TIntObjectHashMap<TIntHashSet>> dfaResult,
|
||||
private static DefinitionMap postprocess(@NotNull final ArrayList<DefinitionMap> dfaResult,
|
||||
@NotNull Instruction[] flow,
|
||||
@NotNull ReachingDefinitionsDfaInstance dfaInstance) {
|
||||
TIntObjectHashMap<TIntHashSet> result = new TIntObjectHashMap<TIntHashSet>();
|
||||
DefinitionMap result = new DefinitionMap();
|
||||
for (int i = 0; i < flow.length; i++) {
|
||||
Instruction insn = flow[i];
|
||||
if (insn instanceof ReadWriteVariableInstruction) {
|
||||
ReadWriteVariableInstruction rwInsn = (ReadWriteVariableInstruction) insn;
|
||||
if (!rwInsn.isWrite()) {
|
||||
int idx = dfaInstance.getVarIndex(rwInsn.getVariableName());
|
||||
TIntHashSet defs = dfaResult.get(i).get(idx);
|
||||
if (defs == null) defs = new TIntHashSet();
|
||||
result.put(i, defs);
|
||||
result.copyFrom(dfaResult.get(i), idx, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-14
@@ -26,7 +26,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class ReachingDefinitionsDfaInstance implements DfaInstance<TIntObjectHashMap<TIntHashSet>> {
|
||||
public class ReachingDefinitionsDfaInstance implements DfaInstance<DefinitionMap> {
|
||||
private final TObjectIntHashMap<String> myVarToIndexMap = new TObjectIntHashMap<String>();
|
||||
private final Instruction[] myFlow;
|
||||
|
||||
@@ -48,30 +48,21 @@ public class ReachingDefinitionsDfaInstance implements DfaInstance<TIntObjectHas
|
||||
}
|
||||
|
||||
|
||||
public void fun(TIntObjectHashMap<TIntHashSet> m, Instruction instruction) {
|
||||
public void fun(DefinitionMap m, Instruction instruction) {
|
||||
if (instruction instanceof ReadWriteVariableInstruction) {
|
||||
final ReadWriteVariableInstruction varInsn = (ReadWriteVariableInstruction) instruction;
|
||||
final String name = varInsn.getVariableName();
|
||||
assert myVarToIndexMap.containsKey(name) : name + "; " + Arrays.asList(myFlow).contains(instruction);
|
||||
final int num = myVarToIndexMap.get(name);
|
||||
if (varInsn.isWrite()) {
|
||||
registerDef(m, varInsn, num);
|
||||
m.registerDef(varInsn, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void registerDef(TIntObjectHashMap<TIntHashSet> m, Instruction varInsn, int num) {
|
||||
TIntHashSet defs = m.get(num);
|
||||
if (defs == null) {
|
||||
defs = new TIntHashSet();
|
||||
m.put(num, defs);
|
||||
} else defs.clear();
|
||||
defs.add(varInsn.num());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TIntObjectHashMap<TIntHashSet> initial() {
|
||||
return new TIntObjectHashMap<TIntHashSet>();
|
||||
public DefinitionMap initial() {
|
||||
return new DefinitionMap();
|
||||
}
|
||||
|
||||
public boolean isForward() {
|
||||
|
||||
+8
-32
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs;
|
||||
|
||||
import gnu.trove.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.Semilattice;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -23,42 +22,19 @@ import java.util.ArrayList;
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class ReachingDefinitionsSemilattice implements Semilattice<TIntObjectHashMap<TIntHashSet>> {
|
||||
public TIntObjectHashMap<TIntHashSet> join(ArrayList<TIntObjectHashMap<TIntHashSet>> ins) {
|
||||
if (ins.isEmpty()) return new TIntObjectHashMap<TIntHashSet>();
|
||||
public class ReachingDefinitionsSemilattice implements Semilattice<DefinitionMap> {
|
||||
public DefinitionMap join(ArrayList<DefinitionMap> ins) {
|
||||
if (ins.isEmpty()) return new DefinitionMap();
|
||||
|
||||
TIntObjectHashMap<TIntHashSet> result = new TIntObjectHashMap<TIntHashSet>();
|
||||
for (TIntObjectHashMap<TIntHashSet> map : ins) {
|
||||
merge(result, map);
|
||||
DefinitionMap result = new DefinitionMap();
|
||||
for (DefinitionMap map : ins) {
|
||||
result.merge(map);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void merge(final TIntObjectHashMap<TIntHashSet> result, TIntObjectHashMap<TIntHashSet> map2) {
|
||||
map2.forEachEntry(new TIntObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(int num, TIntHashSet defs) {
|
||||
TIntHashSet defs2 = result.get(num);
|
||||
if (defs2 == null) {
|
||||
defs2 = new TIntHashSet(defs.toArray());
|
||||
result.put(num, defs2);
|
||||
} else {
|
||||
defs2.addAll(defs.toArray());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean eq(final TIntObjectHashMap<TIntHashSet> m1, final TIntObjectHashMap<TIntHashSet> m2) {
|
||||
if (m1.size() != m2.size()) return false;
|
||||
|
||||
return m1.forEachEntry(new TIntObjectProcedure<TIntHashSet>() {
|
||||
public boolean execute(int num, TIntHashSet defs1) {
|
||||
final TIntHashSet defs2 = m2.get(num);
|
||||
return defs2 != null && defs2.equals(defs1);
|
||||
}
|
||||
});
|
||||
public boolean eq(final DefinitionMap m1, final DefinitionMap m2) {
|
||||
return m1.eq(m2);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-15
@@ -23,8 +23,6 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.util.*;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
@@ -40,6 +38,7 @@ import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstru
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ArgumentInstruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.DefinitionMap;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsDfaInstance;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsSemilattice;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
@@ -137,19 +136,19 @@ public class TypeInferenceHelper {
|
||||
|
||||
@Nullable
|
||||
private static DFAType getInferredType(@NotNull String varName, @NotNull Instruction instruction, @NotNull Instruction[] flow, @NotNull GrControlFlowOwner scope) {
|
||||
final Pair<ReachingDefinitionsDfaInstance, List<TIntObjectHashMap<TIntHashSet>>> pair = getDefUseMaps(scope);
|
||||
final Pair<ReachingDefinitionsDfaInstance, List<DefinitionMap>> pair = getDefUseMaps(scope);
|
||||
|
||||
List<TIntObjectHashMap<TIntHashSet>> dfaResult = pair.second;
|
||||
List<DefinitionMap> dfaResult = pair.second;
|
||||
if (dfaResult == null) return null;
|
||||
|
||||
final int varIndex = pair.first.getVarIndex(varName);
|
||||
|
||||
final TIntObjectHashMap<TIntHashSet> allDefs = dfaResult.get(instruction.num());
|
||||
final TIntHashSet varDefs = allDefs.get(varIndex);
|
||||
final DefinitionMap allDefs = dfaResult.get(instruction.num());
|
||||
final int[] varDefs = allDefs.getDefinitions(varIndex);
|
||||
if (varDefs == null) return null;
|
||||
|
||||
DFAType result = null;
|
||||
for (int defIndex : varDefs.toArray()) {
|
||||
for (int defIndex : varDefs) {
|
||||
DFAType defType = getDefinitionType(flow[defIndex], flow, scope);
|
||||
|
||||
if (defType != null) {
|
||||
@@ -163,27 +162,27 @@ public class TypeInferenceHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Pair<ReachingDefinitionsDfaInstance, List<TIntObjectHashMap<TIntHashSet>>> getDefUseMaps(final GrControlFlowOwner scope) {
|
||||
return CachedValuesManager.getManager(scope.getProject()).getCachedValue(scope, new CachedValueProvider<Pair<ReachingDefinitionsDfaInstance, List<TIntObjectHashMap<TIntHashSet>>>>() {
|
||||
private static Pair<ReachingDefinitionsDfaInstance, List<DefinitionMap>> getDefUseMaps(final GrControlFlowOwner scope) {
|
||||
return CachedValuesManager.getManager(scope.getProject()).getCachedValue(scope, new CachedValueProvider<Pair<ReachingDefinitionsDfaInstance, List<DefinitionMap>>>() {
|
||||
@Override
|
||||
public Result<Pair<ReachingDefinitionsDfaInstance, List<TIntObjectHashMap<TIntHashSet>>>> compute() {
|
||||
public Result<Pair<ReachingDefinitionsDfaInstance, List<DefinitionMap>>> compute() {
|
||||
final Instruction[] flow = scope.getControlFlow();
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow) {
|
||||
@Override
|
||||
public void fun(TIntObjectHashMap<TIntHashSet> m, Instruction instruction) {
|
||||
public void fun(DefinitionMap m, Instruction instruction) {
|
||||
if (instruction instanceof InstanceOfInstruction) {
|
||||
final InstanceOfInstruction instanceOfInstruction = (InstanceOfInstruction)instruction;
|
||||
ReadWriteVariableInstruction i = instanceOfInstruction.getInstructionToMixin(flow);
|
||||
if (i != null) {
|
||||
int varIndex = getVarIndex(i.getVariableName());
|
||||
if (varIndex >= 0) {
|
||||
registerDef(m, instruction, varIndex);
|
||||
m.registerDef(instruction, varIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instruction instanceof ArgumentInstruction) {
|
||||
final int varIndex = getVarIndex(((ArgumentInstruction)instruction).getVariableName());
|
||||
registerDef(m, instruction, varIndex);
|
||||
m.registerDef(instruction, varIndex);
|
||||
}
|
||||
else {
|
||||
super.fun(m, instruction);
|
||||
@@ -191,8 +190,8 @@ public class TypeInferenceHelper {
|
||||
}
|
||||
};
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<TIntObjectHashMap<TIntHashSet>> engine = new DFAEngine<TIntObjectHashMap<TIntHashSet>>(flow, dfaInstance, lattice);
|
||||
final List<TIntObjectHashMap<TIntHashSet>> dfaResult = engine.performDFAWithTimeout();
|
||||
final DFAEngine<DefinitionMap> engine = new DFAEngine<DefinitionMap>(flow, dfaInstance, lattice);
|
||||
final List<DefinitionMap> dfaResult = engine.performDFAWithTimeout();
|
||||
return Result.create(Pair.create(dfaInstance, dfaResult), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user