From 530ab42de6da4c4c94be5ac2783236ee6899d2b7 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 21 Apr 2016 21:06:30 +0300 Subject: [PATCH] Android Extensions: Fix KT-10969 (NullPointerException when finding view in Fragment if getView() is null) (cherry picked from commit 80f5852) --- .../AndroidExpressionCodegenExtension.kt | 11 ++++++ .../testData/codegen/android/FakeFragment.kt | 2 +- .../codegen/android/fragmentNoGetView/0.kt | 34 +++++++++++++++++++ .../codegen/android/fragmentNoGetView/1.kt | 26 ++++++++++++++ .../fragmentNoGetView/AndroidManifest.xml | 33 ++++++++++++++++++ .../fragmentNoGetView/CustomWidgets.kt | 8 +++++ .../fragmentNoGetView/layout/layout.xml | 15 ++++++++ .../android/test/AndroidBoxTestGenerated.java | 12 +++++++ 8 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/0.kt create mode 100644 plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/1.kt create mode 100644 plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/AndroidManifest.xml create mode 100644 plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/CustomWidgets.kt create mode 100644 plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/layout/layout.xml diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt index 0500c1042f6..9d4baa0cf5b 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt @@ -373,6 +373,17 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { } AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> { iv.invokevirtual(className, "getView", "()Landroid/view/View;", false) + iv.dup() + val lgetViewNotNull = Label() + iv.ifnonnull(lgetViewNotNull) + + // Return if getView() is null + iv.pop() + iv.aconst(null) + iv.areturn(viewType) + + // Else return getView().findViewById(id) + iv.visitLabel(lgetViewNotNull) loadId() iv.invokevirtual("android/view/View", "findViewById", "(I)Landroid/view/View;", false) } diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeFragment.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeFragment.kt index a0f13c60673..f4fc69b6557 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeFragment.kt +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeFragment.kt @@ -5,5 +5,5 @@ import android.app.Activity abstract class Fragment { open fun getActivity(): Activity = throw Exception("Function getActivity() is not overridden") - open fun getView(): View = throw Exception("Function getView() is not overridden") + open fun getView(): View? = throw Exception("Function getView() is not overridden") } diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/0.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/0.kt new file mode 100644 index 00000000000..858e029157e --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/0.kt @@ -0,0 +1,34 @@ +package test + +import android.app.Activity +import android.app.Fragment +import android.content.Context +import android.view.View +import android.widget.* +import org.my.cool.MyButton +import kotlinx.android.synthetic.main.layout.* + +class R { + class id { + companion object { + const val login = 5 + } + } +} + +class MyFragment(): Fragment() { + val baseActivity = Activity() + + override fun getActivity(): Activity = baseActivity + + override fun getView(): View? = null + + public fun box(): String { + val button = login + return if (button == null) "OK" else "Button is not null: $button" + } +} + +fun box(): String { + return MyFragment().box() +} diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/1.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/1.kt new file mode 100644 index 00000000000..47e47191437 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/1.kt @@ -0,0 +1,26 @@ +package test + +import android.app.Activity +import android.app.Fragment +import android.content.Context +import android.view.View +import android.widget.* +import org.my.cool.MyButton +import kotlinx.android.synthetic.main.layout.* + +class R { + class id { + companion object { + const val login = 5 + } + } +} + +class MyFragment(): Fragment() { + val baseActivity = Activity() + override fun getView(): View? = null +} + +fun box(): String { + return "OK" +} diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/AndroidManifest.xml b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/AndroidManifest.xml new file mode 100644 index 00000000000..00856b86107 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/CustomWidgets.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/CustomWidgets.kt new file mode 100644 index 00000000000..ddd174f0bc7 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/CustomWidgets.kt @@ -0,0 +1,8 @@ +package org.my.cool + +import android.widget.Button +import android.content.Context + +class MyButton(ctx: Context): Button(ctx) { + override fun toString(): String {return "MyButton"} +} diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/layout/layout.xml b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/layout/layout.xml new file mode 100644 index 00000000000..101bb490115 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/layout/layout.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/lang/resolve/android/test/AndroidBoxTestGenerated.java b/plugins/plugins-tests/tests/org/jetbrains/kotlin/lang/resolve/android/test/AndroidBoxTestGenerated.java index e353428893d..dea270cb1b5 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/lang/resolve/android/test/AndroidBoxTestGenerated.java +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/lang/resolve/android/test/AndroidBoxTestGenerated.java @@ -55,6 +55,12 @@ public class AndroidBoxTestGenerated extends AbstractAndroidBoxTest { doCompileAgainstAndroidSdkTest(fileName); } + @TestMetadata("fragmentNoGetView") + public void testFragmentNoGetView() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/"); + doCompileAgainstAndroidSdkTest(fileName); + } + @TestMetadata("manyWidgets") public void testManyWidgets() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/android/manyWidgets/"); @@ -106,6 +112,12 @@ public class AndroidBoxTestGenerated extends AbstractAndroidBoxTest { doFakeInvocationTest(fileName); } + @TestMetadata("fragmentNoGetView") + public void testFragmentNoGetView() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/android/fragmentNoGetView/"); + doFakeInvocationTest(fileName); + } + @TestMetadata("manyWidgets") public void testManyWidgets() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/codegen/android/manyWidgets/");