diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml
index c76db8aa8e3..334e052ec9c 100644
--- a/.idea/inspectionProfiles/idea_default.xml
+++ b/.idea/inspectionProfiles/idea_default.xml
@@ -117,6 +117,7 @@
+
diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml
index bc772b6624a..2d1cf735aea 100644
--- a/idea/resources/META-INF/plugin-common.xml
+++ b/idea/resources/META-INF/plugin-common.xml
@@ -2650,7 +2650,7 @@
displayName="Local variable naming convention"
level="WEAK WARNING"/>
-
namePattern = value
@@ -297,37 +306,17 @@ class LocalVariableNameInspection :
START_LOWER, NO_UNDERSCORES, NO_BAD_CHARACTERS
)
-class PackageNameInspection :
- NamingConventionInspection("Package", "[a-z_][a-zA-Z\\d_]*(\\.[a-z_][a-zA-Z\\d_]*)*") {
-
- companion object {
- val PART_RULES = arrayOf(NO_BAD_CHARACTERS_OR_UNDERSCORE, NO_START_UPPER)
- }
-
+private class PackageNameInspectionLocal(
+ val parentInspection: InspectionProfileEntry,
+ val namingSettings: NamingConventionInspectionSettings
+) : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return packageDirectiveVisitor { directive ->
val packageNameExpression = directive.packageNameExpression ?: return@packageDirectiveVisitor
- val qualifiedName = directive.qualifiedName
- if (qualifiedName.isEmpty() || namingSettings.nameRegex?.matches(qualifiedName) != false) {
- return@packageDirectiveVisitor
- }
- val partErrorMessage = if (namePattern == namingSettings.defaultNamePattern) {
- directive.packageNames.asSequence()
- .mapNotNull { simpleName ->
- val referencedName = simpleName.getReferencedName()
- findRuleMessage(referencedName, PackageNameInspection.PART_RULES)
- }
- .firstOrNull()
- } else {
- null
- }
+ val checkResult = checkPackageDirective(directive, namingSettings) ?: return@packageDirectiveVisitor
- val descriptionTemplate = if (partErrorMessage != null) {
- "Package name #ref part $partErrorMessage #loc"
- } else {
- "Package name #ref ${namingSettings.getDefaultErrorMessage()} #loc"
- }
+ val descriptionTemplate = checkResult.toProblemTemplateString()
holder.registerProblem(
packageNameExpression,
@@ -337,10 +326,126 @@ class PackageNameInspection :
}
}
+ companion object {
+ data class CheckResult(val errorMessage: String, val isForPart: Boolean)
+
+ fun CheckResult.toProblemTemplateString(): String {
+ return if (isForPart) {
+ "Package name #ref part $errorMessage #loc"
+ } else {
+ "Package name #ref $errorMessage #loc"
+ }
+ }
+
+ fun checkPackageDirective(directive: KtPackageDirective, namingSettings: NamingConventionInspectionSettings): CheckResult? {
+ return checkQualifiedName(directive.qualifiedName, namingSettings)
+ }
+
+ fun checkQualifiedName(qualifiedName: String, namingSettings: NamingConventionInspectionSettings): CheckResult? {
+ if (qualifiedName.isEmpty() || namingSettings.nameRegex?.matches(qualifiedName) != false) {
+ return null
+ }
+
+ val partErrorMessage = if (namingSettings.namePattern == namingSettings.defaultNamePattern) {
+ qualifiedName.split('.').asSequence()
+ .mapNotNull { part -> findRuleMessage(part, PackageNameInspection.PART_RULES) }
+ .firstOrNull()
+ } else {
+ null
+ }
+
+ return if (partErrorMessage != null) {
+ CheckResult(partErrorMessage, true)
+ } else {
+ CheckResult(namingSettings.getDefaultErrorMessage(), false)
+ }
+ }
+ }
+
private class RenamePackageFix : RenameIdentifierFix() {
override fun getElementToRename(element: PsiElement): PsiElement? {
val packageDirective = element as? KtPackageDirective ?: return null
return JavaPsiFacade.getInstance(element.project).findPackage(packageDirective.qualifiedName)
}
}
+
+ override fun getShortName(): String = parentInspection.shortName
+ override fun getDisplayName(): String = parentInspection.displayName
+}
+
+class PackageNameInspection : BaseGlobalInspection() {
+ companion object {
+ const val DEFAULT_PACKAGE_NAME_PATTERN = "[a-z_][a-zA-Z\\d_]*(\\.[a-z_][a-zA-Z\\d_]*)*"
+ val PART_RULES = arrayOf(NO_BAD_CHARACTERS_OR_UNDERSCORE, NO_START_UPPER)
+
+ private fun PackageNameInspectionLocal.Companion.CheckResult.toErrorMessage(qualifiedName: String): String {
+ return if (isForPart) {
+ "Package name $qualifiedName part $errorMessage"
+ } else {
+ "Package name $qualifiedName $errorMessage"
+ }
+ }
+ }
+
+ var namePattern: String = DEFAULT_PACKAGE_NAME_PATTERN
+
+ private val namingSettings = NamingConventionInspectionSettings(
+ "Package",
+ DEFAULT_PACKAGE_NAME_PATTERN,
+ setNamePatternCallback = { value ->
+ namePattern = value
+ }
+ )
+
+ override fun checkElement(
+ refEntity: RefEntity,
+ analysisScope: AnalysisScope,
+ inspectionManager: InspectionManager,
+ globalInspectionContext: GlobalInspectionContext
+ ): Array? {
+ when (refEntity) {
+ is RefFile -> {
+ val psiFile = refEntity.psiFile
+ if (psiFile is KtFile && !psiFile.isInjectedFragment && !psiFile.packageMatchesDirectoryOrImplicit()) {
+ val packageDirective = psiFile.packageDirective
+ if (packageDirective != null) {
+ val qualifiedName = packageDirective.qualifiedName
+ val checkResult = PackageNameInspectionLocal.checkPackageDirective(packageDirective, namingSettings)
+ if (checkResult != null) {
+ return arrayOf(inspectionManager.createProblemDescriptor(checkResult.toErrorMessage(qualifiedName)))
+ }
+ }
+ }
+ }
+
+ is RefPackage -> {
+ @NonNls val name = StringUtil.getShortName(refEntity.getQualifiedName())
+ if (name.isEmpty() || InspectionsBundle.message("inspection.reference.default.package") == name) {
+ return null
+ }
+
+ val checkResult = PackageNameInspectionLocal.checkQualifiedName(name, namingSettings)
+ if (checkResult != null) {
+ return arrayOf(inspectionManager.createProblemDescriptor(checkResult.toErrorMessage(name)))
+ }
+ }
+
+ else -> {
+ return null
+ }
+ }
+
+ return null
+ }
+
+ override fun readSettings(element: Element) {
+ super.readSettings(element)
+ namingSettings.namePattern = namePattern
+ }
+
+ override fun createOptionsPanel() = namingSettings.createOptionsPanel()
+
+ override fun getSharedLocalInspectionTool(): LocalInspectionTool {
+ return PackageNameInspectionLocal(this, namingSettings)
+ }
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt b/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt
new file mode 100644
index 00000000000..0b379a4ef06
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2019 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.idea.util.compat
+
+import com.intellij.codeInspection.reference.RefFile
+import com.intellij.psi.PsiFile
+
+// BUNCH: 182
+@Suppress("IncompatibleAPI")
+val RefFile.psiFile: PsiFile?
+ get() = psiElement
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt.182 b/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt.182
new file mode 100644
index 00000000000..dacd12701a3
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/util/compat/refElements.kt.182
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2019 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.idea.util.compat
+
+import com.intellij.codeInspection.reference.RefFile
+import com.intellij.psi.PsiFile
+
+// BUNCH: 182
+@Suppress("IncompatibleAPI")
+val RefFile.psiFile: PsiFile?
+ get() = element
\ No newline at end of file