From 6a7997642d607eeafe8978fe60a5ecbefe704c93 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 31 Jan 2019 17:29:37 +0100 Subject: [PATCH] =?UTF-8?q?NonDefaultConstructorInspection=20=E2=80=94=20c?= =?UTF-8?q?heck=20all=20referenced=20from=20extension=20registration=20cla?= =?UTF-8?q?sses=20(part=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NonDefaultConstructorInspection.kt | 41 ++++++++++++++++--- .../src/inspections/StatefulEpInspection.kt | 6 +-- .../devkit-core/src/util/ExtensionLocator.kt | 11 ++--- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt b/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt index c5e7de420b8a..267a675871cd 100644 --- a/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt +++ b/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt @@ -10,15 +10,19 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiParameterList import com.intellij.psi.util.PsiUtil +import com.intellij.psi.xml.XmlTag import com.intellij.util.SmartList import gnu.trove.THashSet import org.jetbrains.idea.devkit.util.processExtensionsByClassName import org.jetbrains.uast.UClass +import org.jetbrains.uast.UMethod +import org.jetbrains.uast.convert +import org.jetbrains.uast.getLanguagePlugin internal class NonDefaultConstructorInspection : DevKitUastInspectionBase() { override fun checkClass(aClass: UClass, manager: InspectionManager, isOnTheFly: Boolean): Array? { val javaPsi = aClass.javaPsi - if (!javaPsi.isPhysical || javaPsi.classKind != JvmClassKind.CLASS || + if (javaPsi.classKind != JvmClassKind.CLASS || PsiUtil.isInnerClass(javaPsi) || PsiUtil.isLocalOrAnonymousClass(javaPsi) || PsiUtil.isAbstractClass(javaPsi)) { return null @@ -39,7 +43,7 @@ internal class NonDefaultConstructorInspection : DevKitUastInspectionBase() { } var errors: MutableList? = null - for (method in constructors) { + loop@ for (method in constructors) { val parameters = method.parameterList if (parameters.isEmpty || isAllowedParameters(parameters)) { // allow to have empty constructor and extra (e.g. DartQuickAssistIntention) @@ -49,7 +53,13 @@ internal class NonDefaultConstructorInspection : DevKitUastInspectionBase() { if (errors == null) { errors = SmartList() } - errors.add(manager.createProblemDescriptor(method ?: continue, + + // kotlin is not physical, but here only physical is expected, so, convert to uast element and use sourcePsi + val anchorElement = when { + method.isPhysical -> method + else -> aClass.getLanguagePlugin().convert(method, aClass).sourcePsi ?: continue@loop + } + errors.add(manager.createProblemDescriptor(anchorElement, "Bean extension class should not have constructor with parameters", true, ProblemHighlightType.ERROR, isOnTheFly)) } @@ -60,8 +70,14 @@ internal class NonDefaultConstructorInspection : DevKitUastInspectionBase() { // cannot check com.intellij.codeInsight.intention.IntentionAction by class qualified name because not all IntentionAction used as IntentionActionBean private fun isReferencedByExtension(clazz: UClass, project: Project): Boolean { var isFound = false - processExtensionsByClassName(project, clazz.qualifiedName ?: return false) { tag -> - if (tag.name == "className" || tag.subTags.any { it.name == "className" } || tag.attributes.any { it.name.startsWith("implementation") }) { + val qualifiedNamed = clazz.qualifiedName ?: return false + processExtensionsByClassName(project, qualifiedNamed) { tag, point -> + // check only bean extensions + if (point.beanClass.value == null) { + return@processExtensionsByClassName true + } + + if (tag.name == "className" || tag.subTags.any { it.name == "className" } || checkAttributes(tag, qualifiedNamed)) { isFound = true } !isFound @@ -69,6 +85,21 @@ private fun isReferencedByExtension(clazz: UClass, project: Project): Boolean { return isFound } +// problem - tag +// +// will be found for `com.intellij.psi.css.impl.CssTokenImpl`, but we need to ignore `forClass` and check that we have exact match for implementation attribute +private fun checkAttributes(tag: XmlTag, qualifiedNamed: String): Boolean { + if (tag.name == "modelFacade") { + // DbmsExtension passes Dbms instance directly, doesn't need to check + return false + } + + return tag.attributes.any { + it.name.startsWith("implementation") && it.value == qualifiedNamed + } +} + private fun isAllowedParameters(list: PsiParameterList): Boolean { if (list.parametersCount != 1) { return false diff --git a/plugins/devkit/devkit-core/src/inspections/StatefulEpInspection.kt b/plugins/devkit/devkit-core/src/inspections/StatefulEpInspection.kt index 4e4d821a3105..811a1d9b7fc1 100644 --- a/plugins/devkit/devkit-core/src/inspections/StatefulEpInspection.kt +++ b/plugins/devkit/devkit-core/src/inspections/StatefulEpInspection.kt @@ -59,10 +59,10 @@ private fun findEpCandidates(project: Project, clazz: JvmClass): Collection() val smartPointerManager by lazy { SmartPointerManager.getInstance(project) } - processExtensionsByClassName(project, name) { - val forClass = it.getAttributeValue("forClass") + processExtensionsByClassName(project, name) { tag, _ -> + val forClass = tag.getAttributeValue("forClass") if (forClass == null || !forClass.contains(name)) { - result.add(ExtensionCandidate(smartPointerManager.createSmartPsiElementPointer(it))) + result.add(ExtensionCandidate(smartPointerManager.createSmartPsiElementPointer(tag))) } true } diff --git a/plugins/devkit/devkit-core/src/util/ExtensionLocator.kt b/plugins/devkit/devkit-core/src/util/ExtensionLocator.kt index 173a3ff30c02..2f03f07dd354 100644 --- a/plugins/devkit/devkit-core/src/util/ExtensionLocator.kt +++ b/plugins/devkit/devkit-core/src/util/ExtensionLocator.kt @@ -55,20 +55,21 @@ private fun processExtensionDeclarations(name: String, project: Project, strictM private fun findExtensionsByClassName(project: Project, className: String): List { val result = SmartList() val smartPointerManager by lazy { SmartPointerManager.getInstance(project) } - processExtensionsByClassName(project, className) { - result.add(ExtensionCandidate(smartPointerManager.createSmartPsiElementPointer(it))) + processExtensionsByClassName(project, className) { tag, _ -> + result.add(ExtensionCandidate(smartPointerManager.createSmartPsiElementPointer(tag))) true } return result } -internal inline fun processExtensionsByClassName(project: Project, className: String, crossinline processor: (XmlTag) -> Boolean) { +internal inline fun processExtensionsByClassName(project: Project, className: String, crossinline processor: (XmlTag, ExtensionPoint) -> Boolean) { processExtensionDeclarations(className, project, true) { extension, tag -> - if (extension.extensionPoint == null) { + val point = extension.extensionPoint + if (point == null) { true } else { - processor(tag) + processor(tag, point) } } }