diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index ecb07d02390..65a193930ad 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -21,7 +21,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.JetNodeTypes -import org.jetbrains.kotlin.lexer.JetKeywordToken +import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -238,15 +238,15 @@ public object PositioningStrategies { } platformStatic - public fun modifierSetPosition(vararg tokens: JetKeywordToken): PositioningStrategy { + public fun modifierSetPosition(vararg tokens: JetModifierKeywordToken): PositioningStrategy { return object : PositioningStrategy() { override fun mark(element: JetModifierListOwner): List { val modifierList = element.getModifierList().sure { "No modifier list, but modifier has been found by the analyzer" } for (token in tokens) { - val node = modifierList.getModifierNode(token) - if (node != null) { - return markNode(node) + val element = modifierList.getModifier(token) + if (element != null) { + return markElement(element) } } throw IllegalStateException("None of the modifiers is found: " + listOf(*tokens)) @@ -265,7 +265,7 @@ public object PositioningStrategies { val visibilityTokens = listOf(JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PUBLIC_KEYWORD, JetTokens.INTERNAL_KEYWORD) val modifierList = element.getModifierList() - val result = visibilityTokens.map { modifierList?.getModifierNode(it)?.getTextRange() }.filterNotNull() + val result = visibilityTokens.map { modifierList?.getModifier(it)?.getTextRange() }.filterNotNull() if (!result.isEmpty()) return result // Try to resolve situation when there's no visibility modifiers written before element @@ -289,7 +289,7 @@ public object PositioningStrategies { public val VARIANCE_IN_PROJECTION: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: JetTypeProjection): List { - return markNode(element.getProjectionNode()!!) + return markElement(element.getProjectionToken()!!) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetModifierList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetModifierList.java index 6710c3e7036..3c240e7049b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetModifierList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetModifierList.java @@ -22,7 +22,6 @@ import com.intellij.psi.stubs.IStubElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; -import org.jetbrains.kotlin.lexer.JetToken; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; import org.jetbrains.kotlin.psi.stubs.KotlinModifierListStub; import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; @@ -54,30 +53,28 @@ public abstract class JetModifierList extends JetElementImplStub nodes = modifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets + Map tokens = modifiersChecker.getTokensCorrespondingToModifiers(getterModifierList, Sets .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, JetTokens.INTERNAL_KEYWORD)); if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { - for (ASTNode node : nodes.values()) { - trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi())); + for (PsiElement token : tokens.values()) { + trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(token)); } } else { - for (ASTNode node : nodes.values()) { - trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi())); + for (PsiElement token : tokens.values()) { + trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(token)); } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index 64586da12c7..fb08f004c23 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.resolve; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -256,17 +255,17 @@ public class ModifiersChecker { } @NotNull - public Map getNodesCorrespondingToModifiers( + public Map getTokensCorrespondingToModifiers( @NotNull JetModifierList modifierList, @NotNull Collection possibleModifiers ) { - Map nodes = Maps.newHashMap(); + Map tokens = Maps.newHashMap(); for (JetModifierKeywordToken modifier : possibleModifiers) { if (modifierList.hasModifier(modifier)) { - nodes.put(modifier, modifierList.getModifierNode(modifier)); + tokens.put(modifier, modifierList.getModifier(modifier)); } } - return nodes; + return tokens; } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index df37ae0b282..adb3f9c982a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -20,10 +20,6 @@ make.class.annotation.class.family=Make Class an Annotation Class add.star.projections=Add ''{0}'' change.to.star.projection=Change type arguments to {0} change.to.star.projection.family=Change to Star Projection -make.element.not.modifier=Make {0} not {1} -remove.modifier=Remove ''{0}'' modifier -remove.modifier.family=Remove Modifier -remove.redundant.modifier=Remove redundant ''{0}'' modifier remove.parts.from.property=Remove {0} from property remove.parts.from.property.family=Remove Parts from Property remove.psi.element.family=Remove Element diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveModifierFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveModifierFix.kt index ff5f3df56fd..b53caabbadf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveModifierFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveModifierFix.kt @@ -16,16 +16,18 @@ package org.jetbrains.kotlin.idea.quickfix -import com.intellij.extapi.psi.ASTDelegatePsiElement import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.idea.JetBundle import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil -import org.jetbrains.kotlin.lexer.JetKeywordToken import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.JetModifierListOwner +import org.jetbrains.kotlin.psi.JetTypeParameter +import org.jetbrains.kotlin.psi.JetTypeProjection +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.types.Variance public class RemoveModifierFix( @@ -34,53 +36,37 @@ public class RemoveModifierFix( private val isRedundant: Boolean ) : JetIntentionAction(element) { - override fun getFamilyName() = JetBundle.message("remove.modifier.family") + private val text = run { + val modifierText = modifier.value + when { + isRedundant -> + "Remove redundant '$modifierText' modifier" + modifier === JetTokens.ABSTRACT_KEYWORD || modifier === JetTokens.OPEN_KEYWORD -> + "Make ${AddModifierFix.getElementName(element)} not $modifierText" + else -> + "Remove '$modifierText' modifier" + } + } - override fun getText() = makeText(element, modifier, isRedundant) + override fun getFamilyName() = "Remove modifier" + + override fun getText() = text + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) + = super.isAvailable(project, editor, file) && element.hasModifier(modifier) override fun invoke(project: Project, editor: Editor?, file: JetFile) { invoke() } public fun invoke() { + //TODO: without this copy&replace we get bad formatting on removing last modifier val newElement = element.copy() as JetModifierListOwner - element.replace(removeModifier(newElement, modifier)) + newElement.removeModifier(modifier) + element.replace(newElement) } companion object { - private fun makeText(element: JetModifierListOwner?, modifier: JetKeywordToken, isRedundant: Boolean): String { - if (isRedundant) { - return JetBundle.message("remove.redundant.modifier", modifier.value) - } - if (element != null && (modifier === JetTokens.ABSTRACT_KEYWORD || modifier === JetTokens.OPEN_KEYWORD)) { - return JetBundle.message("make.element.not.modifier", AddModifierFix.getElementName(element), modifier.value) - } - return JetBundle.message("remove.modifier", modifier.value) - } - - private fun removeModifier(element: T, modifier: JetModifierKeywordToken): T { - val modifierList = element.modifierList!! - removeModifierFromList(modifierList, modifier) - if (modifierList.firstChild == null) { - val whiteSpace = modifierList.nextSibling - assert(element is ASTDelegatePsiElement) - (element as ASTDelegatePsiElement).deleteChildInternal(modifierList.node) - QuickFixUtil.removePossiblyWhiteSpace(element, whiteSpace) - } - return element - } - - private fun removeModifierFromList(modifierList: JetModifierList, modifier: JetModifierKeywordToken): JetModifierList { - val modifierNode = modifierList.getModifierNode(modifier)!! - val whiteSpace = modifierNode.psi.nextSibling - val wsRemoved = QuickFixUtil.removePossiblyWhiteSpace(modifierList, whiteSpace) - modifierList.deleteChildInternal(modifierNode) - if (!wsRemoved) { - QuickFixUtil.removePossiblyWhiteSpace(modifierList, modifierList.lastChild) - } - return modifierList - } - public fun createRemoveModifierFromListOwnerFactory(modifier: JetModifierKeywordToken, isRedundant: Boolean = false): JetSingleIntentionActionFactory { return object : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): JetIntentionAction? { @@ -93,10 +79,9 @@ public class RemoveModifierFix( public fun createRemoveModifierFactory(isRedundant: Boolean = false): JetSingleIntentionActionFactory { return object : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): JetIntentionAction? { - val modifierListOwner = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null val psiElement = diagnostic.psiElement - val elementType = psiElement.node.elementType - if (elementType !is JetModifierKeywordToken) return null + val elementType = psiElement.node.elementType as? JetModifierKeywordToken ?: return null + val modifierListOwner = psiElement.getStrictParentOfType() ?: return null return RemoveModifierFix(modifierListOwner, elementType, isRedundant) } } @@ -105,10 +90,8 @@ public class RemoveModifierFix( public fun createRemoveProjectionFactory(isRedundant: Boolean): JetSingleIntentionActionFactory { return object : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): JetIntentionAction? { - val projection = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null - val projectionAstNode = projection.projectionNode ?: return null - val elementType = projectionAstNode.elementType - if (elementType !is JetModifierKeywordToken) return null + val projection = diagnostic.psiElement as JetTypeProjection + val elementType = projection.projectionToken?.node?.elementType as? JetModifierKeywordToken ?: return null return RemoveModifierFix(projection, elementType, isRedundant) } } @@ -117,17 +100,13 @@ public class RemoveModifierFix( public fun createRemoveVarianceFactory(): JetSingleIntentionActionFactory { return object : JetSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): JetIntentionAction? { - val modifierListOwner = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null - val psiElement = diagnostic.psiElement - if (psiElement !is JetTypeParameter) return null - val variance = psiElement.variance - val modifier: JetModifierKeywordToken - when (variance) { - Variance.IN_VARIANCE -> modifier = JetTokens.IN_KEYWORD - Variance.OUT_VARIANCE -> modifier = JetTokens.OUT_KEYWORD + val psiElement = diagnostic.psiElement as JetTypeParameter + val modifier = when (psiElement.variance) { + Variance.IN_VARIANCE -> JetTokens.IN_KEYWORD + Variance.OUT_VARIANCE -> JetTokens.OUT_KEYWORD else -> return null } - return RemoveModifierFix(modifierListOwner, modifier, false) + return RemoveModifierFix(psiElement, modifier, isRedundant = false) } } }