diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt
index ffd67178590..ab369ebfa0c 100644
--- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt
+++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt
@@ -166,6 +166,17 @@ public fun KtClass.getOrCreateCompanionObject() : KtObjectDeclaration {
//TODO: code style option whether to insert redundant 'public' keyword or not
public fun KtDeclaration.setVisibility(visibilityModifier: KtModifierKeywordToken) {
+ val defaultVisibilityKeyword = implicitVisibility()
+
+ if (visibilityModifier == defaultVisibilityKeyword) {
+ this.visibilityModifierType()?.let { removeModifier(it) }
+ return
+ }
+
+ addModifier(visibilityModifier)
+}
+
+fun KtDeclaration.implicitVisibility(): KtModifierKeywordToken? {
val defaultVisibilityKeyword = if (hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
(resolveToDescriptor() as? CallableMemberDescriptor)
?.overriddenDescriptors
@@ -175,13 +186,7 @@ public fun KtDeclaration.setVisibility(visibilityModifier: KtModifierKeywordToke
else {
KtTokens.DEFAULT_VISIBILITY_KEYWORD
}
-
- if (visibilityModifier == defaultVisibilityKeyword) {
- this.visibilityModifierType()?.let { removeModifier(it) }
- return
- }
-
- addModifier(visibilityModifier)
+ return defaultVisibilityKeyword
}
fun KtSecondaryConstructor.getOrCreateBody(): KtBlockExpression {
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 7401485cc76..6c1a109ddb2 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1308,6 +1308,13 @@
cleanupTool="true"
level="WARNING"/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantVisibilityModifierInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantVisibilityModifierInspection.kt
new file mode 100644
index 00000000000..9f6cec56887
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantVisibilityModifierInspection.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.idea.inspections
+
+import com.intellij.codeInspection.*
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElementVisitor
+import org.jetbrains.kotlin.idea.core.implicitVisibility
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtVisitorVoid
+import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
+
+class RedundantVisibilityModifierInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
+ return object : KtVisitorVoid() {
+ override fun visitDeclaration(dcl: KtDeclaration) {
+ val visibilityModifier = dcl.visibilityModifier() ?: return
+ if (visibilityModifier.node.elementType == dcl.implicitVisibility()) {
+ holder.registerProblem(visibilityModifier,
+ "Redundant visibility modifier",
+ ProblemHighlightType.LIKE_UNUSED_SYMBOL,
+ RemoveVisibilityModifierFix())
+ }
+ }
+ }
+ }
+
+ class RemoveVisibilityModifierFix : LocalQuickFix {
+ override fun getName(): String = "Remove redundant visibility modifier"
+
+ override fun getFamilyName(): String = getName()
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ descriptor.psiElement.delete()
+ }
+ }
+}
diff --git a/idea/testData/inspections/redundantVisibilityModifier/inspectionData/expected.xml b/idea/testData/inspections/redundantVisibilityModifier/inspectionData/expected.xml
new file mode 100644
index 00000000000..62cb5ff4b2e
--- /dev/null
+++ b/idea/testData/inspections/redundantVisibilityModifier/inspectionData/expected.xml
@@ -0,0 +1,30 @@
+
+
+ redundantVisibilityModifier.kt
+ 1
+
+ Redundant visibility modifier
+ Redundant visibility modifier
+
+
+ redundantVisibilityModifier.kt
+ 2
+
+ Redundant visibility modifier
+ Redundant visibility modifier
+
+
+ redundantVisibilityModifier.kt
+ 4
+
+ Redundant visibility modifier
+ Redundant visibility modifier
+
+
+ redundantVisibilityModifier.kt
+ 17
+
+ Redundant visibility modifier
+ Redundant visibility modifier
+
+
diff --git a/idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test b/idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test
new file mode 100644
index 00000000000..f9a57e0f5f8
--- /dev/null
+++ b/idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test
@@ -0,0 +1 @@
+// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.RedundantVisibilityModifierInspection
diff --git a/idea/testData/inspections/redundantVisibilityModifier/redundantVisibilityModifier.kt b/idea/testData/inspections/redundantVisibilityModifier/redundantVisibilityModifier.kt
new file mode 100644
index 00000000000..fd2bb8c5f3a
--- /dev/null
+++ b/idea/testData/inspections/redundantVisibilityModifier/redundantVisibilityModifier.kt
@@ -0,0 +1,22 @@
+public class C {
+ public val foo: Int = 0
+
+ public fun bar() {}
+
+}
+
+open class D {
+ protected open fun willRemainProtected() {
+ }
+
+ protected open fun willBecomePublic() {
+ }
+}
+
+class E : D() {
+ protected override fun willRemainProtected() {
+ }
+
+ public override fun willBecomePublic() {
+ }
+}
diff --git a/idea/testData/quickfix/redundantVisibilityModifier/.inspection b/idea/testData/quickfix/redundantVisibilityModifier/.inspection
new file mode 100644
index 00000000000..19adc2428cf
--- /dev/null
+++ b/idea/testData/quickfix/redundantVisibilityModifier/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.RedundantVisibilityModifierInspection
\ No newline at end of file
diff --git a/idea/testData/quickfix/redundantVisibilityModifier/simple.kt b/idea/testData/quickfix/redundantVisibilityModifier/simple.kt
new file mode 100644
index 00000000000..ba4cdeb5f98
--- /dev/null
+++ b/idea/testData/quickfix/redundantVisibilityModifier/simple.kt
@@ -0,0 +1,3 @@
+// "Remove redundant visibility modifier" "true"
+public class C {
+}
diff --git a/idea/testData/quickfix/redundantVisibilityModifier/simple.kt.after b/idea/testData/quickfix/redundantVisibilityModifier/simple.kt.after
new file mode 100644
index 00000000000..27c1041c890
--- /dev/null
+++ b/idea/testData/quickfix/redundantVisibilityModifier/simple.kt.after
@@ -0,0 +1,3 @@
+// "Remove redundant visibility modifier" "true"
+class C {
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
index 1d09b0273a7..5a1ce2b7d4c 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
@@ -118,6 +118,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
doTest(fileName);
}
+ @TestMetadata("redundantVisibilityModifier/inspectionData/inspections.test")
+ public void testRedundantVisibilityModifier_inspectionData_Inspections_test() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/redundantVisibilityModifier/inspectionData/inspections.test");
+ doTest(fileName);
+ }
+
@TestMetadata("spelling/inspectionData/inspections.test")
public void testSpelling_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/spelling/inspectionData/inspections.test");
diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
index 9a67301ffcf..37683af2f5c 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
@@ -5848,6 +5848,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
+ @TestMetadata("idea/testData/quickfix/redundantVisibilityModifier")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class RedundantVisibilityModifier extends AbstractQuickFixTest {
+ public void testAllFilesPresentInRedundantVisibilityModifier() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/redundantVisibilityModifier"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/redundantVisibilityModifier/simple.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/quickfix/removeUnused")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)