diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/SortModifiersInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/SortModifiersInspection.kt index 2aac7e41c4e..433b410c2ce 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/SortModifiersInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/SortModifiersInspection.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2000-2018 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.inspections @@ -20,9 +9,7 @@ import com.intellij.codeInspection.* import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor import org.jetbrains.kotlin.lexer.KtModifierKeywordToken -import org.jetbrains.kotlin.psi.KtModifierList -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.psi.KtVisitorVoid +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.addRemoveModifier.sortModifiers import org.jetbrains.kotlin.psi.psiUtil.allChildren @@ -33,16 +20,32 @@ class SortModifiersInspection : AbstractKotlinInspection(), CleanupLocalInspecti override fun visitModifierList(list: KtModifierList) { super.visitModifierList(list) - val modifiers = list.allChildren.toList().mapNotNull { it.node.elementType as? KtModifierKeywordToken }.toList() + val modifierElements = list.allChildren.toList() + var modifiersBeforeAnnotations = false + var seenModifiers = false + for (modifierElement in modifierElements) { + if (modifierElement.node.elementType is KtModifierKeywordToken) { + seenModifiers = true + } else if (seenModifiers && (modifierElement is KtAnnotationEntry || modifierElement is KtAnnotation)) { + modifiersBeforeAnnotations = true + } + } + + val modifiers = modifierElements.mapNotNull { it.node.elementType as? KtModifierKeywordToken }.toList() if (modifiers.isEmpty()) return val sortedModifiers = sortModifiers(modifiers) - if (modifiers == sortedModifiers) return + if (modifiers == sortedModifiers && !modifiersBeforeAnnotations) return - holder.registerProblem(list, - "Non-canonical modifiers order", - ProblemHighlightType.WEAK_WARNING, - SortModifiersFix(sortedModifiers) + val message = if (modifiersBeforeAnnotations) + "Modifiers should follow annotations" + else + "Non-canonical modifiers order" + holder.registerProblem( + list, + message, + ProblemHighlightType.WEAK_WARNING, + SortModifiersFix(sortedModifiers) ) } } diff --git a/idea/testData/inspectionsLocal/sortModifiers/annotation.kt b/idea/testData/inspectionsLocal/sortModifiers/annotation.kt new file mode 100644 index 00000000000..1e3b1adac7e --- /dev/null +++ b/idea/testData/inspectionsLocal/sortModifiers/annotation.kt @@ -0,0 +1,3 @@ +annotation class Test + +public @Test /* this is a test */ class MyTest diff --git a/idea/testData/inspectionsLocal/sortModifiers/annotation.kt.after b/idea/testData/inspectionsLocal/sortModifiers/annotation.kt.after new file mode 100644 index 00000000000..78aaed93693 --- /dev/null +++ b/idea/testData/inspectionsLocal/sortModifiers/annotation.kt.after @@ -0,0 +1,4 @@ +annotation class Test + +@Test +public /* this is a test */ class MyTest diff --git a/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt b/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt new file mode 100644 index 00000000000..f80a6931cd6 --- /dev/null +++ b/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt @@ -0,0 +1,6 @@ +annotation class Inject +annotation class VisibleForTesting + +class Example { + public @set:[Inject VisibleForTesting] var x: String = "" +} diff --git a/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt.after b/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt.after new file mode 100644 index 00000000000..410a211af90 --- /dev/null +++ b/idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt.after @@ -0,0 +1,7 @@ +annotation class Inject +annotation class VisibleForTesting + +class Example { + @set:[Inject VisibleForTesting] + public var x: String = "" +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index ead270650bf..580287ddf09 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2000-2018 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.inspections; @@ -3830,6 +3819,18 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/sortModifiers"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/sortModifiers/annotation.kt"); + doTest(fileName); + } + + @TestMetadata("annotationGroup.kt") + public void testAnnotationGroup() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/sortModifiers/annotationGroup.kt"); + doTest(fileName); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/sortModifiers/simple.kt");