From 64b2527e318962d42e45d5f74e5f90e5dcd16660 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 25 Jan 2019 21:20:22 +0300 Subject: [PATCH] Revert allowing upper case letters in packages (KT-27900) --- .../NamingConventionInspections.kt | 73 ++++++++++++++----- .../naming/package/hasFirstUpperCase.kt | 1 + .../naming/package/hasUpperCase.kt | 2 +- .../package/inspectionData/expected.xml | 4 +- 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 idea/testData/inspections/naming/package/hasFirstUpperCase.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/NamingConventionInspections.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/NamingConventionInspections.kt index 800bf8d8abc..3fae190a03a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/NamingConventionInspections.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/NamingConventionInspections.kt @@ -29,6 +29,16 @@ import javax.swing.JPanel data class NamingRule(val message: String, val matcher: (String) -> Boolean) +private fun findRuleMessage(checkString: String, rules: Array): String? { + for (rule in rules) { + if (rule.matcher(checkString)) { + return rule.message + } + } + + return null +} + private val START_UPPER = NamingRule("should start with an uppercase letter") { it.getOrNull(0)?.isUpperCase() == false } @@ -41,6 +51,10 @@ private val NO_UNDERSCORES = NamingRule("should not contain underscores") { '_' in it } +private val NO_START_UPPER = NamingRule("should not start with an uppercase letter") { + it.getOrNull(0)?.isUpperCase() == true +} + private val NO_START_UNDERSCORE = NamingRule("should not start with an underscore") { it.startsWith('_') } @@ -57,13 +71,9 @@ private val NO_BAD_CHARACTERS_OR_UNDERSCORE = NamingRule("may contain only lette it.any { c -> c !in 'a'..'z' && c !in 'A'..'Z' && c !in '0'..'9' && c != '_' } } -private val ONLY_LOWER_DIGITS_OR_UNDERSCORE = NamingRule("may contain only lowercase letters, digits or underscores") { - it.any { c -> c !in 'a'..'z' && c !in '0'..'9' && c != '_' } -} - abstract class NamingConventionInspection( private val entityName: String, - @Language("RegExp") private val defaultNamePattern: String, + @Language("RegExp") protected val defaultNamePattern: String, private vararg val rules: NamingRule ) : AbstractKotlinInspection() { protected var nameRegex: Regex? = defaultNamePattern.toRegex() @@ -91,16 +101,15 @@ abstract class NamingConventionInspection( } protected fun getNameMismatchMessage(name: String): String { - if (namePattern == defaultNamePattern) { - for (rule in rules) { - if (rule.matcher(name)) { - return rule.message - } - } + if (namePattern != defaultNamePattern) { + return getDefaultErrorMessage() } - return "doesn't match regex '$namePattern'" + + return findRuleMessage(name, rules) ?: getDefaultErrorMessage() } + protected fun getDefaultErrorMessage() = "doesn't match regex '$namePattern'" + override fun createOptionsPanel() = NamingConventionOptionsPanel(this) } @@ -233,18 +242,42 @@ class LocalVariableNameInspection : ) class PackageNameInspection : - NamingConventionInspection("Package", "[a-z_][a-z\\d_]*(\\.[a-z_][a-z\\d_]*)*", ONLY_LOWER_DIGITS_OR_UNDERSCORE) { + 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) + } + 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.isNotEmpty() && nameRegex?.matches(qualifiedName) == false) { - val message = getNameMismatchMessage(qualifiedName) - holder.registerProblem( - directive.packageNameExpression!!, - "Package name #ref $message #loc", - RenamePackageFix() - ) + if (qualifiedName.isEmpty() || nameRegex?.matches(qualifiedName) != false) { + return@packageDirectiveVisitor } + + val partErrorMessage = if (namePattern == defaultNamePattern) { + directive.packageNames.asSequence() + .mapNotNull { simpleName -> + val referencedName = simpleName.getReferencedName() + findRuleMessage(referencedName, PackageNameInspection.PART_RULES) + } + .firstOrNull() + } else { + null + } + + val descriptionTemplate = if (partErrorMessage != null) { + "Package name #ref part $partErrorMessage #loc" + } else { + "Package name #ref ${getDefaultErrorMessage()} #loc" + } + + holder.registerProblem( + packageNameExpression, + descriptionTemplate, + RenamePackageFix() + ) } } diff --git a/idea/testData/inspections/naming/package/hasFirstUpperCase.kt b/idea/testData/inspections/naming/package/hasFirstUpperCase.kt new file mode 100644 index 00000000000..297ccce9602 --- /dev/null +++ b/idea/testData/inspections/naming/package/hasFirstUpperCase.kt @@ -0,0 +1 @@ +package one.two.Three \ No newline at end of file diff --git a/idea/testData/inspections/naming/package/hasUpperCase.kt b/idea/testData/inspections/naming/package/hasUpperCase.kt index 297ccce9602..339631f7413 100644 --- a/idea/testData/inspections/naming/package/hasUpperCase.kt +++ b/idea/testData/inspections/naming/package/hasUpperCase.kt @@ -1 +1 @@ -package one.two.Three \ No newline at end of file +package one.two.someThree \ No newline at end of file diff --git a/idea/testData/inspections/naming/package/inspectionData/expected.xml b/idea/testData/inspections/naming/package/inspectionData/expected.xml index e68027e913d..dc9da96d2f7 100644 --- a/idea/testData/inspections/naming/package/inspectionData/expected.xml +++ b/idea/testData/inspections/naming/package/inspectionData/expected.xml @@ -1,7 +1,7 @@ - hasUpperCase.kt + hasFirstUpperCase.kt 1 - Package name <code>one.two.Three</code> doesn't match regex '[a-z][A-Za-z\d]*_?(\.[a-z][A-Za-z\d]*_?)*' #loc + Package name <code>one.two.Three</code> part should not start with an uppercase letter #loc \ No newline at end of file