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)
@@ -131,6 +131,8 @@ fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder {
aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_ARGUMENT, CALL_EXPRESSION).spaces(1)
betweenInside(IDENTIFIER, MODIFIER_LIST, CLASS).spaces(1)
}
custom {
@@ -23,31 +23,22 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetModifierList;
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetBundle;
import java.util.HashMap;
import java.util.Map;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
import static org.jetbrains.jet.lexer.JetTokens.*;
import static org.jetbrains.jet.lexer.JetTokens.ABSTRACT_KEYWORD;
public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
private final JetKeywordToken modifier;
private final JetModifierKeywordToken[] modifiersThanCanBeReplaced;
@NotNull private final JetModifierKeywordToken modifier;
private AddModifierFix(@NotNull JetModifierListOwner element, @NotNull JetKeywordToken modifier, @Nullable JetModifierKeywordToken[] modifiersThanCanBeReplaced) {
private AddModifierFix(@NotNull JetModifierListOwner element, @NotNull JetModifierKeywordToken modifier) {
super(element);
this.modifier = modifier;
this.modifiersThanCanBeReplaced = modifiersThanCanBeReplaced;
}
@NotNull
@@ -85,78 +76,7 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
element.replace(addModifier(element, modifier, modifiersThanCanBeReplaced, project, false));
}
@NotNull
/*package*/ static JetModifierListOwner addModifier(@NotNull PsiElement element, @NotNull JetKeywordToken modifier, @Nullable JetModifierKeywordToken[] modifiersThatCanBeReplaced, @NotNull Project project, boolean toBeginning) {
JetModifierListOwner newElement = (JetModifierListOwner) (element.copy());
changeModifier(newElement, newElement.getModifierList(), newElement.getFirstChild(),
modifiersThatCanBeReplaced, project, toBeginning, JetPsiFactory(project).createModifierList(modifier));
return newElement;
}
public static void changeModifier(
PsiElement element, @Nullable JetModifierList modifierList, @Nullable PsiElement insertAnchor,
JetModifierKeywordToken[] modifiersThatCanBeReplaced, Project project, boolean toBeginning, JetModifierList listWithModifier
) {
PsiElement whiteSpace = JetPsiFactory(project).createWhiteSpace();
if (modifierList == null) {
if (listWithModifier != null) {
if (insertAnchor != null) {
listWithModifier = (JetModifierList) element.addBefore(listWithModifier, insertAnchor);
element.addBefore(whiteSpace, insertAnchor);
element.addBefore(whiteSpace, listWithModifier);
}
else {
PsiElement firstChild = element.getFirstChild();
element.addBefore(listWithModifier, firstChild);
element.addBefore(whiteSpace, firstChild);
}
}
}
else {
boolean replaced = false;
if (modifiersThatCanBeReplaced != null) {
PsiElement toBeReplaced = null;
PsiElement toReplace = null;
for (JetModifierKeywordToken modifierThatCanBeReplaced : modifiersThatCanBeReplaced) {
if (modifierList.hasModifier(modifierThatCanBeReplaced)) {
PsiElement modifierElement = modifierList.getModifierNode(modifierThatCanBeReplaced).getPsi();
assert modifierElement != null;
if (!replaced && listWithModifier != null) {
toBeReplaced = modifierElement;
toReplace = listWithModifier.getFirstChild();
//modifierElement.replace(listWithModifier.getFirstChild());
replaced = true;
}
else {
modifierList.deleteChildInternal(modifierElement.getNode());
}
}
}
if (toBeReplaced != null && toReplace != null) {
toBeReplaced.replace(toReplace);
}
}
if (!replaced && listWithModifier != null) {
if (toBeginning) {
PsiElement firstChild = modifierList.getFirstChild();
modifierList.addBefore(listWithModifier.getFirstChild(), firstChild);
modifierList.addBefore(whiteSpace, firstChild);
}
else {
PsiElement lastChild = modifierList.getLastChild();
modifierList.addAfter(listWithModifier.getFirstChild(), lastChild);
modifierList.addAfter(whiteSpace, lastChild);
}
}
}
}
@NotNull
/*package*/ static JetModifierListOwner addModifierWithDefaultReplacement(@NotNull PsiElement element, @NotNull JetModifierKeywordToken modifier, @NotNull Project project, boolean toBeginning) {
return addModifier(element, modifier, MODIFIERS_THAT_CAN_BE_REPLACED.get(modifier), project, toBeginning);
element.addModifier(modifier);
}
@Override
@@ -170,7 +90,7 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
public IntentionAction createAction(Diagnostic diagnostic) {
JetModifierListOwner modifierListOwner = QuickFixUtil.getParentElementOfType(diagnostic, modifierOwnerClass);
if (modifierListOwner == null) return null;
return new AddModifierFix(modifierListOwner, modifier, MODIFIERS_THAT_CAN_BE_REPLACED.get(modifier));
return new AddModifierFix(modifierListOwner, modifier);
}
};
}
@@ -178,11 +98,4 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
public static JetSingleIntentionActionFactory createFactory(JetModifierKeywordToken modifier) {
return createFactory(modifier, JetModifierListOwner.class);
}
private static Map<JetModifierKeywordToken, JetModifierKeywordToken[]> MODIFIERS_THAT_CAN_BE_REPLACED = new HashMap<JetModifierKeywordToken, JetModifierKeywordToken[]>();
static {
MODIFIERS_THAT_CAN_BE_REPLACED.put(ABSTRACT_KEYWORD, new JetModifierKeywordToken[]{OPEN_KEYWORD, FINAL_KEYWORD});
MODIFIERS_THAT_CAN_BE_REPLACED.put(OVERRIDE_KEYWORD, new JetModifierKeywordToken[]{OPEN_KEYWORD});
MODIFIERS_THAT_CAN_BE_REPLACED.put(OPEN_KEYWORD, new JetModifierKeywordToken[]{FINAL_KEYWORD});
}
}
@@ -78,7 +78,7 @@ public class AddOpenModifierToClassDeclarationFix extends JetIntentionAction<Jet
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
classDeclaration.replace(AddModifierFix.addModifierWithDefaultReplacement(classDeclaration, JetTokens.OPEN_KEYWORD, project, false));
classDeclaration.addModifier(JetTokens.OPEN_KEYWORD);
}
@NotNull
@@ -25,11 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.project.PluginJetFilesProvider;
@@ -37,11 +33,10 @@ import org.jetbrains.jet.plugin.project.PluginJetFilesProvider;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.jet.lexer.JetTokens.*;
import static org.jetbrains.jet.lexer.JetTokens.OVERRIDE_KEYWORD;
import static org.jetbrains.jet.lexer.JetTokens.PUBLIC_KEYWORD;
public class AddOverrideToEqualsHashCodeToStringFix extends JetIntentionAction<PsiElement> {
private static final JetModifierKeywordToken[] MODIFIERS_TO_REPLACE = {PUBLIC_KEYWORD, OPEN_KEYWORD};
public AddOverrideToEqualsHashCodeToStringFix(@NotNull PsiElement element) {
super(element);
}
@@ -90,10 +85,11 @@ public class AddOverrideToEqualsHashCodeToStringFix extends JetIntentionAction<P
for (Diagnostic diagnostic : ResolvePackage.getBindingContext(jetFile).getDiagnostics()) {
if (diagnostic.getFactory() != Errors.VIRTUAL_MEMBER_HIDDEN) continue;
PsiElement element = diagnostic.getPsiElement();
JetModifierListOwner element = (JetModifierListOwner) diagnostic.getPsiElement();
if (!isEqualsHashCodeOrToString(element)) continue;
element.replace(AddModifierFix.addModifier(element, OVERRIDE_KEYWORD, MODIFIERS_TO_REPLACE, project, false));
element.addModifier(OVERRIDE_KEYWORD);
element.removeModifier(PUBLIC_KEYWORD);
}
}
}
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibilities;
@@ -31,7 +32,6 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetBundle;
@@ -66,11 +66,13 @@ public class ChangeVisibilityModifierFix extends JetIntentionAction<JetModifierL
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
JetKeywordToken modifier = findVisibilityChangeTo(file);
element.replace(AddModifierFix.addModifier(element, modifier, VISIBILITY_TOKENS, project, true));
JetModifierKeywordToken modifier = findVisibilityChangeTo(file);
assert modifier != null;
element.addModifier(modifier);
}
private JetKeywordToken findVisibilityChangeTo(JetFile file) {
@Nullable
private JetModifierKeywordToken findVisibilityChangeTo(JetFile file) {
BindingContext bindingContext = ResolvePackage.getBindingContext(file);
DeclarationDescriptor descriptor;
if (element instanceof JetParameter) {
@@ -83,7 +83,7 @@ public class MakeClassAnAnnotationClassFix extends JetIntentionAction<JetAnnotat
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
annotationClass.replace(AddModifierFix.addModifier(annotationClass, ANNOTATION_KEYWORD, null, project, false));
annotationClass.addModifier(ANNOTATION_KEYWORD);
}
@NotNull
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetCallableDeclaration;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.JetBundle;
@@ -43,7 +44,7 @@ import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorT
import static org.jetbrains.jet.lexer.JetTokens.OPEN_KEYWORD;
public class MakeOverriddenMemberOpenFix extends JetIntentionAction<JetDeclaration> {
private final List<PsiElement> overriddenNonOverridableMembers = new ArrayList<PsiElement>();
private final List<JetCallableDeclaration> overriddenNonOverridableMembers = new ArrayList<JetCallableDeclaration>();
private final List<String> containingDeclarationsNames = new ArrayList<String>();
public MakeOverriddenMemberOpenFix(@NotNull JetDeclaration declaration) {
@@ -68,11 +69,11 @@ public class MakeOverriddenMemberOpenFix extends JetIntentionAction<JetDeclarati
(CallableMemberDescriptor) descriptor)) {
assert overriddenDescriptor.getKind() == DECLARATION : "Can only be applied to declarations.";
PsiElement overriddenMember = descriptorToDeclaration(overriddenDescriptor);
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember)) {
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember) || !(overriddenMember instanceof JetCallableDeclaration)) {
return false;
}
String containingDeclarationName = overriddenDescriptor.getContainingDeclaration().getName().asString();
overriddenNonOverridableMembers.add(overriddenMember);
overriddenNonOverridableMembers.add((JetCallableDeclaration) overriddenMember);
containingDeclarationsNames.add(containingDeclarationName);
}
return overriddenNonOverridableMembers.size() > 0;
@@ -142,8 +143,8 @@ public class MakeOverriddenMemberOpenFix extends JetIntentionAction<JetDeclarati
@Override
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
for (PsiElement overriddenMember : overriddenNonOverridableMembers) {
overriddenMember.replace(AddModifierFix.addModifierWithDefaultReplacement(overriddenMember, OPEN_KEYWORD, project, false));
for (JetCallableDeclaration overriddenMember : overriddenNonOverridableMembers) {
overriddenMember.addModifier(OPEN_KEYWORD);
}
}
@@ -48,7 +48,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
import org.jetbrains.jet.lang.resolve.OverrideResolver;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
@@ -69,7 +69,8 @@ public class JetRefactoringUtil {
private JetRefactoringUtil() {
}
public static JetKeywordToken getVisibilityToken(Visibility visibility) {
@NotNull
public static JetModifierKeywordToken getVisibilityToken(@NotNull Visibility visibility) {
if (visibility == Visibilities.PUBLIC) {
return JetTokens.PUBLIC_KEYWORD;
}
@@ -21,10 +21,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.quickfix.AddModifierFix;
import org.jetbrains.jet.plugin.quickfix.ChangeVisibilityModifierFix;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeInfo;
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo;
@@ -66,22 +63,26 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo<PsiElement> {
}
}
}
else
else {
parameterList = ((JetClass) element).getPrimaryConstructorParameterList();
}
if (changeInfo.isParameterSetOrOrderChanged()) {
String parametersText = changeInfo.getNewParametersSignature(element, isInherited, 0);
JetParameterList newParameterList = psiFactory.createParameterList(parametersText);
if (parameterList != null)
parameterList = (JetParameterList) parameterList.replace(newParameterList);
if (parameterList != null) {
parameterList.replace(newParameterList);
}
else if (element instanceof JetClass) {
PsiElement anchor = ((JetClass) element).getTypeParameterList();
if (anchor == null)
if (anchor == null) {
anchor = ((JetClass) element).getNameIdentifier();
if (anchor != null)
parameterList = (JetParameterList) element.addAfter(newParameterList, anchor);
}
if (anchor != null) {
element.addAfter(newParameterList, anchor);
}
}
}
else if (parameterList != null) {
@@ -93,27 +94,21 @@ public class JetFunctionDefinitionUsage extends JetUsageInfo<PsiElement> {
}
}
if (changeInfo.isVisibilityChanged())
changeVisibility(changeInfo, element, parameterList);
if (changeInfo.isVisibilityChanged() && !JetPsiUtil.isLocal((JetDeclaration) element)) {
changeVisibility(changeInfo, element);
}
return true;
}
private void changeVisibility(JetChangeInfo changeInfo, PsiElement element, JetParameterList parameterList) {
JetKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility());
private static void changeVisibility(JetChangeInfo changeInfo, PsiElement element) {
JetModifierKeywordToken newVisibilityToken = JetRefactoringUtil.getVisibilityToken(changeInfo.getNewVisibility());
JetPsiFactory psiFactory = JetPsiFactory(getProject());
if (element instanceof JetFunction) {
JetModifierList modifierList = newVisibilityToken == JetTokens.INTERNAL_KEYWORD ? null :
psiFactory.createModifierList(newVisibilityToken);
AddModifierFix.changeModifier(element, ((JetFunction) element).getModifierList(), null,
ChangeVisibilityModifierFix.VISIBILITY_TOKENS, getProject(), true, modifierList);
((JetFunction)element).addModifier(newVisibilityToken);
}
else {
JetModifierList modifierList = newVisibilityToken == JetTokens.PUBLIC_KEYWORD ? null :
psiFactory.createConstructorModifierList(newVisibilityToken);
AddModifierFix.changeModifier(element, ((JetClass) element).getPrimaryConstructorModifierList(), parameterList,
ChangeVisibilityModifierFix.VISIBILITY_TOKENS, getProject(), true, modifierList);
((JetClass)element).addPrimaryConstructorModifier(newVisibilityToken);
}
}
@@ -0,0 +1,4 @@
// "Make 'A' abstract" "true"
public abstract class A() {
<caret>abstract var i : Int
}
@@ -0,0 +1,4 @@
// "Make 'A' abstract" "true"
public class A() {
<caret>abstract var i : Int
}
@@ -0,0 +1,4 @@
// "Make 'A' open" "true"
public open class A() {
<caret>open fun foo() {}
}
@@ -0,0 +1,4 @@
// "Make 'A' open" "true"
deprecated("") open class A() {
<caret>open fun foo() {}
}
@@ -0,0 +1,4 @@
// "Make 'A' open" "true"
public class A() {
<caret>open fun foo() {}
}
@@ -0,0 +1,4 @@
// "Make 'A' open" "true"
deprecated("") class A() {
<caret>open fun foo() {}
}
@@ -79,6 +79,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeAbstractPropertyInNonAbstractClass3.kt")
public void testAbstractPropertyInNonAbstractClass3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/abstract/beforeAbstractPropertyInNonAbstractClass3.kt");
doTest(fileName);
}
@TestMetadata("beforeAbstractPropertyInPrimaryConstructorParameters.kt")
public void testAbstractPropertyInPrimaryConstructorParameters() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/abstract/beforeAbstractPropertyInPrimaryConstructorParameters.kt");
@@ -1768,6 +1774,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("beforeOpenMemberInFinalClass3.kt")
public void testOpenMemberInFinalClass3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/beforeOpenMemberInFinalClass3.kt");
doTest(fileName);
}
@TestMetadata("beforeOpenMemberInFinalClass4.kt")
public void testOpenMemberInFinalClass4() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/beforeOpenMemberInFinalClass4.kt");
doTest(fileName);
}
@TestMetadata("beforeOpenModifierInEnum.kt")
public void testOpenModifierInEnum() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/beforeOpenModifierInEnum.kt");