From 8ec3cc64a010a0623a7b1e92454cf64a207fbb28 Mon Sep 17 00:00:00 2001 From: Jan Reehuis Date: Tue, 19 Feb 2019 15:49:50 +0100 Subject: [PATCH 1/5] nails the Lint API level declaration to 1 to support backwards compatibility --- .../net/grandcentrix/thirtyinch/lint/TiLintRegistry.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/TiLintRegistry.kt b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/TiLintRegistry.kt index 64159cc1..458b1cff 100644 --- a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/TiLintRegistry.kt +++ b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/TiLintRegistry.kt @@ -16,5 +16,10 @@ class TiLintRegistry : IssueRegistry() { } ) - override val api: Int = com.android.tools.lint.detector.api.CURRENT_API + /** + * Lint API Version for which the Checks are build. + * + * See [com.android.tools.lint.detector.api.describeApi] for possible options + */ + override val api: Int = 1 } From bdc44d65848f37870350dfecc273cae1e28fad35 Mon Sep 17 00:00:00 2001 From: Jan Reehuis Date: Tue, 19 Feb 2019 15:50:47 +0100 Subject: [PATCH 2/5] also check the super class when looking for the MVP view --- .../thirtyinch/lint/detector/BaseMissingViewDetector.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/BaseMissingViewDetector.kt b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/BaseMissingViewDetector.kt index 041e16f3..74e1d74e 100644 --- a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/BaseMissingViewDetector.kt +++ b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/BaseMissingViewDetector.kt @@ -73,6 +73,9 @@ abstract class BaseMissingViewDetector : Detector(), Detector.UastScanner { return tryFindViewImplementation(context, uastContext.getClass(resolvedType), viewInterface) } } - return false + + val superClass = declaration.superClass + + return superClass != null && tryFindViewImplementation(context, superClass, viewInterface) } } \ No newline at end of file From 74d9ae0b20da9367396155ffda868e60e134e108 Mon Sep 17 00:00:00 2001 From: Jan Reehuis Date: Tue, 19 Feb 2019 15:51:11 +0100 Subject: [PATCH 3/5] also check the super class when looking for the MVP view implementation --- .../lint/detector/MissingViewInThirtyInchDetector.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt index 5cc81387..0d67c2d4 100644 --- a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt +++ b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt @@ -53,6 +53,9 @@ class MissingViewInThirtyInchDetector : BaseMissingViewDetector() { .firstOrNull() ?: (type as? PsiClassType)?.let { tryFindViewInterface(it) } } + ?: extendedType.superTypes.firstNotNullResult { superType -> + (superType as? PsiClassType)?.let { tryFindViewInterface(it) } + } } override fun allowMissingViewInterface(context: JavaContext, declaration: UClass, From 49267eadf9df499d6968be5cb55583758fb72e05 Mon Sep 17 00:00:00 2001 From: Jan Reehuis Date: Tue, 19 Feb 2019 16:06:11 +0100 Subject: [PATCH 4/5] adds tests for the case that TiActivity, TiPresenter and TiView are just used through base implementations --- .../MissingViewInThirtyInchDetectorTest.kt | 224 +++++++++++++++++- 1 file changed, 222 insertions(+), 2 deletions(-) diff --git a/thirtyinch-lint/src/test/kotlin/net/grandcentrix/thirtyinch/lint/MissingViewInThirtyInchDetectorTest.kt b/thirtyinch-lint/src/test/kotlin/net/grandcentrix/thirtyinch/lint/MissingViewInThirtyInchDetectorTest.kt index 8adb175e..3570e852 100644 --- a/thirtyinch-lint/src/test/kotlin/net/grandcentrix/thirtyinch/lint/MissingViewInThirtyInchDetectorTest.kt +++ b/thirtyinch-lint/src/test/kotlin/net/grandcentrix/thirtyinch/lint/MissingViewInThirtyInchDetectorTest.kt @@ -457,6 +457,226 @@ class MissingViewInThirtyInchDetectorTest : LintDetectorTest() { ).isEqualTo(NO_WARNINGS) } + fun testJava_Activity_throughTransitiveBaseClass_withBasePresenter_withBaseView_noWarning() { + val baseView = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "interface BaseView extends TiView {\n" + + "}" + ) + + val basePresenter = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "abstract class BasePresenter extends TiPresenter {\n" + + "}" + ) + + val baseActivity = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "abstract class BaseActivity

, V extends BaseView> extends TiActivity {\n" + + "}" + ) + + val activity = java( + "package foo;\n" + + "class InformationActivity extends BaseActivity implements MyView {\n" + + "}" + ) + + val view = java( + "package foo;\n" + + "interface MyView extends BaseView {\n" + + "}" + ) + + val customPresenter = java( + "package foo;\n" + + "class MyPresenter extends BasePresenter {\n" + + "}" + ) + + assertThat( + lintProject( + tiActivityStub, + tiPresenterStub, + tiViewStub, + baseView, + view, + basePresenter, + customPresenter, + baseActivity, + activity + ) + ).isEqualTo(NO_WARNINGS) + } + + fun testKotlin_Activity_throughTransitiveBaseClass_withBasePresenter_withBaseView_noWarning() { + val baseView = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "interface BaseView : TiView {\n" + + "}" + ) + + val basePresenter = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "abstract class BasePresenter : TiPresenter() {\n" + + "}" + ) + + val baseActivity = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "abstract class BaseActivity

, V : BaseView> : TiActivity(), MyView {\n" + + "}" + ) + + val activity = kotlin( + "package foo\n" + + "class InformationActivity : BaseActivity() {\n" + + "}" + ) + + val view = kotlin( + "package foo\n" + + "interface MyView : BaseView {\n" + + "}" + ) + + val customPresenter = kotlin( + "package foo\n" + + "class MyPresenter : BasePresenter() {\n" + + "}" + ) + + assertThat( + lintProject( + tiActivityStub, + tiPresenterStub, + tiViewStub, + baseView, + view, + basePresenter, + customPresenter, + baseActivity, + activity + ) + ).isEqualTo(NO_WARNINGS) + } + + fun testJava_Activity_throughTransitiveBaseClass_withBasePresenter_withBaseView_hasWarning() { + val baseView = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "interface BaseView extends TiView {\n" + + "}" + ) + + val basePresenter = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "abstract class BasePresenter extends TiPresenter {\n" + + "}" + ) + + val baseActivity = java( + "package foo;\n" + + "import net.grandcentrix.thirtyinch.*;\n" + + "abstract class BaseActivity

, V extends BaseView> extends TiActivity {\n" + + "}" + ) + + val activity = java( + "package foo;\n" + + "class InformationActivity extends BaseActivity {\n" + + "}" + ) + + val view = java( + "package foo;\n" + + "interface MyView extends BaseView {\n" + + "}" + ) + + val customPresenter = java( + "package foo;\n" + + "class MyPresenter extends BasePresenter {\n" + + "}" + ) + + assertThat( + lintProject( + tiActivityStub, + tiPresenterStub, + tiViewStub, + baseView, + view, + basePresenter, + customPresenter, + baseActivity, + activity + ) + ).containsOnlyOnce(TiIssue.MissingView.id) + } + + fun testKotlin_Activity_throughTransitiveBaseClass_withBasePresenter_withBaseView_hasWarning() { + val baseView = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "interface BaseView : TiView {\n" + + "}" + ) + + val basePresenter = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "abstract class BasePresenter : TiPresenter() {\n" + + "}" + ) + + val baseActivity = kotlin( + "package foo\n" + + "import net.grandcentrix.thirtyinch.*\n" + + "abstract class BaseActivity

, V : BaseView> : TiActivity() {\n" + + "}" + ) + + val activity = kotlin( + "package foo\n" + + "class InformationActivity : BaseActivity() {\n" + + "}" + ) + + val view = kotlin( + "package foo\n" + + "interface MyView : BaseView {\n" + + "}" + ) + + val customPresenter = kotlin( + "package foo\n" + + "class MyPresenter : BasePresenter() {\n" + + "}" + ) + + assertThat( + lintProject( + tiActivityStub, + tiPresenterStub, + tiViewStub, + baseView, + view, + basePresenter, + customPresenter, + baseActivity, + activity + ) + ).containsOnlyOnce(TiIssue.MissingView.id) + } + fun testKotlin_Activity_throughBaseClass_noWarning() { val baseActivity = kotlin( "package foo;\n" + @@ -488,7 +708,7 @@ class MissingViewInThirtyInchDetectorTest : LintDetectorTest() { val baseActivity = kotlin( "package foo;\n" + "import net.grandcentrix.thirtyinch.*;\n" + - "public class BaseActivity : TiActivity, MyView>() {\n" + + "public abstract class BaseActivity : TiActivity, MyView>() {\n" + "}" ) @@ -825,7 +1045,7 @@ class MissingViewInThirtyInchDetectorTest : LintDetectorTest() { val baseFragment = kotlin( "package foo\n" + "import net.grandcentrix.thirtyinch.*\n" + - "class BaseFragment : TiFragment, MyView>() {\n" + + "abstract class BaseFragment : TiFragment, MyView>() {\n" + "}" ) From f410a65212d1afa0e7971c98dd52dc7e62dcd362 Mon Sep 17 00:00:00 2001 From: Jan Reehuis Date: Fri, 15 Mar 2019 10:51:17 +0100 Subject: [PATCH 5/5] prevent that the provideView overridden check succeeds to to the TI super classes --- .../lint/detector/MissingViewInThirtyInchDetector.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt index 0d67c2d4..45b7932a 100644 --- a/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt +++ b/thirtyinch-lint/src/main/kotlin/net/grandcentrix/thirtyinch/lint/detector/MissingViewInThirtyInchDetector.kt @@ -60,8 +60,15 @@ class MissingViewInThirtyInchDetector : BaseMissingViewDetector() { override fun allowMissingViewInterface(context: JavaContext, declaration: UClass, viewInterface: PsiType): Boolean { + // if the superClass is one of the TI base classes, prevent deeper recursive checks + val superClass = declaration.superClass + .let { sClass -> + if (TI_CLASS_NAMES.any { tiName -> tiName == sClass?.qualifiedName }) null else sClass + } + // Interface not implemented; check if provideView() is overridden instead - return declaration.findMethodsByName(PROVIDE_VIEW_METHOD, true) - .any { viewInterface == it.returnType } + return declaration.findMethodsByName(PROVIDE_VIEW_METHOD, false) + .firstNotNullResult { viewInterface == it.returnType } + ?: (superClass != null && allowMissingViewInterface(context, superClass, viewInterface)) } } \ No newline at end of file