mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[groovy] dfa: treat null comparison as instanceof (IDEA-201672)
This commit is contained in:
+13
-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-2019 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.controlFlow;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
@@ -31,6 +17,8 @@ import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtilKt.isNullLiteral;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -75,6 +63,16 @@ public class InstanceOfInstruction extends InstructionImpl implements MixinTypeI
|
||||
return new Pair<>(left, type);
|
||||
}
|
||||
}
|
||||
else if (element instanceof GrBinaryExpression) {
|
||||
GrExpression left = ((GrBinaryExpression)element).getLeftOperand();
|
||||
GrExpression right = ((GrBinaryExpression)element).getRightOperand();
|
||||
if (isNullLiteral(right)) {
|
||||
return Pair.create(left, PsiType.NULL);
|
||||
}
|
||||
else if (right != null && isNullLiteral(left)) {
|
||||
return Pair.create(right, PsiType.NULL);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -41,7 +41,8 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.T_ELVIS_ASSIGN;
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.*;
|
||||
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtilKt.isNullLiteral;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
@@ -559,6 +560,18 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
processInstanceOf(expression, ((GrInExpression)expression).getNegationToken() != null);
|
||||
return;
|
||||
}
|
||||
if (opType == T_EQ || opType == T_NEQ) {
|
||||
if (isNullLiteral(right)) {
|
||||
left.accept(this);
|
||||
processInstanceOf(expression, opType == T_NEQ);
|
||||
return;
|
||||
}
|
||||
else if (right != null && isNullLiteral(left)) {
|
||||
right.accept(this);
|
||||
processInstanceOf(expression, opType == T_NEQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (opType != GroovyTokenTypes.mLOR && opType != GroovyTokenTypes.mLAND && opType != GroovyTokenTypes.kIN) {
|
||||
left.accept(this);
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrInstanceOfExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
@@ -160,6 +161,7 @@ class InferenceCache {
|
||||
return PsiTreeUtil.findFirstParent(
|
||||
element,
|
||||
element1 -> !(element1.getParent() instanceof GrExpression)
|
||||
|| element1 instanceof GrBinaryExpression
|
||||
|| element1 instanceof GrInstanceOfExpression
|
||||
|| isExpressionStatement(element1)
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiParameter
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.kIN
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.KW_NULL
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration
|
||||
@@ -14,11 +15,13 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClaus
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrOperatorExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl
|
||||
|
||||
/**
|
||||
* @param owner modifier list owner
|
||||
@@ -63,3 +66,7 @@ fun GrCodeReferenceElement.mayContainTypeArguments(): Boolean {
|
||||
val (parent, _) = skipParentsOfType<GrCodeReferenceElement>() ?: return true
|
||||
return parent !is GrImportStatement
|
||||
}
|
||||
|
||||
fun GrExpression?.isNullLiteral(): Boolean {
|
||||
return this is GrLiteral && GrLiteralImpl.getLiteralType(this) == KW_NULL
|
||||
}
|
||||
|
||||
+2
@@ -106,6 +106,8 @@ class ControlFlowTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
void testIfInstanceofOr() { doTest() }
|
||||
|
||||
void testIfNullOrInstanceof() { doTest() }
|
||||
|
||||
void testReturnMapFromClosure() { doTest() }
|
||||
|
||||
void testSwitchInTryWithThrows() { doTest() }
|
||||
|
||||
+52
@@ -571,6 +571,58 @@ def foo(a) {
|
||||
''', 'A'
|
||||
}
|
||||
|
||||
void 'test null or instanceof'() {
|
||||
doTest '''\
|
||||
def foo(a) {
|
||||
if (a == null || a instanceof String) {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', JAVA_LANG_STRING
|
||||
}
|
||||
|
||||
void 'test null or instanceof 2'() {
|
||||
doTest '''\
|
||||
def foo(a) {
|
||||
if (null == a || a instanceof String) {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', JAVA_LANG_STRING
|
||||
}
|
||||
|
||||
void 'test instanceof or null'() {
|
||||
doTest '''\
|
||||
def foo(a) {
|
||||
if (a == null || a instanceof String) {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', JAVA_LANG_STRING
|
||||
}
|
||||
|
||||
void 'test instanceof or null 2'() {
|
||||
doTest '''\
|
||||
def foo(a) {
|
||||
if (null == a || a instanceof String) {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', JAVA_LANG_STRING
|
||||
}
|
||||
|
||||
void 'test null or instanceof else'() {
|
||||
doTest '''\
|
||||
def foo(a) {
|
||||
if (a != null && a !instanceof String) {
|
||||
|
||||
} else {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', JAVA_LANG_STRING
|
||||
}
|
||||
|
||||
void 'test enum constant'() {
|
||||
doTest('''\
|
||||
import static MyEnum.*
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
if (a == null || a instanceof String) {
|
||||
a
|
||||
}
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) element: IF statement
|
||||
2(3) Condition Logical expression
|
||||
3(4) READ a
|
||||
4(5,7) Condition Relational expression, dependent: 2
|
||||
5(6) instanceof: a == null
|
||||
6(9) Negating goto instruction, condition=4Relational expression
|
||||
7(8) instanceof: a == null
|
||||
8(14) element: Logical expression
|
||||
9(10) READ a
|
||||
10(11,13) Condition Instanceof expression
|
||||
11(12) instanceof: a instanceof String
|
||||
12(16) Negating goto instruction, condition=10Instanceof expression
|
||||
13(14) instanceof: a instanceof String
|
||||
14(15) READ a
|
||||
15(16) element: Reference expression MAYBE_RETURN
|
||||
16(17) End element: IF statement
|
||||
17() element: null
|
||||
+16
-12
@@ -10,15 +10,19 @@ return url
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) element: IF statement
|
||||
2(3,10) READ url
|
||||
3(4) element: Open block
|
||||
4(11) WRITE url
|
||||
5(6) element: Catch clause
|
||||
6(7) WRITE e
|
||||
7(8) READ e
|
||||
8(9) ARGUMENTS element: NEW expression
|
||||
9(13) THROW. element: THROW statement
|
||||
10(11) End element: IF statement
|
||||
11(12) READ url
|
||||
12(13) element: RETURN statement
|
||||
13() element: null
|
||||
2(3) READ url
|
||||
3(4,6) Condition Relational expression
|
||||
4(5) instanceof: url == null
|
||||
5(14) Negating goto instruction, condition=3Relational expression
|
||||
6(7) instanceof: url == null
|
||||
7(8) element: Open block
|
||||
8(15) WRITE url
|
||||
9(10) element: Catch clause
|
||||
10(11) WRITE e
|
||||
11(12) READ e
|
||||
12(13) ARGUMENTS element: NEW expression
|
||||
13(17) THROW. element: THROW statement
|
||||
14(15) End element: IF statement
|
||||
15(16) READ url
|
||||
16(17) element: RETURN statement
|
||||
17() element: null
|
||||
Reference in New Issue
Block a user