Make ReferenceSearcher a parameter for JavaToKotlinConverter
This commit is contained in:
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.j2k.Converter;
|
import org.jetbrains.jet.j2k.Converter;
|
||||||
import org.jetbrains.jet.j2k.ConverterSettings;
|
import org.jetbrains.jet.j2k.ConverterSettings;
|
||||||
import org.jetbrains.jet.j2k.FilesConversionScope;
|
import org.jetbrains.jet.j2k.FilesConversionScope;
|
||||||
|
import org.jetbrains.jet.j2k.ReferenceSearcherImpl;
|
||||||
import org.jetbrains.jet.plugin.j2k.J2kPostProcessor;
|
import org.jetbrains.jet.plugin.j2k.J2kPostProcessor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -49,6 +50,7 @@ public class JavaToKotlinAction extends AnAction {
|
|||||||
final Converter converter = Converter.OBJECT$.create(project,
|
final Converter converter = Converter.OBJECT$.create(project,
|
||||||
ConverterSettings.defaultSettings,
|
ConverterSettings.defaultSettings,
|
||||||
new FilesConversionScope(selectedJavaFiles),
|
new FilesConversionScope(selectedJavaFiles),
|
||||||
|
ReferenceSearcherImpl.INSTANCE$,
|
||||||
//TODO: (module refactoring) resulting files should be analyzed in context of respective java files
|
//TODO: (module refactoring) resulting files should be analyzed in context of respective java files
|
||||||
new J2kPostProcessor(selectedJavaFiles.iterator().next()));
|
new J2kPostProcessor(selectedJavaFiles.iterator().next()));
|
||||||
CommandProcessor.getInstance().executeCommand(
|
CommandProcessor.getInstance().executeCommand(
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
|||||||
val converter = Converter.create(fileCopiedFrom.getProject(),
|
val converter = Converter.create(fileCopiedFrom.getProject(),
|
||||||
ConverterSettings.defaultSettings,
|
ConverterSettings.defaultSettings,
|
||||||
FilesConversionScope(listOf(fileCopiedFrom)),
|
FilesConversionScope(listOf(fileCopiedFrom)),
|
||||||
|
ReferenceSearcherImpl,
|
||||||
J2kPostProcessor(fileCopiedTo))
|
J2kPostProcessor(fileCopiedTo))
|
||||||
val startOffsets = code.startOffsets
|
val startOffsets = code.startOffsets
|
||||||
val endOffsets = code.endOffsets
|
val endOffsets = code.endOffsets
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ class ConstructorConverter(private val psiClass: PsiClass, private val converter
|
|||||||
val (field, `type`) = parameterToField[parameter]!!
|
val (field, `type`) = parameterToField[parameter]!!
|
||||||
Parameter(field.declarationIdentifier(),
|
Parameter(field.declarationIdentifier(),
|
||||||
`type`,
|
`type`,
|
||||||
if (isVal(field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
if (isVal(converter.referenceSearcher, field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
||||||
converter.convertAnnotations(parameter) + converter.convertAnnotations(field),
|
converter.convertAnnotations(parameter) + converter.convertAnnotations(field),
|
||||||
converter.convertModifiers(field).filter { it in ACCESS_MODIFIERS },
|
converter.convertModifiers(field).filter { it in ACCESS_MODIFIERS },
|
||||||
defaultValue).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
|
defaultValue).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
|
||||||
@@ -278,7 +278,7 @@ class ConstructorConverter(private val psiClass: PsiClass, private val converter
|
|||||||
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
|
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
|
||||||
val body = constructor.getBody() ?: return null
|
val body = constructor.getBody() ?: return null
|
||||||
|
|
||||||
val refs = findVariableUsages(parameter, body)
|
val refs = converter.referenceSearcher.findVariableUsages(parameter, body)
|
||||||
|
|
||||||
if (refs.any { PsiUtil.isAccessedForWriting(it) }) return null
|
if (refs.any { PsiUtil.isAccessedForWriting(it) }) return null
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ class ConstructorConverter(private val psiClass: PsiClass, private val converter
|
|||||||
if (statement.getParent() != body) continue
|
if (statement.getParent() != body) continue
|
||||||
|
|
||||||
// and no other assignments to field should exist in the constructor
|
// and no other assignments to field should exist in the constructor
|
||||||
if (findVariableUsages(field, body).any { it != assignee && PsiUtil.isAccessedForWriting(it) && isQualifierEmptyOrThis(it) }) continue
|
if (converter.referenceSearcher.findVariableUsages(field, body).any { it != assignee && PsiUtil.isAccessedForWriting(it) && isQualifierEmptyOrThis(it) }) continue
|
||||||
//TODO: check access to field before assignment
|
//TODO: check access to field before assignment
|
||||||
|
|
||||||
return field to statement
|
return field to statement
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public trait PostProcessor {
|
|||||||
public class Converter private(val project: Project,
|
public class Converter private(val project: Project,
|
||||||
val settings: ConverterSettings,
|
val settings: ConverterSettings,
|
||||||
val conversionScope: ConversionScope,
|
val conversionScope: ConversionScope,
|
||||||
|
val referenceSearcher: ReferenceSearcher,
|
||||||
private val postProcessor: PostProcessor?,
|
private val postProcessor: PostProcessor?,
|
||||||
private val state: Converter.State) {
|
private val state: Converter.State) {
|
||||||
private class State(val methodReturnType: PsiType?,
|
private class State(val methodReturnType: PsiType?,
|
||||||
@@ -67,34 +68,34 @@ public class Converter private(val project: Project,
|
|||||||
val annotationConverter = AnnotationConverter(this)
|
val annotationConverter = AnnotationConverter(this)
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope, postProcessor: PostProcessor?): Converter {
|
public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope, referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter {
|
||||||
val state = State(null, { ExpressionVisitor(it) }, { StatementVisitor(it) }, null, null, null)
|
val state = State(null, { ExpressionVisitor(it) }, { StatementVisitor(it) }, null, null, null)
|
||||||
return Converter(project, settings, conversionScope, postProcessor, state)
|
return Converter(project, settings, conversionScope, referenceSearcher, postProcessor, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withMethodReturnType(methodReturnType: PsiType?): Converter
|
fun withMethodReturnType(methodReturnType: PsiType?): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
|
State(methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
|
||||||
|
|
||||||
fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter
|
fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(state.methodReturnType, factory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
|
State(state.methodReturnType, factory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
|
||||||
|
|
||||||
fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter
|
fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(state.methodReturnType, state.expressionVisitorFactory, factory, state.specialContext, state.importList, state.importsToAdd))
|
State(state.methodReturnType, state.expressionVisitorFactory, factory, state.specialContext, state.importList, state.importsToAdd))
|
||||||
|
|
||||||
fun withSpecialContext(context: PsiElement): Converter
|
fun withSpecialContext(context: PsiElement): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, context, state.importList, state.importsToAdd))
|
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, context, state.importList, state.importsToAdd))
|
||||||
|
|
||||||
private fun withImportList(importList: ImportList): Converter
|
private fun withImportList(importList: ImportList): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, importList, state.importsToAdd))
|
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, importList, state.importsToAdd))
|
||||||
|
|
||||||
private fun withImportsToAdd(importsToAdd: MutableCollection<String>): Converter
|
private fun withImportsToAdd(importsToAdd: MutableCollection<String>): Converter
|
||||||
= Converter(project, settings, conversionScope, postProcessor,
|
= Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
|
||||||
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd))
|
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd))
|
||||||
|
|
||||||
public fun elementToKotlin(element: PsiElement): String {
|
public fun elementToKotlin(element: PsiElement): String {
|
||||||
@@ -220,7 +221,7 @@ public class Converter private(val project: Project,
|
|||||||
val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) }
|
val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) }
|
||||||
val nestedClasses = members.filterIsInstance(javaClass<PsiClass>()).filter { it.hasModifierProperty(PsiModifier.STATIC) }
|
val nestedClasses = members.filterIsInstance(javaClass<PsiClass>()).filter { it.hasModifierProperty(PsiModifier.STATIC) }
|
||||||
if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) {
|
if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) {
|
||||||
return nestedClasses.any { nestedClass -> classObjectMembers.any { findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } }
|
return nestedClasses.any { nestedClass -> classObjectMembers.any { referenceSearcher.findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true
|
return true
|
||||||
@@ -332,7 +333,7 @@ public class Converter private(val project: Project,
|
|||||||
ExpressionList(convertExpressions(argumentList?.getExpressions())).assignPrototype(argumentList))
|
ExpressionList(convertExpressions(argumentList?.getExpressions())).assignPrototype(argumentList))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val isVal = isVal(field)
|
val isVal = isVal(referenceSearcher, field)
|
||||||
val typeToDeclare = variableTypeToDeclare(field,
|
val typeToDeclare = variableTypeToDeclare(field,
|
||||||
settings.specifyFieldTypeByDefault || modifiers.isPublic || modifiers.isProtected,
|
settings.specifyFieldTypeByDefault || modifiers.isPublic || modifiers.isProtected,
|
||||||
isVal && modifiers.isPrivate)
|
isVal && modifiers.isPrivate)
|
||||||
@@ -344,7 +345,7 @@ public class Converter private(val project: Project,
|
|||||||
initializer,
|
initializer,
|
||||||
isVal,
|
isVal,
|
||||||
typeToDeclare != null,
|
typeToDeclare != null,
|
||||||
initializer.isEmpty && shouldGenerateDefaultInitializer(field))
|
initializer.isEmpty && shouldGenerateDefaultInitializer(referenceSearcher, field))
|
||||||
}
|
}
|
||||||
return converted.assignPrototype(field)
|
return converted.assignPrototype(field)
|
||||||
}
|
}
|
||||||
@@ -378,7 +379,7 @@ public class Converter private(val project: Project,
|
|||||||
|
|
||||||
val statementsToInsert = ArrayList<Statement>()
|
val statementsToInsert = ArrayList<Statement>()
|
||||||
for (parameter in method.getParameterList().getParameters()) {
|
for (parameter in method.getParameterList().getParameters()) {
|
||||||
if (parameter.hasWriteAccesses(method)) {
|
if (parameter.hasWriteAccesses(referenceSearcher, method)) {
|
||||||
val variable = LocalVariable(parameter.declarationIdentifier(),
|
val variable = LocalVariable(parameter.declarationIdentifier(),
|
||||||
Annotations.Empty,
|
Annotations.Empty,
|
||||||
Modifiers.Empty,
|
Modifiers.Empty,
|
||||||
@@ -488,7 +489,7 @@ public class Converter private(val project: Project,
|
|||||||
fun convertLocalVariable(variable: PsiLocalVariable): LocalVariable {
|
fun convertLocalVariable(variable: PsiLocalVariable): LocalVariable {
|
||||||
val isVal = variable.hasModifierProperty(PsiModifier.FINAL) ||
|
val isVal = variable.hasModifierProperty(PsiModifier.FINAL) ||
|
||||||
variable.getInitializer() == null/* we do not know actually and prefer val until we have better analysis*/ ||
|
variable.getInitializer() == null/* we do not know actually and prefer val until we have better analysis*/ ||
|
||||||
!variable.hasWriteAccesses(variable.getContainingMethod())
|
!variable.hasWriteAccesses(referenceSearcher, variable.getContainingMethod())
|
||||||
return LocalVariable(variable.declarationIdentifier(),
|
return LocalVariable(variable.declarationIdentifier(),
|
||||||
annotationConverter.convertAnnotations(variable),
|
annotationConverter.convertAnnotations(variable),
|
||||||
convertModifiers(variable),
|
convertModifiers(variable),
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public object JavaToKotlinTranslator {
|
|||||||
fun generateKotlinCode(javaCode: String): String {
|
fun generateKotlinCode(javaCode: String): String {
|
||||||
val file = createFile(javaCode)
|
val file = createFile(javaCode)
|
||||||
if (file is PsiJavaFile) {
|
if (file is PsiJavaFile) {
|
||||||
val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), null)
|
val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), EmptyReferenceSearcher, null)
|
||||||
return prettify(converter.elementToKotlin(file))
|
return prettify(converter.elementToKotlin(file))
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 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.jet.j2k
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiVariable
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReferenceExpression
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiMethodCallExpression
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
|
public trait ReferenceSearcher {
|
||||||
|
fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression>
|
||||||
|
fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression>
|
||||||
|
}
|
||||||
|
|
||||||
|
public object EmptyReferenceSearcher: ReferenceSearcher {
|
||||||
|
override fun findVariableUsages(variable: PsiVariable, scope: PsiElement) = Collections.emptyList<PsiReferenceExpression>()
|
||||||
|
override fun findMethodCalls(method: PsiMethod, scope: PsiElement) = Collections.emptyList<PsiMethodCallExpression>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ReferenceSearcherImpl: ReferenceSearcher {
|
||||||
|
override fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression> {
|
||||||
|
return ReferencesSearch.search(variable, LocalSearchScope(scope)).findAll().filterIsInstance(javaClass<PsiReferenceExpression>())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression> {
|
||||||
|
return ReferencesSearch.search(method, LocalSearchScope(scope)).findAll().map {
|
||||||
|
if (it is PsiReferenceExpression) {
|
||||||
|
val methodCall = it.getParent() as? PsiMethodCallExpression
|
||||||
|
if (methodCall?.getMethodExpression() == it) methodCall else null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.filterNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -126,7 +126,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nullability == Nullability.Default) {
|
if (nullability == Nullability.Default) {
|
||||||
if (variable is PsiField && variable.hasModifierProperty(PsiModifier.PRIVATE) && shouldGenerateDefaultInitializer(variable)) {
|
if (variable is PsiField && variable.hasModifierProperty(PsiModifier.PRIVATE) && shouldGenerateDefaultInitializer(converter.referenceSearcher, variable)) {
|
||||||
return Nullability.Nullable
|
return Nullability.Nullable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
if (nullability == Nullability.Default) {
|
if (nullability == Nullability.Default) {
|
||||||
val scope = searchScope(variable)
|
val scope = searchScope(variable)
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
if (findVariableUsages(variable, scope).any { isNullableFromUsage(it) }) {
|
if (converter.referenceSearcher.findVariableUsages(variable, scope).any { isNullableFromUsage(it) }) {
|
||||||
nullability = Nullability.Nullable
|
nullability = Nullability.Nullable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
val parameters = method.getParameterList().getParameters()
|
val parameters = method.getParameterList().getParameters()
|
||||||
val parameterIndex = parameters.indexOf(variable)
|
val parameterIndex = parameters.indexOf(variable)
|
||||||
for (call in findMethodCalls(method, scope)) {
|
for (call in converter.referenceSearcher.findMethodCalls(method, scope)) {
|
||||||
val args = call.getArgumentList().getExpressions()
|
val args = call.getArgumentList().getExpressions()
|
||||||
if (args.size == parameters.size) {
|
if (args.size == parameters.size) {
|
||||||
if (args[parameterIndex].nullability() == Nullability.Nullable) {
|
if (args[parameterIndex].nullability() == Nullability.Nullable) {
|
||||||
@@ -211,7 +211,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
if (nullability == Nullability.Default) {
|
if (nullability == Nullability.Default) {
|
||||||
val scope = searchScope(method)
|
val scope = searchScope(method)
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
if (findMethodCalls(method, scope).any { isNullableFromUsage(it) }) {
|
if (converter.referenceSearcher.findMethodCalls(method, scope).any { isNullableFromUsage(it) }) {
|
||||||
nullability = Nullability.Nullable
|
nullability = Nullability.Nullable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,8 +275,8 @@ class TypeConverter(val converter: Converter) {
|
|||||||
private fun PsiVariable.isEffectivelyFinal(): Boolean {
|
private fun PsiVariable.isEffectivelyFinal(): Boolean {
|
||||||
if (hasModifierProperty(PsiModifier.FINAL)) return true
|
if (hasModifierProperty(PsiModifier.FINAL)) return true
|
||||||
return when(this) {
|
return when(this) {
|
||||||
is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod())
|
is PsiLocalVariable -> !hasWriteAccesses(converter.referenceSearcher, getContainingMethod())
|
||||||
is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false
|
is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(converter.referenceSearcher, getContainingClass()) else false
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,34 +19,16 @@ package org.jetbrains.jet.j2k
|
|||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.util.PsiUtil
|
import com.intellij.psi.util.PsiUtil
|
||||||
import com.intellij.psi.search.LocalSearchScope
|
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
|
||||||
import org.jetbrains.jet.j2k.ast.*
|
import org.jetbrains.jet.j2k.ast.*
|
||||||
import com.intellij.psi.util.PsiMethodUtil
|
import com.intellij.psi.util.PsiMethodUtil
|
||||||
|
|
||||||
fun quoteKeywords(packageName: String): String = packageName.split("\\.").map { Identifier.toKotlin(it) }.joinToString(".")
|
fun quoteKeywords(packageName: String): String = packageName.split("\\.").map { Identifier.toKotlin(it) }.joinToString(".")
|
||||||
|
|
||||||
fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression> {
|
fun PsiVariable.countWriteAccesses(searcher: ReferenceSearcher, scope: PsiElement?): Int
|
||||||
return ReferencesSearch.search(variable, LocalSearchScope(scope)).findAll().filterIsInstance(javaClass<PsiReferenceExpression>())
|
= if (scope != null) searcher.findVariableUsages(this, scope).count { PsiUtil.isAccessedForWriting(it) } else 0
|
||||||
}
|
|
||||||
|
|
||||||
fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression> {
|
fun PsiVariable.hasWriteAccesses(searcher: ReferenceSearcher, scope: PsiElement?): Boolean
|
||||||
return ReferencesSearch.search(method, LocalSearchScope(scope)).findAll().map {
|
= if (scope != null) searcher.findVariableUsages(this, scope).any { PsiUtil.isAccessedForWriting(it) } else false
|
||||||
if (it is PsiReferenceExpression) {
|
|
||||||
val methodCall = it.getParent() as? PsiMethodCallExpression
|
|
||||||
if (methodCall?.getMethodExpression() == it) methodCall else null
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}.filterNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun PsiVariable.countWriteAccesses(scope: PsiElement?): Int
|
|
||||||
= if (scope != null) findVariableUsages(this, scope).count { PsiUtil.isAccessedForWriting(it) } else 0
|
|
||||||
|
|
||||||
fun PsiVariable.hasWriteAccesses(scope: PsiElement?): Boolean
|
|
||||||
= if (scope != null) findVariableUsages(this, scope).any { PsiUtil.isAccessedForWriting(it) } else false
|
|
||||||
|
|
||||||
fun getDefaultInitializer(field: Field): Expression? {
|
fun getDefaultInitializer(field: Field): Expression? {
|
||||||
val t = field.`type`
|
val t = field.`type`
|
||||||
@@ -68,11 +50,11 @@ fun getDefaultInitializer(field: Field): Expression? {
|
|||||||
return result?.assignNoPrototype()
|
return result?.assignNoPrototype()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isVal(field: PsiField): Boolean {
|
fun isVal(searcher: ReferenceSearcher, field: PsiField): Boolean {
|
||||||
if (field.hasModifierProperty(PsiModifier.FINAL)) return true
|
if (field.hasModifierProperty(PsiModifier.FINAL)) return true
|
||||||
if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false
|
if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false
|
||||||
val containingClass = field.getContainingClass() ?: return false
|
val containingClass = field.getContainingClass() ?: return false
|
||||||
val writes = findVariableUsages(field, containingClass).filter { PsiUtil.isAccessedForWriting(it) }
|
val writes = searcher.findVariableUsages(field, containingClass).filter { PsiUtil.isAccessedForWriting(it) }
|
||||||
if (writes.size == 0) return true
|
if (writes.size == 0) return true
|
||||||
if (writes.size > 1) return false
|
if (writes.size > 1) return false
|
||||||
val write = writes.single()
|
val write = writes.single()
|
||||||
@@ -89,8 +71,8 @@ fun isVal(field: PsiField): Boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldGenerateDefaultInitializer(field: PsiField)
|
fun shouldGenerateDefaultInitializer(searcher: ReferenceSearcher, field: PsiField)
|
||||||
= field.getInitializer() == null && !(isVal(field) && field.hasWriteAccesses(field.getContainingClass()))
|
= field.getInitializer() == null && !(isVal(searcher, field) && field.hasWriteAccesses(searcher, field.getContainingClass()))
|
||||||
|
|
||||||
fun isQualifierEmptyOrThis(ref: PsiReferenceExpression): Boolean {
|
fun isQualifierEmptyOrThis(ref: PsiReferenceExpression): Boolean {
|
||||||
val qualifier = ref.getQualifierExpression()
|
val qualifier = ref.getQualifierExpression()
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ class ForConverter(private val statement: PsiForStatement, private val converter
|
|||||||
if (initialization is PsiDeclarationStatement) {
|
if (initialization is PsiDeclarationStatement) {
|
||||||
val loopVar = initialization.getDeclaredElements().singleOrNull2() as? PsiLocalVariable
|
val loopVar = initialization.getDeclaredElements().singleOrNull2() as? PsiLocalVariable
|
||||||
if (loopVar != null
|
if (loopVar != null
|
||||||
&& !loopVar.hasWriteAccesses(body)
|
&& !loopVar.hasWriteAccesses(converter.referenceSearcher, body)
|
||||||
&& !loopVar.hasWriteAccesses(condition)
|
&& !loopVar.hasWriteAccesses(converter.referenceSearcher, condition)
|
||||||
&& condition is PsiBinaryExpression) {
|
&& condition is PsiBinaryExpression) {
|
||||||
val operationTokenType = condition.getOperationTokenType()
|
val operationTokenType = condition.getOperationTokenType()
|
||||||
val lowerBound = condition.getLOperand()
|
val lowerBound = condition.getLOperand()
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.intellij.testFramework.LightProjectDescriptor
|
|||||||
import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor
|
||||||
import com.intellij.psi.PsiJavaFile
|
import com.intellij.psi.PsiJavaFile
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
|
import org.jetbrains.jet.j2k.ReferenceSearcherImpl
|
||||||
|
|
||||||
public abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixtureTestCase() {
|
public abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixtureTestCase() {
|
||||||
val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n")
|
val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n")
|
||||||
@@ -125,14 +126,14 @@ public abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixt
|
|||||||
|
|
||||||
private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
||||||
val fileWithText = createJavaFile(text)
|
val fileWithText = createJavaFile(text)
|
||||||
val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText)), J2kPostProcessor(fileWithText))
|
val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText)), ReferenceSearcherImpl, J2kPostProcessor(fileWithText))
|
||||||
val element = fileWithText.getFirstChild()!!
|
val element = fileWithText.getFirstChild()!!
|
||||||
return converter.elementToKotlin(element)
|
return converter.elementToKotlin(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
||||||
val file = createJavaFile(text)
|
val file = createJavaFile(text)
|
||||||
val converter = Converter.create(project, settings, FilesConversionScope(listOf(file)), J2kPostProcessor(file))
|
val converter = Converter.create(project, settings, FilesConversionScope(listOf(file)), ReferenceSearcherImpl, J2kPostProcessor(file))
|
||||||
return converter.elementToKotlin(file)
|
return converter.elementToKotlin(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user