From 582472c0528fa4879f53c369183ef8d0e93913d3 Mon Sep 17 00:00:00 2001 From: develar Date: Mon, 29 Apr 2019 13:43:06 +0200 Subject: [PATCH] NonDefaultConstructorInspection - correctly handle nested classes GitOrigin-RevId: a97b592ae9c9f2d0f74d00431dfc216b26d6dfa7 --- .../NonDefaultConstructorInspection.kt | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt b/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt index 9e863624a2bd..9b59de636f09 100644 --- a/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt +++ b/plugins/devkit/devkit-core/src/inspections/NonDefaultConstructorInspection.kt @@ -7,6 +7,7 @@ import com.intellij.codeInspection.ProblemHighlightType import com.intellij.lang.jvm.JvmClassKind import com.intellij.openapi.project.Project import com.intellij.psi.PsiClassType +import com.intellij.psi.PsiModifier import com.intellij.psi.PsiParameterList import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.PsiUtil @@ -26,8 +27,8 @@ class NonDefaultConstructorInspection : DevKitUastInspectionBase() { val javaPsi = aClass.javaPsi // Groovy from test data - ignore it if (javaPsi.language.id == "Groovy" || javaPsi.classKind != JvmClassKind.CLASS || - PsiUtil.isInnerClass(javaPsi) || PsiUtil.isLocalOrAnonymousClass(javaPsi) || - PsiUtil.isAbstractClass(javaPsi)) { + PsiUtil.isInnerClass(javaPsi) || PsiUtil.isLocalOrAnonymousClass(javaPsi) || PsiUtil.isAbstractClass(javaPsi) || + javaPsi.hasModifierProperty(PsiModifier.PRIVATE) /* ignore private classes */) { return null } @@ -74,19 +75,32 @@ class NonDefaultConstructorInspection : DevKitUastInspectionBase() { } private fun findExtensionPoint(clazz: UClass, project: Project): ExtensionPoint? { + val parentClass = clazz.uastParent as? UClass + if (parentClass == null) { + val qualifiedName = clazz.qualifiedName ?: return null + return findExtensionPointByImplementationClass(qualifiedName, qualifiedName, project) + } + else { + val parentQualifiedName = parentClass.qualifiedName ?: return null + // parent$inner string cannot be found, so, search by parent FQN + return findExtensionPointByImplementationClass(parentQualifiedName, "$parentQualifiedName$${clazz.javaPsi.name}", project) + } +} + +private fun findExtensionPointByImplementationClass(searchString: String, qualifiedName: String, project: Project): ExtensionPoint? { var result: ExtensionPoint? = null - val qualifiedNamed = clazz.qualifiedName ?: return null - processExtensionDeclarations(qualifiedNamed, project) { extension, tag -> + val strictMatch = searchString === qualifiedName + processExtensionDeclarations(searchString, project, strictMatch = strictMatch) { extension, tag -> val point = extension.extensionPoint ?: return@processExtensionDeclarations true if (point.beanClass.stringValue == null) { - if (tag.attributes.any { it.name == "implementation" && it.value == qualifiedNamed }) { + if (tag.attributes.any { it.name == "implementation" && it.value == qualifiedName }) { result = point return@processExtensionDeclarations false } } else { // bean EP - if (tag.name == "className" || tag.subTags.any { it.name == "className" } || checkAttributes(tag, qualifiedNamed)) { + if (tag.name == "className" || tag.subTags.any { it.name == "className" && (strictMatch || it.textMatches(qualifiedName)) } || checkAttributes(tag, qualifiedName)) { result = point return@processExtensionDeclarations false } @@ -103,14 +117,14 @@ private val ignoredTagNames = THashSet(listOf("semContributor", "modelFacade", " // // 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 { +private fun checkAttributes(tag: XmlTag, qualifiedName: String): Boolean { if (ignoredTagNames.contains(tag.name)) { // DbmsExtension passes Dbms instance directly, doesn't need to check return false } return tag.attributes.any { - it.name.startsWith("implementation") && it.value == qualifiedNamed + it.name.startsWith("implementation") && it.value == qualifiedName } } @@ -119,8 +133,8 @@ private fun isAllowedParameters(list: PsiParameterList, extensionPoint: Extensio return true } - val area = extensionPoint?.area?.value ?: ExtensionPoint.Area.IDEA_APPLICATION - val isAppLevelExtensionPoint = area == ExtensionPoint.Area.IDEA_APPLICATION + val area = extensionPoint?.area?.stringValue + val isAppLevelExtensionPoint = area == null || area == "IDEA_APPLICATION" // hardcoded for now, later will be generalized if (isAppLevelExtensionPoint || extensionPoint?.effectiveQualifiedName == "com.intellij.semContributor") {