Illegal Dalvik identifier inspection
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
|
||||
fun PsiElement.getAndroidFacetForFile(): AndroidFacet? {
|
||||
val file = containingFile ?: return null
|
||||
return AndroidFacet.getInstance(file)
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.inspection
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.refactoring.rename.RenameHandlerRegistry
|
||||
import org.jetbrains.kotlin.android.getAndroidFacetForFile
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
class IllegalIdentifierInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
return object : KtVisitorVoid() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (element.node.elementType != KtTokens.IDENTIFIER) return
|
||||
|
||||
val text = element.text
|
||||
// '`' can't be escaped now
|
||||
if (!text.startsWith('`') || !text.endsWith('`')) return
|
||||
|
||||
val unquotedName = KtPsiUtil.unquoteIdentifier(text)
|
||||
// This is already an error
|
||||
if (unquotedName.isEmpty()) return
|
||||
|
||||
if (!unquotedName.all { isValidDalvikCharacter(it) } && checkAndroidFacet(element)) {
|
||||
holder.registerProblem(element,
|
||||
"Identifier not allowed in Android projects",
|
||||
ProblemHighlightType.GENERIC_ERROR,
|
||||
RenameIdentifierFix())
|
||||
}
|
||||
}
|
||||
|
||||
fun checkAndroidFacet(element: PsiElement): Boolean {
|
||||
return element.getAndroidFacetForFile() != null || ApplicationManager.getApplication().isUnitTestMode
|
||||
}
|
||||
|
||||
// https://source.android.com/devices/tech/dalvik/dex-format.html#string-syntax
|
||||
fun isValidDalvikCharacter(c: Char) = when (c) {
|
||||
in 'A'..'Z' -> true
|
||||
in 'a'..'z' -> true
|
||||
in '0'..'9' -> true
|
||||
'$', '-', '_' -> true
|
||||
in '\u00a1' .. '\u1fff' -> true
|
||||
in '\u2010' .. '\u2027' -> true
|
||||
in '\u2030' .. '\ud7ff' -> true
|
||||
in '\ue000' .. '\uffef' -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RenameIdentifierFix : LocalQuickFix {
|
||||
override fun getName() = "Rename"
|
||||
override fun getFamilyName() = name
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val element = descriptor.psiElement ?: return
|
||||
val file = element.containingFile ?: return
|
||||
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return
|
||||
val editorManager = FileEditorManager.getInstance(project)
|
||||
val editor = editorManager.getSelectedEditor(file.virtualFile) ?: return
|
||||
val dataContext = DataManager.getInstance().getDataContext(editor.component)
|
||||
val renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext)
|
||||
renameHandler?.invoke(project, arrayOf(element), dataContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -21,7 +21,6 @@ import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import org.jetbrains.android.dom.AndroidAttributeValue;
|
||||
import org.jetbrains.android.dom.manifest.Manifest;
|
||||
@@ -35,6 +34,7 @@ import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.android.AndroidUtilKt;
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -51,12 +51,7 @@ public class KotlinAndroidGotoDeclarationHandler implements GotoDeclarationHandl
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiFile file = referenceExpression.getContainingFile();
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AndroidFacet facet = AndroidFacet.getInstance(file);
|
||||
AndroidFacet facet = AndroidUtilKt.getAndroidFacetForFile(referenceExpression);
|
||||
if (facet == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor"/>
|
||||
<errorHandler implementation="org.jetbrains.kotlin.plugin.android.AndroidExtensionsReportSubmitter"/>
|
||||
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidGotoDeclarationHandler"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.IllegalIdentifierInspection"
|
||||
displayName="Illegal Android Identifier"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
level="ERROR"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<problems>
|
||||
<problem>
|
||||
<file>temp:///src/test.kt</file>
|
||||
<line>7</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Illegal Android Identifier</problem_class>
|
||||
<description>Illegal Android Identifier</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>temp:///src/test.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Illegal Android Identifier</problem_class>
|
||||
<description>Illegal Android Identifier</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>temp:///src/test.kt</file>
|
||||
<line>9</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Illegal Android Identifier</problem_class>
|
||||
<description>Illegal Android Identifier</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>temp:///src/test.kt</file>
|
||||
<line>10</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Illegal Android Identifier</problem_class>
|
||||
<description>Illegal Android Identifier</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>temp:///src/test.kt</file>
|
||||
<line>11</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Illegal Android Identifier</problem_class>
|
||||
<description>Illegal Android Identifier</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+1
@@ -0,0 +1 @@
|
||||
// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.IllegalIdentifierInspection
|
||||
@@ -0,0 +1,11 @@
|
||||
val `Kotlin` = 0
|
||||
val `Котлин` = 0
|
||||
val `ことりん` = 0
|
||||
val `§*!`` = 0
|
||||
val `0a0b0c` = 0
|
||||
val `$a-b_c` = 0
|
||||
val `with space` = 0 //illegal
|
||||
val `a+b` = 0 //illegal
|
||||
val `#` = 0 //illegal
|
||||
val `!` = 0 //illegal
|
||||
val `()` = 0 //illegal
|
||||
@@ -106,6 +106,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/inspections"), Pattern.compile("^(inspections\\.test)$"));
|
||||
}
|
||||
|
||||
@TestMetadata("androidIllegalIdentifiers/inspectionData/inspections.test")
|
||||
public void testAndroidIllegalIdentifiers_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/androidIllegalIdentifiers/inspectionData/inspections.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingExtensionProperty/inspectionData/inspections.test")
|
||||
public void testConflictingExtensionProperty_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/conflictingExtensionProperty/inspectionData/inspections.test");
|
||||
|
||||
Reference in New Issue
Block a user