Added API in PSI to add/remove modifiers and refactored quickfixes to use it

This commit is contained in:
Valentin Kipyatkov
2014-10-07 15:46:17 +04:00
parent 12b7d218b7
commit 05aaea48e9
23 changed files with 250 additions and 161 deletions
@@ -27,9 +27,11 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.psi.addRemoveModifier.AddRemoveModifierPackage;
import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
@@ -90,6 +92,31 @@ public class JetClass extends JetTypeParameterListOwnerStub<PsiJetClassStub> imp
return getStubOrPsiChild(JetStubElementTypes.PRIMARY_CONSTRUCTOR_MODIFIER_LIST);
}
public void addPrimaryConstructorModifier(@NotNull JetModifierKeywordToken modifier) {
JetModifierList modifierList = getPrimaryConstructorModifierList();
if (modifierList != null) {
AddRemoveModifierPackage.addModifier(modifierList, modifier, JetTokens.PUBLIC_KEYWORD);
}
else {
if (modifier == JetTokens.PUBLIC_KEYWORD) return;
JetParameterList parameterList = getPrimaryConstructorParameterList();
assert parameterList != null;
JetModifierList newModifierList = new JetPsiFactory(getProject()).createModifierList(modifier);
addBefore(newModifierList, parameterList);
}
}
public void removePrimaryConstructorModifier(@NotNull JetModifierKeywordToken modifier) {
JetModifierList list = getPrimaryConstructorModifierList();
if (list != null) {
PsiElement token = list.getModifier(modifier);
if (token != null) {
token.delete();
}
}
}
@Override
@NotNull
public List<JetClassInitializer> getAnonymousInitializers() {
@@ -20,7 +20,9 @@ import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.psi.addRemoveModifier.AddRemoveModifierPackage;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
import java.util.List;
@@ -37,11 +39,21 @@ abstract class JetDeclarationImpl extends JetExpressionImpl implements JetDeclar
}
@Override
public boolean hasModifier(JetModifierKeywordToken modifier) {
public boolean hasModifier(@NotNull JetModifierKeywordToken modifier) {
JetModifierList modifierList = getModifierList();
return modifierList != null && modifierList.hasModifier(modifier);
}
@Override
public void addModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.addModifier(this, modifier, JetTokens.INTERNAL_KEYWORD);
}
@Override
public void removeModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.removeModifier(this, modifier);
}
@NotNull
@Override
public List<JetAnnotationEntry> getAnnotationEntries() {
@@ -62,21 +62,7 @@ public abstract class JetModifierList extends JetElementImplStub<PsiJetModifierL
return answer != null ? answer : Collections.<JetAnnotationEntry>emptyList();
}
@NotNull
public List<ASTNode> getModifierNodes() {
List<ASTNode> modifierNodes = new ArrayList<ASTNode>();
ASTNode node = getNode().getFirstChildNode();
while (node != null) {
if (node.getElementType() instanceof JetModifierKeywordToken) {
modifierNodes.add(node);
}
node = node.getTreeNext();
}
return modifierNodes;
}
public boolean hasModifier(JetModifierKeywordToken token) {
public boolean hasModifier(@NotNull JetModifierKeywordToken token) {
PsiJetModifierListStub stub = getStub();
if (stub != null) {
return stub.hasModifier(token);
@@ -85,12 +71,12 @@ public abstract class JetModifierList extends JetElementImplStub<PsiJetModifierL
}
@Nullable
public PsiElement getModifier(JetModifierKeywordToken token) {
public PsiElement getModifier(@NotNull JetModifierKeywordToken token) {
return findChildByType(token);
}
@Nullable
public ASTNode getModifierNode(JetToken token) {
public ASTNode getModifierNode(@NotNull JetToken token) {
ASTNode node = getNode().getFirstChildNode();
while (node != null) {
if (node.getElementType() == token) return node;
@@ -98,6 +84,4 @@ public abstract class JetModifierList extends JetElementImplStub<PsiJetModifierL
}
return null;
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
@@ -24,5 +25,8 @@ public interface JetModifierListOwner extends PsiElement, JetAnnotated {
@Nullable
JetModifierList getModifierList();
boolean hasModifier(JetModifierKeywordToken modifier);
boolean hasModifier(@NotNull JetModifierKeywordToken modifier);
void addModifier(@NotNull JetModifierKeywordToken modifier);
void removeModifier(@NotNull JetModifierKeywordToken modifier);
}
@@ -21,8 +21,10 @@ import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.addRemoveModifier.AddRemoveModifierPackage;
import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
import java.util.List;
@@ -43,11 +45,21 @@ public class JetModifierListOwnerStub<T extends StubElement> extends JetElementI
}
@Override
public boolean hasModifier(JetModifierKeywordToken modifier) {
public boolean hasModifier(@NotNull JetModifierKeywordToken modifier) {
JetModifierList modifierList = getModifierList();
return modifierList != null && modifierList.hasModifier(modifier);
}
@Override
public void addModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.addModifier(this, modifier, JetTokens.INTERNAL_KEYWORD);
}
@Override
public void removeModifier(@NotNull JetModifierKeywordToken modifier) {
AddRemoveModifierPackage.removeModifier(this, modifier);
}
@Override
@NotNull
public List<JetAnnotationEntry> getAnnotationEntries() {
@@ -110,7 +110,7 @@ public class JetObjectDeclaration extends JetNamedDeclarationStub<PsiJetObjectSt
}
@Override
public boolean hasModifier(JetModifierKeywordToken modifier) {
public boolean hasModifier(@NotNull JetModifierKeywordToken modifier) {
JetModifierList modifierList = getModifierList();
return modifierList != null && modifierList.hasModifier(modifier);
}
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2014 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.jet.lang.psi.addRemoveModifier
import org.jetbrains.jet.lexer.JetModifierKeywordToken
import org.jetbrains.jet.lexer.JetTokens.*
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.jet.lang.psi.JetModifierListOwner
import org.jetbrains.jet.lang.psi.JetPsiFactory
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.psi.JetAnnotation
import org.jetbrains.jet.lang.psi.JetModifierList
import org.jetbrains.jet.lang.psi.psiUtil.siblings
internal fun addModifier(owner: JetModifierListOwner, modifier: JetModifierKeywordToken, defaultVisibilityModifier: JetModifierKeywordToken) {
val modifierList = owner.getModifierList()
if (modifierList == null) {
if (modifier == defaultVisibilityModifier) return
val newModifierList = JetPsiFactory(owner).createModifierList(modifier)
val anchor = owner.getFirstChild()!!.siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
.first()
owner.addBefore(newModifierList, anchor)
}
else {
addModifier(modifierList, modifier, defaultVisibilityModifier)
}
}
internal fun addModifier(modifierList: JetModifierList, modifier: JetModifierKeywordToken, defaultVisibilityModifier: JetModifierKeywordToken) {
val newModifier = JetPsiFactory(modifierList).createModifierList(modifier).getModifier(modifier)!!
val modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
?.map { modifierList.getModifier(it) }
?.filterNotNull()
?.firstOrNull()
if (modifier == defaultVisibilityModifier) { // do not insert explicit 'internal' keyword (or 'public' for primary constructor)
//TODO: code style option
if (modifierToReplace != null) {
modifierToReplace.delete()
}
return
}
if (modifierToReplace != null) {
modifierToReplace.replace(newModifier)
}
else {
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
fun placeAfter(child: PsiElement): Boolean {
if (child is PsiWhiteSpace) return false
if (child is JetAnnotation) return true // place modifiers after annotations
val elementType = child.getNode()!!.getElementType()
val order = MODIFIERS_ORDER.indexOf(elementType)
return newModifierOrder > order
}
val anchor = modifierList.getLastChild()?.siblings(forward = false)?.firstOrNull(::placeAfter)
modifierList.addAfter(newModifier, anchor)
}
}
internal fun removeModifier(owner: JetModifierListOwner, modifier: JetModifierKeywordToken) {
owner.getModifierList()?.getModifier(modifier)?.delete()
}
private val MODIFIERS_TO_REPLACE = mapOf(
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
OPEN_KEYWORD to listOf(FINAL_KEYWORD),
PUBLIC_KEYWORD to listOf(PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PROTECTED_KEYWORD to listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PRIVATE_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD),
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD)
)
private val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD,
OVERRIDE_KEYWORD,
INNER_KEYWORD,
ANNOTATION_KEYWORD, ENUM_KEYWORD)