Converted to Kotlin + no i18n
This commit is contained in:
@@ -161,10 +161,6 @@ move.when.else.branch.to.the.end.action=Move else branch to the end
|
||||
move.when.else.branch.to.the.end.family.name=Move Else Branch to the End
|
||||
change.to.property.name.family.name=Change to property name
|
||||
change.to.property.name.action=Change ''{0}'' to ''{1}''
|
||||
map.platform.class.to.kotlin=Change all usages of ''{0}'' in this file to ''{1}''
|
||||
map.platform.class.to.kotlin.multiple=Change all usages of ''{0}'' in this file to a Kotlin class
|
||||
map.platform.class.to.kotlin.advertisement=Choose an appropriate Kotlin class
|
||||
map.platform.class.to.kotlin.family=Change to Kotlin class
|
||||
create.from.usage.family=Create from usage
|
||||
create.local.variable.from.usage=Create local variable ''{0}''
|
||||
create.parameter.from.usage=Create parameter ''{0}''
|
||||
|
||||
@@ -1,224 +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.codeInsight.template.*;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
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.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.rename.inplace.MyLookupExpression;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters1;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.idea.JetBundle;
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class MapPlatformClassToKotlinFix extends KotlinQuickFixAction<JetReferenceExpression> {
|
||||
private static final String PRIMARY_USAGE = "PrimaryUsage";
|
||||
private static final String OTHER_USAGE = "OtherUsage";
|
||||
|
||||
private final ClassDescriptor platformClass;
|
||||
private final Collection<ClassDescriptor> possibleClasses;
|
||||
|
||||
public MapPlatformClassToKotlinFix(@NotNull JetReferenceExpression element, @NotNull ClassDescriptor platformClass,
|
||||
@NotNull Collection<ClassDescriptor> possibleClasses) {
|
||||
super(element);
|
||||
this.platformClass = platformClass;
|
||||
this.possibleClasses = possibleClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
String platformClassQualifiedName = DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(platformClass.getDefaultType());
|
||||
return possibleClasses.size() == 1
|
||||
? JetBundle.message("map.platform.class.to.kotlin", platformClassQualifiedName,
|
||||
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(possibleClasses.iterator().next().getDefaultType()))
|
||||
: JetBundle.message("map.platform.class.to.kotlin.multiple", platformClassQualifiedName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return JetBundle.message("map.platform.class.to.kotlin.family");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
|
||||
BindingContext context = ResolutionUtils.analyzeFully(file);
|
||||
Iterable<Diagnostic> diagnostics = context.getDiagnostics();
|
||||
List<JetImportDirective> imports = new ArrayList<JetImportDirective>();
|
||||
List<JetUserType> usages = new ArrayList<JetUserType>();
|
||||
|
||||
for (Diagnostic diagnostic : diagnostics) {
|
||||
if (diagnostic.getFactory() != Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN) continue;
|
||||
JetReferenceExpression refExpr = getImportOrUsageFromDiagnostic(diagnostic);
|
||||
if (refExpr == null) continue;
|
||||
ClassDescriptor descriptor = resolveToClass(refExpr, context);
|
||||
if (descriptor == null || !(descriptor.equals(platformClass))) continue;
|
||||
JetImportDirective imp = PsiTreeUtil.getParentOfType(refExpr, JetImportDirective.class);
|
||||
if (imp == null) {
|
||||
JetUserType type = PsiTreeUtil.getParentOfType(refExpr, JetUserType.class);
|
||||
if (type == null) continue;
|
||||
usages.add(type);
|
||||
}
|
||||
else {
|
||||
imports.add(imp);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetImportDirective imp : imports) {
|
||||
imp.delete();
|
||||
}
|
||||
|
||||
if (usages.isEmpty()) { // if we are not going to replace any usages, there's no reason to continue at all
|
||||
return;
|
||||
}
|
||||
|
||||
List<PsiElement> replacedElements = replaceUsagesWithFirstClass(project, usages);
|
||||
|
||||
if (possibleClasses.size() > 1) {
|
||||
LinkedHashSet<String> possibleTypes = new LinkedHashSet<String>();
|
||||
for (ClassDescriptor klass : possibleClasses) {
|
||||
possibleTypes.add(klass.getName().asString());
|
||||
}
|
||||
buildAndShowTemplate(project, editor, file, replacedElements, possibleTypes);
|
||||
}
|
||||
}
|
||||
|
||||
private List<PsiElement> replaceUsagesWithFirstClass(Project project, List<JetUserType> usages) {
|
||||
ClassDescriptor replacementClass = possibleClasses.iterator().next();
|
||||
String replacementClassName = replacementClass.getName().asString();
|
||||
List<PsiElement> replacedElements = new ArrayList<PsiElement>();
|
||||
for (JetUserType usage : usages) {
|
||||
JetTypeArgumentList typeArguments = usage.getTypeArgumentList();
|
||||
String typeArgumentsString = typeArguments == null ? "" : typeArguments.getText();
|
||||
JetTypeReference replacementType = JetPsiFactoryKt.JetPsiFactory(project).createType(replacementClassName + typeArgumentsString);
|
||||
JetTypeElement replacementTypeElement = replacementType.getTypeElement();
|
||||
assert replacementTypeElement != null;
|
||||
PsiElement replacedElement = usage.replace(replacementTypeElement);
|
||||
PsiElement replacedExpression = replacedElement.getFirstChild();
|
||||
assert replacedExpression instanceof JetSimpleNameExpression; // assumption: the Kotlin class requires no imports
|
||||
replacedElements.add(replacedExpression);
|
||||
}
|
||||
return replacedElements;
|
||||
}
|
||||
|
||||
private static void buildAndShowTemplate(
|
||||
Project project, Editor editor, PsiFile file,
|
||||
Collection<PsiElement> replacedElements, LinkedHashSet<String> options
|
||||
) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
|
||||
|
||||
PsiElement primaryReplacedExpression = replacedElements.iterator().next();
|
||||
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
final int oldOffset = caretModel.getOffset();
|
||||
caretModel.moveToOffset(file.getNode().getStartOffset());
|
||||
|
||||
TemplateBuilderImpl builder = new TemplateBuilderImpl(file);
|
||||
Expression expression = new MyLookupExpression(primaryReplacedExpression.getText(), options, null, null, false,
|
||||
JetBundle.message("map.platform.class.to.kotlin.advertisement"));
|
||||
|
||||
builder.replaceElement(primaryReplacedExpression, PRIMARY_USAGE, expression, true);
|
||||
for (PsiElement replacedExpression : replacedElements) {
|
||||
if (replacedExpression == primaryReplacedExpression) continue;
|
||||
builder.replaceElement(replacedExpression, OTHER_USAGE, PRIMARY_USAGE, false);
|
||||
}
|
||||
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), new TemplateEditingAdapter() {
|
||||
@Override
|
||||
public void templateFinished(Template template, boolean brokenOff) {
|
||||
caretModel.moveToOffset(oldOffset);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static JetReferenceExpression getImportOrUsageFromDiagnostic(@NotNull Diagnostic diagnostic) {
|
||||
JetImportDirective imp = QuickFixUtil.getParentElementOfType(diagnostic, JetImportDirective.class);
|
||||
JetReferenceExpression typeExpr;
|
||||
if (imp == null) {
|
||||
JetUserType type = QuickFixUtil.getParentElementOfType(diagnostic, JetUserType.class);
|
||||
if (type == null) return null;
|
||||
typeExpr = type.getReferenceExpression();
|
||||
} else {
|
||||
JetExpression importRef = imp.getImportedReference();
|
||||
if (importRef == null || !(importRef instanceof JetDotQualifiedExpression)) return null;
|
||||
JetExpression refExpr = ((JetDotQualifiedExpression) importRef).getSelectorExpression();
|
||||
if (refExpr == null || !(refExpr instanceof JetReferenceExpression)) return null;
|
||||
typeExpr = (JetReferenceExpression) refExpr;
|
||||
}
|
||||
return typeExpr;
|
||||
}
|
||||
|
||||
public static JetSingleIntentionActionFactory createFactory() {
|
||||
return new JetSingleIntentionActionFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
||||
JetReferenceExpression typeExpr = getImportOrUsageFromDiagnostic(diagnostic);
|
||||
if (typeExpr == null) return null;
|
||||
|
||||
BindingContext context = ResolutionUtils.analyze(typeExpr);
|
||||
ClassDescriptor platformClass = resolveToClass(typeExpr, context);
|
||||
if (platformClass == null) return null;
|
||||
|
||||
DiagnosticWithParameters1<JetElement, Collection<ClassDescriptor>> parametrizedDiagnostic =
|
||||
Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic);
|
||||
|
||||
return new MapPlatformClassToKotlinFix(typeExpr, platformClass, parametrizedDiagnostic.getA());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClassDescriptor resolveToClass(@NotNull JetReferenceExpression referenceExpression, @NotNull BindingContext context) {
|
||||
DeclarationDescriptor descriptor = context.get(BindingContext.REFERENCE_TARGET, referenceExpression);
|
||||
Collection<? extends DeclarationDescriptor> ambiguousTargets =
|
||||
context.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression);
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return (ClassDescriptor) descriptor;
|
||||
}
|
||||
else if (ambiguousTargets != null) {
|
||||
for (DeclarationDescriptor target : ambiguousTargets) {
|
||||
if (target instanceof ClassDescriptor) {
|
||||
return (ClassDescriptor) target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.codeInsight.template.Template
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.TemplateEditingAdapter
|
||||
import com.intellij.codeInsight.template.TemplateManager
|
||||
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.PsiFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.rename.inplace.MyLookupExpression
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import java.util.*
|
||||
|
||||
class MapPlatformClassToKotlinFix(
|
||||
element: JetReferenceExpression,
|
||||
private val platformClass: ClassDescriptor,
|
||||
private val possibleClasses: Collection<ClassDescriptor>
|
||||
) : KotlinQuickFixAction<JetReferenceExpression>(element) {
|
||||
|
||||
override fun getText(): String {
|
||||
val platformClassQualifiedName = DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(platformClass.defaultType)
|
||||
val singleClass = possibleClasses.singleOrNull()
|
||||
return if (singleClass != null)
|
||||
"Change all usages of '$platformClassQualifiedName' in this file to '${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(singleClass.defaultType)}'"
|
||||
else
|
||||
"Change all usages of '$platformClassQualifiedName' in this file to a Kotlin class"
|
||||
}
|
||||
|
||||
override fun getFamilyName() = "Change to Kotlin class"
|
||||
|
||||
public override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val context = file.analyzeFully()
|
||||
val diagnostics = context.diagnostics
|
||||
val imports = ArrayList<JetImportDirective>()
|
||||
val usages = ArrayList<JetUserType>()
|
||||
|
||||
for (diagnostic in diagnostics) {
|
||||
if (diagnostic.factory !== Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN) continue
|
||||
val refExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: continue
|
||||
val descriptor = resolveToClass(refExpr, context)
|
||||
if (descriptor == null || descriptor != platformClass) continue
|
||||
val imp = PsiTreeUtil.getParentOfType(refExpr, JetImportDirective::class.java)
|
||||
if (imp == null) {
|
||||
val type = PsiTreeUtil.getParentOfType(refExpr, JetUserType::class.java) ?: continue
|
||||
usages.add(type)
|
||||
} else {
|
||||
imports.add(imp)
|
||||
}
|
||||
}
|
||||
|
||||
for (imp in imports) {
|
||||
imp.delete()
|
||||
}
|
||||
|
||||
if (usages.isEmpty()) {
|
||||
// if we are not going to replace any usages, there's no reason to continue at all
|
||||
return
|
||||
}
|
||||
|
||||
val replacedElements = replaceUsagesWithFirstClass(project, usages)
|
||||
|
||||
if (possibleClasses.size > 1 && editor != null) {
|
||||
val possibleTypes = LinkedHashSet<String>()
|
||||
for (klass in possibleClasses) {
|
||||
possibleTypes.add(klass.name.asString())
|
||||
}
|
||||
buildAndShowTemplate(project, editor, file, replacedElements, possibleTypes)
|
||||
}
|
||||
}
|
||||
|
||||
private fun replaceUsagesWithFirstClass(project: Project, usages: List<JetUserType>): List<PsiElement> {
|
||||
val replacementClass = possibleClasses.iterator().next()
|
||||
val replacementClassName = replacementClass.name.asString()
|
||||
val replacedElements = ArrayList<PsiElement>()
|
||||
for (usage in usages) {
|
||||
val typeArguments = usage.typeArgumentList
|
||||
val typeArgumentsString = if (typeArguments == null) "" else typeArguments.text
|
||||
val replacementType = JetPsiFactory(project).createType(replacementClassName + typeArgumentsString)
|
||||
val replacementTypeElement = replacementType.typeElement!!
|
||||
val replacedElement = usage.replace(replacementTypeElement)
|
||||
val replacedExpression = replacedElement.firstChild
|
||||
assert(replacedExpression is JetSimpleNameExpression) // assumption: the Kotlin class requires no imports
|
||||
replacedElements.add(replacedExpression)
|
||||
}
|
||||
return replacedElements
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PRIMARY_USAGE = "PrimaryUsage"
|
||||
private val OTHER_USAGE = "OtherUsage"
|
||||
|
||||
private fun buildAndShowTemplate(
|
||||
project: Project, editor: Editor, file: PsiFile,
|
||||
replacedElements: Collection<PsiElement>, options: LinkedHashSet<String>) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||
|
||||
val primaryReplacedExpression = replacedElements.iterator().next()
|
||||
|
||||
val caretModel = editor.caretModel
|
||||
val oldOffset = caretModel.offset
|
||||
caretModel.moveToOffset(file.node.startOffset)
|
||||
|
||||
val builder = TemplateBuilderImpl(file)
|
||||
val expression = MyLookupExpression(primaryReplacedExpression.text, options, null, null, false, "Choose an appropriate Kotlin class")
|
||||
|
||||
builder.replaceElement(primaryReplacedExpression, PRIMARY_USAGE, expression, true)
|
||||
for (replacedExpression in replacedElements) {
|
||||
if (replacedExpression === primaryReplacedExpression) continue
|
||||
builder.replaceElement(replacedExpression, OTHER_USAGE, PRIMARY_USAGE, false)
|
||||
}
|
||||
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object : TemplateEditingAdapter() {
|
||||
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||
caretModel.moveToOffset(oldOffset)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getImportOrUsageFromDiagnostic(diagnostic: Diagnostic): JetReferenceExpression? {
|
||||
val imp = QuickFixUtil.getParentElementOfType(diagnostic, JetImportDirective::class.java)
|
||||
val typeExpr: JetReferenceExpression?
|
||||
if (imp == null) {
|
||||
val type = QuickFixUtil.getParentElementOfType(diagnostic, JetUserType::class.java) ?: return null
|
||||
typeExpr = type.referenceExpression
|
||||
} else {
|
||||
val importRef = imp.importedReference
|
||||
if (importRef == null || importRef !is JetDotQualifiedExpression) return null
|
||||
val refExpr = (importRef as JetDotQualifiedExpression?)?.getSelectorExpression()
|
||||
if (refExpr == null || refExpr !is JetReferenceExpression) return null
|
||||
typeExpr = refExpr
|
||||
}
|
||||
return typeExpr
|
||||
}
|
||||
|
||||
fun createFactory(): JetSingleIntentionActionFactory {
|
||||
return object : JetSingleIntentionActionFactory() {
|
||||
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val typeExpr = getImportOrUsageFromDiagnostic(diagnostic) ?: return null
|
||||
|
||||
val context = typeExpr.analyze()
|
||||
val platformClass = resolveToClass(typeExpr, context) ?: return null
|
||||
|
||||
val parametrizedDiagnostic = Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN.cast(diagnostic)
|
||||
|
||||
return MapPlatformClassToKotlinFix(typeExpr, platformClass, parametrizedDiagnostic.a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveToClass(referenceExpression: JetReferenceExpression, context: BindingContext): ClassDescriptor? {
|
||||
val descriptor = context.get(BindingContext.REFERENCE_TARGET, referenceExpression)
|
||||
val ambiguousTargets = context.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression)
|
||||
if (descriptor is ClassDescriptor) {
|
||||
return descriptor
|
||||
} else if (ambiguousTargets != null) {
|
||||
for (target in ambiguousTargets) {
|
||||
if (target is ClassDescriptor) {
|
||||
return target
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user