From 89c4196c060353aa94e53ec7e51c0d1b67c317f1 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 20 Oct 2017 20:54:01 +0300 Subject: [PATCH] Add inspections for implicit and explicit 'this' #KT-4580 Fixed --- .../idea/util/implicitReceiversUtils.kt | 17 +- .../inspectionDescriptions/ExplicitThis.html | 5 + .../inspectionDescriptions/ImplicitThis.html | 5 + idea/src/META-INF/plugin.xml | 19 +++ .../inspections/ExplicitThisInspection.kt | 80 ++++++++++ .../inspections/ImplicitThisInspection.kt | 74 +++++++++ .../inspectionsLocal/explicitThis/.inspection | 1 + .../explicitThis/differentReceiverInstance.kt | 12 ++ .../differentReceiverInstanceExtension.kt | 12 ++ .../explicitThis/differentReceiverType.kt | 16 ++ .../differentReceiverTypeExtension.kt | 16 ++ .../explicitThis/extension.kt | 7 + .../explicitThis/extension.kt.after | 7 + .../inspectionsLocal/explicitThis/function.kt | 7 + .../explicitThis/function.kt.after | 7 + .../explicitThis/multipleReceivers.kt | 11 ++ .../explicitThis/multipleReceivers.kt.after | 11 ++ .../multipleReceiversExtension.kt | 11 ++ .../multipleReceiversExtension.kt.after | 11 ++ .../explicitThis/nestedReceivers.kt | 18 +++ .../nestedReceiversDifferentParameters.kt | 17 ++ .../explicitThis/nestedReceiversExtension.kt | 17 ++ ...edReceiversExtensionDifferentParameters.kt | 15 ++ .../inspectionsLocal/explicitThis/property.kt | 7 + .../explicitThis/property.kt.after | 7 + .../explicitThis/variableWithSameName.kt | 11 ++ .../inspectionsLocal/implicitThis/.inspection | 1 + .../inspectionsLocal/implicitThis/function.kt | 7 + .../implicitThis/function.kt.after | 7 + .../implicitThis/functionPartOfCall.kt | 9 ++ .../implicitThis/multipleReceivers.kt | 15 ++ .../implicitThis/multipleReceivers.kt.after | 15 ++ .../inspectionsLocal/implicitThis/nested.kt | 11 ++ .../implicitThis/nested.kt.after | 11 ++ .../implicitThis/nestedCall.kt | 8 + .../implicitThis/nestedCall.kt.after | 8 + .../inspectionsLocal/implicitThis/property.kt | 7 + .../implicitThis/property.kt.after | 7 + .../implicitThis/propertyPartOfCall.kt | 9 ++ .../inspectionsLocal/implicitThis/topLevel.kt | 9 ++ .../LocalInspectionTestGenerated.java | 150 ++++++++++++++++++ 41 files changed, 694 insertions(+), 1 deletion(-) create mode 100644 idea/resources/inspectionDescriptions/ExplicitThis.html create mode 100644 idea/resources/inspectionDescriptions/ImplicitThis.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/ExplicitThisInspection.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/.inspection create mode 100644 idea/testData/inspectionsLocal/explicitThis/differentReceiverInstance.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/differentReceiverTypeExtension.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/extension.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/extension.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/function.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/function.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/nestedReceivers.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/nestedReceiversDifferentParameters.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtension.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtensionDifferentParameters.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/property.kt create mode 100644 idea/testData/inspectionsLocal/explicitThis/property.kt.after create mode 100644 idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/.inspection create mode 100644 idea/testData/inspectionsLocal/implicitThis/function.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/function.kt.after create mode 100644 idea/testData/inspectionsLocal/implicitThis/functionPartOfCall.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt.after create mode 100644 idea/testData/inspectionsLocal/implicitThis/nested.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/nested.kt.after create mode 100644 idea/testData/inspectionsLocal/implicitThis/nestedCall.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/nestedCall.kt.after create mode 100644 idea/testData/inspectionsLocal/implicitThis/property.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/property.kt.after create mode 100644 idea/testData/inspectionsLocal/implicitThis/propertyPartOfCall.kt create mode 100644 idea/testData/inspectionsLocal/implicitThis/topLevel.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/implicitReceiversUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/implicitReceiversUtils.kt index 438c2b2db06..47fa23c1515 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/implicitReceiversUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/implicitReceiversUtils.kt @@ -26,15 +26,28 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import java.util.* fun LexicalScope.getImplicitReceiversWithInstance(): Collection = getImplicitReceiversWithInstanceToExpression().keys interface ReceiverExpressionFactory { + val isImmediate: Boolean + val expressionText: String fun createExpression(psiFactory: KtPsiFactory, shortThis: Boolean = true): KtExpression } +fun LexicalScope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType: KotlinType): ReceiverExpressionFactory? { + return getImplicitReceiversWithInstanceToExpression() + .entries + .firstOrNull { (receiverDescriptor, _) -> + receiverDescriptor.type.isSubtypeOf(receiverType) + } + ?.value +} + fun LexicalScope.getImplicitReceiversWithInstanceToExpression(): Map { // we use a set to workaround a bug with receiver for companion object present twice in the result of getImplicitReceiversHierarchy() val receivers = LinkedHashSet(getImplicitReceiversHierarchy()) @@ -43,7 +56,7 @@ fun LexicalScope.getImplicitReceiversWithInstanceToExpression(): Map + +This inspection reports usages of explicit 'this' when it can be omitted. + + diff --git a/idea/resources/inspectionDescriptions/ImplicitThis.html b/idea/resources/inspectionDescriptions/ImplicitThis.html new file mode 100644 index 00000000000..08225eb3eef --- /dev/null +++ b/idea/resources/inspectionDescriptions/ImplicitThis.html @@ -0,0 +1,5 @@ + + +This inspection reports usages of implicit 'this'. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 888b4fcb85d..ddf48eb2dbe 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2623,6 +2623,25 @@ level="WARNING" language="kotlin" /> + + + + + LexicalScope::getAllAccessibleVariables + is KtCallExpression -> LexicalScope::getAllAccessibleFunctions + else -> return + } + + //we avoid overload-related problems by enforcing that there is only one candidate + val candidates = scopeFunction(scope, referenceExpression.getReferencedNameAsName()) + if (candidates.size != 1) return + + + val receiverType = context[BindingContext.EXPRESSION_TYPE_INFO, thisExpression]?.type ?: return + val expressionFactory = scope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType) ?: return + + val label = thisExpression.getLabelName() ?: "" + if (!expressionFactory.matchesLabel(label)) return + + holder.registerProblem(thisExpression, "Redundant explicit this", LIKE_UNUSED_SYMBOL, Fix(thisExpression.text)) + } + + private fun ReceiverExpressionFactory.matchesLabel(label: String): Boolean { + val implicitLabel = expressionText.substringAfter("@", "") + return label == implicitLabel || (label == "" && isImmediate) + } + } + + private class Fix(private val text: String) : LocalQuickFix { + override fun getFamilyName(): String = "Remove redundant '$text'" + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val thisExpression = descriptor.psiElement as? KtThisExpression ?: return + val parent = thisExpression.parent as? KtDotQualifiedExpression ?: return + parent.replace(parent.selectorExpression ?: return) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt new file mode 100644 index 00000000000..35066fe4fe0 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ImplicitThisInspection.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-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. + */ + +package org.jetbrains.kotlin.idea.inspections + +import com.intellij.codeInspection.LocalQuickFix +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully +import org.jetbrains.kotlin.idea.util.getFactoryForImplicitReceiverWithSubtypeOf +import org.jetbrains.kotlin.idea.util.getResolutionScope +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getChildOfType +import org.jetbrains.kotlin.resolve.BindingContext + +class ImplicitThisInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : KtVisitorVoid() { + override fun visitExpression(expression: KtExpression) { + if (expression !is KtNameReferenceExpression) return + if (expression.isSelectorOfDotQualifiedExpression()) return + val parent = expression.parent + if (parent is KtCallExpression && parent.isSelectorOfDotQualifiedExpression()) return + + val referenceExpression = expression as? KtNameReferenceExpression + ?: expression.getChildOfType() + ?: return + + val context = expression.analyzeFully() + val scope = expression.getResolutionScope(context) ?: return + + val descriptor = context[BindingContext.REFERENCE_TARGET, referenceExpression] as? CallableDescriptor ?: return + val receiverDescriptor = descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter ?: return + val receiverType = receiverDescriptor.type + + val expressionFactory = scope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType) ?: return + val receiverText = if (expressionFactory.isImmediate) "this" else expressionFactory.expressionText + + holder.registerProblem(expression, "Add explicit '$receiverText'", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, Fix(receiverText)) + } + + private fun KtExpression.isSelectorOfDotQualifiedExpression(): Boolean { + val parent = parent + return parent is KtDotQualifiedExpression && parent.selectorExpression == this + } + } + + private class Fix(private val receiverText: String) : LocalQuickFix { + override fun getFamilyName() = "Add explicit '$receiverText'" + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val expression = descriptor.psiElement as? KtExpression ?: return + val factory = KtPsiFactory(project) + val call = expression.parent as? KtCallExpression ?: expression + + call.replace(factory.createExpressionByPattern("$0.$1", receiverText, call.text)) + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/.inspection b/idea/testData/inspectionsLocal/explicitThis/.inspection new file mode 100644 index 00000000000..f1cdd6c10d3 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ExplicitThisInspection diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstance.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstance.kt new file mode 100644 index 00000000000..554978703dd --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstance.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + val s = "" + + fun test() { + Foo().apply { + this@Foo.s + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt new file mode 100644 index 00000000000..aa82cedc209 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + fun test() { + Foo().apply { + this@Foo.s() + } + } +} + +fun Foo.s() {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt new file mode 100644 index 00000000000..04fb3f2db3d --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt @@ -0,0 +1,16 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + val s = "" + + fun test() { + Bar().apply { + this@Foo.s + } + } +} + +class Bar { + val s = "" +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/differentReceiverTypeExtension.kt b/idea/testData/inspectionsLocal/explicitThis/differentReceiverTypeExtension.kt new file mode 100644 index 00000000000..87f5d92ab46 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/differentReceiverTypeExtension.kt @@ -0,0 +1,16 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + fun test() { + Bar().apply { + this@Foo.s() + } + } +} + +class Bar + + +fun Foo.s() {} +fun Bar.s() {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/extension.kt b/idea/testData/inspectionsLocal/explicitThis/extension.kt new file mode 100644 index 00000000000..7ffa62e5c60 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/extension.kt @@ -0,0 +1,7 @@ +class Foo { + fun test() { + this.s() + } +} + +fun Foo.s() = "" \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/extension.kt.after b/idea/testData/inspectionsLocal/explicitThis/extension.kt.after new file mode 100644 index 00000000000..8c11d39aad7 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/extension.kt.after @@ -0,0 +1,7 @@ +class Foo { + fun test() { + s() + } +} + +fun Foo.s() = "" \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/function.kt b/idea/testData/inspectionsLocal/explicitThis/function.kt new file mode 100644 index 00000000000..40c83941356 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/function.kt @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + this.s() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/function.kt.after b/idea/testData/inspectionsLocal/explicitThis/function.kt.after new file mode 100644 index 00000000000..c2cb7ac7a83 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/function.kt.after @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + s() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt b/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt new file mode 100644 index 00000000000..0f99eb1562b --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + val s = "" + + fun test() { + "".apply { + this@Foo.s + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt.after b/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt.after new file mode 100644 index 00000000000..0e7deecdf93 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + val s = "" + + fun test() { + "".apply { + s + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt b/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt new file mode 100644 index 00000000000..07f79def712 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + fun test() { + "".apply { + this@Foo.s() + } + } +} + +fun Foo.s() = "" \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt.after b/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt.after new file mode 100644 index 00000000000..741e7c63e9d --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + fun test() { + "".apply { + s() + } + } +} + +fun Foo.s() = "" \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/nestedReceivers.kt b/idea/testData/inspectionsLocal/explicitThis/nestedReceivers.kt new file mode 100644 index 00000000000..b0e6fe00aa1 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/nestedReceivers.kt @@ -0,0 +1,18 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + val s = "" + + fun test() { + Bar().apply { + "".run { + this@apply.s + } + } + } +} + +class Bar { + val s = "" +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/nestedReceiversDifferentParameters.kt b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversDifferentParameters.kt new file mode 100644 index 00000000000..185188a5a98 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversDifferentParameters.kt @@ -0,0 +1,17 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + fun s(a: String) {} + + fun test() { + Bar().apply { + this@Foo.s("") + } + } +} + +class Bar { + fun s() {} +} + diff --git a/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtension.kt b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtension.kt new file mode 100644 index 00000000000..3bbcce71d67 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtension.kt @@ -0,0 +1,17 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + fun test() { + Bar().apply { + "".run { + this@apply.s() + } + } + } +} + +class Bar + +fun Foo.s() {} +fun Bar.s() {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtensionDifferentParameters.kt b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtensionDifferentParameters.kt new file mode 100644 index 00000000000..742a264b185 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtensionDifferentParameters.kt @@ -0,0 +1,15 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + fun test() { + Bar().apply { + this@Foo.s("") + } + } +} + +class Bar + +fun Foo.s(a: String) {} +fun Bar.s() {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/property.kt b/idea/testData/inspectionsLocal/explicitThis/property.kt new file mode 100644 index 00000000000..87a8e6f260f --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/property.kt @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + this.s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/property.kt.after b/idea/testData/inspectionsLocal/explicitThis/property.kt.after new file mode 100644 index 00000000000..fdea7118b93 --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/property.kt.after @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt b/idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt new file mode 100644 index 00000000000..9a6b003efbc --- /dev/null +++ b/idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME +// PROBLEM: none + +class Foo { + var s = "" + + fun test() { + val s = "" + this.s = s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/.inspection b/idea/testData/inspectionsLocal/implicitThis/.inspection new file mode 100644 index 00000000000..0b06290c9be --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ImplicitThisInspection diff --git a/idea/testData/inspectionsLocal/implicitThis/function.kt b/idea/testData/inspectionsLocal/implicitThis/function.kt new file mode 100644 index 00000000000..c2cb7ac7a83 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/function.kt @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + s() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/function.kt.after b/idea/testData/inspectionsLocal/implicitThis/function.kt.after new file mode 100644 index 00000000000..40c83941356 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/function.kt.after @@ -0,0 +1,7 @@ +class Foo { + fun s() = "" + + fun test() { + this.s() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/functionPartOfCall.kt b/idea/testData/inspectionsLocal/implicitThis/functionPartOfCall.kt new file mode 100644 index 00000000000..eef9bb6a8bf --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/functionPartOfCall.kt @@ -0,0 +1,9 @@ +// PROBLEM: none + +class Foo { + fun s() = "" + + fun test() { + this.s() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt b/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt new file mode 100644 index 00000000000..aa6fd04a962 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt @@ -0,0 +1,15 @@ +// WITH_RUNTIME + +class Foo { + fun Bar.s() = "" +} + +class Bar + +fun test() { + Bar().apply { + Foo().apply apply2@ { + s() + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt.after b/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt.after new file mode 100644 index 00000000000..203cd7935db --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt.after @@ -0,0 +1,15 @@ +// WITH_RUNTIME + +class Foo { + fun Bar.s() = "" +} + +class Bar + +fun test() { + Bar().apply { + Foo().apply apply2@ { + this@apply.s() + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/nested.kt b/idea/testData/inspectionsLocal/implicitThis/nested.kt new file mode 100644 index 00000000000..ed753b4f30e --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/nested.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + fun s() = "" + + fun test() { + "".apply { + s() + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/nested.kt.after b/idea/testData/inspectionsLocal/implicitThis/nested.kt.after new file mode 100644 index 00000000000..e70dfa01fca --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/nested.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +class Foo { + fun s() = "" + + fun test() { + "".apply { + this@Foo.s() + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt b/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt new file mode 100644 index 00000000000..cded016d44c --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt @@ -0,0 +1,8 @@ +class Foo { + val f = Foo() + val s = "" + + fun test() { + f.s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt.after b/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt.after new file mode 100644 index 00000000000..4f34d1c510a --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/nestedCall.kt.after @@ -0,0 +1,8 @@ +class Foo { + val f = Foo() + val s = "" + + fun test() { + this.f.s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/property.kt b/idea/testData/inspectionsLocal/implicitThis/property.kt new file mode 100644 index 00000000000..fdea7118b93 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/property.kt @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/property.kt.after b/idea/testData/inspectionsLocal/implicitThis/property.kt.after new file mode 100644 index 00000000000..87a8e6f260f --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/property.kt.after @@ -0,0 +1,7 @@ +class Foo { + val s = "" + + fun test() { + this.s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/propertyPartOfCall.kt b/idea/testData/inspectionsLocal/implicitThis/propertyPartOfCall.kt new file mode 100644 index 00000000000..4ffffd0327f --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/propertyPartOfCall.kt @@ -0,0 +1,9 @@ +// PROBLEM: none + +class Foo { + val s = "" + + fun test() { + this.s + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/implicitThis/topLevel.kt b/idea/testData/inspectionsLocal/implicitThis/topLevel.kt new file mode 100644 index 00000000000..b1cd84d0e07 --- /dev/null +++ b/idea/testData/inspectionsLocal/implicitThis/topLevel.kt @@ -0,0 +1,9 @@ +// PROBLEM: none + +class Foo { + fun test() { + s() + } +} + +fun s() = "" \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 74b8f23883c..844cedcd544 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -621,6 +621,156 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/explicitThis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExplicitThis extends AbstractLocalInspectionTest { + public void testAllFilesPresentInExplicitThis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/explicitThis"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("differentReceiverInstance.kt") + public void testDifferentReceiverInstance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstance.kt"); + doTest(fileName); + } + + @TestMetadata("differentReceiverInstanceExtension.kt") + public void testDifferentReceiverInstanceExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/differentReceiverInstanceExtension.kt"); + doTest(fileName); + } + + @TestMetadata("differentReceiverType.kt") + public void testDifferentReceiverType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/differentReceiverType.kt"); + doTest(fileName); + } + + @TestMetadata("differentReceiverTypeExtension.kt") + public void testDifferentReceiverTypeExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/differentReceiverTypeExtension.kt"); + doTest(fileName); + } + + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/extension.kt"); + doTest(fileName); + } + + @TestMetadata("function.kt") + public void testFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/function.kt"); + doTest(fileName); + } + + @TestMetadata("multipleReceivers.kt") + public void testMultipleReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/multipleReceivers.kt"); + doTest(fileName); + } + + @TestMetadata("multipleReceiversExtension.kt") + public void testMultipleReceiversExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/multipleReceiversExtension.kt"); + doTest(fileName); + } + + @TestMetadata("nestedReceivers.kt") + public void testNestedReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/nestedReceivers.kt"); + doTest(fileName); + } + + @TestMetadata("nestedReceiversDifferentParameters.kt") + public void testNestedReceiversDifferentParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/nestedReceiversDifferentParameters.kt"); + doTest(fileName); + } + + @TestMetadata("nestedReceiversExtension.kt") + public void testNestedReceiversExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtension.kt"); + doTest(fileName); + } + + @TestMetadata("nestedReceiversExtensionDifferentParameters.kt") + public void testNestedReceiversExtensionDifferentParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/nestedReceiversExtensionDifferentParameters.kt"); + doTest(fileName); + } + + @TestMetadata("property.kt") + public void testProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/property.kt"); + doTest(fileName); + } + + @TestMetadata("variableWithSameName.kt") + public void testVariableWithSameName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/explicitThis/variableWithSameName.kt"); + doTest(fileName); + } + } + + @TestMetadata("idea/testData/inspectionsLocal/implicitThis") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ImplicitThis extends AbstractLocalInspectionTest { + public void testAllFilesPresentInImplicitThis() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/implicitThis"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("function.kt") + public void testFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/function.kt"); + doTest(fileName); + } + + @TestMetadata("functionPartOfCall.kt") + public void testFunctionPartOfCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/functionPartOfCall.kt"); + doTest(fileName); + } + + @TestMetadata("multipleReceivers.kt") + public void testMultipleReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/multipleReceivers.kt"); + doTest(fileName); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/nested.kt"); + doTest(fileName); + } + + @TestMetadata("nestedCall.kt") + public void testNestedCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/nestedCall.kt"); + doTest(fileName); + } + + @TestMetadata("property.kt") + public void testProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/property.kt"); + doTest(fileName); + } + + @TestMetadata("propertyPartOfCall.kt") + public void testPropertyPartOfCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/propertyPartOfCall.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/implicitThis/topLevel.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/kdocMissingDocumentation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)