Inspection "can be primary constructor property" with relevant quick-fix #KT-8477 Fixed

(cherry picked from commit 2db7562)
This commit is contained in:
Mikhail Glukhikh
2016-06-16 13:09:32 +03:00
parent 9240c82934
commit ac03d98cb2
13 changed files with 196 additions and 0 deletions
+8
View File
@@ -1569,6 +1569,14 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.CanBePrimaryConstructorPropertyInspection"
displayName="Property is explicitly assigned to constructor parameter"
groupName="Kotlin"
enabledByDefault="true"
level="WARNING"
language="kotlin"
/>
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() {
override fun visitProperty(property: KtProperty) {
if (property.isLocal) return
if (property.getter != null || property.setter != null || property.delegate != null) return
val assigned = property.initializer as? KtReferenceExpression ?: return
val context = property.analyzeFully()
val assignedDescriptor = context.get(BindingContext.REFERENCE_TARGET, assigned) as? ValueParameterDescriptor ?: return
// to prevent some exotic situations
if (!assignedDescriptor.annotations.isEmpty() || !assigned.getAnnotationEntries().isEmpty()) return
val containingConstructor = assignedDescriptor.containingDeclaration as? ConstructorDescriptor ?: return
if (containingConstructor.containingDeclaration.isData) return
val propertyTypeReference = property.typeReference
val propertyType = context.get(BindingContext.TYPE, propertyTypeReference)
if (propertyType != null && propertyType != assignedDescriptor.type) return
val nameIdentifier = property.nameIdentifier ?: return
if (nameIdentifier.text != assignedDescriptor.name.asString()) return
val assignedParameter = DescriptorToSourceUtils.descriptorToDeclaration(assignedDescriptor) as? KtParameter ?: return
holder.registerProblem(holder.manager.createProblemDescriptor(
nameIdentifier,
nameIdentifier,
"Property is explicitly assigned by parameter ${assignedDescriptor.name}, can be declared directly in constructor",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
isOnTheFly,
MakeConstructorPropertyFix(property, assignedParameter)
))
}
}
}
class MakeConstructorPropertyFix(val original: KtProperty, val parameter: KtParameter) : LocalQuickFix {
override fun getName() = "Move to constructor"
override fun getFamilyName() = "Move to constructor"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val isVar = original.isVar
val modifiers = original.modifierList?.text
val factory = KtPsiFactory(project)
val valOrVar = if (isVar) factory.createVarKeyword() else factory.createValKeyword()
parameter.addBefore(valOrVar, parameter.nameIdentifier)
if (modifiers != null) {
val newModifiers = factory.createModifierList(modifiers)
parameter.addBefore(newModifiers, parameter.valOrVarKeyword)
}
original.delete()
}
}
}