Converted to Kotlin (step 1)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user