From e4df4059d19f8bd3c3ee6f9e34a5c00d97044775 Mon Sep 17 00:00:00 2001 From: Andrey Ponomarev Date: Thu, 21 Feb 2013 01:46:09 +0100 Subject: [PATCH] J2K: Detect @NotNull references in call chains --- .../jet/j2k/ast/CallChainExpression.java | 2 +- .../jet/j2k/visitors/ExpressionVisitor.java | 12 +++++++++- .../file/jetbrainsNotNullChainExpr.jav | 22 +++++++++++++++++++ .../file/jetbrainsNotNullChainExpr.kt | 17 ++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.jav create mode 100644 j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java b/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java index 48170f069b1..fa51f44691d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java +++ b/j2k/src/org/jetbrains/jet/j2k/ast/CallChainExpression.java @@ -39,7 +39,7 @@ public class CallChainExpression extends Expression { @Override public boolean isNullable() { - return myIdentifier.isNullable(); + return myExpression.isNullable() || myIdentifier.isNullable(); } @NotNull diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.java b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.java index 6c540134b58..7fefb7220e0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.java +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.java @@ -21,6 +21,7 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.j2k.Converter; +import org.jetbrains.jet.j2k.ConverterUtil; import org.jetbrains.jet.j2k.ast.*; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; @@ -345,7 +346,8 @@ public class ExpressionVisitor extends StatementVisitor { final boolean insideSecondaryConstructor = isInsideSecondaryConstructor(expression); final boolean hasReceiver = isFieldReference && insideSecondaryConstructor; final boolean isThis = isThisExpression(expression); - final boolean isNullable = getConverter().typeToType(expression.getType()).isNullable(); + final boolean notNull = isResolvedToNotNull(expression); + final boolean isNullable = getConverter().typeToType(expression.getType(), notNull).isNullable(); final String className = getClassNameWithConstructor(expression); Expression identifier = new IdentifierImpl(expression.getReferenceName(), isNullable); @@ -364,6 +366,14 @@ public class ExpressionVisitor extends StatementVisitor { ); } + private static boolean isResolvedToNotNull(PsiReference expression) { + PsiElement target = expression.resolve(); + if (target instanceof PsiModifierListOwner) { + return ConverterUtil.isAnnotatedAsNotNull(((PsiModifierListOwner) target).getModifierList()); + } + return false; + } + @NotNull private static String getClassNameWithConstructor(@NotNull PsiReferenceExpression expression) { PsiElement context = expression.getContext(); diff --git a/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.jav b/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.jav new file mode 100644 index 00000000000..c8d50704ff8 --- /dev/null +++ b/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.jav @@ -0,0 +1,22 @@ +package test; + +import org.jetbrains.annotations.NotNull; + +class Foo { + void execute() {} +} + +class Bar { + @NotNull + Foo fooNotNull = Foo(); + Foo fooNullable = null; +} + +class Test { + public void test(@NotNull Bar barNotNull, Bar barNullable) { + barNotNull.fooNotNull.execute(); + barNotNull.fooNullable.execute(); + barNullable.fooNotNull.execute(); + barNullable.fooNullable.execute(); + } +} diff --git a/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.kt b/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.kt new file mode 100644 index 00000000000..8f43666f096 --- /dev/null +++ b/j2k/tests/testData/ast/annotations/file/jetbrainsNotNullChainExpr.kt @@ -0,0 +1,17 @@ +package test +open class Foo() { +open fun execute() : Unit { +} +} +open class Bar() { +var fooNotNull : Foo = Foo() +var fooNullable : Foo? = null +} +open class Test() { +public open fun test(barNotNull : Bar, barNullable : Bar?) : Unit { +barNotNull.fooNotNull.execute() +barNotNull.fooNullable?.execute() +barNullable?.fooNotNull?.execute() +barNullable?.fooNullable?.execute() +} +} \ No newline at end of file