diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyAction.java b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyAction.java index 620ab64a8df..21c8993a367 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyAction.java +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyAction.java @@ -14,205 +14,178 @@ * limitations under the License. */ -package org.jetbrains.kotlin.idea.intentions; +package org.jetbrains.kotlin.idea.intentions -import com.google.common.collect.Lists; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; -import com.intellij.codeInsight.template.*; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; -import org.jetbrains.kotlin.diagnostics.Diagnostic; -import org.jetbrains.kotlin.diagnostics.Errors; -import org.jetbrains.kotlin.idea.JetBundle; -import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers; -import org.jetbrains.kotlin.idea.util.ShortenReferences; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.DescriptorUtils; -import org.jetbrains.kotlin.types.ErrorUtils; -import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.TypeUtils; +import com.google.common.collect.Lists +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction +import com.intellij.codeInsight.template.* +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.idea.JetBundle +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeUtils +import java.util.ArrayList -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory; - -public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction { - @NotNull - @Override - public String getFamilyName() { - return JetBundle.message("specify.type.explicitly.action.family.name"); +public class SpecifyTypeExplicitlyAction : PsiElementBaseIntentionAction() { + override fun getFamilyName(): String { + return JetBundle.message("specify.type.explicitly.action.family.name") } - @Override - public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) { - JetTypeReference typeRefParent = PsiTreeUtil.getTopmostParentOfType(element, JetTypeReference.class); + override fun invoke(project: Project, editor: Editor, element: PsiElement) { + var element = element + val typeRefParent = PsiTreeUtil.getTopmostParentOfType(element, javaClass()) if (typeRefParent != null) { - element = typeRefParent; + element = typeRefParent } - JetCallableDeclaration declaration = (JetCallableDeclaration)element.getParent(); - JetType type = getTypeForDeclaration(declaration); + val declaration = element.getParent() as JetCallableDeclaration + val type = getTypeForDeclaration(declaration) if (declaration.getTypeReference() == null) { - addTypeAnnotation(project, editor, declaration, type); + addTypeAnnotation(project, editor, declaration, type) } else { - declaration.setTypeReference(null); + declaration.setTypeReference(null) } } - @Override - public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) { - if (element.getContainingFile() instanceof JetCodeFragment) { - return false; + override fun isAvailable(project: Project, editor: Editor, element: PsiElement): Boolean { + var element = element + if (element.getContainingFile() is JetCodeFragment) { + return false } - JetTypeReference typeRefParent = PsiTreeUtil.getTopmostParentOfType(element, JetTypeReference.class); + val typeRefParent = PsiTreeUtil.getTopmostParentOfType(element, javaClass()) if (typeRefParent != null) { - element = typeRefParent; + element = typeRefParent } - PsiElement parent = element.getParent(); - if (!(parent instanceof JetCallableDeclaration)) return false; - JetCallableDeclaration declaration = (JetCallableDeclaration) parent; + val parent = element.getParent() + if (parent !is JetCallableDeclaration) return false - if (declaration instanceof JetProperty && !PsiTreeUtil.isAncestor(((JetProperty) declaration).getInitializer(), element, false)) { - if (declaration.getTypeReference() != null) { - setText(JetBundle.message("specify.type.explicitly.remove.action.name")); - return true; + if (parent is JetProperty && !PsiTreeUtil.isAncestor(parent.getInitializer(), element, false)) { + if (parent.getTypeReference() != null) { + setText(JetBundle.message("specify.type.explicitly.remove.action.name")) + return true } else { - setText(JetBundle.message("specify.type.explicitly.add.action.name")); + setText(JetBundle.message("specify.type.explicitly.add.action.name")) } } - else if (declaration instanceof JetNamedFunction && declaration.getTypeReference() == null - && !((JetNamedFunction) declaration).hasBlockBody()) { - setText(JetBundle.message("specify.type.explicitly.add.return.type.action.name")); + else if (parent is JetNamedFunction && parent.getTypeReference() == null && !parent.hasBlockBody()) { + setText(JetBundle.message("specify.type.explicitly.add.return.type.action.name")) } - else if (declaration instanceof JetParameter && ((JetParameter) declaration).isLoopParameter()) { - if (declaration.getTypeReference() != null) { - setText(JetBundle.message("specify.type.explicitly.remove.action.name")); - return true; + else if (parent is JetParameter && parent.isLoopParameter()) { + if (parent.getTypeReference() != null) { + setText(JetBundle.message("specify.type.explicitly.remove.action.name")) + return true } else { - setText(JetBundle.message("specify.type.explicitly.add.action.name")); + setText(JetBundle.message("specify.type.explicitly.add.action.name")) } } else { - return false; + return false } - if (getTypeForDeclaration(declaration).isError()) { - return false; + if (getTypeForDeclaration(parent).isError()) { + return false } - return !hasPublicMemberDiagnostic(declaration); + return !hasPublicMemberDiagnostic(parent) } + companion object { - private static boolean hasPublicMemberDiagnostic(@NotNull JetNamedDeclaration declaration) { - BindingContext bindingContext = ResolvePackage.analyzeFully(declaration.getContainingJetFile()); - for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { - //noinspection ConstantConditions - if (Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE == diagnostic.getFactory() && declaration == diagnostic.getPsiElement()) { - return true; - } - } - return false; - } - @NotNull - public static JetType getTypeForDeclaration(@NotNull JetCallableDeclaration declaration) { - BindingContext bindingContext = ResolvePackage.analyzeFully(declaration.getContainingJetFile()); - CallableDescriptor descriptor = (CallableDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); - - JetType type = descriptor != null ? descriptor.getReturnType() : null; - return type == null ? ErrorUtils.createErrorType("null type") : type; - } - - @NotNull - public static Expression createTypeExpressionForTemplate(JetType exprType) { - ClassifierDescriptor descriptor = exprType.getConstructor().getDeclarationDescriptor(); - boolean isAnonymous = descriptor != null && DescriptorUtils.isAnonymousObject(descriptor); - - Set allSupertypes = TypeUtils.getAllSupertypes(exprType); - List types = isAnonymous ? new ArrayList() : Lists.newArrayList(exprType); - types.addAll(allSupertypes); - - return new JetTypeLookupExpression( - types, - types.iterator().next(), - JetBundle.message("specify.type.explicitly.add.action.name") - ) { - @Override - protected String getLookupString(JetType element) { - return IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(element); - } - - @Override - protected String getResult(JetType element) { - return IdeDescriptorRenderers.SOURCE_CODE.renderType(element); - } - }; - } - - public static void addTypeAnnotation(Project project, @Nullable Editor editor, @NotNull JetCallableDeclaration declaration, @NotNull JetType exprType) { - if (editor != null) { - addTypeAnnotationWithTemplate(project, editor, declaration, exprType); - } - else { - declaration.setTypeReference(anyTypeRef(project)); - } - } - - public static TemplateEditingAdapter createTypeReferencePostprocessor(final JetCallableDeclaration declaration) { - return new TemplateEditingAdapter() { - @Override - public void templateFinished(Template template, boolean brokenOff) { - JetTypeReference typeRef = declaration.getTypeReference(); - if (typeRef != null && typeRef.isValid()) { - ShortenReferences.DEFAULT.process(typeRef); + private fun hasPublicMemberDiagnostic(declaration: JetNamedDeclaration): Boolean { + val bindingContext = declaration.getContainingJetFile().analyzeFully() + for (diagnostic in bindingContext.getDiagnostics()) { + //noinspection ConstantConditions + if (Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE == diagnostic.getFactory() && declaration == diagnostic.getPsiElement()) { + return true } } - }; - } + return false + } - private static void addTypeAnnotationWithTemplate( - @NotNull Project project, - @NotNull Editor editor, - @NotNull JetCallableDeclaration declaration, - @NotNull JetType exprType - ) { - assert !exprType.isError() : "Unexpected error type, should have been checked before: " - + PsiUtilPackage.getElementTextWithContext(declaration) + ", type = " + exprType; + public fun getTypeForDeclaration(declaration: JetCallableDeclaration): JetType { + val bindingContext = declaration.getContainingJetFile().analyzeFully() - Expression expression = createTypeExpressionForTemplate(exprType); + val type = if (bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration) != null) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration).getReturnType() else null + return type ?: ErrorUtils.createErrorType("null type") + } - declaration.setTypeReference(anyTypeRef(project)); + public fun createTypeExpressionForTemplate(exprType: JetType): Expression { + val descriptor = exprType.getConstructor().getDeclarationDescriptor() + val isAnonymous = descriptor != null && DescriptorUtils.isAnonymousObject(descriptor) - PsiDocumentManager.getInstance(project).commitAllDocuments(); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + val allSupertypes = TypeUtils.getAllSupertypes(exprType) + val types = if (isAnonymous) ArrayList() else Lists.newArrayList(exprType) + types.addAll(allSupertypes) - JetTypeReference newTypeRef = declaration.getTypeReference(); - assert newTypeRef != null; - TemplateBuilderImpl builder = new TemplateBuilderImpl(newTypeRef); - builder.replaceElement(newTypeRef, expression); + return object : JetTypeLookupExpression(types, types.iterator().next(), JetBundle.message("specify.type.explicitly.add.action.name")) { + override fun getLookupString(element: JetType): String { + return IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(element) + } - editor.getCaretModel().moveToOffset(newTypeRef.getNode().getStartOffset()); + override fun getResult(element: JetType): String { + return IdeDescriptorRenderers.SOURCE_CODE.renderType(element) + } + } + } - TemplateManager.getInstance(project) - .startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration)); - } + public fun addTypeAnnotation(project: Project, editor: Editor?, declaration: JetCallableDeclaration, exprType: JetType) { + if (editor != null) { + addTypeAnnotationWithTemplate(project, editor, declaration, exprType) + } + else { + declaration.setTypeReference(anyTypeRef(project)) + } + } - private static JetTypeReference anyTypeRef(@NotNull Project project) { - return JetPsiFactory(project).createType("Any"); + public fun createTypeReferencePostprocessor(declaration: JetCallableDeclaration): TemplateEditingAdapter { + return object : TemplateEditingAdapter() { + override fun templateFinished(template: Template?, brokenOff: Boolean) { + val typeRef = declaration.getTypeReference() + if (typeRef != null && typeRef.isValid()) { + ShortenReferences.DEFAULT.process(typeRef) + } + } + } + } + + private fun addTypeAnnotationWithTemplate(project: Project, editor: Editor, declaration: JetCallableDeclaration, exprType: JetType) { + assert(!exprType.isError()) { "Unexpected error type, should have been checked before: " + declaration.getElementTextWithContext() + ", type = " + exprType } + + val expression = createTypeExpressionForTemplate(exprType) + + declaration.setTypeReference(anyTypeRef(project)) + + PsiDocumentManager.getInstance(project).commitAllDocuments() + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()) + + val newTypeRef = declaration.getTypeReference() + assert(newTypeRef != null) + val builder = TemplateBuilderImpl(newTypeRef) + builder.replaceElement(newTypeRef, expression) + + editor.getCaretModel().moveToOffset(newTypeRef!!.getNode().getStartOffset()) + + TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration)) + } + + private fun anyTypeRef(project: Project): JetTypeReference { + return JetPsiFactory(project).createType("Any") + } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePartsFromPropertyFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePartsFromPropertyFix.java index e2a91c8ab41..a3e72ac8b84 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePartsFromPropertyFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePartsFromPropertyFix.java @@ -116,7 +116,7 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction } element = (JetProperty) element.replace(newElement); if (typeToAdd != null) { - SpecifyTypeExplicitlyAction.addTypeAnnotation(project, editor, element, typeToAdd); + SpecifyTypeExplicitlyAction.Companion.addTypeAnnotation(project, editor, element, typeToAdd); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/SpecifyTypeExplicitlyFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/SpecifyTypeExplicitlyFix.java index 830d443c71f..3fcd784a2f1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/SpecifyTypeExplicitlyFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/SpecifyTypeExplicitlyFix.java @@ -23,14 +23,12 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.JetBundle; +import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyAction; import org.jetbrains.kotlin.psi.JetCallableDeclaration; import org.jetbrains.kotlin.psi.JetNamedFunction; import org.jetbrains.kotlin.psi.JetProperty; import org.jetbrains.kotlin.types.JetType; -import static org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyAction.addTypeAnnotation; -import static org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyAction.getTypeForDeclaration; - @SuppressWarnings("IntentionDescriptionNotFoundInspection") public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { @NotNull @@ -43,8 +41,8 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) { //noinspection unchecked JetCallableDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetProperty.class, JetNamedFunction.class); - JetType type = getTypeForDeclaration(declaration); - addTypeAnnotation(project, editor, declaration, type); + JetType type = SpecifyTypeExplicitlyAction.Companion.getTypeForDeclaration(declaration); + SpecifyTypeExplicitlyAction.Companion.addTypeAnnotation(project, editor, declaration, type); } @Override @@ -61,6 +59,6 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { return false; } - return !getTypeForDeclaration(declaration).isError(); + return !SpecifyTypeExplicitlyAction.Companion.getTypeForDeclaration(declaration).isError(); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinInplaceVariableIntroducer.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinInplaceVariableIntroducer.java index 576592bf74d..e38f9721e7f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinInplaceVariableIntroducer.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinInplaceVariableIntroducer.java @@ -356,7 +356,7 @@ public class KotlinInplaceVariableIntroducer e if (typeReference != null) { builder.replaceElement(typeReference, TYPE_REFERENCE_VARIABLE_NAME, - SpecifyTypeExplicitlyAction.createTypeExpressionForTemplate(myExprType), + SpecifyTypeExplicitlyAction.Companion.createTypeExpressionForTemplate(myExprType), false); } } @@ -381,7 +381,7 @@ public class KotlinInplaceVariableIntroducer e TemplateState templateState = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor)); if (templateState != null && myDeclaration.getTypeReference() != null) { - templateState.addTemplateStateListener(SpecifyTypeExplicitlyAction.createTypeReferencePostprocessor(myDeclaration)); + templateState.addTemplateStateListener(SpecifyTypeExplicitlyAction.Companion.createTypeReferencePostprocessor(myDeclaration)); } return result;