From e65b55b2da31ff7dbda7d4f26d737c1fa826df5a Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 30 Aug 2012 20:31:59 +0200 Subject: [PATCH] wrap def-use structure into a bit more friendly DefinitionMap --- .../unusedDef/UnusedDefInspection.java | 8 +- .../dataFlow/reachingDefs/DefinitionMap.java | 84 +++++++++++++++++++ .../ReachingDefinitionsCollector.java | 35 ++++---- .../ReachingDefinitionsDfaInstance.java | 19 ++--- .../ReachingDefinitionsSemilattice.java | 40 ++------- .../lang/psi/impl/TypeInferenceHelper.java | 29 ++++--- 6 files changed, 130 insertions(+), 85 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/DefinitionMap.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java index b74bd85d7457..a0548f290e06 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java @@ -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> engine = new DFAEngine>(flow, dfaInstance, lattice); - final List> dfaResult = engine.performDFAWithTimeout(); + final DFAEngine engine = new DFAEngine(flow, dfaInstance, lattice); + final List 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 e = dfaResult.get(i); + DefinitionMap e = dfaResult.get(i); e.forEachValue(new TObjectProcedure() { public boolean execute(TIntHashSet reaching) { reaching.forEach(new TIntProcedure() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/DefinitionMap.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/DefinitionMap.java new file mode 100644 index 000000000000..39b441232876 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/DefinitionMap.java @@ -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 myMap = new TIntObjectHashMap(); + + 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() { + 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() { + 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 procedure) { + myMap.forEachValue(procedure); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java index 4ebd0621742f..a7326d954b37 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java @@ -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> engine = new DFAEngine>(flow, dfaInstance, lattice); - final TIntObjectHashMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance); + final DFAEngine engine = new DFAEngine(flow, dfaInstance, lattice); + final DefinitionMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance); final LinkedHashSet 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 getReachable(final LinkedHashSet fragmentInsns, final Instruction[] flow, TIntObjectHashMap dfaResult, final int[] postorder) { + private static LinkedHashSet getReachable(final LinkedHashSet fragmentInsns, final Instruction[] flow, DefinitionMap dfaResult, final int[] postorder) { final LinkedHashSet result = new LinkedHashSet(); 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 postprocess(@NotNull final ArrayList> dfaResult, + private static DefinitionMap postprocess(@NotNull final ArrayList dfaResult, @NotNull Instruction[] flow, @NotNull ReachingDefinitionsDfaInstance dfaInstance) { - TIntObjectHashMap result = new TIntObjectHashMap(); + 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); } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsDfaInstance.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsDfaInstance.java index b94554853e9c..6e6fdf4cfdab 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsDfaInstance.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsDfaInstance.java @@ -26,7 +26,7 @@ import java.util.Arrays; /** * @author ven */ -public class ReachingDefinitionsDfaInstance implements DfaInstance> { +public class ReachingDefinitionsDfaInstance implements DfaInstance { private final TObjectIntHashMap myVarToIndexMap = new TObjectIntHashMap(); private final Instruction[] myFlow; @@ -48,30 +48,21 @@ public class ReachingDefinitionsDfaInstance implements DfaInstance 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 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 initial() { - return new TIntObjectHashMap(); + public DefinitionMap initial() { + return new DefinitionMap(); } public boolean isForward() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsSemilattice.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsSemilattice.java index 51631c10f86d..b536e6ec4e97 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsSemilattice.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsSemilattice.java @@ -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> { - public TIntObjectHashMap join(ArrayList> ins) { - if (ins.isEmpty()) return new TIntObjectHashMap(); +public class ReachingDefinitionsSemilattice implements Semilattice { + public DefinitionMap join(ArrayList ins) { + if (ins.isEmpty()) return new DefinitionMap(); - TIntObjectHashMap result = new TIntObjectHashMap(); - for (TIntObjectHashMap map : ins) { - merge(result, map); + DefinitionMap result = new DefinitionMap(); + for (DefinitionMap map : ins) { + result.merge(map); } return result; } - private void merge(final TIntObjectHashMap result, TIntObjectHashMap map2) { - map2.forEachEntry(new TIntObjectProcedure() { - 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 m1, final TIntObjectHashMap m2) { - if (m1.size() != m2.size()) return false; - - return m1.forEachEntry(new TIntObjectProcedure() { - 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); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java index 9b9f0cdd1aad..795ba9ebd61d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java @@ -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>> pair = getDefUseMaps(scope); + final Pair> pair = getDefUseMaps(scope); - List> dfaResult = pair.second; + List dfaResult = pair.second; if (dfaResult == null) return null; final int varIndex = pair.first.getVarIndex(varName); - final TIntObjectHashMap 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>> getDefUseMaps(final GrControlFlowOwner scope) { - return CachedValuesManager.getManager(scope.getProject()).getCachedValue(scope, new CachedValueProvider>>>() { + private static Pair> getDefUseMaps(final GrControlFlowOwner scope) { + return CachedValuesManager.getManager(scope.getProject()).getCachedValue(scope, new CachedValueProvider>>() { @Override - public Result>>> compute() { + public Result>> compute() { final Instruction[] flow = scope.getControlFlow(); final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow) { @Override - public void fun(TIntObjectHashMap 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> engine = new DFAEngine>(flow, dfaInstance, lattice); - final List> dfaResult = engine.performDFAWithTimeout(); + final DFAEngine engine = new DFAEngine(flow, dfaInstance, lattice); + final List dfaResult = engine.performDFAWithTimeout(); return Result.create(Pair.create(dfaInstance, dfaResult), PsiModificationTracker.MODIFICATION_COUNT); } });