Convert MoveDeclarationsOutHelper to Kotlin and minor improvements
This commit is contained in:
+81
-102
@@ -14,143 +14,122 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight.surroundWith;
|
||||
package org.jetbrains.kotlin.idea.codeInsight.surroundWith
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils;
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences;
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.KotlinTypeKt;
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import java.util.*
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MoveDeclarationsOutHelper {
|
||||
|
||||
public static PsiElement[] move(@NotNull PsiElement container, @NotNull PsiElement[] statements, boolean generateDefaultInitializers) {
|
||||
if (statements.length == 0) {
|
||||
return statements;
|
||||
object MoveDeclarationsOutHelper {
|
||||
fun move(container: PsiElement, statements: Array<PsiElement>, generateDefaultInitializers: Boolean): Array<PsiElement> {
|
||||
if (statements.isEmpty()) {
|
||||
return statements
|
||||
}
|
||||
|
||||
Project project = container.getProject();
|
||||
val project = container.project
|
||||
|
||||
List<PsiElement> resultStatements = new ArrayList<PsiElement>();
|
||||
List<KtProperty> propertiesDeclarations = new ArrayList<KtProperty>();
|
||||
val resultStatements = ArrayList<PsiElement>()
|
||||
val propertiesDeclarations = ArrayList<KtProperty>()
|
||||
|
||||
// Dummy element to add new declarations at the beginning
|
||||
KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(project);
|
||||
PsiElement dummyFirstStatement = container.addBefore(psiFactory.createExpression("dummyStatement"), statements[0]);
|
||||
val psiFactory = KtPsiFactory(project)
|
||||
val dummyFirstStatement = container.addBefore(psiFactory.createExpression("dummyStatement"), statements[0])
|
||||
|
||||
try {
|
||||
SearchScope scope = new LocalSearchScope(container);
|
||||
int lastStatementOffset = statements[statements.length - 1].getTextRange().getEndOffset();
|
||||
val scope = LocalSearchScope(container)
|
||||
val lastStatementOffset = statements[statements.size - 1].textRange.endOffset
|
||||
|
||||
for (PsiElement statement : statements) {
|
||||
for (statement in statements) {
|
||||
if (needToDeclareOut(statement, lastStatementOffset, scope)) {
|
||||
if (statement instanceof KtProperty && ((KtProperty) statement).getInitializer() != null) {
|
||||
KtProperty property = (KtProperty) statement;
|
||||
KtProperty declaration = createVariableDeclaration(property, generateDefaultInitializers);
|
||||
declaration = (KtProperty) container.addBefore(declaration, dummyFirstStatement);
|
||||
propertiesDeclarations.add(declaration);
|
||||
container.addAfter(psiFactory.createNewLine(), declaration);
|
||||
val property = statement as? KtProperty
|
||||
if (property?.initializer != null) {
|
||||
var declaration = createVariableDeclaration(property, generateDefaultInitializers)
|
||||
declaration = container.addBefore(declaration, dummyFirstStatement) as KtProperty
|
||||
propertiesDeclarations.add(declaration)
|
||||
container.addAfter(psiFactory.createNewLine(), declaration)
|
||||
|
||||
KtBinaryExpression assignment = createVariableAssignment(property);
|
||||
resultStatements.add(property.replace(assignment));
|
||||
val assignment = createVariableAssignment(property)
|
||||
resultStatements.add(property.replace(assignment))
|
||||
} else {
|
||||
val newStatement = container.addBefore(statement, dummyFirstStatement)
|
||||
container.addAfter(psiFactory.createNewLine(), newStatement)
|
||||
container.deleteChildRange(statement, statement)
|
||||
}
|
||||
else {
|
||||
PsiElement newStatement = container.addBefore(statement, dummyFirstStatement);
|
||||
container.addAfter(psiFactory.createNewLine(), newStatement);
|
||||
container.deleteChildRange(statement, statement);
|
||||
}
|
||||
}
|
||||
else {
|
||||
resultStatements.add(statement);
|
||||
} else {
|
||||
resultStatements.add(statement)
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
dummyFirstStatement.delete();
|
||||
} finally {
|
||||
dummyFirstStatement.delete()
|
||||
}
|
||||
|
||||
ShortenReferences.DEFAULT.process(propertiesDeclarations);
|
||||
ShortenReferences.DEFAULT.process(propertiesDeclarations)
|
||||
|
||||
return PsiUtilCore.toPsiElementArray(resultStatements);
|
||||
return PsiUtilCore.toPsiElementArray(resultStatements)
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KtBinaryExpression createVariableAssignment(@NotNull KtProperty property) {
|
||||
String propertyName = property.getName();
|
||||
assert propertyName != null : "Property should have a name " + property.getText();
|
||||
KtBinaryExpression assignment = (KtBinaryExpression) KtPsiFactoryKt
|
||||
.KtPsiFactory(property).createExpression(propertyName + " = x");
|
||||
KtExpression right = assignment.getRight();
|
||||
assert right != null : "Created binary expression should have a right part " + assignment.getText();
|
||||
KtExpression initializer = property.getInitializer();
|
||||
assert initializer != null : "Initializer should exist for property " + property.getText();
|
||||
right.replace(initializer);
|
||||
return assignment;
|
||||
private fun createVariableAssignment(property: KtProperty): KtBinaryExpression {
|
||||
val propertyName = property.name ?: error("Property should have a name " + property.text)
|
||||
val assignment = KtPsiFactory(property).createExpression("$propertyName = x") as KtBinaryExpression
|
||||
val right = assignment.right ?: error("Created binary expression should have a right part " + assignment.text)
|
||||
val initializer = property.initializer ?: error("Initializer should exist for property " + property.text)
|
||||
right.replace(initializer)
|
||||
return assignment
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KtProperty createVariableDeclaration(@NotNull KtProperty property, boolean generateDefaultInitializers) {
|
||||
KotlinType propertyType = getPropertyType(property);
|
||||
String defaultInitializer = null;
|
||||
if (generateDefaultInitializers && property.isVar()) {
|
||||
defaultInitializer = CodeInsightUtils.defaultInitializer(propertyType);
|
||||
private fun createVariableDeclaration(property: KtProperty, generateDefaultInitializers: Boolean): KtProperty {
|
||||
val propertyType = getPropertyType(property)
|
||||
var defaultInitializer: String? = null
|
||||
if (generateDefaultInitializers && property.isVar) {
|
||||
defaultInitializer = CodeInsightUtils.defaultInitializer(propertyType)
|
||||
}
|
||||
return createProperty(property, propertyType, defaultInitializer);
|
||||
return createProperty(property, propertyType, defaultInitializer)
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KotlinType getPropertyType(@NotNull KtProperty property) {
|
||||
VariableDescriptor variableDescriptor = ResolutionUtils.resolveToDescriptorIfAny(property, BodyResolveMode.PARTIAL);
|
||||
assert variableDescriptor != null : "Couldn't resolve property to property descriptor " + property.getText();
|
||||
return variableDescriptor.getType();
|
||||
private fun getPropertyType(property: KtProperty): KotlinType {
|
||||
val variableDescriptor = property.resolveToDescriptorIfAny(BodyResolveMode.PARTIAL)
|
||||
?: error("Couldn't resolve property to property descriptor " + property.text)
|
||||
return variableDescriptor.type
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KtProperty createProperty(@NotNull KtProperty property, @NotNull KotlinType propertyType, @Nullable String initializer) {
|
||||
KtTypeReference typeRef = property.getTypeReference();
|
||||
String typeString = null;
|
||||
private fun createProperty(property: KtProperty, propertyType: KotlinType, initializer: String?): KtProperty {
|
||||
val typeRef = property.typeReference
|
||||
var typeString: String? = null
|
||||
if (typeRef != null) {
|
||||
typeString = typeRef.getText();
|
||||
}
|
||||
else if (!KotlinTypeKt.isError(propertyType)) {
|
||||
typeString = IdeDescriptorRenderers.SOURCE_CODE.renderType(propertyType);
|
||||
typeString = typeRef.text
|
||||
} else if (!propertyType.isError) {
|
||||
typeString = IdeDescriptorRenderers.SOURCE_CODE.renderType(propertyType)
|
||||
}
|
||||
|
||||
return KtPsiFactoryKt.KtPsiFactory(property).createProperty(property.getName(), typeString, property.isVar(), initializer);
|
||||
return KtPsiFactory(property).createProperty(property.name!!, typeString, property.isVar, initializer)
|
||||
}
|
||||
|
||||
private static boolean needToDeclareOut(@NotNull PsiElement element, int lastStatementOffset, @NotNull SearchScope scope) {
|
||||
if (element instanceof KtProperty ||
|
||||
element instanceof KtClassOrObject ||
|
||||
element instanceof KtFunction) {
|
||||
|
||||
PsiReference[] refs = ReferencesSearch.search(element, scope, false).toArray(PsiReference.EMPTY_ARRAY);
|
||||
if (refs.length > 0) {
|
||||
PsiReference lastRef = refs[refs.length - 1];
|
||||
if (lastRef.getElement().getTextOffset() > lastStatementOffset) {
|
||||
return true;
|
||||
private fun needToDeclareOut(element: PsiElement, lastStatementOffset: Int, scope: SearchScope): Boolean {
|
||||
if (element is KtProperty ||
|
||||
element is KtClassOrObject ||
|
||||
element is KtFunction
|
||||
) {
|
||||
val refs = ReferencesSearch.search(element, scope, false).toArray(PsiReference.EMPTY_ARRAY)
|
||||
if (refs.isNotEmpty()) {
|
||||
val lastRef = refs[refs.size - 1]
|
||||
if (lastRef.element.textOffset > lastStatementOffset) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private MoveDeclarationsOutHelper() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ public class KotlinFunctionLiteralSurrounder extends KotlinStatementsSurrounder
|
||||
@Nullable
|
||||
@Override
|
||||
protected TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) {
|
||||
statements = MoveDeclarationsOutHelper.move(container, statements, true);
|
||||
statements = MoveDeclarationsOutHelper.INSTANCE.move(container, statements, true);
|
||||
|
||||
if (statements.length == 0) {
|
||||
KotlinSurrounderUtils.showErrorHint(project, editor, KotlinSurrounderUtils.SURROUND_WITH_ERROR);
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public abstract class KotlinIfSurrounderBase extends KotlinStatementsSurrounder
|
||||
@Nullable
|
||||
@Override
|
||||
protected TextRange surroundStatements(Project project, Editor editor, PsiElement container, PsiElement[] statements) {
|
||||
statements = MoveDeclarationsOutHelper.move(container, statements, isGenerateDefaultInitializers());
|
||||
statements = MoveDeclarationsOutHelper.INSTANCE.move(container, statements, isGenerateDefaultInitializers());
|
||||
|
||||
if (statements.length == 0) {
|
||||
KotlinSurrounderUtils.showErrorHint(project, editor, KotlinSurrounderUtils.SURROUND_WITH_ERROR);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public abstract class KotlinTrySurrounderBase extends KotlinStatementsSurrounder
|
||||
@Nullable
|
||||
@Override
|
||||
protected TextRange surroundStatements(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement container, @NotNull PsiElement[] statements) {
|
||||
statements = MoveDeclarationsOutHelper.move(container, statements, true);
|
||||
statements = MoveDeclarationsOutHelper.INSTANCE.move(container, statements, true);
|
||||
|
||||
if (statements.length == 0) {
|
||||
KotlinSurrounderUtils.showErrorHint(project, editor, KotlinSurrounderUtils.SURROUND_WITH_ERROR);
|
||||
|
||||
Reference in New Issue
Block a user