API for building visitors from lambdas

This commit is contained in:
Dmitry Jemerov
2018-01-05 15:06:03 +01:00
parent 46ac14198c
commit d15fa83749
52 changed files with 1532 additions and 1865 deletions
@@ -0,0 +1,396 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi
fun classOrObjectVisitor(block: (KtClassOrObject) -> Unit) =
object : KtVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
block(classOrObject)
}
}
fun classOrObjectRecursiveVisitor(block: (KtClassOrObject) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
super.visitClassOrObject(classOrObject)
block(classOrObject)
}
}
fun classVisitor(block: (KtClass) -> Unit) =
object : KtVisitorVoid() {
override fun visitClass(klass: KtClass) {
block(klass)
}
}
fun classRecursiveVisitor(block: (KtClass) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitClass(klass: KtClass) {
super.visitClass(klass)
block(klass)
}
}
fun expressionVisitor(block: (KtExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitExpression(expression: KtExpression) {
block(expression)
}
}
fun expressionRecursiveVisitor(block: (KtExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitExpression(expression: KtExpression) {
super.visitExpression(expression)
block(expression)
}
}
fun parameterVisitor(block: (KtParameter) -> Unit) =
object : KtVisitorVoid() {
override fun visitParameter(parameter: KtParameter) {
block(parameter)
}
}
fun parameterRecursiveVisitor(block: (KtParameter) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitParameter(parameter: KtParameter) {
super.visitParameter(parameter)
block(parameter)
}
}
fun propertyVisitor(block: (KtProperty) -> Unit) =
object : KtVisitorVoid() {
override fun visitProperty(property: KtProperty) {
block(property)
}
}
fun propertyRecursiveVisitor(block: (KtProperty) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
block(property)
}
}
fun ifExpressionVisitor(block: (KtIfExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitIfExpression(ifExpression: KtIfExpression) {
block(ifExpression)
}
}
fun ifExpressionRecursiveVisitor(block: (KtIfExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitIfExpression(ifExpression: KtIfExpression) {
super.visitIfExpression(ifExpression)
block(ifExpression)
}
}
fun callExpressionVisitor(block: (KtCallExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitCallExpression(callExpression: KtCallExpression) {
block(callExpression)
}
}
fun callExpressionRecursiveVisitor(block: (KtCallExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitCallExpression(callExpression: KtCallExpression) {
super.visitCallExpression(callExpression)
block(callExpression)
}
}
fun primaryConstructorVisitor(block: (KtPrimaryConstructor) -> Unit) =
object : KtVisitorVoid() {
override fun visitPrimaryConstructor(primaryConstructor: KtPrimaryConstructor) {
block(primaryConstructor)
}
}
fun primaryConstructorRecursiveVisitor(block: (KtPrimaryConstructor) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitPrimaryConstructor(primaryConstructor: KtPrimaryConstructor) {
super.visitPrimaryConstructor(primaryConstructor)
block(primaryConstructor)
}
}
fun destructuringDeclarationVisitor(block: (KtDestructuringDeclaration) -> Unit) =
object : KtVisitorVoid() {
override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
block(destructuringDeclaration)
}
}
fun destructuringDeclarationRecursiveVisitor(block: (KtDestructuringDeclaration) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
super.visitDestructuringDeclaration(destructuringDeclaration)
block(destructuringDeclaration)
}
}
fun dotQualifiedExpressionVisitor(block: (KtDotQualifiedExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitDotQualifiedExpression(dotQualifiedExpression: KtDotQualifiedExpression) {
block(dotQualifiedExpression)
}
}
fun dotQualifiedExpressionRecursiveVisitor(block: (KtDotQualifiedExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitDotQualifiedExpression(dotQualifiedExpression: KtDotQualifiedExpression) {
super.visitDotQualifiedExpression(dotQualifiedExpression)
block(dotQualifiedExpression)
}
}
fun prefixExpressionVisitor(block: (KtPrefixExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitPrefixExpression(prefixExpression: KtPrefixExpression) {
block(prefixExpression)
}
}
fun prefixExpressionRecursiveVisitor(block: (KtPrefixExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitPrefixExpression(prefixExpression: KtPrefixExpression) {
super.visitPrefixExpression(prefixExpression)
block(prefixExpression)
}
}
fun namedFunctionVisitor(block: (KtNamedFunction) -> Unit) =
object : KtVisitorVoid() {
override fun visitNamedFunction(namedFunction: KtNamedFunction) {
block(namedFunction)
}
}
fun namedFunctionRecursiveVisitor(block: (KtNamedFunction) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitNamedFunction(namedFunction: KtNamedFunction) {
super.visitNamedFunction(namedFunction)
block(namedFunction)
}
}
fun annotationEntryVisitor(block: (KtAnnotationEntry) -> Unit) =
object : KtVisitorVoid() {
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
block(annotationEntry)
}
}
fun annotationEntryRecursiveVisitor(block: (KtAnnotationEntry) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
super.visitAnnotationEntry(annotationEntry)
block(annotationEntry)
}
}
fun lambdaExpressionVisitor(block: (KtLambdaExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
block(lambdaExpression)
}
}
fun lambdaExpressionRecursiveVisitor(block: (KtLambdaExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
super.visitLambdaExpression(lambdaExpression)
block(lambdaExpression)
}
}
fun enumEntryVisitor(block: (KtEnumEntry) -> Unit) =
object : KtVisitorVoid() {
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
block(enumEntry)
}
}
fun enumEntryRecursiveVisitor(block: (KtEnumEntry) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
super.visitEnumEntry(enumEntry)
block(enumEntry)
}
}
fun packageDirectiveVisitor(block: (KtPackageDirective) -> Unit) =
object : KtVisitorVoid() {
override fun visitPackageDirective(packageDirective: KtPackageDirective) {
block(packageDirective)
}
}
fun packageDirectiveRecursiveVisitor(block: (KtPackageDirective) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitPackageDirective(packageDirective: KtPackageDirective) {
super.visitPackageDirective(packageDirective)
block(packageDirective)
}
}
fun binaryExpressionVisitor(block: (KtBinaryExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitBinaryExpression(binaryExpression: KtBinaryExpression) {
block(binaryExpression)
}
}
fun binaryExpressionRecursiveVisitor(block: (KtBinaryExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitBinaryExpression(binaryExpression: KtBinaryExpression) {
super.visitBinaryExpression(binaryExpression)
block(binaryExpression)
}
}
fun declarationVisitor(block: (KtDeclaration) -> Unit) =
object : KtVisitorVoid() {
override fun visitDeclaration(declaration: KtDeclaration) {
block(declaration)
}
}
fun declarationRecursiveVisitor(block: (KtDeclaration) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitDeclaration(declaration: KtDeclaration) {
super.visitDeclaration(declaration)
block(declaration)
}
}
fun simpleNameExpressionVisitor(block: (KtSimpleNameExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitSimpleNameExpression(simpleNameExpression: KtSimpleNameExpression) {
block(simpleNameExpression)
}
}
fun simpleNameExpressionRecursiveVisitor(block: (KtSimpleNameExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitSimpleNameExpression(simpleNameExpression: KtSimpleNameExpression) {
super.visitSimpleNameExpression(simpleNameExpression)
block(simpleNameExpression)
}
}
fun propertyAccessorVisitor(block: (KtPropertyAccessor) -> Unit) =
object : KtVisitorVoid() {
override fun visitPropertyAccessor(propertyAccessor: KtPropertyAccessor) {
block(propertyAccessor)
}
}
fun propertyAccessorRecursiveVisitor(block: (KtPropertyAccessor) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitPropertyAccessor(propertyAccessor: KtPropertyAccessor) {
super.visitPropertyAccessor(propertyAccessor)
block(propertyAccessor)
}
}
fun referenceExpressionVisitor(block: (KtReferenceExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitReferenceExpression(referenceExpression: KtReferenceExpression) {
block(referenceExpression)
}
}
fun referenceExpressionRecursiveVisitor(block: (KtReferenceExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitReferenceExpression(referenceExpression: KtReferenceExpression) {
super.visitReferenceExpression(referenceExpression)
block(referenceExpression)
}
}
fun valueArgumentVisitor(block: (KtValueArgument) -> Unit) =
object : KtVisitorVoid() {
override fun visitArgument(valueArgument: KtValueArgument) {
block(valueArgument)
}
}
fun valueArgumentRecursiveVisitor(block: (KtValueArgument) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitArgument(valueArgument: KtValueArgument) {
super.visitArgument(valueArgument)
block(valueArgument)
}
}
fun whenExpressionVisitor(block: (KtWhenExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitWhenExpression(whenExpression: KtWhenExpression) {
block(whenExpression)
}
}
fun whenExpressionRecursiveVisitor(block: (KtWhenExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitWhenExpression(whenExpression: KtWhenExpression) {
super.visitWhenExpression(whenExpression)
block(whenExpression)
}
}
fun modifierListVisitor(block: (KtModifierList) -> Unit) =
object : KtVisitorVoid() {
override fun visitModifierList(modifierList: KtModifierList) {
block(modifierList)
}
}
fun modifierListRecursiveVisitor(block: (KtModifierList) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitModifierList(modifierList: KtModifierList) {
super.visitModifierList(modifierList)
block(modifierList)
}
}
fun namedDeclarationVisitor(block: (KtNamedDeclaration) -> Unit) =
object : KtVisitorVoid() {
override fun visitNamedDeclaration(namedDeclaration: KtNamedDeclaration) {
block(namedDeclaration)
}
}
fun namedDeclarationRecursiveVisitor(block: (KtNamedDeclaration) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitNamedDeclaration(namedDeclaration: KtNamedDeclaration) {
super.visitNamedDeclaration(namedDeclaration)
block(namedDeclaration)
}
}
fun qualifiedExpressionVisitor(block: (KtQualifiedExpression) -> Unit) =
object : KtVisitorVoid() {
override fun visitQualifiedExpression(qualifiedExpression: KtQualifiedExpression) {
block(qualifiedExpression)
}
}
fun qualifiedExpressionRecursiveVisitor(block: (KtQualifiedExpression) -> Unit) =
object : KtTreeVisitorVoid() {
override fun visitQualifiedExpression(qualifiedExpression: KtQualifiedExpression) {
super.visitQualifiedExpression(qualifiedExpression)
block(qualifiedExpression)
}
}
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -23,7 +12,7 @@ import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.expressionVisitor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
@@ -34,19 +23,15 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
abstract class AbstractPrimitiveRangeToInspection : AbstractKotlinInspection() { abstract class AbstractPrimitiveRangeToInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return expressionVisitor { expression ->
override fun visitExpression(expression: KtExpression) { if (expression !is KtBinaryExpression && expression !is KtDotQualifiedExpression) return@expressionVisitor
super.visitExpression(expression)
if (expression !is KtBinaryExpression && expression !is KtDotQualifiedExpression) return val fqName = expression.getCallableDescriptor()?.fqNameUnsafe?.asString() ?: return@expressionVisitor
if (!fqName.matches(REGEX_RANGE_TO)) return@expressionVisitor
val fqName = expression.getCallableDescriptor()?.fqNameUnsafe?.asString() ?: return
if (!fqName.matches(REGEX_RANGE_TO)) return
visitRangeToExpression(expression, holder) visitRangeToExpression(expression, holder)
} }
} }
}
abstract fun visitRangeToExpression(expression: KtExpression, holder: ProblemsHolder) abstract fun visitRangeToExpression(expression: KtExpression, holder: ProblemsHolder)
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -60,20 +49,7 @@ class AddVarianceModifierInspection : AbstractKotlinInspection() {
} }
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return classOrObjectVisitor { klass ->
private fun variancePossible(
klass: KtClassOrObject,
parameterDescriptor: TypeParameterDescriptor,
variance: Variance,
context: BindingContext
) = VarianceCheckerCore(
context,
DiagnosticSink.DO_NOTHING,
ManualVariance(parameterDescriptor, variance)
).checkClassOrObject(klass)
override fun visitClassOrObject(klass: KtClassOrObject) {
val context = klass.analyzeFully() val context = klass.analyzeFully()
for (typeParameter in klass.typeParameters) { for (typeParameter in klass.typeParameters) {
if (typeParameter.variance != Variance.INVARIANT) continue if (typeParameter.variance != Variance.INVARIANT) continue
@@ -95,7 +71,18 @@ class AddVarianceModifierInspection : AbstractKotlinInspection() {
} }
} }
} }
}
private fun variancePossible(
klass: KtClassOrObject,
parameterDescriptor: TypeParameterDescriptor,
variance: Variance,
context: BindingContext
) = VarianceCheckerCore(
context,
DiagnosticSink.DO_NOTHING,
ManualVariance(parameterDescriptor, variance)
).checkClassOrObject(klass)
class AddVarianceFix(val variance: Variance) : LocalQuickFix { class AddVarianceFix(val variance: Variance) : LocalQuickFix {
override fun getName() = "Add '$variance' variance" override fun getName() = "Add '$variance' variance"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -26,7 +15,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.classVisitor
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -34,11 +23,10 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
class ArrayInDataClassInspection : AbstractKotlinInspection() { class ArrayInDataClassInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return classVisitor { klass ->
override fun visitClass(klass: KtClass) { if (!klass.isData()) return@classVisitor
if (!klass.isData()) return val constructor = klass.primaryConstructor ?: return@classVisitor
val constructor = klass.primaryConstructor ?: return if (hasOverriddenEqualsAndHashCode(klass)) return@classVisitor
if (hasOverriddenEqualsAndHashCode(klass)) return
val context = constructor.analyze(BodyResolveMode.PARTIAL) val context = constructor.analyze(BodyResolveMode.PARTIAL)
for (parameter in constructor.valueParameters) { for (parameter in constructor.valueParameters) {
if (!parameter.hasValOrVar()) continue if (!parameter.hasValOrVar()) continue
@@ -51,6 +39,7 @@ class ArrayInDataClassInspection : AbstractKotlinInspection() {
} }
} }
} }
}
private fun hasOverriddenEqualsAndHashCode(klass: KtClass): Boolean { private fun hasOverriddenEqualsAndHashCode(klass: KtClass): Boolean {
var overriddenEquals = false var overriddenEquals = false
@@ -72,8 +61,6 @@ class ArrayInDataClassInspection : AbstractKotlinInspection() {
} }
return overriddenEquals && overriddenHashCode return overriddenEquals && overriddenHashCode
} }
}
}
class GenerateEqualsAndHashcodeFix : LocalQuickFix { class GenerateEqualsAndHashcodeFix : LocalQuickFix {
override fun getName() = "Generate equals() and hashCode()" override fun getName() = "Generate equals() and hashCode()"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -78,9 +67,7 @@ class CanBeParameterInspection : AbstractKotlinInspection() {
} }
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return parameterVisitor(fun(parameter) {
override fun visitParameter(parameter: KtParameter) {
// Applicable to val / var parameters of a class / object primary constructors // Applicable to val / var parameters of a class / object primary constructors
val valOrVar = parameter.valOrVarKeyword ?: return val valOrVar = parameter.valOrVarKeyword ?: return
val name = parameter.name ?: return val name = parameter.name ?: return
@@ -116,8 +103,7 @@ class CanBeParameterInspection : AbstractKotlinInspection() {
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
RemoveValVarFix(parameter) RemoveValVarFix(parameter)
) )
} })
}
} }
class RemoveValVarFix(val parameter: KtParameter) : LocalQuickFix { class RemoveValVarFix(val parameter: KtParameter) : LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -25,9 +14,8 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.intentions.MovePropertyToConstructorIntention import org.jetbrains.kotlin.idea.intentions.MovePropertyToConstructorIntention
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtReferenceExpression import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.propertyVisitor
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
@@ -35,8 +23,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() { class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return propertyVisitor(fun(property) {
override fun visitProperty(property: KtProperty) {
if (property.isLocal) return if (property.isLocal) return
if (property.getter != null || property.setter != null || property.delegate != null) return if (property.getter != null || property.setter != null || property.delegate != null) return
val assigned = property.initializer as? KtReferenceExpression ?: return val assigned = property.initializer as? KtReferenceExpression ?: return
@@ -67,7 +54,6 @@ class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() {
isOnTheFly, isOnTheFly,
MovePropertyToConstructorIntention() MovePropertyToConstructorIntention()
)) ))
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -21,8 +10,8 @@ import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfToWhenIntention import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfToWhenIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isOneLiner
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isElseIf import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isElseIf
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isOneLiner
import org.jetbrains.kotlin.idea.intentions.branches import org.jetbrains.kotlin.idea.intentions.branches
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -31,10 +20,7 @@ import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
class CascadeIfInspection : AbstractKotlinInspection() { class CascadeIfInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { ifExpressionVisitor(fun(expression) {
override fun visitIfExpression(expression: KtIfExpression) {
super.visitIfExpression(expression)
val branches = expression.branches val branches = expression.branches
if (branches.size <= 2) return if (branches.size <= 2) return
if (expression.isOneLiner()) return if (expression.isOneLiner()) return
@@ -70,6 +56,5 @@ class CascadeIfInspection : AbstractKotlinInspection() {
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
IntentionWrapper(IfToWhenIntention(), expression.containingKtFile) IntentionWrapper(IfToWhenIntention(), expression.containingKtFile)
) )
} })
}
} }
@@ -1,24 +1,16 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.FileModificationService import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.intention.LowPriorityAction import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInspection.* import com.intellij.codeInspection.IntentionWrapper
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@@ -34,8 +26,8 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.targetDescriptors import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
@@ -63,10 +55,7 @@ class ConflictingExtensionPropertyInspection : AbstractKotlinInspection() {
val file = session.file as? KtFile ?: return PsiElementVisitor.EMPTY_VISITOR val file = session.file as? KtFile ?: return PsiElementVisitor.EMPTY_VISITOR
val resolutionFacade = file.getResolutionFacade() val resolutionFacade = file.getResolutionFacade()
return object : KtVisitorVoid() { return propertyVisitor(fun(property: KtProperty) {
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
if (property.receiverTypeReference != null) { if (property.receiverTypeReference != null) {
val nameElement = property.nameIdentifier ?: return val nameElement = property.nameIdentifier ?: return
val propertyDescriptor = property.resolveToDescriptorIfAny() as? PropertyDescriptor ?: return val propertyDescriptor = property.resolveToDescriptorIfAny() as? PropertyDescriptor ?: return
@@ -88,8 +77,7 @@ class ConflictingExtensionPropertyInspection : AbstractKotlinInspection() {
) )
holder.registerProblem(problemDescriptor) holder.registerProblem(problemDescriptor)
} }
} })
}
} }
private fun conflictingSyntheticExtension(descriptor: PropertyDescriptor, scopes: SyntheticScopes): SyntheticJavaPropertyDescriptor? { private fun conflictingSyntheticExtension(descriptor: PropertyDescriptor, scopes: SyntheticScopes): SyntheticJavaPropertyDescriptor? {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -37,10 +26,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ConstantConditionIfInspection : AbstractKotlinInspection() { class ConstantConditionIfInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return ifExpressionVisitor(fun(expression) {
override fun visitIfExpression(expression: KtIfExpression) {
super.visitIfExpression(expression)
val condition = expression.condition ?: return val condition = expression.condition ?: return
val context = condition.analyze(BodyResolveMode.PARTIAL) val context = condition.analyze(BodyResolveMode.PARTIAL)
@@ -60,8 +46,7 @@ class ConstantConditionIfInspection : AbstractKotlinInspection() {
holder.registerProblem(condition, holder.registerProblem(condition,
"Condition is always '$constantValue'", "Condition is always '$constantValue'",
*fixes.toTypedArray()) *fixes.toTypedArray())
} })
}
} }
private class SimplifyFix( private class SimplifyFix(
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -23,9 +12,8 @@ import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.AddNamesToCallArgumentsIntention import org.jetbrains.kotlin.idea.intentions.AddNamesToCallArgumentsIntention
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.callExpressionVisitor
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
@@ -35,10 +23,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class CopyWithoutNamedArgumentsInspection : AbstractKotlinInspection() { class CopyWithoutNamedArgumentsInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return callExpressionVisitor(fun(expression) {
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
val reference = expression.referenceExpression() as? KtNameReferenceExpression ?: return val reference = expression.referenceExpression() as? KtNameReferenceExpression ?: return
if (reference.getReferencedNameAsName() != DataClassDescriptorResolver.COPY_METHOD_NAME) return if (reference.getReferencedNameAsName() != DataClassDescriptorResolver.COPY_METHOD_NAME) return
if (expression.valueArguments.all { it.isNamed() }) return if (expression.valueArguments.all { it.isNamed() }) return
@@ -56,8 +41,7 @@ class CopyWithoutNamedArgumentsInspection : AbstractKotlinInspection() {
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
IntentionWrapper(AddNamesToCallArgumentsIntention(), expression.containingKtFile) IntentionWrapper(AddNamesToCallArgumentsIntention(), expression.containingKtFile)
) )
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -20,19 +9,15 @@ import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPrimaryConstructor import org.jetbrains.kotlin.psi.primaryConstructorVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.isPrivate import org.jetbrains.kotlin.psi.psiUtil.isPrivate
class DataClassPrivateConstructorInspection : AbstractKotlinInspection() { class DataClassPrivateConstructorInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return primaryConstructorVisitor { constructor ->
override fun visitPrimaryConstructor(constructor: KtPrimaryConstructor) {
super.visitPrimaryConstructor(constructor)
if (constructor.containingClass()?.isData() == true && constructor.isPrivate()) { if (constructor.containingClass()?.isData() == true && constructor.isPrivate()) {
val keyword = constructor.modifierList?.getModifier(KtTokens.PRIVATE_KEYWORD) ?: return val keyword = constructor.modifierList?.getModifier(KtTokens.PRIVATE_KEYWORD) ?: return@primaryConstructorVisitor
val problemDescriptor = holder.manager.createProblemDescriptor( val problemDescriptor = holder.manager.createProblemDescriptor(
keyword, keyword,
keyword, keyword,
@@ -45,5 +30,4 @@ class DataClassPrivateConstructorInspection : AbstractKotlinInspection() {
} }
} }
} }
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -21,15 +10,11 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.destructuringDeclarationVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
class DestructuringWrongNameInspection : AbstractKotlinInspection() { class DestructuringWrongNameInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return destructuringDeclarationVisitor(fun(destructuringDeclaration) {
override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
super.visitDestructuringDeclaration(destructuringDeclaration)
val initializer = destructuringDeclaration.initializer ?: return val initializer = destructuringDeclaration.initializer ?: return
val type = initializer.analyze().getType(initializer) ?: return val type = initializer.analyze().getType(initializer) ?: return
@@ -56,7 +41,6 @@ class DestructuringWrongNameInspection : AbstractKotlinInspection() {
} }
} }
} }
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -29,10 +18,7 @@ import org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateEqualsAndHashcod
import org.jetbrains.kotlin.idea.actions.generate.findDeclaredEquals import org.jetbrains.kotlin.idea.actions.generate.findDeclaredEquals
import org.jetbrains.kotlin.idea.actions.generate.findDeclaredHashCode import org.jetbrains.kotlin.idea.actions.generate.findDeclaredHashCode
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
@@ -71,8 +57,7 @@ sealed class GenerateEqualsOrHashCodeFix : LocalQuickFix {
class EqualsOrHashCodeInspection : AbstractKotlinInspection() { class EqualsOrHashCodeInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object: KtVisitorVoid() { return classOrObjectVisitor(fun(classOrObject) {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val nameIdentifier = classOrObject.nameIdentifier ?: return val nameIdentifier = classOrObject.nameIdentifier ?: return
val classDescriptor = classOrObject.resolveToDescriptorIfAny() as? ClassDescriptor ?: return val classDescriptor = classOrObject.resolveToDescriptorIfAny() as? ClassDescriptor ?: return
val hasEquals = classDescriptor.findDeclaredEquals(false) != null val hasEquals = classDescriptor.findDeclaredEquals(false) != null
@@ -99,7 +84,6 @@ class EqualsOrHashCodeInspection : AbstractKotlinInspection() {
} }
else -> return else -> return
} }
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -38,10 +27,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class JavaCollectionsStaticMethodInspection : AbstractKotlinInspection() { class JavaCollectionsStaticMethodInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return dotQualifiedExpressionVisitor(fun(expression) {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
super.visitDotQualifiedExpression(expression)
val callExpression = expression.callExpression ?: return val callExpression = expression.callExpression ?: return
val args = callExpression.valueArguments val args = callExpression.valueArguments
val firstArg = args.firstOrNull() ?: return val firstArg = args.firstOrNull() ?: return
@@ -59,8 +45,7 @@ class JavaCollectionsStaticMethodInspection : AbstractKotlinInspection() {
"Java Collections static method call should be replaced with Kotlin stdlib", "Java Collections static method call should be replaced with Kotlin stdlib",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
ReplaceWithStdLibFix(methodName, firstArg.text)) ReplaceWithStdLibFix(methodName, firstArg.text))
} })
}
} }
private fun canReplaceWithStdLib(expression: KtDotQualifiedExpression, fqName: String, args: List<KtValueArgument>): Boolean { private fun canReplaceWithStdLib(expression: KtDotQualifiedExpression, fqName: String, args: List<KtValueArgument>): Boolean {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -23,14 +12,13 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtParenthesizedExpression import org.jetbrains.kotlin.psi.KtParenthesizedExpression
import org.jetbrains.kotlin.psi.KtPrefixExpression import org.jetbrains.kotlin.psi.KtPrefixExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.prefixExpressionVisitor
import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.types.typeUtil.isBoolean import org.jetbrains.kotlin.types.typeUtil.isBoolean
class KotlinDoubleNegationInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class KotlinDoubleNegationInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { prefixExpressionVisitor(fun(expression) {
override fun visitPrefixExpression(expression: KtPrefixExpression) {
if (expression.operationToken != KtTokens.EXCL || if (expression.operationToken != KtTokens.EXCL ||
expression.baseExpression?.getType(expression.analyze())?.isBoolean() != true) { expression.baseExpression?.getType(expression.analyze())?.isBoolean() != true) {
return return
@@ -45,8 +33,7 @@ class KotlinDoubleNegationInspection : AbstractKotlinInspection(), CleanupLocalI
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
DoubleNegationFix()) DoubleNegationFix())
} }
} })
}
private class DoubleNegationFix : LocalQuickFix { private class DoubleNegationFix : LocalQuickFix {
override fun getName() = "Remove redundant negations" override fun getName() = "Remove redundant negations"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -29,9 +18,7 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { namedFunctionVisitor(fun(function) {
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
val funKeyword = function.funKeyword ?: return val funKeyword = function.funKeyword ?: return
val modifierList = function.modifierList ?: return val modifierList = function.modifierList ?: return
if (!modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return if (!modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return
@@ -73,8 +60,7 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc
RedundantOverrideFix() RedundantOverrideFix()
) )
holder.registerProblem(descriptor) holder.registerProblem(descriptor)
} })
}
private fun isSameArguments(superCallElement: KtCallElement, function: KtNamedFunction): Boolean { private fun isSameArguments(superCallElement: KtCallElement, function: KtNamedFunction): Boolean {
val arguments = superCallElement.valueArguments val arguments = superCallElement.valueArguments
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -28,28 +17,30 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.psi.expressionVisitor
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext.LEAKING_THIS import org.jetbrains.kotlin.resolve.BindingContext.LEAKING_THIS
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
class LeakingThisInspection : AbstractKotlinInspection() { class LeakingThisInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return expressionVisitor { expression ->
override fun visitExpression(expression: KtExpression) {
val context = expression.analyzeFully() val context = expression.analyzeFully()
val leakingThisDescriptor = context.get(LEAKING_THIS, expression) ?: return val leakingThisDescriptor = context.get(LEAKING_THIS, expression) ?: return@expressionVisitor
val description = when (leakingThisDescriptor) { val description = when (leakingThisDescriptor) {
is NonFinalClass -> is NonFinalClass ->
if (expression is KtThisExpression) if (expression is KtThisExpression)
"Leaking 'this' in constructor of non-final class ${leakingThisDescriptor.klass.name}" "Leaking 'this' in constructor of non-final class ${leakingThisDescriptor.klass.name}"
else else
return // Not supported yet return@expressionVisitor // Not supported yet
is NonFinalProperty -> is NonFinalProperty ->
"Accessing non-final property ${leakingThisDescriptor.property.name} in constructor" "Accessing non-final property ${leakingThisDescriptor.property.name} in constructor"
is NonFinalFunction -> is NonFinalFunction ->
"Calling non-final function ${leakingThisDescriptor.function.name} in constructor" "Calling non-final function ${leakingThisDescriptor.function.name} in constructor"
else -> return // Not supported yet else -> return@expressionVisitor // Not supported yet
} }
val memberDescriptorToFix = when (leakingThisDescriptor) { val memberDescriptorToFix = when (leakingThisDescriptor) {
is NonFinalProperty -> leakingThisDescriptor.property is NonFinalProperty -> leakingThisDescriptor.property
@@ -81,7 +72,6 @@ class LeakingThisInspection : AbstractKotlinInspection() {
) )
} }
} }
}
companion object { companion object {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -27,7 +16,7 @@ import org.jetbrains.kotlin.idea.quickfix.AddConstModifierFix
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.propertyVisitor
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.ErrorValue import org.jetbrains.kotlin.resolve.constants.ErrorValue
@@ -48,13 +37,11 @@ class MayBeConstantInspection : AbstractKotlinInspection() {
} }
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return propertyVisitor { property ->
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
val status = property.getStatus() val status = property.getStatus()
when (status) { when (status) {
NONE, JVM_FIELD_MIGHT_BE_CONST_NO_INITIALIZER, NONE, JVM_FIELD_MIGHT_BE_CONST_NO_INITIALIZER,
MIGHT_BE_CONST_ERRONEOUS, JVM_FIELD_MIGHT_BE_CONST_ERRONEOUS -> return MIGHT_BE_CONST_ERRONEOUS, JVM_FIELD_MIGHT_BE_CONST_ERRONEOUS -> return@propertyVisitor
MIGHT_BE_CONST, JVM_FIELD_MIGHT_BE_CONST -> { MIGHT_BE_CONST, JVM_FIELD_MIGHT_BE_CONST -> {
holder.registerProblem( holder.registerProblem(
property.nameIdentifier ?: property, property.nameIdentifier ?: property,
@@ -66,7 +53,6 @@ class MayBeConstantInspection : AbstractKotlinInspection() {
} }
} }
} }
}
companion object { companion object {
fun KtProperty.getStatus(): Status { fun KtProperty.getStatus(): Status {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -25,17 +14,15 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.annotationEntryVisitor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class MigrateDiagnosticSuppressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class MigrateDiagnosticSuppressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return annotationEntryVisitor(fun(annotationEntry) {
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
super.visitAnnotationEntry(annotationEntry)
if (annotationEntry.calleeExpression?.text != "Suppress") return if (annotationEntry.calleeExpression?.text != "Suppress") return
val context = annotationEntry.analyze(BodyResolveMode.PARTIAL) val context = annotationEntry.analyze(BodyResolveMode.PARTIAL)
val descriptor = context[BindingContext.ANNOTATION, annotationEntry] ?: return val descriptor = context[BindingContext.ANNOTATION, annotationEntry] ?: return
@@ -54,8 +41,7 @@ class MigrateDiagnosticSuppressionInspection : AbstractKotlinInspection(), Clean
ReplaceDiagnosticNameFix(newDiagnosticFactory) ReplaceDiagnosticNameFix(newDiagnosticFactory)
) )
} }
} })
}
} }
class ReplaceDiagnosticNameFix(private val diagnosticFactory: DiagnosticFactory<*>) : LocalQuickFix { class ReplaceDiagnosticNameFix(private val diagnosticFactory: DiagnosticFactory<*>) : LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -28,16 +17,15 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.ConvertLambdaToReferenceIntention import org.jetbrains.kotlin.idea.intentions.ConvertLambdaToReferenceIntention
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.psi.lambdaExpressionVisitor
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinInspection() { class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return lambdaExpressionVisitor(fun(lambdaExpression) {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
val callableReference = lambdaExpression.bodyExpression?.statements?.singleOrNull() as? KtCallableReferenceExpression val callableReference = lambdaExpression.bodyExpression?.statements?.singleOrNull() as? KtCallableReferenceExpression
if (callableReference != null) { if (callableReference != null) {
val context = lambdaExpression.analyze() val context = lambdaExpression.analyze()
@@ -61,8 +49,7 @@ class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinI
) )
} }
} })
}
} }
class MoveIntoParenthesesIntention : ConvertLambdaToReferenceIntention( class MoveIntoParenthesesIntention : ConvertLambdaToReferenceIntention(
@@ -123,11 +123,7 @@ class EnumEntryNameInspection : NamingConventionInspection(
START_UPPER, NO_BAD_CHARACTERS_OR_UNDERSCORE START_UPPER, NO_BAD_CHARACTERS_OR_UNDERSCORE
) { ) {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return enumEntryVisitor { enumEntry -> verifyName(enumEntry, holder) }
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
verifyName(enumEntry, holder)
}
}
} }
} }
@@ -137,11 +133,8 @@ class FunctionNameInspection : NamingConventionInspection(
START_LOWER, NO_UNDERSCORES, NO_BAD_CHARACTERS START_LOWER, NO_UNDERSCORES, NO_BAD_CHARACTERS
) { ) {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return namedFunctionVisitor { function ->
override fun visitNamedFunction(function: KtNamedFunction) { if (!TestUtils.isInTestSourceContent(function)) {
if (TestUtils.isInTestSourceContent(function)) {
return
}
verifyName(function, holder) verifyName(function, holder)
} }
} }
@@ -154,18 +147,16 @@ class TestFunctionNameInspection : NamingConventionInspection(
START_LOWER START_LOWER
) { ) {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return namedFunctionVisitor { function ->
override fun visitNamedFunction(function: KtNamedFunction) {
if (!TestUtils.isInTestSourceContent(function)) { if (!TestUtils.isInTestSourceContent(function)) {
return return@namedFunctionVisitor
} }
if (function.nameIdentifier?.text?.startsWith("`") == true) { if (function.nameIdentifier?.text?.startsWith("`") == true) {
return return@namedFunctionVisitor
} }
verifyName(function, holder) verifyName(function, holder)
} }
} }
}
} }
abstract class PropertyNameInspectionBase protected constructor( abstract class PropertyNameInspectionBase protected constructor(
@@ -178,14 +169,12 @@ abstract class PropertyNameInspectionBase protected constructor(
protected enum class PropertyKind { NORMAL, PRIVATE, OBJECT_OR_TOP_LEVEL, CONST, LOCAL } protected enum class PropertyKind { NORMAL, PRIVATE, OBJECT_OR_TOP_LEVEL, CONST, LOCAL }
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return propertyVisitor { property ->
override fun visitProperty(property: KtProperty) {
if (property.getKind() == kind) { if (property.getKind() == kind) {
verifyName(property, holder) verifyName(property, holder)
} }
} }
} }
}
private fun KtProperty.getKind(): PropertyKind = when { private fun KtProperty.getKind(): PropertyKind = when {
isLocal -> PropertyKind.LOCAL isLocal -> PropertyKind.LOCAL
@@ -234,8 +223,7 @@ class LocalVariableNameInspection :
class PackageNameInspection : class PackageNameInspection :
NamingConventionInspection("Package", "[a-z][A-Za-z\\d]*(\\.[a-z][A-Za-z\\d]*)*", NO_UNDERSCORES) { NamingConventionInspection("Package", "[a-z][A-Za-z\\d]*(\\.[a-z][A-Za-z\\d]*)*", NO_UNDERSCORES) {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return packageDirectiveVisitor { directive ->
override fun visitPackageDirective(directive: KtPackageDirective) {
val qualifiedName = directive.qualifiedName val qualifiedName = directive.qualifiedName
if (qualifiedName.isNotEmpty() && nameRegex?.matches(qualifiedName) == false) { if (qualifiedName.isNotEmpty() && nameRegex?.matches(qualifiedName) == false) {
val message = getNameMismatchMessage(qualifiedName) val message = getNameMismatchMessage(qualifiedName)
@@ -247,7 +235,6 @@ class PackageNameInspection :
} }
} }
} }
}
private class RenamePackageFix : RenameIdentifierFix() { private class RenamePackageFix : RenameIdentifierFix() {
override fun getElementToRename(element: PsiElement): PsiElement? { override fun getElementToRename(element: PsiElement): PsiElement? {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -31,8 +20,7 @@ import org.jetbrains.kotlin.types.TypeUtils
class NullChecksToSafeCallInspection : AbstractKotlinInspection() { class NullChecksToSafeCallInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { binaryExpressionVisitor { expression ->
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (isNullChecksToSafeCallFixAvailable(expression)) { if (isNullChecksToSafeCallFixAvailable(expression)) {
holder.registerProblem(expression, holder.registerProblem(expression,
"Null-checks replaceable with safe-calls", "Null-checks replaceable with safe-calls",
@@ -40,7 +28,6 @@ class NullChecksToSafeCallInspection : AbstractKotlinInspection() {
NullChecksToSafeCallCheckFix()) NullChecksToSafeCallCheckFix())
} }
} }
}
private class NullChecksToSafeCallCheckFix : LocalQuickFix { private class NullChecksToSafeCallCheckFix : LocalQuickFix {
override fun getName() = "Replace chained null-checks with safe-calls" override fun getName() = "Replace chained null-checks with safe-calls"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -34,8 +23,7 @@ import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean
class NullableBooleanElvisInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class NullableBooleanElvisInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { binaryExpressionVisitor(fun(expression) {
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (expression.operationToken != KtTokens.ELVIS) return if (expression.operationToken != KtTokens.ELVIS) return
val lhs = expression.left ?: return val lhs = expression.left ?: return
val rhs = expression.right ?: return val rhs = expression.right ?: return
@@ -62,8 +50,7 @@ class NullableBooleanElvisInspection : AbstractKotlinInspection(), CleanupLocalI
ReplaceWithEqualityCheckFix() ReplaceWithEqualityCheckFix()
) )
} }
} })
}
private class ReplaceWithEqualityCheckFix : LocalQuickFix { private class ReplaceWithEqualityCheckFix : LocalQuickFix {
override fun getName() = "Replace with equality check" override fun getName() = "Replace with equality check"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -24,17 +13,15 @@ import org.jetbrains.kotlin.idea.core.implicitVisibility
import org.jetbrains.kotlin.idea.core.isInheritable import org.jetbrains.kotlin.idea.core.isInheritable
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.addRemoveModifier.addModifier import org.jetbrains.kotlin.psi.addRemoveModifier.addModifier
import org.jetbrains.kotlin.psi.declarationVisitor
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
class ProtectedInFinalInspection : AbstractKotlinInspection() { class ProtectedInFinalInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return declarationVisitor(fun(declaration) {
override fun visitDeclaration(declaration: KtDeclaration) {
val visibilityModifier = declaration.visibilityModifier() ?: return val visibilityModifier = declaration.visibilityModifier() ?: return
val modifierType = visibilityModifier.node?.elementType val modifierType = visibilityModifier.node?.elementType
if (modifierType == KtTokens.PROTECTED_KEYWORD) { if (modifierType == KtTokens.PROTECTED_KEYWORD) {
@@ -49,8 +36,7 @@ class ProtectedInFinalInspection : AbstractKotlinInspection() {
) )
} }
} }
} })
}
} }
class MakePrivateFix : LocalQuickFix { class MakePrivateFix : LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -35,9 +24,7 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
class RecursivePropertyAccessorInspection : AbstractKotlinInspection() { class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return simpleNameExpressionVisitor { expression ->
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
super.visitSimpleNameExpression(expression)
if (isRecursivePropertyAccess(expression)) { if (isRecursivePropertyAccess(expression)) {
holder.registerProblem(expression, holder.registerProblem(expression,
"Recursive property accessor", "Recursive property accessor",
@@ -51,7 +38,6 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
} }
} }
} }
}
class ReplaceWithFieldFix : LocalQuickFix { class ReplaceWithFieldFix : LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -29,10 +18,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class RedundantExplicitTypeInspection : AbstractKotlinInspection() { class RedundantExplicitTypeInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
object : KtVisitorVoid() { propertyVisitor(fun(property) {
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
if (!property.isLocal) return if (!property.isLocal) return
val typeReference = property.typeReference ?: return val typeReference = property.typeReference ?: return
val initializer = property.initializer ?: return val initializer = property.initializer ?: return
@@ -84,6 +70,5 @@ class RedundantExplicitTypeInspection : AbstractKotlinInspection() {
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
IntentionWrapper(RemoveExplicitTypeIntention(), property.containingKtFile) IntentionWrapper(RemoveExplicitTypeIntention(), property.containingKtFile)
) )
} })
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -20,13 +9,10 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class RedundantGetterInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantGetterInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return propertyAccessorVisitor { accessor ->
override fun visitPropertyAccessor(accessor: KtPropertyAccessor) {
super.visitPropertyAccessor(accessor)
if (accessor.isRedundantGetter()) { if (accessor.isRedundantGetter()) {
holder.registerProblem(accessor, holder.registerProblem(accessor,
"Redundant getter", "Redundant getter",
@@ -35,7 +21,6 @@ class RedundantGetterInspection : AbstractKotlinInspection(), CleanupLocalInspec
} }
} }
} }
}
} }
private fun KtPropertyAccessor.isRedundantGetter(): Boolean { private fun KtPropertyAccessor.isRedundantGetter(): Boolean {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -27,12 +16,10 @@ import org.jetbrains.kotlin.psi.*
class RedundantIfInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantIfInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return ifExpressionVisitor { expression ->
override fun visitIfExpression(expression: KtIfExpression) { if (expression.condition == null) return@ifExpressionVisitor
super.visitIfExpression(expression)
if (expression.condition == null) return
val (redundancyType, branchType) = RedundancyType.of(expression) val (redundancyType, branchType) = RedundancyType.of(expression)
if (redundancyType == RedundancyType.NONE) return if (redundancyType == RedundancyType.NONE) return@ifExpressionVisitor
holder.registerProblem(expression, holder.registerProblem(expression,
"Redundant 'if' statement", "Redundant 'if' statement",
@@ -40,7 +27,6 @@ class RedundantIfInspection : AbstractKotlinInspection(), CleanupLocalInspection
RemoveRedundantIf(redundancyType, branchType)) RemoveRedundantIf(redundancyType, branchType))
} }
} }
}
private sealed class BranchType { private sealed class BranchType {
object Simple : BranchType() object Simple : BranchType()
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -23,16 +12,14 @@ import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.lambdaExpressionVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
class RedundantLambdaArrowInspection : AbstractKotlinInspection() { class RedundantLambdaArrowInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return lambdaExpressionVisitor { lambdaExpression ->
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
val functionLiteral = lambdaExpression.functionLiteral val functionLiteral = lambdaExpression.functionLiteral
if (functionLiteral.valueParameters.isNotEmpty()) return if (functionLiteral.valueParameters.isNotEmpty()) return@lambdaExpressionVisitor
val arrow = functionLiteral.arrow ?: return val arrow = functionLiteral.arrow ?: return@lambdaExpressionVisitor
holder.registerProblem( holder.registerProblem(
arrow, arrow,
@@ -41,7 +28,6 @@ class RedundantLambdaArrowInspection : AbstractKotlinInspection() {
DeleteFix()) DeleteFix())
} }
} }
}
class DeleteFix : LocalQuickFix { class DeleteFix : LocalQuickFix {
override fun getFamilyName() = "Remove arrow" override fun getFamilyName() = "Remove arrow"
@@ -1,46 +1,25 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.* import com.intellij.codeInspection.*
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.implicitModality import org.jetbrains.kotlin.idea.core.implicitModality
import org.jetbrains.kotlin.idea.core.mapModality
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.declarationVisitor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return declarationVisitor { declaration ->
override fun visitDeclaration(declaration: KtDeclaration) { val modalityModifier = declaration.modalityModifier() ?: return@declarationVisitor
val modalityModifier = declaration.modalityModifier() ?: return
val modalityModifierType = modalityModifier.node.elementType val modalityModifierType = modalityModifier.node.elementType
val implicitModality = declaration.implicitModality() val implicitModality = declaration.implicitModality()
if (modalityModifierType != implicitModality) return if (modalityModifierType != implicitModality) return@declarationVisitor
holder.registerProblem(modalityModifier, holder.registerProblem(modalityModifier,
"Redundant modality modifier", "Redundant modality modifier",
@@ -49,5 +28,4 @@ class RedundantModalityModifierInspection : AbstractKotlinInspection(), CleanupL
declaration.containingFile)) declaration.containingFile))
} }
} }
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -53,32 +42,7 @@ import org.jetbrains.kotlin.utils.keysToMapExceptNulls
class RedundantSamConstructorInspection : AbstractKotlinInspection() { class RedundantSamConstructorInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return callExpressionVisitor(fun(expression) {
private fun createQuickFix(expression: KtCallExpression): LocalQuickFix {
return object : LocalQuickFix {
override fun getName() = "Remove redundant SAM-constructor"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(expression)) return
replaceSamConstructorCall(expression)
}
}
}
private fun createQuickFix(expressions: Collection<KtCallExpression>): LocalQuickFix {
return object : LocalQuickFix {
override fun getName() = "Remove redundant SAM-constructors"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
for (callExpression in expressions) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(callExpression)) return
replaceSamConstructorCall(callExpression)
}
}
}
}
override fun visitCallExpression(expression: KtCallExpression) {
if (expression.valueArguments.isEmpty()) return if (expression.valueArguments.isEmpty()) return
val samConstructorCalls = samConstructorCallsToBeConverted(expression) val samConstructorCalls = samConstructorCallsToBeConverted(expression)
@@ -106,10 +70,32 @@ class RedundantSamConstructorInspection : AbstractKotlinInspection() {
holder.registerProblem(problemDescriptor) holder.registerProblem(problemDescriptor)
} }
})
}
private fun createQuickFix(expression: KtCallExpression): LocalQuickFix {
return object : LocalQuickFix {
override fun getName() = "Remove redundant SAM-constructor"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(expression)) return
replaceSamConstructorCall(expression)
} }
} }
} }
private fun createQuickFix(expressions: Collection<KtCallExpression>): LocalQuickFix {
return object : LocalQuickFix {
override fun getName() = "Remove redundant SAM-constructors"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
for (callExpression in expressions) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(callExpression)) return
replaceSamConstructorCall(callExpression)
}
}
}
}
companion object { companion object {
fun replaceSamConstructorCall(callExpression: KtCallExpression): KtLambdaExpression { fun replaceSamConstructorCall(callExpression: KtCallExpression): KtLambdaExpression {
val functionalArgument = callExpression.samConstructorValueArgument()?.getArgumentExpression() val functionalArgument = callExpression.samConstructorValueArgument()?.getArgumentExpression()
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -25,9 +14,7 @@ import org.jetbrains.kotlin.psi.*
class RedundantSetterInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantSetterInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return propertyAccessorVisitor { accessor ->
override fun visitPropertyAccessor(accessor: KtPropertyAccessor) {
super.visitPropertyAccessor(accessor)
if (accessor.isRedundantSetter()) { if (accessor.isRedundantSetter()) {
holder.registerProblem(accessor, holder.registerProblem(accessor,
"Redundant setter", "Redundant setter",
@@ -36,7 +23,6 @@ class RedundantSetterInspection : AbstractKotlinInspection(), CleanupLocalInspec
} }
} }
} }
}
} }
private fun KtPropertyAccessor.isRedundantSetter(): Boolean { private fun KtPropertyAccessor.isRedundantSetter(): Boolean {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -24,22 +13,18 @@ import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.core.getModalityFromDescriptor
import org.jetbrains.kotlin.idea.highlighter.hasSuspendCalls import org.jetbrains.kotlin.idea.highlighter.hasSuspendCalls
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.namedFunctionVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
class RedundantSuspendModifierInspection : AbstractKotlinInspection() { class RedundantSuspendModifierInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return namedFunctionVisitor(fun(function) {
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
if (!function.languageVersionSettings.supportsFeature(LanguageFeature.Coroutines)) return if (!function.languageVersionSettings.supportsFeature(LanguageFeature.Coroutines)) return
val suspendModifier = function.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD) ?: return val suspendModifier = function.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD) ?: return
@@ -59,8 +44,6 @@ class RedundantSuspendModifierInspection : AbstractKotlinInspection() {
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
IntentionWrapper(RemoveModifierFix(function, KtTokens.SUSPEND_KEYWORD, isRedundant = true), IntentionWrapper(RemoveModifierFix(function, KtTokens.SUSPEND_KEYWORD, isRedundant = true),
function.containingFile)) function.containingFile))
})
}
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -25,11 +14,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
class RedundantUnitExpressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantUnitExpressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return referenceExpressionVisitor(fun(expression) {
override fun visitReferenceExpression(expression: KtReferenceExpression) {
super.visitReferenceExpression(expression)
if (KotlinBuiltIns.FQ_NAMES.unit.shortName() != (expression as? KtNameReferenceExpression)?.getReferencedNameAsName()) { if (KotlinBuiltIns.FQ_NAMES.unit.shortName() != (expression as? KtNameReferenceExpression)?.getReferencedNameAsName()) {
return return
} }
@@ -44,8 +29,7 @@ class RedundantUnitExpressionInspection : AbstractKotlinInspection(), CleanupLoc
"Redundant 'Unit'", "Redundant 'Unit'",
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
RemoveRedundantUnitFix()) RemoveRedundantUnitFix())
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -24,19 +13,14 @@ import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention
import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.namedFunctionVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
class RedundantUnitReturnTypeInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantUnitReturnTypeInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return namedFunctionVisitor(fun(function) {
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
if (function.containingFile is KtCodeFragment) return if (function.containingFile is KtCodeFragment) return
val typeElement = function.typeReference?.typeElement ?: return val typeElement = function.typeReference?.typeElement ?: return
val context = function.analyze(BodyResolveMode.PARTIAL) val context = function.analyze(BodyResolveMode.PARTIAL)
@@ -51,7 +35,6 @@ class RedundantUnitReturnTypeInspection : AbstractKotlinInspection(), CleanupLoc
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
IntentionWrapper(RemoveExplicitTypeIntention(), function.containingKtFile)) IntentionWrapper(RemoveExplicitTypeIntention(), function.containingKtFile))
} }
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -20,15 +9,13 @@ import com.intellij.codeInspection.*
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.core.implicitVisibility import org.jetbrains.kotlin.idea.core.implicitVisibility
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.declarationVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
class RedundantVisibilityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RedundantVisibilityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return declarationVisitor { declaration ->
override fun visitDeclaration(declaration: KtDeclaration) { val visibilityModifier = declaration.visibilityModifier() ?: return@declarationVisitor
val visibilityModifier = declaration.visibilityModifier() ?: return
val implicitVisibility = declaration.implicitVisibility() val implicitVisibility = declaration.implicitVisibility()
if (visibilityModifier.node.elementType == implicitVisibility) { if (visibilityModifier.node.elementType == implicitVisibility) {
holder.registerProblem(visibilityModifier, holder.registerProblem(visibilityModifier,
@@ -39,5 +26,4 @@ class RedundantVisibilityModifierInspection : AbstractKotlinInspection(), Cleanu
} }
} }
} }
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -31,10 +20,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
class RemoveRedundantSpreadOperatorInspection : AbstractKotlinInspection() { class RemoveRedundantSpreadOperatorInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return valueArgumentVisitor(fun(argument) {
override fun visitArgument(argument: KtValueArgument) {
super.visitArgument(argument)
val spreadElement = argument.getSpreadElement() ?: return val spreadElement = argument.getSpreadElement() ?: return
if (argument.isNamed()) return if (argument.isNamed()) return
val argumentExpression = argument.getArgumentExpression() ?: return val argumentExpression = argument.getArgumentExpression() ?: return
@@ -59,8 +45,7 @@ class RemoveRedundantSpreadOperatorInspection : AbstractKotlinInspection() {
RemoveRedundantSpreadOperatorQuickfix() RemoveRedundantSpreadOperatorQuickfix()
) )
holder.registerProblem(problemDescriptor) holder.registerProblem(problemDescriptor)
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -22,20 +11,16 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention
import org.jetbrains.kotlin.idea.intentions.isSetterParameter import org.jetbrains.kotlin.idea.intentions.isSetterParameter
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.parameterVisitor
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtVisitorVoid
class RemoveSetterParameterTypeInspection : AbstractKotlinInspection() { class RemoveSetterParameterTypeInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return parameterVisitor { dcl ->
override fun visitDeclaration(dcl: KtDeclaration) { val typeReference = dcl.takeIf { it.isSetterParameter }?.typeReference ?: return@parameterVisitor
val typeReference = (dcl as? KtParameter)?.takeIf { it.isSetterParameter }?.typeReference ?: return
holder.registerProblem(typeReference, holder.registerProblem(typeReference,
"Redundant setter parameter type", "Redundant setter parameter type",
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
IntentionWrapper(RemoveExplicitTypeIntention(), dcl.containingKtFile)) IntentionWrapper(RemoveExplicitTypeIntention(), dcl.containingKtFile))
} }
} }
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -29,10 +18,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class RemoveToStringInStringTemplateInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class RemoveToStringInStringTemplateInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { dotQualifiedExpressionVisitor(fun(expression) {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
super.visitDotQualifiedExpression(expression)
if (expression.parent !is KtBlockStringTemplateEntry) return if (expression.parent !is KtBlockStringTemplateEntry) return
if (expression.receiverExpression is KtSuperExpression) return if (expression.receiverExpression is KtSuperExpression) return
val selectorExpression = expression.selectorExpression ?: return val selectorExpression = expression.selectorExpression ?: return
@@ -42,14 +28,13 @@ class RemoveToStringInStringTemplateInspection : AbstractKotlinInspection(), Cle
"Redundant 'toString()' call in string template", "Redundant 'toString()' call in string template",
ProblemHighlightType.LIKE_UNUSED_SYMBOL, ProblemHighlightType.LIKE_UNUSED_SYMBOL,
RemoveToStringFix()) RemoveToStringFix())
} })
}
private fun KtDotQualifiedExpression.isToString(): Boolean { private fun KtDotQualifiedExpression.isToString(): Boolean {
val resolvedCall = toResolvedCall(BodyResolveMode.PARTIAL) ?: return false val resolvedCall = toResolvedCall(BodyResolveMode.PARTIAL) ?: return false
val callableDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return false val callableDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return false
return callableDescriptor.getDeepestSuperDeclarations().any { it.fqNameUnsafe.asString() == "kotlin.Any.toString" } return callableDescriptor.getDeepestSuperDeclarations().any { it.fqNameUnsafe.asString() == "kotlin.Any.toString" }
}
}
} }
class RemoveToStringFix: LocalQuickFix { class RemoveToStringFix: LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -32,10 +21,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
class ReplaceArrayOfWithLiteralInspection : AbstractKotlinInspection() { class ReplaceArrayOfWithLiteralInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return callExpressionVisitor(fun(expression) {
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
if (!expression.languageVersionSettings.supportsFeature(ArrayLiteralsInAnnotations) && if (!expression.languageVersionSettings.supportsFeature(ArrayLiteralsInAnnotations) &&
!ApplicationManager.getApplication().isUnitTestMode) return !ApplicationManager.getApplication().isUnitTestMode) return
@@ -63,8 +49,7 @@ class ReplaceArrayOfWithLiteralInspection : AbstractKotlinInspection() {
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
ReplaceWithArrayLiteralFix() ReplaceWithArrayLiteralFix()
) )
} })
}
} }
private class ReplaceWithArrayLiteralFix : LocalQuickFix { private class ReplaceWithArrayLiteralFix : LocalQuickFix {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -26,7 +15,10 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.callExpression import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.intentions.calleeName import org.jetbrains.kotlin.idea.intentions.calleeName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.psi.dotQualifiedExpressionVisitor
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -34,9 +26,7 @@ class ReplaceToWithInfixFormInspection : AbstractKotlinInspection() {
private val compatibleNames = setOf("to") private val compatibleNames = setOf("to")
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return dotQualifiedExpressionVisitor(fun(expression) {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
super.visitDotQualifiedExpression(expression)
if (expression.callExpression?.valueArguments?.size != 1) return if (expression.callExpression?.valueArguments?.size != 1) return
if (expression.calleeName !in compatibleNames) return if (expression.calleeName !in compatibleNames) return
@@ -52,8 +42,7 @@ class ReplaceToWithInfixFormInspection : AbstractKotlinInspection() {
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
ReplaceToWithInfixFormQuickfix() ReplaceToWithInfixFormQuickfix()
) )
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -31,32 +20,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
class SelfAssignmentInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { class SelfAssignmentInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return binaryExpressionVisitor(fun(expression) {
private fun KtExpression.asNameReferenceExpression(): KtNameReferenceExpression? = when (this) {
is KtNameReferenceExpression ->
this
is KtDotQualifiedExpression ->
(selectorExpression as? KtNameReferenceExpression)?.takeIf { receiverExpression is KtThisExpression }
else ->
null
}
private fun KtExpression.receiverDeclarationDescriptor(
resolvedCall: ResolvedCall<out CallableDescriptor>,
context: BindingContext
): DeclarationDescriptor? {
val thisExpression = (this as? KtDotQualifiedExpression)?.receiverExpression as? KtThisExpression
if (thisExpression != null) {
return thisExpression.getResolvedCall(context)?.resultingDescriptor?.containingDeclaration
}
val implicitReceiver = with (resolvedCall) { dispatchReceiver ?: extensionReceiver } as? ImplicitReceiver
return implicitReceiver?.declarationDescriptor
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
super.visitBinaryExpression(expression)
if (expression.operationToken != KtTokens.EQ) return if (expression.operationToken != KtTokens.EQ) return
val left = expression.left val left = expression.left
val leftRefExpr = left?.asNameReferenceExpression() ?: return val leftRefExpr = left?.asNameReferenceExpression() ?: return
@@ -87,8 +51,28 @@ class SelfAssignmentInspection : AbstractKotlinInspection(), CleanupLocalInspect
"Variable '${rightCallee.name}' is assigned to itself", "Variable '${rightCallee.name}' is assigned to itself",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
RemoveSelfAssignmentFix()) RemoveSelfAssignmentFix())
})
} }
private fun KtExpression.asNameReferenceExpression(): KtNameReferenceExpression? = when (this) {
is KtNameReferenceExpression ->
this
is KtDotQualifiedExpression ->
(selectorExpression as? KtNameReferenceExpression)?.takeIf { receiverExpression is KtThisExpression }
else ->
null
} }
private fun KtExpression.receiverDeclarationDescriptor(
resolvedCall: ResolvedCall<out CallableDescriptor>,
context: BindingContext
): DeclarationDescriptor? {
val thisExpression = (this as? KtDotQualifiedExpression)?.receiverExpression as? KtThisExpression
if (thisExpression != null) {
return thisExpression.getResolvedCall(context)?.resultingDescriptor?.containingDeclaration
}
val implicitReceiver = with (resolvedCall) { dispatchReceiver ?: extensionReceiver } as? ImplicitReceiver
return implicitReceiver?.declarationDescriptor
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -30,11 +19,7 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
class SimplifyWhenWithBooleanConstantConditionInspection : AbstractKotlinInspection() { class SimplifyWhenWithBooleanConstantConditionInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return whenExpressionVisitor(fun(expression) {
override fun visitWhenExpression(expression: KtWhenExpression) {
super.visitWhenExpression(expression)
if (expression.closeBrace == null) return if (expression.closeBrace == null) return
if (expression.subjectExpression != null) return if (expression.subjectExpression != null) return
if (expression.entries.none { it.isTrueConstantCondition() || it.isFalseConstantCondition() }) return if (expression.entries.none { it.isTrueConstantCondition() || it.isFalseConstantCondition() }) return
@@ -43,9 +28,7 @@ class SimplifyWhenWithBooleanConstantConditionInspection : AbstractKotlinInspect
"This 'when' is simplifiable", "This 'when' is simplifiable",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
SimplifyWhenFix()) SimplifyWhenFix())
} })
}
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -24,8 +13,7 @@ import org.jetbrains.kotlin.psi.*
class SuspiciousEqualsCombination : AbstractKotlinInspection() { class SuspiciousEqualsCombination : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
object : KtVisitorVoid() { binaryExpressionVisitor(fun(expression) {
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (expression.parent is KtBinaryExpression) return if (expression.parent is KtBinaryExpression) return
val operands = expression.parseBinary() val operands = expression.parseBinary()
val eqeq = operands.eqEqOperands.map { it.text } val eqeq = operands.eqEqOperands.map { it.text }
@@ -34,8 +22,7 @@ class SuspiciousEqualsCombination : AbstractKotlinInspection() {
holder.registerProblem(expression, "Suspicious combination of == and ===", holder.registerProblem(expression, "Suspicious combination of == and ===",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING) ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
} }
} })
}
private fun KtBinaryExpression.parseBinary(pair: ComparisonOperands = ComparisonOperands()): ComparisonOperands { private fun KtBinaryExpression.parseBinary(pair: ComparisonOperands = ComparisonOperands()): ComparisonOperands {
when (operationToken) { when (operationToken) {
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -20,8 +9,7 @@ import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.expressionVisitor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -30,10 +18,7 @@ import org.jetbrains.kotlin.types.isDynamic
class UnsafeCastFromDynamicInspection : AbstractKotlinInspection() { class UnsafeCastFromDynamicInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return expressionVisitor(fun(expression) {
override fun visitExpression(expression: KtExpression) {
super.visitExpression(expression)
val context = expression.analyze(BodyResolveMode.PARTIAL) val context = expression.analyze(BodyResolveMode.PARTIAL)
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, expression] ?: return val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, expression] ?: return
val actualType = expression.getType(context) ?: return val actualType = expression.getType(context) ?: return
@@ -41,7 +26,6 @@ class UnsafeCastFromDynamicInspection : AbstractKotlinInspection() {
if (actualType.isDynamic() && !expectedType.isDynamic() && !TypeUtils.noExpectedType(expectedType)) { if (actualType.isDynamic() && !expectedType.isDynamic() && !TypeUtils.noExpectedType(expectedType)) {
holder.registerProblem(expression, "Implicit (unsafe) cast from dynamic to $expectedType") holder.registerProblem(expression, "Implicit (unsafe) cast from dynamic to $expectedType")
} }
} })
}
} }
} }
@@ -1,25 +1,12 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.FileModificationService import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.LocalQuickFixOnPsiElement import com.intellij.codeInspection.LocalQuickFixOnPsiElement
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
@@ -28,7 +15,10 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.callExpressionVisitor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -37,8 +27,7 @@ import org.jetbrains.kotlin.resolve.source.getPsi
class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() { class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return callExpressionVisitor(fun(expression) {
override fun visitCallExpression(expression: KtCallExpression) {
val context = expression.analyze(BodyResolveMode.PARTIAL) val context = expression.analyze(BodyResolveMode.PARTIAL)
if (expression.used(context)) { if (expression.used(context)) {
return return
@@ -57,8 +46,7 @@ class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() {
holder.registerProblem(expression, holder.registerProblem(expression,
"Unused return value of a function with lambda expression body", "Unused return value of a function with lambda expression body",
RemoveEqTokenFromFunctionDeclarationFix(function)) RemoveEqTokenFromFunctionDeclarationFix(function))
} })
}
} }
private fun KtExpression.used(context: BindingContext): Boolean = context[BindingContext.USED_AS_EXPRESSION, this] ?: true private fun KtExpression.used(context: BindingContext): Boolean = context[BindingContext.USED_AS_EXPRESSION, this] ?: true
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -139,9 +128,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
override fun runForWholeFile() = true override fun runForWholeFile() = true
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() { return namedDeclarationVisitor(fun(declaration) {
override fun visitDeclaration(declaration: KtDeclaration) {
if (declaration !is KtNamedDeclaration) return
val message = declaration.describe()?.let { "$it is never used" } ?: return val message = declaration.describe()?.let { "$it is never used" } ?: return
if (!ProjectRootsUtil.isInProjectSource(declaration)) return if (!ProjectRootsUtil.isInProjectSource(declaration)) return
@@ -178,8 +165,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
) )
holder.registerProblem(problemDescriptor) holder.registerProblem(problemDescriptor)
} })
}
} }
override val suppressionKey: String get() = "unused" override val suppressionKey: String get() = "unused"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -67,10 +56,7 @@ class UseExpressionBodyInspection(private val convertEmptyToUnit: Boolean) : Abs
} }
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
object : KtVisitorVoid() { declarationVisitor(fun(declaration) {
override fun visitDeclaration(declaration: KtDeclaration) {
super.visitDeclaration(declaration)
declaration as? KtDeclarationWithBody ?: return declaration as? KtDeclarationWithBody ?: return
val (toHighlightElement, suffix, highlightType) = statusFor(declaration) ?: return val (toHighlightElement, suffix, highlightType) = statusFor(declaration) ?: return
// Change range to start with left brace // Change range to start with left brace
@@ -94,8 +80,7 @@ class UseExpressionBodyInspection(private val convertEmptyToUnit: Boolean) : Abs
toHighlightRange?.shiftRight(-declaration.startOffset), toHighlightRange?.shiftRight(-declaration.startOffset),
ConvertToExpressionBodyFix() ConvertToExpressionBodyFix()
) )
} })
}
private fun KtDeclarationWithBody.findValueStatement(): KtExpression? { private fun KtDeclarationWithBody.findValueStatement(): KtExpression? {
val body = blockExpression() ?: return null val body = blockExpression() ?: return null
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -23,16 +12,15 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.whenExpressionVisitor
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
class WhenWithOnlyElseInspection : AbstractKotlinInspection() { class WhenWithOnlyElseInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return whenExpressionVisitor { expression ->
override fun visitWhenExpression(expression: KtWhenExpression) {
val singleEntry = expression.entries.singleOrNull() val singleEntry = expression.entries.singleOrNull()
if (singleEntry?.isElse != true) return if (singleEntry?.isElse != true) return@whenExpressionVisitor
val usedAsExpression = expression.isUsedAsExpression(expression.analyze()) val usedAsExpression = expression.isUsedAsExpression(expression.analyze())
@@ -42,7 +30,6 @@ class WhenWithOnlyElseInspection : AbstractKotlinInspection() {
) )
} }
} }
}
private class SimplifyFix( private class SimplifyFix(
private val isUsedAsExpression: Boolean private val isUsedAsExpression: Boolean
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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 package org.jetbrains.kotlin.idea.inspections
@@ -34,9 +23,7 @@ class WrapUnaryOperatorInspection : AbstractKotlinInspection() {
val numberTypes = listOf(KtNodeTypes.INTEGER_CONSTANT, KtNodeTypes.FLOAT_CONSTANT) val numberTypes = listOf(KtNodeTypes.INTEGER_CONSTANT, KtNodeTypes.FLOAT_CONSTANT)
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() { return prefixExpressionVisitor { expression ->
override fun visitPrefixExpression(expression: KtPrefixExpression) {
super.visitPrefixExpression(expression)
if (expression.operationToken.isUnaryMinusOrPlus()) { if (expression.operationToken.isUnaryMinusOrPlus()) {
val baseExpression = expression.baseExpression val baseExpression = expression.baseExpression
if (baseExpression is KtDotQualifiedExpression) { if (baseExpression is KtDotQualifiedExpression) {
@@ -51,10 +38,9 @@ class WrapUnaryOperatorInspection : AbstractKotlinInspection() {
} }
} }
} }
}
private fun IElementType.isUnaryMinusOrPlus() = this == KtTokens.MINUS || this == KtTokens.PLUS private fun IElementType.isUnaryMinusOrPlus() = this == KtTokens.MINUS || this == KtTokens.PLUS
}
}
private class WrapUnaryOperatorQuickfix : LocalQuickFix { private class WrapUnaryOperatorQuickfix : LocalQuickFix {
override fun getName() = "Wrap unary operator and value with ()" override fun getName() = "Wrap unary operator and value with ()"
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.collections package org.jetbrains.kotlin.idea.inspections.collections
@@ -34,10 +23,7 @@ class SimplifiableCallChainInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
object : KtVisitorVoid() { qualifiedExpressionVisitor(fun(expression) {
override fun visitQualifiedExpression(expression: KtQualifiedExpression) {
super.visitQualifiedExpression(expression)
val firstExpression = expression.receiverExpression val firstExpression = expression.receiverExpression
val firstCallExpression = getCallExpression(firstExpression) ?: return val firstCallExpression = getCallExpression(firstExpression) ?: return
@@ -93,8 +79,7 @@ class SimplifiableCallChainInspection : AbstractKotlinInspection() {
SimplifyCallChainFix(conversion.replacement) SimplifyCallChainFix(conversion.replacement)
) )
holder.registerProblem(descriptor) holder.registerProblem(descriptor)
} })
}
companion object { companion object {
@@ -11,7 +11,6 @@ import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.editor.EditorModificationUtil import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.siyeh.ig.psiutils.TestUtils import com.siyeh.ig.psiutils.TestUtils
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
@@ -26,6 +25,7 @@ import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory
import org.jetbrains.kotlin.idea.kdoc.findKDoc import org.jetbrains.kotlin.idea.kdoc.findKDoc
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.namedDeclarationVisitor
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -34,27 +34,21 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KDocMissingDocumentationInspection : AbstractKotlinInspection() { class KDocMissingDocumentationInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor = override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
KDocMissingDocumentationInspection(holder) namedDeclarationVisitor { element ->
private class KDocMissingDocumentationInspection(private val holder: ProblemsHolder) : PsiElementVisitor() {
override fun visitElement(element: PsiElement) {
if (TestUtils.isInTestSourceContent(element)) { if (TestUtils.isInTestSourceContent(element)) {
return return@namedDeclarationVisitor
} }
if (element is KtNamedDeclaration) {
val nameIdentifier = element.nameIdentifier val nameIdentifier = element.nameIdentifier
val descriptor = element.resolveToDescriptorIfAny(BodyResolveMode.FULL) val descriptor = element.resolveToDescriptorIfAny(BodyResolveMode.FULL)
as? DeclarationDescriptorWithVisibility as? DeclarationDescriptorWithVisibility
as? MemberDescriptor ?: return as? MemberDescriptor ?: return@namedDeclarationVisitor
if (nameIdentifier != null && descriptor.isEffectivelyPublicApi) { if (nameIdentifier != null && descriptor.isEffectivelyPublicApi) {
if (descriptor.findKDoc { DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, it) } == null) { if (descriptor.findKDoc { DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, it) } == null) {
val message = element.describe()?.let { "$it is missing documentation" } ?: "Missing documentation" val message = element.describe()?.let { "$it is missing documentation" } ?: "Missing documentation"
holder.registerProblem(nameIdentifier, message, AddDocumentationFix()) holder.registerProblem(nameIdentifier, message, AddDocumentationFix())
} }
} }
}
}
} }
class AddDocumentationFix : LocalQuickFix { class AddDocumentationFix : LocalQuickFix {