Fixed "Make class open" in case of primary constructor

#KT-9767 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-10-27 19:36:13 +03:00
parent fc924d1c9f
commit 3c1538997e
25 changed files with 45 additions and 126 deletions
@@ -20,16 +20,18 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiNameIdentifierOwner
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.ABSTRACT_KEYWORD
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
open class AddModifierFix(
element: KtModifierListOwner,
@@ -85,4 +87,17 @@ open class AddModifierFix(
}
}
}
object MakeClassOpenFactory : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val typeReference = diagnostic.psiElement as KtTypeReference
val bindingContext = typeReference.analyze(BodyResolveMode.PARTIAL)
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return null
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(classDescriptor) as? KtClass ?: return null
if (!QuickFixUtil.canModifyElement(declaration)) return null
if (declaration.isEnum()) return null
return AddModifierFix(declaration, KtTokens.OPEN_KEYWORD)
}
}
}
@@ -1,95 +0,0 @@
/*
* Copyright 2010-2015 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.quickfix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
import org.jetbrains.kotlin.idea.references.ReferenceUtilKt;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
public class AddOpenModifierToClassDeclarationFix extends KotlinQuickFixAction<KtTypeReference> {
private KtClass classDeclaration;
public AddOpenModifierToClassDeclarationFix(@NotNull KtTypeReference typeReference) {
super(typeReference);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!super.isAvailable(project, editor, file)) {
return false;
}
KtSimpleNameExpression referenceExpression = PsiTreeUtil.findChildOfType(getElement(), KtSimpleNameExpression.class);
if (referenceExpression == null) {
return false;
}
PsiReference reference = ReferenceUtilKt.getMainReference(referenceExpression);
PsiElement target = reference.resolve();
if (target instanceof KtSecondaryConstructor) {
target = ((KtSecondaryConstructor) target).getContainingClassOrObject();
}
if (target instanceof KtClass && QuickFixUtil.canModifyElement(target)) {
classDeclaration = (KtClass) target;
return !(classDeclaration.isEnum() || classDeclaration.isInterface());
}
return false;
}
@NotNull
@Override
public String getText() {
return JetBundle.message("make.element.modifier", classDeclaration != null ? classDeclaration.getName() : "<unknown>", "open");
}
@NotNull
@Override
public String getFamilyName() {
return JetBundle.message("add.modifier.family");
}
@Override
public void invoke(@NotNull Project project, Editor editor, KtFile file) throws IncorrectOperationException {
classDeclaration.addModifier(KtTokens.OPEN_KEYWORD);
}
@NotNull
public static JetSingleIntentionActionFactory createFactory() {
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
KtTypeReference typeReference = QuickFixUtil.getParentElementOfType(diagnostic, KtTypeReference.class);
return typeReference == null ? null : new AddOpenModifierToClassDeclarationFix(typeReference);
}
};
}
}
@@ -195,9 +195,8 @@ public class QuickFixRegistrar : QuickFixContributor {
INACCESSIBLE_OUTER_CLASS_EXPRESSION.registerFactory(AddModifierFix.createFactory(INNER_KEYWORD, javaClass<KtClass>()))
val addOpenModifierToClassDeclarationFix = AddOpenModifierToClassDeclarationFix.createFactory()
FINAL_SUPERTYPE.registerFactory(addOpenModifierToClassDeclarationFix)
FINAL_UPPER_BOUND.registerFactory(addOpenModifierToClassDeclarationFix)
FINAL_SUPERTYPE.registerFactory(AddModifierFix.MakeClassOpenFactory)
FINAL_UPPER_BOUND.registerFactory(AddModifierFix.MakeClassOpenFactory)
OVERRIDING_FINAL_MEMBER.registerFactory(MakeOverriddenMemberOpenFix)
@@ -1,4 +1,4 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
// ERROR: This type is final, so it cannot be inherited from
// ERROR: Cannot access '<init>': it is 'private' in 'E'
enum class E {}
@@ -1,3 +1,3 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
enum class E {}
class A<T : E<caret>> {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
final class A {}
class B : A<caret>() {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
open class A {}
class B : A<caret>() {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
final class A {}
class B<T : A<caret>> {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
open class A {}
class B<T : A<caret>> {}
@@ -1,4 +1,4 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
// ERROR: This type is final, so it cannot be inherited from
// ACTION: Create test
import testPackage.*
@@ -1,4 +1,4 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
import testPackage.*
class foo<T : JavaClass>() {}
@@ -1,3 +1,3 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
// ERROR: This type is final, so it cannot be inherited from
class A : String<caret>() {}
@@ -1,2 +1,2 @@
// "class org.jetbrains.kotlin.idea.quickfix.AddOpenModifierToClassDeclarationFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.AddModifierFix" "false"
class A<T : String<caret>> {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
class A {}
class B : A<caret>() {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
open class A {}
class B : A<caret>() {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
final class A {}
class B<T : A<caret>> {}
@@ -1,3 +1,3 @@
// "Make A open" "true"
// "Make 'A' open" "true"
open class A {}
class B<T : A<caret>> {}
@@ -1,4 +1,4 @@
// "Make A open" "true"
// "Make 'A' open" "true"
interface X {}
interface Y {}
@@ -1,4 +1,4 @@
// "Make A open" "true"
// "Make 'A' open" "true"
interface X {}
interface Y {}
@@ -1,4 +1,4 @@
// "Make B open" "true"
// "Make 'B' open" "true"
class B {
constructor() {
}
@@ -1,4 +1,4 @@
// "Make B open" "true"
// "Make 'B' open" "true"
open class B {
constructor() {
}
@@ -1,4 +1,4 @@
// "Make B open" "true"
// "Make 'B' open" "true"
class B {
constructor() {
}
@@ -1,4 +1,4 @@
// "Make B open" "true"
// "Make 'B' open" "true"
open class B {
constructor() {
}
@@ -1,4 +1,4 @@
// "Make A open" "true"
// "Make 'A' open" "true"
class A(val v: Int)
class B : A<caret>()
class B : A<caret>(1)
@@ -1,4 +1,4 @@
// "Make A open" "true"
// "Make 'A' open" "true"
open class A(val v: Int)
class B : A<caret>()
class B : A<caret>(1)