mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[groovy] dfa: allow to analyze only instructions reachable from root
After 'for' updates (IDEA-188433) classic 'for' variables are no longer parameters and they are not treated as
initialized by default, thus making GrUnassignedVariableAccessTest#testForLoopWithNestedEndlessLoop fail:
```
for (int x = 1; x < 10; x++) {
for (;;) {}
}
```
`x++` in the above code became highlighted as read-before-write warning despite it being unreachable from root. Skipping
such unreachable instructions in read-before-write analysis helps to avoid introducing unnecessary warnings.
This commit is contained in:
+20
-23
@@ -1,37 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
@file:JvmName("OrderUtil")
|
||||
|
||||
package org.jetbrains.plugins.groovy.lang.psi.controlFlow
|
||||
|
||||
import com.intellij.util.ArrayUtil.EMPTY_INT_ARRAY
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl
|
||||
import java.util.*
|
||||
|
||||
private val fakeRoot = InstructionImpl(null)
|
||||
|
||||
fun reversedPostOrder(flow: Array<Instruction>): IntArray = postOrder(flow).reversedArray()
|
||||
@JvmOverloads
|
||||
fun reversedPostOrder(flow: Array<Instruction>, reachable: Boolean = false): IntArray = postOrder(flow, reachable).reversedArray()
|
||||
|
||||
fun postOrder(flow: Array<Instruction>): IntArray {
|
||||
val N = flow.size
|
||||
val result = IntArray(N)
|
||||
fun postOrder(flow: Array<Instruction>, reachable: Boolean): IntArray {
|
||||
val n = flow.size
|
||||
if (n == 0) return EMPTY_INT_ARRAY
|
||||
|
||||
val result = IntArray(n) { -1 }
|
||||
var resultIndex = 0
|
||||
|
||||
val visited = BooleanArray(N)
|
||||
val visited = BooleanArray(n)
|
||||
val stack: Deque<Pair<Instruction, Iterator<Instruction>>> = LinkedList()
|
||||
stack.push(fakeRoot to flow.iterator())
|
||||
|
||||
val rootIterator = if (reachable) listOf(flow[0]).iterator() else flow.iterator()
|
||||
stack.push(fakeRoot to rootIterator)
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
val (instruction, iterator) = stack.peek()
|
||||
@@ -51,8 +43,13 @@ fun postOrder(flow: Array<Instruction>): IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
assert(resultIndex == N)
|
||||
return result
|
||||
if (reachable) {
|
||||
assert(resultIndex <= n)
|
||||
}
|
||||
else {
|
||||
assert(resultIndex == n)
|
||||
}
|
||||
return if (resultIndex == n) result else result.take(resultIndex).toIntArray()
|
||||
}
|
||||
|
||||
private inline fun <T> Iterator<T>.firstOrNull(predicate: (T) -> Boolean): T? {
|
||||
|
||||
+4
-18
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
@@ -84,7 +70,7 @@ public class DFAEngine<E> {
|
||||
final List<E> info = new ArrayList<>(Collections.nCopies(n, myDfa.initial()));
|
||||
final CallEnvironment env = new MyCallEnvironment(n);
|
||||
|
||||
final WorkList workList = new WorkList(getFlowOrder());
|
||||
final WorkList workList = new WorkList(n, getFlowOrder());
|
||||
|
||||
while (!workList.isEmpty()) {
|
||||
ProgressManager.checkCanceled();
|
||||
@@ -108,10 +94,10 @@ public class DFAEngine<E> {
|
||||
@NotNull
|
||||
private int[] getFlowOrder() {
|
||||
if (myDfa.isForward()) {
|
||||
return reversedPostOrder(myFlow);
|
||||
return reversedPostOrder(myFlow, myDfa.isReachable());
|
||||
}
|
||||
else {
|
||||
return postOrder(myFlow);
|
||||
return postOrder(myFlow, myDfa.isReachable());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -31,4 +17,11 @@ public interface DfaInstance<E> {
|
||||
default boolean isForward() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this instance expects only instructions reachable from root
|
||||
*/
|
||||
default boolean isReachable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-17
@@ -1,23 +1,9 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow
|
||||
|
||||
import java.util.*
|
||||
|
||||
internal class WorkList(order: IntArray) {
|
||||
internal class WorkList(flowSize: Int, order: IntArray) {
|
||||
|
||||
private val mySize: Int = order.size
|
||||
/**
|
||||
@@ -27,7 +13,7 @@ internal class WorkList(order: IntArray) {
|
||||
/**
|
||||
* Mapping: instruction number -> index in [myOrder] array
|
||||
*/
|
||||
private val myInstructionToOrder: IntArray = IntArray(mySize)
|
||||
private val myInstructionToOrder: IntArray = IntArray(flowSize)
|
||||
/**
|
||||
* Mapping: index -> whether instruction number needs to be processed
|
||||
*
|
||||
|
||||
+3
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite
|
||||
|
||||
import gnu.trove.TObjectIntHashMap
|
||||
@@ -41,4 +27,6 @@ class ReadBeforeWriteInstance(val nameIndex: TObjectIntHashMap<String>, val only
|
||||
}
|
||||
|
||||
override fun initial(): ReadBeforeWriteState = ReadBeforeWriteState.bottom
|
||||
|
||||
override fun isReachable(): Boolean = true
|
||||
}
|
||||
Reference in New Issue
Block a user