diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml
new file mode 100644
index 0000000..a8fcc84
--- /dev/null
+++ b/.idea/markdown-navigator-enh.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml
new file mode 100644
index 0000000..a2fc086
--- /dev/null
+++ b/.idea/markdown-navigator.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/lint/MainActivity.kt b/app/src/main/java/com/example/lint/MainActivity.kt
index d100c8e..53048e4 100644
--- a/app/src/main/java/com/example/lint/MainActivity.kt
+++ b/app/src/main/java/com/example/lint/MainActivity.kt
@@ -1,89 +1,137 @@
package com.example.lint
+import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.util.Log
import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
- companion object {
+ private val someaaa = "photo11111111111111111111111111111111111111111111111111111111111"
- const val SS_S_SFDAS = 2
+ companion object {
- val some = 2
+ const val ASAS = 2 * 1
- private const val EXTRA_PHOTO = "photo"
+ val some = 2
- fun createIntent(context: Context, photo: String): Intent {
- return Intent(context, MainActivity ::class.java).putExtra(EXTRA_PHOTO, photo)
- }
- fun someFunction() {}
+ private val FREQUENCIES = listOf(50, 60)
- fun createLauncher() = { someFunction() }
- }
+ private const val EXTRA_PHOTO =
+ "photo1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
- val SSs = 2
+ fun ppp() {
+ String.toString()?.toString()
+ }
- fun spme() {
- String?.toString()
+ }
- }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ fun someFunction() {
+ }
- val cTX: Context = this
- String
- .toString()
+ fun some(): Int = 1
+ val s = 2
- val list = listOf()
+ fun createIntent(context: Context, photo: String): Intent = Intent()
- list.forEach { line ->
- val s = line
- }
- }
+ fun spme() {
+ String.toString()
+ val tag = emptyList()
+ tag.forEach {
+ Log.d("some", it)
+ }
- private fun SSsome ( ) {
- MainActivity .createIntent(this, "")
- }
- class SomeClass() {
- val soURL = 2
- }
+ }
+ override fun onCreate(savedInstanceState: Bundle?) {
- fun emptyFun(): Int {
- try {
- val s = 2
- } catch (e: Exception) {
- throw e
- }
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
- return when(1) {
- 1 -> 2
- else -> 0
- }
+ val cTX: Context = this
- }
+ var croppingBlock: (() -> Int)? = null
- protected val s2: String = ""
+ try {
+ } catch (e: Exception) {
+ val some = 2
+ }
- fun Get() {
- val s = 2
- s.toString()
- //nothing
- }
+ val list = listOf()
- fun aAA() {
+ list.forEach { line ->
+ val s = line
+ }
+ }
- }
+ private fun asome() {
+ createIntent(this, "")
+ emptyURL({ val s = 2 }, { val s = 2 })
+ }
+ private fun emptyURL(function: () -> Unit, function2: () -> Unit) {
+ //nothing
+ }
+
+ @SuppressLint("OMEGA_ABBREVIATION_AS_WORD")
+ val soURL = 2
+
+ class SomeClass() {
+
+ }
+
+
+ fun em(): Int {
+ try {
+ val s = 2
+ } catch (e: Exception) {
+ throw e
+ }
+
+ return when (1) {
+ 1 -> 2
+ else -> 0
+ }
+
+ }
+
+ protected val s2: String = ""
+
+
+ fun agset() {
+ val s = 2
+ s.toString()
+ //nothing
+ }
+
+ fun aAa() {
+ //nothing
+ }
+
+ data class GeneralSettings(
+ var doorStatus: Int = 1,
+ var keepDoorOpen: Boolean = false,
+ var keepDoorOpenSip: Boolean = false,
+ var doorOpenDuration: Int = 5,
+ var callDuration: Int = 5,
+ var talkDuration: Int = 5,
+ var conciergeApartment: Int = 100,
+ val conciergeApartment1: Int = 100,
+ var conciergeApartment2: Int = 100,
+ val conciergeApartment3: Int = 100,
+ var conciergeApartment5: Int = 100
+ )
+
+ class BasePresenter
}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 6757ae8..3e3f8f2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -8,7 +8,7 @@
tools:context=".MainActivity">
+
+
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/LintIssueRegistry.kt b/checks/src/main/java/com/omegar/lint/checks/LintIssueRegistry.kt
index 27b8cdc..2400a86 100644
--- a/checks/src/main/java/com/omegar/lint/checks/LintIssueRegistry.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/LintIssueRegistry.kt
@@ -11,8 +11,9 @@ import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.elements_for
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.name.`class`.NameFileSufixDetector
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.name.abbreviation.AbbreviationDetector
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.name.field.CompanionObjectFieldsDetector
-import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.file_class_interface.ComponentPositionDetector
-import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.function_params.PositionArgumentDetector
+import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.class_interface.ComponentPositionDetector
+import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.file_package.PackageComponentDetector
+import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.function_params.ArgumentPositionDetector
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.restrictions.class_length.MaxClassLengthDetector
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.restrictions.class_methods_count.MaxMethodCountDetector
import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.restrictions.classes_in_package_count.MaxClassInPackageDetector
@@ -31,36 +32,38 @@ import com.omegar.lint.checks.detector.code_guidelines.xml_style.name_resource.t
import com.omegar.lint.checks.detector.project_guidelines.file_name.`class`.NameFileUpperCamelCaseDetector
import com.omegar.lint.checks.detector.project_guidelines.file_name.resource.layout.NameResourceLayoutDetector
+@Suppress("UnstableApiUsage")
class LintIssueRegistry : IssueRegistry() {
override val issues: List
get() = listOf(
NameFileUpperCamelCaseDetector.ISSUE,
- AbbreviationDetector.ISSUE, // TODO need testing
- PositionArgumentDetector.ISSUE,
- MaxFunctionsArgumentsDetector.ISSUE,
+ AbbreviationDetector.ISSUE, // TODO need rewriting & lint quick fix
+ ArgumentPositionDetector.ISSUE, // TODO add lint quick fix
+ MaxFunctionsArgumentsDetector.ISSUE, // TODO ??lint quick fix??
ExceptionCatchDetector.ISSUE,
- ComponentPositionDetector.ISSUE,
+ ComponentPositionDetector.ISSUE, //TODO add lint quick fix for
+ PackageComponentDetector.ISSUE,
NameIdentifierXmlDetector.ISSUE,
NameResourceStringXmlDetector.ISSUE,
- NameResourceStyleXmlDetector.ISSUE,
- MaxMethodCountDetector.ISSUE,
- EmptyBodyFunctionDetector.ISSUE,
+ NameResourceStyleXmlDetector.ISSUE, //TODO change lint quick fix for
+ MaxMethodCountDetector.ISSUE, // TODO ??lint quick fix??
+ EmptyBodyFunctionDetector.ISSUE, //TODO add lint quick fix for
CompanionObjectFieldsDetector.ISSUE,
- MaxFunctionLengthDetector.ISSUE,
- MaxClassLengthDetector.ISSUE,
+ MaxFunctionLengthDetector.ISSUE, // TODO ??lint quick fix??
+ MaxClassLengthDetector.ISSUE, // TODO ??lint quick fix??
SimplificationsFunctionDetector.ISSUE,
- MaxLineLengthDetector.ISSUE,
+ MaxLineLengthDetector.ISSUE, // TODO ??lint quick fix??
AnnotationDetector.ISSUE,
SpaceMethodDetector.ISSUE,
NameFileSufixDetector.ISSUE,
AttributesPositionXmlDetector.ISSUE,
- MaxClassInPackageDetector.ISSUE, // TODO need testing
- MaxPackageCountDetector.ISSUE, // TODO need testing
- SimplificationsControlInstructionsDetector.ISSUE, // TODO need testing
+ MaxClassInPackageDetector.ISSUE, // TODO ??lint quick fix??
+ MaxPackageCountDetector.ISSUE, // TODO ??lint quick fix??
+ SimplificationsControlInstructionsDetector.ISSUE, //TODO add lint quick fix for
IntentExtraParametersDetector.ISSUE,
ArgumentsBundleKeyPrefixDetector.ISSUE,
- LambdaDetector.ISSUE,
- NameResourceLayoutDetector.ISSUE
+ LambdaDetector.ISSUE, //TODO add lint quick fix for
+ NameResourceLayoutDetector.ISSUE //TODO add lint quick fix for
)
override val api: Int
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_rules/exception/ExceptionCatchDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_rules/exception/ExceptionCatchDetector.kt
index 00b3061..b3c1fcb 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_rules/exception/ExceptionCatchDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_rules/exception/ExceptionCatchDetector.kt
@@ -61,7 +61,7 @@ class ExceptionCatchDetector : Detector(), Detector.UastScanner {
context.report(
ISSUE,
body,
- context.getLocation(it as UElement),
+ context.getLocation(body),
GENERALIZED_EXCEPTION_MESSAGE,
createEmptyBodyFix()
)
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/abbreviation/AbbreviationDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/abbreviation/AbbreviationDetector.kt
index 3f1345e..0db925e 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/abbreviation/AbbreviationDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/abbreviation/AbbreviationDetector.kt
@@ -12,7 +12,7 @@ class AbbreviationDetector : Detector(), Detector.UastScanner {
@JvmField
val ISSUE: Issue = Issue.create(
id = "OMEGA_ABBREVIATION_AS_WORD",
- briefDescription = "Use this abbreviation does not match the coding convention",
+ briefDescription = "Use of this abbreviation does not match the coding convention",
explanation = """
Don't use abbreviations.
http://wiki.omega-r.club/dev-android-code#rec228153340
@@ -25,66 +25,65 @@ class AbbreviationDetector : Detector(), Detector.UastScanner {
)
)
- private val ABBREVIATION_REGEX = Regex("""[A-Z][A-Z]""")
- private val ANNOTATION_REGEX = Regex("""^@""")
- private const val OPEN_SCOPE_LABEL = "("
- private const val EQUAL_LABEL = "="
- private const val SPACE_LABEL = " "
+ private val ABBREVIATION_REGEX = Regex("[A-Z][A-Z]")
+ private val EXTENSION_REGEX = Regex("fun.*\\.|val.*?\\.|var.*?\\.")
+ private val ANNOTATION_REGEX = Regex("^@")
+ private const val SPACE_LABEL = " "
//exclusion
- private const val MILLISECONDS_LABEL = "MSec"
- private const val UELEMENT_LABEL = "UElement"
- private const val TODO_LABEL = "TODO"
private const val CLASS_LABEL = "class"
private const val ENUM_LABEL = "enum class"
val exclusionsList = listOf(
- MILLISECONDS_LABEL,
- TODO_LABEL,
- UELEMENT_LABEL
+ "MSec",
+ "TODO",
+ "UElement"
+ )
+ val specialSymbolList = listOf(
+ "(",
+ "<",
+ "=",
+ ":"
)
-
}
override fun getApplicableUastTypes(): List> = listOf(UDeclaration::class.java)
- override fun createUastHandler(context: JavaContext): UElementHandler {
- return object : UElementHandler() {
- override fun visitDeclaration(node: UDeclaration) {
- val parent = node.parent ?: return
- val fileLines = parent.text.lines()
- val nameLine = fileLines.firstOrNull { it.contains(CLASS_LABEL) }
-
- if (nameLine != null && nameLine.contains(ENUM_LABEL)) {
- return
- }
-
- val lines = node.text?.lines() ?: return
-
- var checkText = getNameString(lines) ?: return
-
- checkText = deleteAfterSymbol(checkText, EQUAL_LABEL)
- checkText = deleteAfterSymbol(checkText, OPEN_SCOPE_LABEL)
-
- checkText = deleteExclusions(checkText)
-
- if (checkText.contains(ABBREVIATION_REGEX) && !node.isStatic) {
- context.report(
- ISSUE,
- node as UElement,
- context.getNameLocation(node),
- checkText + "\n" + ISSUE.getExplanation(TextFormat.TEXT)
- )
- }
- }
- }
-
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitDeclaration(node: UDeclaration) {
+ val parent = node.parent ?: return
+ val nameLine = parent.text.lines().firstOrNull { it.contains(CLASS_LABEL) }
+
+ if (nameLine != null && nameLine.contains(ENUM_LABEL)) {
+ return
+ }
+
+ val lines = node.text?.lines() ?: return
+
+ var checkText = getNameString(lines) ?: return
+
+ checkText = checkForExtension(checkText)
+ checkText = deleteSpecialSymbols(checkText)
+ checkText = deleteExclusions(checkText)
+
+ if (checkText.contains(ABBREVIATION_REGEX) && !node.isStatic) {
+ context.report(
+ ISSUE,
+ node as UElement,
+ context.getNameLocation(node),
+ checkText + "\n" + ISSUE.getExplanation(TextFormat.TEXT),
+ createLintFix(checkText)
+ )
+ }
+ }
}
- private fun deleteAfterSymbol(checkText: String, symbol: String): String {
+ private fun deleteSpecialSymbols(checkText: String): String {
var text = checkText
- if (text.indexOf(symbol) > 0) {
- text = checkText.substring(0, checkText.indexOf(symbol))
+ specialSymbolList.forEach { symbol ->
+ if (text.contains(symbol) && text.indexOf(symbol) > 0) {
+ text = checkText.substring(0, checkText.indexOf(symbol))
+ }
}
return text
}
@@ -105,4 +104,34 @@ class AbbreviationDetector : Detector(), Detector.UastScanner {
}
return resultText
}
+
+ private fun checkForExtension(checkText: String): String =
+ if (checkText.contains(EXTENSION_REGEX)) checkText.substring(checkText.indexOf('.') + 1)
+ else checkText
+
+ private fun getNewName(oldName: String): String {
+ var resultName = ""
+ val charArray = oldName.toCharArray()
+
+ for (i in 1 until oldName.length) {
+ val currentChar = charArray[i]
+ val previousChar = charArray[i - 1]
+
+ resultName += if (currentChar.isUpperCase() && previousChar.isUpperCase()) {
+ currentChar.toLowerCase()
+ } else {
+ currentChar
+ }
+ }
+
+ return resultName
+ }
+
+ private fun createLintFix(oldName: String): LintFix {
+ return LintFix.create()
+ .replace()
+ .text(oldName)
+ .with(getNewName(oldName))
+ .build()
+ }
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/class/NameFileSufixDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/class/NameFileSufixDetector.kt
index e3d7b65..ca7c770 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/class/NameFileSufixDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/class/NameFileSufixDetector.kt
@@ -106,11 +106,11 @@ class NameFileSufixDetector : Detector(), Detector.UastScanner {
node,
context.getNameLocation(node),
"$REPORT_MESSAGE_BEGIN $value.\n${ISSUE.getExplanation(TextFormat.TEXT)}",
- createContextReport(node.name, value)
+ createLintFix(node.name, value)
)
}
- private fun createContextReport(part: String?, value: String): LintFix {
+ private fun createLintFix(part: String?, value: String): LintFix {
return fix()
.replace()
.text(part)
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/field/CompanionObjectFieldsDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/field/CompanionObjectFieldsDetector.kt
index cb7f73f..e41a86b 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/field/CompanionObjectFieldsDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/name/field/CompanionObjectFieldsDetector.kt
@@ -5,7 +5,9 @@ import com.android.tools.lint.detector.api.*
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
+import java.util.Locale
+@Suppress("UnstableApiUsage")
class CompanionObjectFieldsDetector : Detector(), Detector.UastScanner {
companion object {
/** Issue describing the problem and pointing to the detector implementation */
@@ -14,8 +16,8 @@ class CompanionObjectFieldsDetector : Detector(), Detector.UastScanner {
id = "OMEGA_NAME_CONSTANTS_SCREAMING_SNAKE_CASE",
briefDescription = "The line size does not match the coding convention",
explanation = """
- The immutable fields in the Companion Object and compile-time constants are named in the
- SCREAMING_SNAKE_CASE style.
+ The immutable fields in the Companion Object and compile-time constants
+ should be named in the SCREAMING_SNAKE_CASE style.
http://wiki.omega-r.club/dev-android-code#rec226457239
""",
category = Category.CORRECTNESS,
@@ -31,56 +33,63 @@ class CompanionObjectFieldsDetector : Detector(), Detector.UastScanner {
private const val VAL_LABEL = "val"
private const val COMPANION_NAME_LABEL = "Companion"
- private val UPPER_REGEX = Regex("""^([A-Z]*_*)*$""")
+ private val UPPER_REGEX = Regex("^([A-Z0-9]*_*)*$")
}
override fun getApplicableUastTypes(): List> = listOf(UClass::class.java)
- override fun createUastHandler(context: JavaContext): UElementHandler {
- return object : UElementHandler() {
- override fun visitClass(node: UClass) {
- val innerClass = node.innerClasses.firstOrNull() ?: return
- val name = innerClass.name ?: return
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitClass(node: UClass) {
+ val innerClass = node.innerClasses.firstOrNull() ?: return
+ val name = innerClass.name ?: return
- if (name != COMPANION_NAME_LABEL) {
- return
- }
+ if (name != COMPANION_NAME_LABEL) {
+ return
+ }
- val declarations = innerClass.uastDeclarations.distinctBy { it.text }
-
- declarations.forEach { declaration ->
- val text = declaration.text ?: return
- val lines = text.lines()
- lines.forEach { line ->
- if (isIncorrectConstantName(line)) {
- context.report(
- ISSUE,
- node,
- context.getNameLocation(declaration),
- "$line\n${ISSUE.getExplanation(TextFormat.TEXT)}"
- )
- }
+ val declarations = innerClass.uastDeclarations.distinctBy { it.text }
+
+ declarations.forEach { declaration ->
+ val text = declaration.text ?: return
+ val lines = text.lines()
+ lines.forEach { line ->
+ val identifierName = getName(line)
+ if (identifierName.isNotEmpty() && !identifierName.matches(UPPER_REGEX)) {
+ context.report(
+ ISSUE,
+ node,
+ context.getNameLocation(declaration),
+ "$line\n${ISSUE.getExplanation(TextFormat.TEXT)}",
+ createLintFix(identifierName)
+ )
}
}
}
}
}
- private fun isIncorrectConstantName(line: String): Boolean {
+ private fun getName(line: String): String {
if (!line.contains(CONST_VAL_LABEL)) {
- return false
+ return ""
}
val substrings = line.split(" ")
val valIndex = substrings.indexOf(VAL_LABEL)
if (valIndex == substrings.size - 1 || valIndex <= 0) {
- return false
+ return ""
}
- val identifierName = substrings[valIndex + 1]
+ return substrings[valIndex + 1]
+ }
- return !identifierName.matches(UPPER_REGEX)
+ private fun createLintFix(name: String): LintFix {
+ return LintFix.create()
+ .replace()
+ .text(name)
+ .with(name.toUpperCase(Locale.ROOT))
+ .build()
}
}
+
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/class_interface/ComponentPositionDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/class_interface/ComponentPositionDetector.kt
new file mode 100644
index 0000000..85491d5
--- /dev/null
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/class_interface/ComponentPositionDetector.kt
@@ -0,0 +1,217 @@
+package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.class_interface
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.*
+import org.jetbrains.uast.*
+import java.lang.Integer.min
+
+@Suppress("UnstableApiUsage")
+class ComponentPositionDetector : Detector(), Detector.UastScanner {
+ companion object {
+ /** Issue describing the problem and pointing to the detector implementation */
+ @JvmField
+ val ISSUE: Issue = Issue.create(
+ id = "OMEGA_USE_CLASS_COMPONENTS_IN_CORRECT_ORDER",
+ briefDescription = "Place class members in correct order",
+ explanation = """
+ Order warning.
+ http://wiki.omega-r.club/dev-android-code#rec228155171
+ """,
+ category = Category.CORRECTNESS,
+ priority = 7,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ ComponentPositionDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private const val COMPANION_NAME = "Companion"
+ private const val MODIFIERS_RANK_MESSAGE =
+ "Class members with access modifiers should be positioned in the following order:\n" +
+ "abstract, override, public, internal, protected, private.\n"
+
+ // Access modifiers rank
+ private val modifiers = arrayOf(
+ Pair("abstract", 1),
+ Pair("override", 2),
+ Pair("public", 3),
+ Pair("internal", 4),
+ Pair("protected", 5),
+ Pair("private", 6),
+ Pair("", 3),
+ )
+
+ // 1. companion object members
+ private const val COMPANION_OBJECT = "const val"
+ private const val COMPANION_OBJECT_RANK = 1
+ private const val COMPANION_OBJECT_MESSAGE = "Companion object should be the first"
+ private val COMPANION_OBJECT_REGEX_LIST = makeRegexList(COMPANION_OBJECT)
+ private val COMPANION_OBJECT_PARAMS =
+ StaticParams(COMPANION_OBJECT_REGEX_LIST, COMPANION_OBJECT_RANK, modifiers.last().second,COMPANION_OBJECT_MESSAGE)
+
+ // 2. val + var variables
+ private const val VAL = "val"
+ private const val VAR = "var"
+ private const val VARIABLES_RANK = 2
+ private const val VARIABLES_MESSAGE =
+ "Variables should be positioned earlier than constructors, functions, enums, interfaces and classes"
+ private val VAL_REGEX_LIST = makeRegexList(VAL)
+ private val VAR_REGEX_LIST = makeRegexList(VAR)
+ private val VAL_PARAMS = StaticParams(VAL_REGEX_LIST, VARIABLES_RANK, modifiers.last().second, VARIABLES_MESSAGE)
+ private val VAR_PARAMS = StaticParams(VAR_REGEX_LIST, VARIABLES_RANK, modifiers.last().second, VARIABLES_MESSAGE)
+
+ // 3. constructors and inits
+ private const val CONSTRUCTOR = "constructor"
+ private const val CONSTRUCTOR_RANK = 3
+ private const val CONSTRUCTOR_MESSAGE = "Constructors should be positioned earlier than functions, enums, interfaces and classes"
+ private val CONSTRUCTOR_REGEX_LIST = makeRegexList(CONSTRUCTOR)
+ private val CONSTRUCTOR_PARAMS = StaticParams(CONSTRUCTOR_REGEX_LIST, CONSTRUCTOR_RANK, modifiers.last().second, CONSTRUCTOR_MESSAGE)
+
+ // 4. functions
+ private const val FUNCTION = "fun"
+ private const val FUNCTION_RANK = 4
+ private const val FUNCTION_MESSAGE = "Functions should be positioned earlier than enums, interfaces and classes"
+ private val FUNCTION_REGEX_LIST = makeRegexList(FUNCTION)
+ private val FUNCTION_PARAMS = StaticParams(FUNCTION_REGEX_LIST, FUNCTION_RANK, modifiers.last().second, FUNCTION_MESSAGE)
+
+ // 5. enums
+ private const val ENUM = "enum"
+ private const val ENUM_RANK = 5
+ private const val ENUM_MESSAGE = "Enums should be positioned earlier than interfaces and classes"
+ private val ENUM_REGEX_LIST = makeRegexList(ENUM)
+ private val ENUM_PARAMS = StaticParams(ENUM_REGEX_LIST, ENUM_RANK, modifiers.last().second, ENUM_MESSAGE)
+
+ // 6. interfaces
+ private const val INTERFACE = "interface"
+ private const val INTERFACE_RANK = 6
+ private const val INTERFACE_MESSAGE = "Interfaces should be positioned earlier than classes"
+ private val INTERFACE_REGEX_LIST = makeRegexList(INTERFACE)
+ private val INTERFACE_PARAMS = StaticParams(INTERFACE_REGEX_LIST, INTERFACE_RANK, modifiers.last().second, INTERFACE_MESSAGE)
+
+ // 7. classes
+ private const val CLASS = "class"
+ private const val CLASS_RANK = 7
+ private val CLASS_REGEX_LIST = makeRegexList(CLASS)
+
+ private fun makeRegexList(value: String): List {
+ return listOf(
+ Regex("^${modifiers[0].first} $value"),
+ Regex("^${modifiers[1].first} $value"),
+ Regex("^${modifiers[2].first} $value"),
+ Regex("^${modifiers[3].first} $value"),
+ Regex("^${modifiers[4].first} $value"),
+ Regex("^${modifiers[5].first} $value"),
+ Regex("^${modifiers[6].first}${value}")
+ )
+ }
+
+ }
+
+ /**
+ * Sorting declarations by file's lines
+ * node.uastDeclarations gives elements in wrong order
+ * https://github.com/JetBrains/intellij-community/blob/master/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt
+ */
+
+ override fun getApplicableUastTypes(): List> = listOf(UClass::class.java)
+
+ override fun createUastHandler(context: JavaContext) = object: UElementHandler() {
+ override fun visitClass(node: UClass) {
+ val name = node.name ?: return
+ val lines = node.text.lines().toMutableList().apply {
+ removeFirst()
+ removeLast()
+ removeIf { it == "" }
+ }
+ val sortedDeclarationList = getSortedDeclarationList(lines, node.uastDeclarations)
+
+ if (name != COMPANION_NAME) {
+ var currentRank = Pair(0, 0)
+ sortedDeclarationList.forEach { declaration ->
+ val text = declaration.text ?: return
+ val currentParams = CurrentParams(context, text, node, declaration)
+
+ /** 1) It cannot find companion object*/
+ currentRank = checkOrder(currentParams, COMPANION_OBJECT_PARAMS, currentRank)
+
+ /** 2) Variables */
+ currentRank = checkOrder(currentParams, VAL_PARAMS, currentRank)
+ currentRank = checkOrder(currentParams, VAR_PARAMS, currentRank)
+
+ /** 3) Constructors */
+ currentRank = checkOrder(currentParams, CONSTRUCTOR_PARAMS, currentRank)
+
+ /** 4 Functions */
+ currentRank = checkOrder(currentParams, FUNCTION_PARAMS, currentRank)
+
+ /** 5 Enums */
+ currentRank = checkOrder(currentParams, ENUM_PARAMS, currentRank)
+
+ /** 6) Interfaces */
+ currentRank = checkOrder(currentParams, INTERFACE_PARAMS, currentRank)
+
+ /** 7) Classes */
+ val classRegex = CLASS_REGEX_LIST.firstOrNull { text.contains(it) }
+ if (classRegex != null) {
+ currentRank = Pair(CLASS_RANK, modifiers.last().second)
+ }
+ }
+ }
+ }
+ }
+
+ private fun getSortedDeclarationList(
+ lines: List,
+ listUDeclaration: List,
+ ): List {
+ val list = mutableListOf()
+ lines.forEach { line ->
+ listUDeclaration.forEach { declaration ->
+ val text = declaration.text
+ if (text.substring(0, min(text.length, line.length)).trim() == line.trim()) {
+ list.add(declaration)
+ }
+ }
+ }
+ return list
+ }
+
+ private fun checkOrder(currentParams: CurrentParams, staticParams: StaticParams, currentRank: Pair): Pair {
+ val isVariable = staticParams.regexList.firstOrNull { currentParams.text.contains(it) }
+ if (isVariable != null) {
+ staticParams.modifierRank = modifiers.first { currentParams.text.contains(it.first) }.second
+ if (currentRank.first <= staticParams.rank && currentRank.second <= staticParams.modifierRank) {
+ return Pair(staticParams.rank, staticParams.modifierRank)
+ } else if (currentRank.second > staticParams.modifierRank) {
+ makeContextReport(currentParams.context, currentParams.node, currentParams.declaration, MODIFIERS_RANK_MESSAGE)
+ } else {
+ makeContextReport(currentParams.context, currentParams.node, currentParams.declaration, staticParams.message)
+ }
+ }
+ return currentRank
+ }
+
+ private fun makeContextReport(context: JavaContext, node: UClass, declaration: UDeclaration, message: String) {
+ context.report(
+ ISSUE,
+ node,
+ context.getNameLocation(declaration),
+ "$message. ${ISSUE.getExplanation(TextFormat.TEXT)}"
+ )
+ }
+
+ private class StaticParams(
+ val regexList: List,
+ val rank: Int,
+ var modifierRank: Int,
+ val message: String
+ )
+
+ private class CurrentParams(
+ val context: JavaContext,
+ val text: String,
+ val node: UClass,
+ val declaration: UDeclaration
+ )
+}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_class_interface/ComponentPositionDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_class_interface/ComponentPositionDetector.kt
deleted file mode 100644
index 442b5e8..0000000
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_class_interface/ComponentPositionDetector.kt
+++ /dev/null
@@ -1,208 +0,0 @@
-package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.file_class_interface
-
-import com.android.tools.lint.client.api.UElementHandler
-import com.android.tools.lint.detector.api.*
-import org.jetbrains.uast.*
-import java.lang.Integer.min
-
-class ComponentPositionDetector : Detector(), Detector.UastScanner {
- companion object {
- /** Issue describing the problem and pointing to the detector implementation */
- @JvmField
- val ISSUE: Issue = Issue.create(
- id = "OMEGA_USE_COMPONENTS_IN_CORRECT_ORDER",
- briefDescription = "The line size does not match the coding convention",
- explanation = """
- Order warning.
- http://wiki.omega-r.club/dev-android-code#rec228155171
- """,
- category = Category.CORRECTNESS,
- priority = 7,
- severity = Severity.WARNING,
- implementation = Implementation(
- ComponentPositionDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
- )
-
- private const val COMPANION_NAME = "Companion"
-
- // 1. companion object
- private const val COMPANION_OBJECT = "companion object"
- private const val COMPANION_OBJECT_RANK = 1
- private const val COMPANION_OBJECT_MESSAGE = "companion object should be the first"
- private val COMPANION_OBJECT_REGEX_LIST = makeRegexList(COMPANION_OBJECT)
- private val COMPANION_OBJECT_PARAMS =
- StaticParams(COMPANION_OBJECT_REGEX_LIST, COMPANION_OBJECT_RANK, COMPANION_OBJECT_MESSAGE)
-
- // 2. val + var variables
- private const val VAL = "val"
- private const val VAR = "var"
- private const val VARIABLES_RANK = 2
- private const val VARIABLES_MESSAGE =
- "Variables should be earlier than constructors, functions, enums, interfaces and classes"
- private val VAL_REGEX_LIST = makeRegexList(VAL)
- private val VAR_REGEX_LIST = makeRegexList(VAR)
- private val VAL_PARAMS = StaticParams(VAL_REGEX_LIST, VARIABLES_RANK, VARIABLES_MESSAGE)
- private val VAR_PARAMS = StaticParams(VAR_REGEX_LIST, VARIABLES_RANK, VARIABLES_MESSAGE)
-
- // 3. constructors and inits
- private const val CONSTRUCTOR = "constructor"
- private const val CONSTRUCTOR_RANK = 3
- private const val CONSTRUCTOR_MESSAGE = "Constructor should be earlier than functions, enums, interfaces and classes"
- private val CONSTRUCTOR_REGEX_LIST = makeRegexList(CONSTRUCTOR)
- private val CONSTRUCTOR_PARAMS = StaticParams(CONSTRUCTOR_REGEX_LIST, CONSTRUCTOR_RANK, CONSTRUCTOR_MESSAGE)
-
- // 4. functions
- private const val FUNCTION = "fun"
- private const val FUNCTION_RANK = 4
- private const val FUNCTION_MESSAGE = "Functions should be earlier than enums, interfaces and classes"
- private val FUNCTION_REGEX_LIST = makeRegexList(FUNCTION)
- private val FUNCTION_PARAMS = StaticParams(FUNCTION_REGEX_LIST, FUNCTION_RANK, FUNCTION_MESSAGE)
-
- // 5. enums
- private const val ENUM = "enum"
- private const val ENUM_RANK = 5
- private const val ENUM_MESSAGE = "Enum should be earlier than interfaces and classes"
- private val ENUM_REGEX_LIST = makeRegexList(ENUM)
- private val ENUM_PARAMS = StaticParams(ENUM_REGEX_LIST, ENUM_RANK, ENUM_MESSAGE)
-
- // 6. interfaces
- private const val INTERFACE = "interface"
- private const val INTERFACE_RANK = 6
- private const val INTERFACE_MESSAGE = "Enum should be earlier than classes"
- private val INTERFACE_REGEX_LIST = makeRegexList(INTERFACE)
- private val INTERFACE_PARAMS = StaticParams(INTERFACE_REGEX_LIST, INTERFACE_RANK, INTERFACE_MESSAGE)
-
- // 7. classes
- private const val CLASS = "class"
- private const val CLASS_RANK = 7
- private val CLASS_REGEX_LIST = makeRegexList(CLASS)
- private val CLASS_PARAMS = StaticParams(CLASS_REGEX_LIST, CLASS_RANK, "")
-
- private fun makeRegexList(value: String): List {
- return listOf(
- Regex("^abstract $value"),
- Regex("^override $value"),
- Regex("^public $value"),
- Regex("^internal $value"),
- Regex("^protected $value"),
- Regex("^private $value"),
- Regex("^${value}")
- )
- }
-
- }
-
- /**
- * Sorting declarations by file's lines
- * node.uastDeclarations give elements in wrong order
- * https://github.com/JetBrains/intellij-community/blob/master/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt
- */
-
- override fun getApplicableUastTypes(): List> = listOf(UClass::class.java)
-
- override fun createUastHandler(context: JavaContext): UElementHandler {
- return object : UElementHandler() {
- override fun visitClass(node: UClass) {
- val name = node.name ?: return
- val lines = node.parent?.text?.lines() ?: return
- val sortedDeclarationList = getSortedDeclarationList(lines, node.uastDeclarations, name)
-
- if (name != COMPANION_NAME) {
- var currentRank = 0
- sortedDeclarationList.forEach { declaration ->
- val text = declaration.text ?: return
- val currentParams = CurrentParams(context, text, currentRank, node, declaration)
-
- /** 1) it's can find companion object*/
- currentRank = checkOrder(currentParams, COMPANION_OBJECT_PARAMS)
-
- /** 2) Variables*/
- currentRank = checkOrder(currentParams, VAL_PARAMS)
- currentRank = checkOrder(currentParams, VAR_PARAMS)
-
- /** 3) Constructor */
- currentRank = checkOrder(currentParams, CONSTRUCTOR_PARAMS)
-
- /** 4 Function */
- currentRank = checkOrder(currentParams, FUNCTION_PARAMS)
-
- /** 5 Enum */
- currentRank = checkOrder(currentParams, ENUM_PARAMS)
-
- /** 6) Interface */
- currentRank = checkOrder(currentParams, INTERFACE_PARAMS)
-
- /** 7) Class */
- val classRegex = CLASS_REGEX_LIST.firstOrNull { text.contains(it) }
- if (classRegex != null) {
- currentRank = CLASS_RANK
- }
- }
- }
- }
- }
- }
-
- private fun getSortedDeclarationList(
- lines: List,
- listUDeclaration: List,
- name: String
- ): List {
- val list = mutableListOf()
- lines.forEach { line ->
- if (line != "") {
- listUDeclaration.forEach { declaration ->
- val dt = declaration.text
- if (dt != null) {
- if ((dt.substring(0, min(dt.length, line.length)).trim() == line.trim()) &&
- !(line.contains("class $name"))
- ) {
- list.add(declaration)
- }
- }
- }
- }
- }
-
- return list.distinctBy { it.text }
- }
-
- private fun checkOrder(currentParams: CurrentParams, staticParams: StaticParams): Int {
- val isVariable = staticParams.regexList.firstOrNull { currentParams.text.contains(it) }
- if (isVariable != null) {
- if (currentParams.currentRank <= staticParams.rank) {
- return staticParams.rank
- } else {
- makeContextReport(currentParams.context, currentParams.node, currentParams.declaration, staticParams.message)
- }
- }
- return currentParams.currentRank
- }
-
- private fun makeContextReport(context: JavaContext, node: UClass, declaration: UDeclaration, message: String) {
- context.report(
- ISSUE,
- node,
- context.getNameLocation(declaration),
- "$message ${ISSUE.getExplanation(TextFormat.TEXT)}"
- )
- }
-
- private class StaticParams(
- val regexList: List,
- val rank: Int,
- val message: String
- )
-
- private class CurrentParams(
- val context: JavaContext,
- val text: String,
- val currentRank: Int,
- val node: UClass,
- val declaration: UDeclaration
- )
-}
-
-
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_package/PackageComponentDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_package/PackageComponentDetector.kt
new file mode 100644
index 0000000..8302555
--- /dev/null
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/file_package/PackageComponentDetector.kt
@@ -0,0 +1,79 @@
+package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.file_package
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.*
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiField
+import org.jetbrains.uast.*
+
+@Suppress("UnstableApiUsage")
+class PackageComponentDetector : Detector(), Detector.UastScanner {
+
+ companion object {
+ @JvmField
+ val ISSUE = Issue.create(
+ id = "OMEGA_USE_FILE_COMPONENTS_IN_CORRECT_ORDER",
+ briefDescription = "Place file components in correct order",
+ explanation = """
+ Order warning.
+ http://wiki.omega-r.club/dev-android-code#rec228155171
+ """,
+ category = Category.CORRECTNESS,
+ priority = 7,
+ severity = Severity.WARNING,
+ implementation = Implementation(
+ PackageComponentDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+
+ private const val CLASS_LABEL = "class"
+ private const val CONSTANT_MESSAGE = "Constants should be positioned before classes, interfaces or any public elements"
+ private const val ELEMENTS_MESSAGE = "All public elements should be positioned after classes and interfaces"
+ }
+
+ override fun getApplicableUastTypes(): List> = listOf(UFile::class.java)
+
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitFile(node: UFile) {
+ val publicElements = node.classes.drop(1)
+ val classes = node.classes.filter { !it.isInterface }.filter { !it.isEnum }
+ val fields = node.classes[0].fields
+
+ fields.forEach fieldScope@ { uField ->
+ publicElements.forEach { uElement ->
+ if (uField.getStartPosition() > uElement.getStartPosition()) {
+ makeContextReport(context, node, uField, CONSTANT_MESSAGE)
+ return@fieldScope
+ }
+ }
+ }
+
+ publicElements.forEach elementsScope@ { uElement ->
+ classes.drop(1).forEach classesScope@ { uClass ->
+ if (!uClass.text.startsWith(CLASS_LABEL) && !uElement.text.startsWith(CLASS_LABEL)) {
+ return@classesScope
+ }
+ if (!uElement.isInterface && !uElement.text.startsWith(CLASS_LABEL) && uClass.getStartPosition() > uElement.getStartPosition()) {
+ makeContextReport(context, node, uElement, ELEMENTS_MESSAGE)
+ return@elementsScope
+ }
+ }
+ }
+ }
+
+ private fun PsiField.getStartPosition() = context.getNameLocation(this).start?.line ?: 0
+
+ private fun PsiClass.getStartPosition() = context.getNameLocation(this).start?.line ?: 0
+
+ }
+
+ private fun makeContextReport(context: JavaContext, node: UFile, declaration: UElement, message: String) {
+ context.report(
+ ISSUE,
+ node,
+ context.getLocation(declaration),
+ "$message ${ISSUE.getExplanation(TextFormat.TEXT)}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/PositionArgumentDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/ArgumentPositionDetector.kt
similarity index 94%
rename from checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/PositionArgumentDetector.kt
rename to checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/ArgumentPositionDetector.kt
index 23cefc5..14a0e55 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/PositionArgumentDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/order/function_params/ArgumentPositionDetector.kt
@@ -2,13 +2,12 @@ package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.order.funct
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.*
-import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.UParameter
@Suppress("UnstableApiUsage")
-class PositionArgumentDetector : Detector(), Detector.UastScanner {
+class ArgumentPositionDetector : Detector(), Detector.UastScanner {
companion object {
/** Issue describing the problem and pointing to the detector implementation */
@JvmField
@@ -23,7 +22,7 @@ class PositionArgumentDetector : Detector(), Detector.UastScanner {
priority = 6,
severity = Severity.WARNING,
implementation = Implementation(
- PositionArgumentDetector::class.java,
+ ArgumentPositionDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/class_methods_count/MaxMethodCountDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/class_methods_count/MaxMethodCountDetector.kt
index f717906..36fd3b6 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/class_methods_count/MaxMethodCountDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/class_methods_count/MaxMethodCountDetector.kt
@@ -2,10 +2,9 @@ package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.restriction
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.*
+import org.jetbrains.uast.*
-import org.jetbrains.uast.UClass
-import org.jetbrains.uast.UElement
-
+@Suppress("UnstableApiUsage")
class MaxMethodCountDetector : Detector(), Detector.UastScanner {
companion object {
/** Issue describing the problem and pointing to the detector implementation */
@@ -26,21 +25,41 @@ class MaxMethodCountDetector : Detector(), Detector.UastScanner {
)
)
+ private const val DATA_CLASS_FUNCTION_VALUE = "public final fun copy"
+ private const val KEYWORD_VAR = "var"
+ private const val KEYWORD_VAL = "val"
+ private const val METHOD_GET = "get"
+ private const val METHOD_SET = "set"
private const val MAX_METHOD_COUNT = 30
}
override fun getApplicableUastTypes(): List> = listOf(UClass::class.java)
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitClass(node: UClass) {
+ val resultMethods = mutableListOf()
+ val text = node.uastDeclarations.distinctBy { it.text }
+ var propertyCount = 0
- override fun createUastHandler(context: JavaContext): UElementHandler {
- return object : UElementHandler() {
- override fun visitClass(node: UClass) {
- val methods = node.methods
- if (methods.size > MAX_METHOD_COUNT) {
- context.report(ISSUE, node, context.getNameLocation(node), ISSUE.getExplanation(TextFormat.TEXT))
+ text.forEachIndexed { _, uDeclaration ->
+ if (uDeclaration.text.contains(KEYWORD_VAL) && uDeclaration.text.contains(METHOD_GET)) {
+ propertyCount++
+ } else if (uDeclaration.text.contains(KEYWORD_VAR)) {
+ if (uDeclaration.text.contains(METHOD_GET)) propertyCount++
+ if (uDeclaration.text.contains(METHOD_SET)) propertyCount++
+ }
+ }
+ node.methods.forEach {
+ if (it.asRenderString().contains(DATA_CLASS_FUNCTION_VALUE)) {
+ return@visitClass
}
+ if (!it.isVarArgs && !it.isConstructor) {
+ resultMethods.add(it)
+ }
+ }
+ if (resultMethods.size - propertyCount > MAX_METHOD_COUNT) {
+ context.report(ISSUE, node, context.getNameLocation(node), ISSUE.getExplanation(TextFormat.TEXT))
}
}
}
-}
-
+}
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/emptiness/EmptyBodyFunctionDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/emptiness/EmptyBodyFunctionDetector.kt
index 8bea675..31924b3 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/emptiness/EmptyBodyFunctionDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/emptiness/EmptyBodyFunctionDetector.kt
@@ -45,7 +45,7 @@ class EmptyBodyFunctionDetector : Detector(), Detector.UastScanner {
val text = node.text ?: return
if (text.contains(EMPTY_BODY_REGEX) && (body.asRenderString().matches(EMPTY_BODY_REGEX))) {
- context.report(ISSUE, node, context.getLocation(body), ISSUE.getExplanation(TextFormat.TEXT))
+ context.report(ISSUE, node, context.getLocation(body), text, createFix(text))
}
}
@@ -53,10 +53,26 @@ class EmptyBodyFunctionDetector : Detector(), Detector.UastScanner {
val renderText = node.asRenderString()
if (renderText.contains(EMPTY_BRANCH_REGEX)) {
- context.report(ISSUE, node, context.getLocation(node), ISSUE.getExplanation(TextFormat.TEXT))
+ context.report(
+ ISSUE,
+ node,
+ context.getLocation(node),
+ ISSUE.getExplanation(TextFormat.TEXT),
+ createFix(renderText)
+ )
}
}
}
}
+
+ private fun createFix(body: String): LintFix? {
+ val indexOfScope = body.indexOf("{")
+// val newBody = "${body.removeRange(indexOfScope, body.length)}\n//nothing\n}}"
+ return LintFix.create()
+ .replace()
+ .text(body)
+ .with("newBody")
+ .build()
+ }
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/params_count/MaxFunctionsArgumentsDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/params_count/MaxFunctionsArgumentsDetector.kt
index 92660d8..8b32a5d 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/params_count/MaxFunctionsArgumentsDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/restrictions/params_count/MaxFunctionsArgumentsDetector.kt
@@ -25,6 +25,8 @@ class MaxFunctionsArgumentsDetector : Detector(), Detector.UastScanner {
)
)
+ // lint can't understand data class constructors because it understand them as fun with name "copy"
+ private const val DATA_CLASS_FUNCTION_VALUE = "public final fun copy"
private const val MAX_COUNT_OF_ARGUMENTS = 5
}
@@ -33,7 +35,7 @@ class MaxFunctionsArgumentsDetector : Detector(), Detector.UastScanner {
override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitMethod(node: UMethod) {
- if (node.isConstructor) {
+ if (node.isConstructor || node.asRenderString().contains(DATA_CLASS_FUNCTION_VALUE)) {
return
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/control_instructions/SimplificationsControlInstructionsDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/control_instructions/SimplificationsControlInstructionsDetector.kt
index 5492323..599390b 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/control_instructions/SimplificationsControlInstructionsDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/control_instructions/SimplificationsControlInstructionsDetector.kt
@@ -26,10 +26,18 @@ class SimplificationsControlInstructionsDetector : Detector(), Detector.UastScan
)
private val EMPTY_BRANCH_REGEX = Regex("""\{\s*\}""")
+ private val END_SPACE_REGEX = Regex("""\s*$""")
+ private val MORE_THAN_ONE_SPACE_REGEX = Regex("""\s+""")
private const val ELSE_LABEL = "-> {"
private const val ELSE_TEXT = "else -> {"
private const val DELTA = 2
+ private const val OPEN_SCOPE_SYMBOL = "{"
+ private const val CLOSE_SCOPE_SYMBOL = "}"
+ private const val EQUALS_SYMBOL = "="
+ private const val NEW_LINE_SYMBOL = "\n"
+ private const val SPACE_SYMBOL = " "
+
}
override fun getApplicableUastTypes(): List> = listOf(USwitchClauseExpression::class.java)
@@ -65,9 +73,27 @@ class SimplificationsControlInstructionsDetector : Detector(), Detector.UastScan
private fun exceedMaxLineLength(text: String): Boolean {
val lines = text.lines()
- if(lines.size > 1) {
+ if (lines.size > 1) {
return lines[0].length + lines[1].trim().length - DELTA < MAX_LENGTH
}
return false
}
+
+ private fun createFix(text: String): LintFix? {
+ return fix()
+ .replace()
+ .text(text)
+ .with(getSimpleString(text))
+ .build()
+ }
+
+ private fun getSimpleString(text: String): String {
+ return text
+ .replace(OPEN_SCOPE_SYMBOL, EQUALS_SYMBOL)
+ .replace(NEW_LINE_SYMBOL, "")
+ .replace(CLOSE_SCOPE_SYMBOL, "")
+ .replace(END_SPACE_REGEX, "")
+ .replace(MORE_THAN_ONE_SPACE_REGEX, SPACE_SYMBOL)
+ }
+
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/function/SimplificationsFunctionDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/function/SimplificationsFunctionDetector.kt
index d6c75d1..4e3879e 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/function/SimplificationsFunctionDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/simplifications/function/SimplificationsFunctionDetector.kt
@@ -2,6 +2,7 @@ package com.omegar.lint.checks.detector.code_guidelines.kotlin_style.simplificat
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.*
+import com.omegar.lint.checks.detector.code_guidelines.kotlin_style.restrictions.line_length.MaxLineLengthDetector.Companion.MAX_LENGTH
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMethod
@@ -10,24 +11,33 @@ class SimplificationsFunctionDetector : Detector(), Detector.UastScanner {
/** Issue describing the problem and pointing to the detector implementation */
@JvmField
val ISSUE: Issue = Issue.create(
- "OMEGA_CAN_USE_EXPRESSION_FUNCTION",
- "When a function contains only one expression, it can be represented as an \"expression function\".",
- """
+ "OMEGA_CAN_USE_EXPRESSION_FUNCTION",
+ "When a function contains only one expression, it can be represented as an \"expression function\".",
+ """
You can change it to "expression function"
http://wiki.omega-r.club/dev-android-code#rec228389255
""",
- Category.CORRECTNESS,
- 7,
- Severity.INFORMATIONAL,
- Implementation(
- SimplificationsFunctionDetector::class.java,
- Scope.JAVA_FILE_SCOPE
- )
- )
+ Category.CORRECTNESS,
+ 7,
+ Severity.INFORMATIONAL,
+ Implementation(
+ SimplificationsFunctionDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
private val ONE_EXPRESSION_REGEX = Regex("""\{\s*return\s*.*""")
private val RETURN_REGEX = Regex("""\s*return""")
private const val MAX_LINE_COUNT_IN_EXPRESSION_FUNCTION = 3
+
+ private const val OPEN_SCOPE_SYMBOL = "{"
+ private const val CLOSE_SCOPE_SYMBOL = "}"
+ private const val EQUALS_SYMBOL = "="
+ private const val NEW_LINE_SYMBOL = "\n"
+ private const val SPACE_SYMBOL = " "
+
+ private val END_SPACE_REGEX = Regex("""\s*$""")
+ private val MORE_THAN_ONE_SPACE_REGEX = Regex("""\s+""")
}
override fun getApplicableUastTypes(): List> = listOf(UMethod::class.java)
@@ -37,32 +47,41 @@ class SimplificationsFunctionDetector : Detector(), Detector.UastScanner {
override fun visitMethod(node: UMethod) {
val text = node.text ?: return
val linesCount = text.count { it == '\n' } + 1
- if (linesCount <= MAX_LINE_COUNT_IN_EXPRESSION_FUNCTION && text.contains(ONE_EXPRESSION_REGEX)) {
+ if (linesCount <= MAX_LINE_COUNT_IN_EXPRESSION_FUNCTION
+ && text.contains(ONE_EXPRESSION_REGEX)
+ ) {
+ val newText = getSimpleFunctionString(text)
+
+ if (newText.length > MAX_LENGTH) return
+
context.report(
- ISSUE,
- node,
- context.getLocation(node),
- ISSUE.getExplanation(TextFormat.TEXT),
- createFix(text)
- )
+ ISSUE,
+ node,
+ context.getLocation(node),
+ ISSUE.getExplanation(TextFormat.TEXT),
+ createFix(text, newText)
+ )
}
}
}
}
- private fun createFix(text: String): LintFix {
- val newText = text
- .replace("{", "=")
- .replace(RETURN_REGEX, "")
- .replace("\n", "")
- .replace("}", "")
- .replace(Regex("""\s*$"""), "")
-
+ private fun createFix(text: String, newText: String): LintFix? {
return fix()
.replace()
.text(text)
.with(newText)
.build()
+ }
+ private fun getSimpleFunctionString(text: String): String {
+ return text
+ .replace(OPEN_SCOPE_SYMBOL, EQUALS_SYMBOL)
+ .replace(RETURN_REGEX, "")
+ .replace(NEW_LINE_SYMBOL, "")
+ .replace(CLOSE_SCOPE_SYMBOL, "")
+ .replace(END_SPACE_REGEX, "")
+ .replace(MORE_THAN_ONE_SPACE_REGEX, SPACE_SYMBOL)
}
+
}
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/use_spaces/around_operands/SpaceMethodDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/use_spaces/around_operands/SpaceMethodDetector.kt
index c1b49bd..1e1dca9 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/use_spaces/around_operands/SpaceMethodDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/kotlin_style/use_spaces/around_operands/SpaceMethodDetector.kt
@@ -5,7 +5,7 @@ import com.android.tools.lint.detector.api.*
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
-class SpaceMethodDetector : Detector(), Detector.UastScanner {
+open class SpaceMethodDetector : Detector(), Detector.UastScanner {
companion object {
/** Issue describing the problem and pointing to the detector implementation */
@JvmField
@@ -30,17 +30,26 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
Regex("""([a-z]|[A-Z]|"|'|\)|=|>|\?)\s\{$""")
private val RIGHT_FUNCTIONS_OPEN_SCOPE_REGEX = Regex("""([a-z]|[A-Z]|\d)\s*\(""")
- private val POINT_BEGIN_REGEX = Regex("""^\s*\.""")
- private val QUESTION_MARK_POINT_BEGIN_REGEX = Regex("""^\s*\?\.""")
- private const val DELETE_SPACES_MESSAGE = "Remove extra spaces."
private const val FUNCTION_VALUE = "fun"
private const val OPEN_SCOPE_VALUE = "("
private const val QUOTE_VALUE = "\""
+ private val OPEN_BRACE_REGEX = Regex("""\s*\{""")
+ private val OPEN_SCOPE_REGEX = Regex("""\s*\(""")
+
+ private val KEY_SYMBOLS_MAP = mapOf(
+ "." to Regex("""(\s+\.\s*|\s*\.\s+)"""),
+ "::" to Regex("""(\s+::\s*|\s*::\s+)"""),
+ "?." to Regex("""(\s+\?\.\s*|\s*\?\.\s+)""")
+ )
+
+ private val KEY_BEGIN_SYMBOLS_MAP = mapOf(
+ "." to Regex("""^\s*\."""),
+ "::" to Regex("""^\s*::"""),
+ "?." to Regex("""^\s*\?\.""")
+ )
- private val CHAR_ARRAY = arrayOf(".", "::", "?.")
- private val REGEXPS = CHAR_ARRAY.map { it to Regex("""\s*$it\s""") }.toMap()
private val COMMENTS_REGEX = Regex("""([//]|[/\*])""")
}
@@ -55,51 +64,35 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
var beginPosition = 0
lines.forEach { line ->
val length = line.length
- REGEXPS.forEach { pair ->
+
+ KEY_SYMBOLS_MAP.forEach { pair ->
if (line.contains(pair.value) && !line.contains(COMMENTS_REGEX)) {
val beforeIndex = line.indexOf(" ${pair.key}")
val afterIndex = line.indexOf("${pair.key} ")
-
- when {
- beforeIndex > 0
- && afterIndex <= 0
- && !line.contains(POINT_BEGIN_REGEX)
- && !line.contains(QUESTION_MARK_POINT_BEGIN_REGEX) -> {
- makeContextReport(
- Params(
- context,
- node,
- beginPosition + beforeIndex,
- pair.key.length + 1,
- line,
- beforeIndex
- )
- )
- }
-
- afterIndex > 0 && beforeIndex <= 0 -> {
- makeContextReport(
- Params(
- context,
- node,
- beginPosition + afterIndex,
- pair.key.length + 1,
- line,
+ val match = pair.value.find(line)
+
+ if (match != null && (beforeIndex > 0 || afterIndex > 0)) {
+ var index = line.indexOf(match.value)
+ if (index >= 0 && !(pair.key == "." && line[line.indexOf(pair.key) - 1] == '?')) {
+ val selectedText = if (checkIsSymbolFirst(line, pair.key)) {
+ index = if (beforeIndex > 0) {
+ beforeIndex - 1
+ } else {
afterIndex
- )
- )
- }
-
- afterIndex > 0 && beforeIndex > 0 -> {
+ }
+ match.value.substring(match.value.indexOf(pair.key) - 1, match.value.length - 1)
+ } else {
+ match.value
+ }
makeContextReport(
Params(
context,
node,
- beginPosition + beforeIndex,
- pair.key.length + 2,
+ beginPosition + index,
+ selectedText.length,
line,
- beforeIndex
+ index
)
)
}
@@ -116,6 +109,11 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
}
}
+ private fun checkIsSymbolFirst(line: String, key: String): Boolean {
+ val beginSymbolRegex = KEY_BEGIN_SYMBOLS_MAP[key] ?: return false
+ return line.contains(beginSymbolRegex)
+ }
+
private fun checkSpaceForScopes(
context: JavaContext,
line: String,
@@ -125,9 +123,13 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
val length = line.length
if (line.contains(RIGHT_FUNCTIONS_OPEN_SCOPE_REGEX) && line.contains(FUNCTION_VALUE)) {
val functionLine = line.substring(0, line.indexOf(OPEN_SCOPE_VALUE) + 1)
- val index = functionLine.indexOf(" (")
- if (index > 0) {
- makeContextReport(Params(context, node, beginPosition + index, 2, line, index))
+ val spaceIndex = functionLine.indexOf(" $OPEN_SCOPE_VALUE")
+ if (spaceIndex > 0) {
+ val match = OPEN_SCOPE_REGEX.find(line)
+ if (match != null) {
+ val index = spaceIndex - match.value.length + 2
+ makeContextReport(Params(context, node, beginPosition + index, match.value.length, line, index))
+ }
}
}
@@ -135,22 +137,17 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
&& line.contains(END_FUNCTION_DECLARATION_REGEX)
&& !line.matches(END_FUNCTION_DECLARATION_REGEX)
) {
- if (line[line.indexOf("{") - 1].toString() != OPEN_SCOPE_VALUE)
- makeContextReport(
- Params(
- context,
- node,
- beginPosition + length - 1,
- 1,
- line,
- length - 1
- )
- )
+ val match = OPEN_BRACE_REGEX.find(line)
+ if (match != null) {
+ val index = length - match.value.length
+ makeContextReport(Params(context, node, beginPosition + index, match.value.length, line, index, " "))
+ }
}
}
private fun makeContextReport(params: Params) {
if (!isInQuote(params.line, params.index)) {
+
params.context.report(
ISSUE,
params.node,
@@ -159,7 +156,8 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
params.beginPosition,
params.length
),
- ISSUE.getExplanation(TextFormat.TEXT)
+ ISSUE.getExplanation(TextFormat.TEXT),
+ createLintFix(params.line, params.index, params.length, params.toReplaceString)
)
}
}
@@ -177,15 +175,26 @@ class SpaceMethodDetector : Detector(), Detector.UastScanner {
return inside
}
}
+
return false
}
+ private fun createLintFix(line: String, index: Int, length: Int, toReplaceString: String): LintFix {
+ val substringWithSpace = line.substring(index, index + length)
+ return LintFix.create()
+ .replace()
+ .text(substringWithSpace)
+ .with(substringWithSpace.trim() + toReplaceString)
+ .build()
+ }
+
class Params(
val context: JavaContext,
val node: UClass,
val beginPosition: Int,
val length: Int,
val line: String,
- val index: Int
+ val index: Int,
+ val toReplaceString: String = ""
)
}
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/identifier/NameIdentifierXmlDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/identifier/NameIdentifierXmlDetector.kt
index 6c2d08e..9eff89a 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/identifier/NameIdentifierXmlDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/identifier/NameIdentifierXmlDetector.kt
@@ -3,13 +3,15 @@ package com.omegar.lint.checks.detector.code_guidelines.xml_style.name_resource.
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.*
import org.w3c.dom.Attr
+import java.util.Locale
+@Suppress("UnstableApiUsage")
class NameIdentifierXmlDetector : ResourceXmlDetector() {
companion object {
val ISSUE = Issue.create(
id = "OMEGA_NAME_VARIABLES_CORRECTLY",
- briefDescription = "Detects wrongs name of view's identifier",
+ briefDescription = "Detects wrong name of view's identifier",
explanation = """
Name of identifier should begin with prefix, which depends of view name.
http://wiki.omega-r.club/dev-android-code#rec228390320
@@ -23,7 +25,8 @@ class NameIdentifierXmlDetector : ResourceXmlDetector() {
)
)
- const val REPORT_MESSAGE = "Wrong prefix of identifier name. Should begin with: "
+ private val CAMEL_REGEX = Regex("(?<=[a-zA-Z])[A-Z]")
+ private const val REPORT_MESSAGE = "Wrong prefix of identifier name. Should begin with: "
//elements
private const val TEXT_VIEW_ELEMENT = "TextView"
@@ -44,6 +47,7 @@ class NameIdentifierXmlDetector : ResourceXmlDetector() {
private const val LAYOUT_PREFIX = "@+id/layout"
private const val FLOATING_ACTION_BUTTON_PREFIX = "@+id/fab"
private const val IMAGE_BUTTON_PREFIX = "@+id/button"
+ private const val IDENTIFIER_PREFIX = "@+id/"
}
@@ -56,67 +60,74 @@ class NameIdentifierXmlDetector : ResourceXmlDetector() {
val attributeValue = attribute.nodeValue ?: return
if (attribute.name == "android:id") {
when (attribute.ownerElement.tagName) {
- TEXT_VIEW_ELEMENT -> {
- if (!attributeValue.contains(TEXT_VIEW_PREFIX)) {
- makeContextReport(context, attribute, TEXT_VIEW_PREFIX)
- }
- }
-
- IMAGE_VIEW_ELEMENT -> {
- if (!attributeValue.contains(IMAGE_VIEW_PREFIX)) {
- makeContextReport(context, attribute, IMAGE_VIEW_PREFIX)
- }
- }
-
- BUTTON_ELEMENT -> {
- if (!attributeValue.contains(BUTTON_PREFIX)) {
- makeContextReport(context, attribute, BUTTON_PREFIX)
- }
- }
-
- EDIT_TEXT_ELEMENT -> {
- if (!attributeValue.contains(EDIT_TEXT_PREFIX)) {
- makeContextReport(context, attribute, EDIT_TEXT_PREFIX)
- }
- }
-
+ TEXT_VIEW_ELEMENT -> checkPrefix(context, attributeValue, attribute, TEXT_VIEW_PREFIX)
+ IMAGE_VIEW_ELEMENT -> checkPrefix(context, attributeValue, attribute, IMAGE_VIEW_PREFIX)
+ BUTTON_ELEMENT -> checkPrefix(context, attributeValue, attribute, BUTTON_PREFIX)
+ EDIT_TEXT_ELEMENT -> checkPrefix(context, attributeValue, attribute, EDIT_TEXT_PREFIX)
+ FLOATING_ACTION_BUTTON_ELEMENT -> checkPrefix(context, attributeValue, attribute, FLOATING_ACTION_BUTTON_PREFIX)
+ IMAGE_BUTTON_ELEMENT -> checkPrefix(context, attributeValue, attribute, IMAGE_BUTTON_PREFIX)
LAYOUT_ELEMENT, TABLE_LAYOUT_ELEMENT, LINEAR_LAYOUT_ELEMENT -> {
- if (!attributeValue.contains(LAYOUT_PREFIX)) {
- makeContextReport(context, attribute, LAYOUT_PREFIX)
- }
+ checkPrefix(context, attributeValue, attribute, LAYOUT_PREFIX)
}
-
- FLOATING_ACTION_BUTTON_ELEMENT -> {
- if (!attributeValue.contains(FLOATING_ACTION_BUTTON_PREFIX)) {
- makeContextReport(context, attribute, FLOATING_ACTION_BUTTON_PREFIX)
- }
+ else -> {
+ val tagName = IDENTIFIER_PREFIX + attribute.ownerElement.tagName.split(".").last().replace("View", "")
+ val prefix = tagName.convertCamelToSnakeCase()
+ checkPrefix(context, attributeValue, attribute, prefix)
}
+ }
+ }
+ }
- IMAGE_BUTTON_ELEMENT -> {
- if (!attributeValue.contains(IMAGE_BUTTON_PREFIX)) {
- makeContextReport(context, attribute, IMAGE_BUTTON_PREFIX)
- }
- }
+ // String extensions
+ private fun String.convertCamelToSnakeCase(): String {
+ return CAMEL_REGEX.replace(this) {
+ it.value
+ }.toLowerCase(Locale.ROOT)
+ }
+
+ private fun checkPrefix(context: XmlContext, attributeValue: String, attribute: Attr, prefix: String) {
+ if (!attributeValue.contains(prefix) && attributeValue.replace("_", "").contains(prefix)) {
+ makeContextReport(context, attribute, prefix) {
+ createFixForUnderscore(attributeValue, prefix)
+ }
+ }
+ else if (!attributeValue.contains(prefix)) {
+ makeContextReport(context, attribute, prefix) {
+ createFix(attributeValue, prefix)
}
}
}
- private fun makeContextReport(context: XmlContext, attribute: Attr, message: String) {
+ private fun makeContextReport(context: XmlContext, attribute: Attr, message: String, fix:() -> LintFix) {
context.report(
issue = ISSUE,
scope = attribute,
location = context.getValueLocation(attribute),
message = "$REPORT_MESSAGE $message\n${ISSUE.getExplanation(TextFormat.TEXT)}",
- quickfixData = createFix(attribute.nodeValue, message)
+ quickfixData = fix()
)
}
- private fun createFix(attributeValue: String, correctPrefix: String): LintFix {
- val oldText = attributeValue.replace("@+id/", "")
+ private fun createFixForUnderscore(attributeValue: String, prefix: String): LintFix {
+ var finalValue = ""
+ attributeValue.forEach { char ->
+ if (!finalValue.contains(prefix) && char != '_' || finalValue.contains(prefix)) {
+ finalValue += char
+ }
+ }
+ return fix()
+ .replace()
+ .text(attributeValue)
+ .with(finalValue)
+ .build()
+ }
+
+ private fun createFix(attributeValue: String, prefix: String): LintFix {
+ val attributeValueWithoutPrefix = attributeValue.replace(IDENTIFIER_PREFIX, "")
return fix()
.replace()
.text(attributeValue)
- .with("${correctPrefix}_$oldText")
+ .with("${prefix}_$attributeValueWithoutPrefix")
.build()
}
}
\ No newline at end of file
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/resource/NameResourceStringXmlDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/resource/NameResourceStringXmlDetector.kt
index 7e6dc09..45959fa 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/resource/NameResourceStringXmlDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/code_guidelines/xml_style/name_resource/resource/NameResourceStringXmlDetector.kt
@@ -5,6 +5,7 @@ import com.android.tools.lint.detector.api.*
import org.w3c.dom.Element
import org.w3c.dom.Node
+@Suppress("UnstableApiUsage")
class NameResourceStringXmlDetector : ResourceXmlDetector() {
companion object {
@@ -32,7 +33,9 @@ class NameResourceStringXmlDetector : ResourceXmlDetector() {
"label",
"button",
"action",
- "hint"
+ "hint",
+ "format",
+ "mask"
)
private const val ATTRIBUTE_NAME_VAL = "name" //Attribute
@@ -54,7 +57,7 @@ class NameResourceStringXmlDetector : ResourceXmlDetector() {
val stringText = element.getAttribute(ATTRIBUTE_NAME_VAL) ?: return
- if ((stringText == APP_NAME) || CORRECT_PREFIXES_LIST.firstOrNull() { stringText.contains(it) } != null) {
+ if ((stringText == APP_NAME) || CORRECT_PREFIXES_LIST.firstOrNull { stringText.contains(it) } != null) {
return
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/class/NameFileUpperCamelCaseDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/class/NameFileUpperCamelCaseDetector.kt
index 35edfa1..3c72e43 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/class/NameFileUpperCamelCaseDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/class/NameFileUpperCamelCaseDetector.kt
@@ -73,7 +73,7 @@ class NameFileUpperCamelCaseDetector : Detector(), Detector.UastScanner {
}
}
- return resultName
+ return "${charArray[0]}$resultName"
}
}
diff --git a/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/resource/layout/NameResourceLayoutDetector.kt b/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/resource/layout/NameResourceLayoutDetector.kt
index fd26e30..cb8284e 100644
--- a/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/resource/layout/NameResourceLayoutDetector.kt
+++ b/checks/src/main/java/com/omegar/lint/checks/detector/project_guidelines/file_name/resource/layout/NameResourceLayoutDetector.kt
@@ -117,15 +117,25 @@ class NameResourceLayoutDetector : Detector(), Detector.UastScanner {
private fun checkLayoutName(arguments: List, newClassName: String, node: UCallExpression, context: JavaContext) {
arguments.forEach { argument ->
val argumentName = argument.asRenderString()
- if (argumentName.contains(LAYOUT_PREFIX_VAL) && LAYOUT_PREFIX_VAL + newClassName != argumentName) {
+ val layoutName = LAYOUT_PREFIX_VAL + newClassName
+ if (argumentName.contains(LAYOUT_PREFIX_VAL) && layoutName != argumentName) {
context.report(
ISSUE,
node,
context.getNameLocation(argument),
- "$LAYOUT_PREFIX_VAL$newClassName\n${ISSUE.getExplanation(TextFormat.TEXT)}"
+ "$LAYOUT_PREFIX_VAL$newClassName\n${ISSUE.getExplanation(TextFormat.TEXT)}",
+ createLintFix(argumentName, layoutName)
)
}
}
}
+
+ private fun createLintFix(argumentName: String, layoutName: String): LintFix? {
+ return LintFix.create()
+ .replace()
+ .text(argumentName)
+ .with(layoutName)
+ .build()
+ }
}