Converted to Kotlin (step 1)

This commit is contained in:
Valentin Kipyatkov
2015-05-05 14:37:00 +03:00
parent 7499c4bc19
commit 1251663099
4 changed files with 136 additions and 165 deletions
@@ -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<JetTypeReference>(element, javaClass<JetTypeReference>())
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<JetTypeReference>(element, javaClass<JetTypeReference>())
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<JetType> allSupertypes = TypeUtils.getAllSupertypes(exprType);
List<JetType> types = isAnonymous ? new ArrayList<JetType>() : Lists.newArrayList(exprType);
types.addAll(allSupertypes);
return new JetTypeLookupExpression<JetType>(
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<PsiElement, DeclarationDescriptor>(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration) != null) bindingContext.get<PsiElement, DeclarationDescriptor>(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<JetType>() else Lists.newArrayList<JetType>(exprType)
types.addAll(allSupertypes)
JetTypeReference newTypeRef = declaration.getTypeReference();
assert newTypeRef != null;
TemplateBuilderImpl builder = new TemplateBuilderImpl(newTypeRef);
builder.replaceElement(newTypeRef, expression);
return object : JetTypeLookupExpression<JetType>(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")
}
}
}
@@ -116,7 +116,7 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction<JetProperty>
}
element = (JetProperty) element.replace(newElement);
if (typeToAdd != null) {
SpecifyTypeExplicitlyAction.addTypeAnnotation(project, editor, element, typeToAdd);
SpecifyTypeExplicitlyAction.Companion.addTypeAnnotation(project, editor, element, typeToAdd);
}
}
@@ -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();
}
}
@@ -356,7 +356,7 @@ public class KotlinInplaceVariableIntroducer<D extends JetCallableDeclaration> 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<D extends JetCallableDeclaration> 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;