Minor: fix warnings

This commit is contained in:
Natalia Ukhorskaya
2015-10-23 16:47:29 +03:00
parent cacc50dc32
commit 05dbb875a9
4 changed files with 225 additions and 246 deletions
@@ -40,7 +40,6 @@ import com.intellij.util.ExceptionUtil
import com.sun.jdi.InvocationException import com.sun.jdi.InvocationException
import com.sun.jdi.ObjectReference import com.sun.jdi.ObjectReference
import com.sun.jdi.VMDisconnectedException import com.sun.jdi.VMDisconnectedException
import com.sun.jdi.VirtualMachine
import com.sun.jdi.request.EventRequest import com.sun.jdi.request.EventRequest
import org.jetbrains.eval4j.* import org.jetbrains.eval4j.*
import org.jetbrains.eval4j.jdi.JDIEval import org.jetbrains.eval4j.jdi.JDIEval
@@ -66,8 +65,6 @@ import org.jetbrains.kotlin.idea.util.DebuggerUtils
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo
@@ -84,6 +81,7 @@ import java.util.*
internal val RECEIVER_NAME = "\$receiver" internal val RECEIVER_NAME = "\$receiver"
internal val THIS_NAME = "this" internal val THIS_NAME = "this"
val logger = Logger.getInstance(KotlinEvaluator::class.java)
object KotlinEvaluationBuilder: EvaluatorBuilder { object KotlinEvaluationBuilder: EvaluatorBuilder {
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
@@ -120,14 +118,10 @@ object KotlinEvaluationBuilder: EvaluatorBuilder {
} }
} }
val logger = Logger.getInstance(javaClass<KotlinEvaluator>()) class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: SourcePosition): Evaluator {
class KotlinEvaluator(val codeFragment: KtCodeFragment,
val sourcePosition: SourcePosition
) : Evaluator {
override fun evaluate(context: EvaluationContextImpl): Any? { override fun evaluate(context: EvaluationContextImpl): Any? {
if (codeFragment.text.isEmpty()) { if (codeFragment.text.isEmpty()) {
return context.debugProcess.virtualMachineProxy.mirrorOf() return context.debugProcess.virtualMachineProxy.mirrorOfVoid()
} }
var isCompiledDataFromCache = true var isCompiledDataFromCache = true
@@ -164,7 +158,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
ExceptionUtil.getThrowableText(e), ExceptionUtil.getThrowableText(e),
mergeAttachments(*attachments))) mergeAttachments(*attachments)))
val cause = if (e.getMessage() != null) ": ${e.getMessage()}" else "" val cause = if (e.message != null) ": ${e.message}" else ""
exception("An exception occurs during Evaluate Expression Action $cause") exception("An exception occurs during Evaluate Expression Action $cause")
} }
} }
@@ -178,24 +172,20 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
codeFragment.checkForErrors(false) codeFragment.checkForErrors(false)
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line) val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
if (extractionResult == null) { ?: throw IllegalStateException("Code fragment cannot be extracted to function")
throw IllegalStateException("Code fragment cannot be extracted to function")
}
val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment) val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment)
val extractedFunction = extractionResult.declaration as KtNamedFunction val extractedFunction = extractionResult.declaration as KtNamedFunction
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor) val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor)
val outputFiles = classFileFactory.asList().filterClassFiles() val outputFiles = classFileFactory.asList().filterClassFiles()
.sortedBy { it.relativePath.length() } .sortedBy { it.relativePath.length }
val funName = runReadAction { extractedFunction.name } val funName = runReadAction { extractedFunction.name }
if (funName == null) { ?: throw IllegalStateException("Extracted function should have a name: ${extractedFunction.text}")
throw IllegalStateException("Extracted function should have a name: ${extractedFunction.text}")
}
val additionalFiles = if (outputFiles.size() < 2) emptyList() val additionalFiles = if (outputFiles.size < 2) emptyList()
else outputFiles.subList(1, outputFiles.size()).map { getClassName(it.relativePath) to it.asByteArray() } else outputFiles.subList(1, outputFiles.size).map { getClassName(it.relativePath) to it.asByteArray() }
return CompiledDataDescriptor( return CompiledDataDescriptor(
outputFiles.first().asByteArray(), outputFiles.first().asByteArray(),
@@ -353,7 +343,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
val (bindingContext, moduleDescriptor, files) = jetFile.checkForErrors(true) val (bindingContext, moduleDescriptor, files) = jetFile.checkForErrors(true)
val generateClassFilter = object : GenerationState.GenerateClassFilter() { val generateClassFilter = object : GenerationState.GenerateClassFilter() {
override fun shouldGeneratePackagePart(file: KtFile) = file == jetFile override fun shouldGeneratePackagePart(jetFile: KtFile) = jetFile == jetFile
override fun shouldAnnotateClass(classOrObject: KtClassOrObject) = true override fun shouldAnnotateClass(classOrObject: KtClassOrObject) = true
override fun shouldGenerateClass(classOrObject: KtClassOrObject) = classOrObject.getContainingJetFile() == jetFile override fun shouldGenerateClass(classOrObject: KtClassOrObject) = classOrObject.getContainingJetFile() == jetFile
override fun shouldGenerateScript(script: KtScript) = false override fun shouldGenerateScript(script: KtScript) = false
@@ -405,9 +395,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
val declarationDescriptor = paramAnonymousType.constructor.declarationDescriptor val declarationDescriptor = paramAnonymousType.constructor.declarationDescriptor
if (declarationDescriptor is ClassDescriptor) { if (declarationDescriptor is ClassDescriptor) {
val localVariable = visitor.findValue(localVariableName, asmType = null, checkType = false, failIfNotFound = false) val localVariable = visitor.findValue(localVariableName, asmType = null, checkType = false, failIfNotFound = false)
if (localVariable == null) { ?: exception("Couldn't find local variable this in current frame to get classType for anonymous type $paramAnonymousType}")
exception("Couldn't find local variable this in current frame to get classType for anonymous type ${paramAnonymousType}}")
}
record(CodegenBinding.ASM_TYPE, declarationDescriptor, localVariable.asmType) record(CodegenBinding.ASM_TYPE, declarationDescriptor, localVariable.asmType)
} }
} }
@@ -416,7 +404,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg) private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg)
private fun exception(e: Throwable): Nothing { private fun exception(e: Throwable): Nothing {
val message = e.getMessage() val message = e.message
if (message != null) { if (message != null) {
throw EvaluateExceptionUtil.createEvaluateException(message, e) throw EvaluateExceptionUtil.createEvaluateException(message, e)
} }
@@ -429,7 +417,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment,
AnalyzingUtils.checkForSyntacticErrors(this) AnalyzingUtils.checkForSyntacticErrors(this)
} }
catch (e: IllegalArgumentException) { catch (e: IllegalArgumentException) {
throw EvaluateExceptionUtil.createEvaluateException(e.getMessage()) throw EvaluateExceptionUtil.createEvaluateException(e.message)
} }
val resolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this, createFlexibleTypesFile())) val resolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this, createFlexibleTypesFile()))
@@ -489,7 +477,7 @@ private fun createFileForDebugger(codeFragment: KtCodeFragment,
jetFile.suppressDiagnosticsInDebugMode = true jetFile.suppressDiagnosticsInDebugMode = true
val list = jetFile.declarations val list = jetFile.declarations
val function = list.get(0) as KtNamedFunction val function = list[0] as KtNamedFunction
function.receiverTypeReference?.debugTypeInfo = extractedFunction.receiverTypeReference?.debugTypeInfo function.receiverTypeReference?.debugTypeInfo = extractedFunction.receiverTypeReference?.debugTypeInfo
@@ -44,17 +44,17 @@ fun getFunctionForExtractedFragment(
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult, tmpFile: KtFile): String { fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult, tmpFile: KtFile): String {
if (KotlinInternalMode.enabled) { if (KotlinInternalMode.enabled) {
logger.error("Couldn't extract function for debugger:\n" + logger.error("Couldn't extract function for debugger:\n" +
"FILE NAME: ${breakpointFile.getName()}\n" + "FILE NAME: ${breakpointFile.name}\n" +
"BREAKPOINT LINE: ${breakpointLine}\n" + "BREAKPOINT LINE: $breakpointLine\n" +
"CODE FRAGMENT:\n${codeFragment.getText()}\n" + "CODE FRAGMENT:\n${codeFragment.text}\n" +
"ERRORS:\n${analysisResult.messages.map { "$it: ${it.renderMessage()}" }.joinToString("\n")}\n" + "ERRORS:\n${analysisResult.messages.map { "$it: ${it.renderMessage()}" }.joinToString("\n")}\n" +
"TMPFILE_TEXT:\n${tmpFile.text}\n" + "TMPFILE_TEXT:\n${tmpFile.text}\n" +
"FILE TEXT: \n${breakpointFile.getText()}\n") "FILE TEXT: \n${breakpointFile.text}\n")
} }
return analysisResult.messages.map { errorMessage -> return analysisResult.messages.map { errorMessage ->
val message = when(errorMessage) { val message = when(errorMessage) {
ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression" ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression"
ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}" ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.name}:$breakpointLine"
ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call" ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call"
ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope" ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope"
ErrorMessage.ERROR_TYPES -> "Cannot perform an action because this code fragment contains erroneous types" ErrorMessage.ERROR_TYPES -> "Cannot perform an action because this code fragment contains erroneous types"
@@ -74,16 +74,14 @@ fun getFunctionForExtractedFragment(
val tmpFile = originalFile.createTempCopy { it } val tmpFile = originalFile.createTempCopy { it }
tmpFile.suppressDiagnosticsInDebugMode = true tmpFile.suppressDiagnosticsInDebugMode = true
val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.getContext(), breakpointLine) val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.context, breakpointLine) ?: return null
if (contextElement == null) return null
addImportsToFile(codeFragment.importsAsImportList(), tmpFile) addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
val newDebugExpressions = addDebugExpressionBeforeContextElement(codeFragment, contextElement) val newDebugExpressions = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
if (newDebugExpressions.isEmpty()) return null if (newDebugExpressions.isEmpty()) return null
val targetSibling = tmpFile.getDeclarations().firstOrNull() val targetSibling = tmpFile.declarations.firstOrNull() ?: return null
if (targetSibling == null) return null
val options = ExtractionOptions(inferUnitTypeForUnusedValues = false, val options = ExtractionOptions(inferUnitTypeForUnusedValues = false,
enableListBoxing = true, enableListBoxing = true,
@@ -95,8 +93,8 @@ fun getFunctionForExtractedFragment(
} }
val validationResult = analysisResult.descriptor!!.validate() val validationResult = analysisResult.descriptor!!.validate()
if (!validationResult.conflicts.isEmpty()) { if (!validationResult.conflicts.isEmpty) {
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().map { it.getText() }.joinToString(",")}") throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().map { it.text }.joinToString(",")}")
} }
val generatorOptions = ExtractionGeneratorOptions(inTempFile = true, val generatorOptions = ExtractionGeneratorOptions(inTempFile = true,
@@ -111,12 +109,12 @@ fun getFunctionForExtractedFragment(
private fun addImportsToFile(newImportList: KtImportList?, tmpFile: KtFile) { private fun addImportsToFile(newImportList: KtImportList?, tmpFile: KtFile) {
if (newImportList != null) { if (newImportList != null) {
val tmpFileImportList = tmpFile.getImportList() val tmpFileImportList = tmpFile.importList
val packageDirective = tmpFile.getPackageDirective() val packageDirective = tmpFile.packageDirective
val psiFactory = KtPsiFactory(tmpFile) val psiFactory = KtPsiFactory(tmpFile)
if (tmpFileImportList == null) { if (tmpFileImportList == null) {
tmpFile.addAfter(psiFactory.createNewLine(), packageDirective) tmpFile.addAfter(psiFactory.createNewLine(), packageDirective)
tmpFile.addAfter(newImportList, tmpFile.getPackageDirective()) tmpFile.addAfter(newImportList, tmpFile.packageDirective)
} }
else { else {
val tmpFileImports = tmpFileImportList.imports val tmpFileImports = tmpFileImportList.imports
@@ -136,51 +134,46 @@ private fun addImportsToFile(newImportList: KtImportList?, tmpFile: KtFile) {
} }
private fun KtFile.getElementInCopy(e: PsiElement): PsiElement? { private fun KtFile.getElementInCopy(e: PsiElement): PsiElement? {
val offset = e.getTextRange()?.getStartOffset() val offset = e.textRange?.startOffset ?: return null
if (offset == null) {
return null
}
var elementAt = this.findElementAt(offset) var elementAt = this.findElementAt(offset)
while (elementAt == null || elementAt.getTextRange()?.getEndOffset() != e.getTextRange()?.getEndOffset()) { while (elementAt == null || elementAt.textRange?.endOffset != e.textRange?.endOffset) {
elementAt = elementAt?.getParent() elementAt = elementAt?.parent
} }
return elementAt return elementAt
} }
private fun getExpressionToAddDebugExpressionBefore(tmpFile: KtFile, contextElement: PsiElement?, line: Int): PsiElement? { private fun getExpressionToAddDebugExpressionBefore(tmpFile: KtFile, contextElement: PsiElement?, line: Int): PsiElement? {
if (contextElement == null) { if (contextElement == null) {
val lineStart = CodeInsightUtils.getStartLineOffset(tmpFile, line) val lineStart = CodeInsightUtils.getStartLineOffset(tmpFile, line) ?: return null
if (lineStart == null) return null
val elementAtOffset = tmpFile.findElementAt(lineStart) val elementAtOffset = tmpFile.findElementAt(lineStart) ?: return null
if (elementAtOffset == null) return null
return CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset return CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
} }
val containingFile = contextElement.getContainingFile() val containingFile = contextElement.containingFile
if (containingFile is KtCodeFragment) { if (containingFile is KtCodeFragment) {
return getExpressionToAddDebugExpressionBefore(tmpFile, containingFile.getContext(), line) return getExpressionToAddDebugExpressionBefore(tmpFile, containingFile.context, line)
} }
fun shouldStop(el: PsiElement?, p: PsiElement?) = p is KtBlockExpression || el is KtDeclaration || el is KtFile fun shouldStop(el: PsiElement?, p: PsiElement?) = p is KtBlockExpression || el is KtDeclaration || el is KtFile
var elementAt = tmpFile.getElementInCopy(contextElement) var elementAt = tmpFile.getElementInCopy(contextElement)
var parent = elementAt?.getParent() var parent = elementAt?.parent
if (shouldStop(elementAt, parent)) { if (shouldStop(elementAt, parent)) {
return elementAt return elementAt
} }
var parentOfParent = parent?.getParent() var parentOfParent = parent?.parent
while (parent != null && parentOfParent != null) { while (parent != null && parentOfParent != null) {
if (shouldStop(parent, parentOfParent)) { if (shouldStop(parent, parentOfParent)) {
break break
} }
parent = parent.getParent() parent = parent.parent
parentOfParent = parent?.getParent() parentOfParent = parent?.parent
} }
return parent return parent
@@ -191,9 +184,9 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
fun insertNewInitializer(classBody: KtClassBody): PsiElement? { fun insertNewInitializer(classBody: KtClassBody): PsiElement? {
val initializer = psiFactory.createAnonymousInitializer() val initializer = psiFactory.createAnonymousInitializer()
val newInitializer = (classBody.addAfter(initializer, classBody.getFirstChild()) as KtClassInitializer) val newInitializer = (classBody.addAfter(initializer, classBody.firstChild) as KtClassInitializer)
val block = newInitializer.getBody() as KtBlockExpression? val block = newInitializer.body as KtBlockExpression?
return block?.getLastChild() return block?.lastChild
} }
val elementBefore = when { val elementBefore = when {
@@ -201,20 +194,20 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
val fakeFunction = psiFactory.createFunction("fun _debug_fun_() {}") val fakeFunction = psiFactory.createFunction("fun _debug_fun_() {}")
contextElement.add(psiFactory.createNewLine()) contextElement.add(psiFactory.createNewLine())
val newFakeFun = contextElement.add(fakeFunction) as KtNamedFunction val newFakeFun = contextElement.add(fakeFunction) as KtNamedFunction
newFakeFun.getBodyExpression()!!.getLastChild() newFakeFun.bodyExpression!!.lastChild
} }
contextElement is KtProperty && !contextElement.isLocal() -> { contextElement is KtProperty && !contextElement.isLocal -> {
val delegateExpressionOrInitializer = contextElement.getDelegateExpressionOrInitializer() val delegateExpressionOrInitializer = contextElement.delegateExpressionOrInitializer
if (delegateExpressionOrInitializer != null) { if (delegateExpressionOrInitializer != null) {
wrapInRunFun(delegateExpressionOrInitializer) wrapInRunFun(delegateExpressionOrInitializer)
} }
else { else {
val getter = contextElement.getGetter()!! val getter = contextElement.getter!!
if (!getter.hasBlockBody()) { if (!getter.hasBlockBody()) {
wrapInRunFun(getter.getBodyExpression()!!) wrapInRunFun(getter.bodyExpression!!)
} }
else { else {
(getter.getBodyExpression() as KtBlockExpression).getStatements().first() (getter.bodyExpression as KtBlockExpression).statements.first()
} }
} }
} }
@@ -226,29 +219,29 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
insertNewInitializer(contextElement.getBody()!!) insertNewInitializer(contextElement.getBody()!!)
} }
contextElement is KtFunctionLiteral -> { contextElement is KtFunctionLiteral -> {
val block = contextElement.getBodyExpression()!! val block = contextElement.bodyExpression!!
block.getStatements().firstOrNull() ?: block.getLastChild() block.statements.firstOrNull() ?: block.lastChild
} }
contextElement is KtDeclarationWithBody && !contextElement.hasBody()-> { contextElement is KtDeclarationWithBody && !contextElement.hasBody()-> {
val block = psiFactory.createBlock("") val block = psiFactory.createBlock("")
val newBlock = contextElement.add(block) as KtBlockExpression val newBlock = contextElement.add(block) as KtBlockExpression
newBlock.getRBrace() newBlock.rBrace
} }
contextElement is KtDeclarationWithBody && !contextElement.hasBlockBody()-> { contextElement is KtDeclarationWithBody && !contextElement.hasBlockBody()-> {
wrapInRunFun(contextElement.getBodyExpression()!!) wrapInRunFun(contextElement.bodyExpression!!)
} }
contextElement is KtDeclarationWithBody && contextElement.hasBlockBody()-> { contextElement is KtDeclarationWithBody && contextElement.hasBlockBody()-> {
val block = contextElement.getBodyExpression() as KtBlockExpression val block = contextElement.bodyExpression as KtBlockExpression
val last = block.getStatements().lastOrNull() val last = block.statements.lastOrNull()
if (last is KtReturnExpression) if (last is KtReturnExpression)
last last
else else
block.getRBrace() block.rBrace
} }
contextElement is KtWhenEntry -> { contextElement is KtWhenEntry -> {
val entryExpression = contextElement.getExpression() val entryExpression = contextElement.expression
if (entryExpression is KtBlockExpression) { if (entryExpression is KtBlockExpression) {
entryExpression.getStatements().firstOrNull() ?: entryExpression.getLastChild() entryExpression.statements.firstOrNull() ?: entryExpression.lastChild
} }
else { else {
wrapInRunFun(entryExpression!!) wrapInRunFun(entryExpression!!)
@@ -259,18 +252,18 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
} }
} }
val parent = elementBefore?.getParent() val parent = elementBefore?.parent
if (parent == null || elementBefore == null) return emptyList() if (parent == null || elementBefore == null) return emptyList()
parent.addBefore(psiFactory.createNewLine(), elementBefore) parent.addBefore(psiFactory.createNewLine(), elementBefore)
fun insertExpression(expr: KtElement?): List<KtExpression> { fun insertExpression(expr: KtElement?): List<KtExpression> {
when (expr) { when (expr) {
is KtBlockExpression -> return expr.getStatements().flatMap { insertExpression(it) } is KtBlockExpression -> return expr.statements.flatMap { insertExpression(it) }
is KtExpression -> { is KtExpression -> {
val newDebugExpression = parent.addBefore(expr, elementBefore) val newDebugExpression = parent.addBefore(expr, elementBefore)
if (newDebugExpression == null) { if (newDebugExpression == null) {
logger.error("Couldn't insert debug expression ${expr.getText()} to context file before ${elementBefore.getText()}") logger.error("Couldn't insert debug expression ${expr.text} to context file before ${elementBefore.text}")
return emptyList() return emptyList()
} }
parent.addBefore(psiFactory.createNewLine(), elementBefore) parent.addBefore(psiFactory.createNewLine(), elementBefore)
@@ -280,7 +273,7 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
return emptyList() return emptyList()
} }
val containingFile = codeFragment.getContext()?.getContainingFile() val containingFile = codeFragment.context?.containingFile
if (containingFile is KtCodeFragment) { if (containingFile is KtCodeFragment) {
insertExpression(containingFile.getContentElement() as? KtExpression) insertExpression(containingFile.getContentElement() as? KtExpression)
} }
@@ -290,11 +283,11 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: KtCodeFragment,
} }
private fun replaceByRunFunction(expression: KtExpression): KtCallExpression { private fun replaceByRunFunction(expression: KtExpression): KtCallExpression {
val callExpression = KtPsiFactory(expression).createExpression("run { \n${expression.getText()} \n}") as KtCallExpression val callExpression = KtPsiFactory(expression).createExpression("run { \n${expression.text} \n}") as KtCallExpression
val replaced = expression.replaced(callExpression) val replaced = expression.replaced(callExpression)
val typeArguments = InsertExplicitTypeArgumentsIntention.createTypeArguments(replaced, replaced.analyze()) val typeArguments = InsertExplicitTypeArgumentsIntention.createTypeArguments(replaced, replaced.analyze())
if (typeArguments?.getArguments()?.isNotEmpty() ?: false) { if (typeArguments?.arguments?.isNotEmpty() ?: false) {
val calleeExpression = replaced.getCalleeExpression() val calleeExpression = replaced.calleeExpression
replaced.addAfter(typeArguments!!, calleeExpression) replaced.addAfter(typeArguments!!, calleeExpression)
} }
return replaced return replaced
@@ -304,7 +297,7 @@ private fun wrapInRunFun(expression: KtExpression): PsiElement? {
val replacedBody = replaceByRunFunction(expression) val replacedBody = replaceByRunFunction(expression)
// Increment modification tracker to clear ResolveCache after changes in function body // Increment modification tracker to clear ResolveCache after changes in function body
(PsiManager.getInstance(expression.getProject()).getModificationTracker() as PsiModificationTrackerImpl).incCounter() (PsiManager.getInstance(expression.project).modificationTracker as PsiModificationTrackerImpl).incCounter()
return replacedBody.getFunctionLiteralArguments().first().getFunctionLiteral().getBodyExpression()?.getFirstChild() return replacedBody.functionLiteralArguments.first().getFunctionLiteral().bodyExpression?.firstChild
} }
@@ -124,7 +124,7 @@ private fun List<Instruction>.getVarDescriptorsAccessedAfterwards(bindingContext
PseudocodeUtil.extractVariableDescriptorIfAny(it, false, bindingContext)?.let { accessedAfterwards.add(it) } PseudocodeUtil.extractVariableDescriptorIfAny(it, false, bindingContext)?.let { accessedAfterwards.add(it) }
it is LocalFunctionDeclarationInstruction -> it is LocalFunctionDeclarationInstruction ->
doTraversal(it.body.getEnterInstruction()) doTraversal(it.body.enterInstruction)
} }
true true
@@ -155,14 +155,13 @@ private fun List<Instruction>.getResultTypeAndExpressions(
} }
fun instructionToType(instruction: Instruction): KotlinType? { fun instructionToType(instruction: Instruction): KotlinType? {
val expression = instructionToExpression(instruction, true) val expression = instructionToExpression(instruction, true) ?: return null
if (expression == null) return null
if (options.inferUnitTypeForUnusedValues && expression.isUsedAsStatement(bindingContext)) return null if (options.inferUnitTypeForUnusedValues && expression.isUsedAsStatement(bindingContext)) return null
return bindingContext.getType(expression) return bindingContext.getType(expression)
?: (expression as? KtReferenceExpression)?.let { ?: (expression as? KtReferenceExpression)?.let {
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.getReturnType() (bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.returnType
} }
} }
@@ -205,7 +204,7 @@ private fun getCommonNonTrivialSuccessorIfAny(instructions: List<Instruction>):
} }
if (instructions.flatMap { it.nextInstructions }.any { !it.accept(singleSuccessorCheckingVisitor) }) return null if (instructions.flatMap { it.nextInstructions }.any { !it.accept(singleSuccessorCheckingVisitor) }) return null
return singleSuccessorCheckingVisitor.target ?: instructions.firstOrNull()?.owner?.getSinkInstruction() return singleSuccessorCheckingVisitor.target ?: instructions.firstOrNull()?.owner?.sinkInstruction
} }
private fun KotlinType.isMeaningful(): Boolean { private fun KotlinType.isMeaningful(): Boolean {
@@ -228,7 +227,7 @@ private fun ExtractionData.getLocalDeclarationsWithNonLocalUsages(
} }
} }
} }
return declarations.sortedBy { it.getTextRange()!!.getStartOffset() } return declarations.sortedBy { it.textRange!!.startOffset }
} }
private fun ExtractionData.analyzeControlFlow( private fun ExtractionData.analyzeControlFlow(
@@ -248,7 +247,7 @@ private fun ExtractionData.analyzeControlFlow(
val jumpExits = ArrayList<AbstractJumpInstruction>() val jumpExits = ArrayList<AbstractJumpInstruction>()
exitPoints.forEach { exitPoints.forEach {
val e = (it as? UnconditionalJumpInstruction)?.element val e = (it as? UnconditionalJumpInstruction)?.element
val insn = val inst =
when { when {
it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode -> it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode ->
null null
@@ -258,38 +257,38 @@ private fun ExtractionData.analyzeControlFlow(
it it
} }
when (insn) { when (inst) {
is ReturnValueInstruction -> { is ReturnValueInstruction -> {
if (insn.owner == pseudocode) { if (inst.owner == pseudocode) {
if (insn.returnExpressionIfAny == null) { if (inst.returnExpressionIfAny == null) {
defaultExits.add(insn) defaultExits.add(inst)
} }
else { else {
valuedReturnExits.add(insn) valuedReturnExits.add(inst)
} }
} }
} }
is AbstractJumpInstruction -> { is AbstractJumpInstruction -> {
val element = insn.element val element = inst.element
if ((element is KtReturnExpression && insn.owner == pseudocode) if ((element is KtReturnExpression && inst.owner == pseudocode)
|| element is KtBreakExpression || element is KtBreakExpression
|| element is KtContinueExpression) { || element is KtContinueExpression) {
jumpExits.add(insn) jumpExits.add(inst)
} }
else if (element !is KtThrowExpression) { else if (element !is KtThrowExpression) {
defaultExits.add(insn) defaultExits.add(inst)
} }
} }
else -> if (insn != null && insn !is LocalFunctionDeclarationInstruction) { else -> if (inst != null && inst !is LocalFunctionDeclarationInstruction) {
defaultExits.add(insn) defaultExits.add(inst)
} }
} }
} }
val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext) val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)
val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is KtProperty && it.isLocal() } val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is KtProperty && it.isLocal }
val (typeOfDefaultFlow, defaultResultExpressions) = defaultExits.getResultTypeAndExpressions(bindingContext, targetScope, options, module) val (typeOfDefaultFlow, defaultResultExpressions) = defaultExits.getResultTypeAndExpressions(bindingContext, targetScope, options, module)
val (returnValueType, valuedReturnExpressions) = valuedReturnExits.getResultTypeAndExpressions(bindingContext, targetScope, options, module) val (returnValueType, valuedReturnExpressions) = valuedReturnExits.getResultTypeAndExpressions(bindingContext, targetScope, options, module)
@@ -298,7 +297,7 @@ private fun ExtractionData.analyzeControlFlow(
ControlFlow(Collections.emptyList(), { OutputValueBoxer.AsTuple(it, module) }, declarationsToCopy) ControlFlow(Collections.emptyList(), { OutputValueBoxer.AsTuple(it, module) }, declarationsToCopy)
val defaultReturnType = if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow val defaultReturnType = if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow
if (defaultReturnType.isError()) return emptyControlFlow to ErrorMessage.ERROR_TYPES if (defaultReturnType.isError) return emptyControlFlow to ErrorMessage.ERROR_TYPES
val controlFlow = if (defaultReturnType.isMeaningful()) { val controlFlow = if (defaultReturnType.isMeaningful()) {
emptyControlFlow.copy(outputValues = Collections.singletonList(ExpressionValue(false, defaultResultExpressions, defaultReturnType))) emptyControlFlow.copy(outputValues = Collections.singletonList(ExpressionValue(false, defaultResultExpressions, defaultReturnType)))
@@ -313,10 +312,10 @@ private fun ExtractionData.analyzeControlFlow(
} }
val outParameters = val outParameters =
parameters.filter { it.mirrorVarName != null && modifiedVarDescriptors[it.originalDescriptor] != null }.sortedBy { it.nameForRef } parameters.filter { it.mirrorVarName != null && modifiedVarDescriptors.getRaw(it.originalDescriptor) != null }.sortedBy { it.nameForRef }
val outDeclarations = val outDeclarations =
declarationsToCopy.filter { modifiedVarDescriptors[bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]] != null } declarationsToCopy.filter { modifiedVarDescriptors.getRaw(bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]) != null }
val modifiedValueCount = outParameters.size() + outDeclarations.size() val modifiedValueCount = outParameters.size + outDeclarations.size
val outputValues = ArrayList<OutputValue>() val outputValues = ArrayList<OutputValue>()
@@ -333,7 +332,7 @@ private fun ExtractionData.analyzeControlFlow(
if (defaultExits.isNotEmpty()) { if (defaultExits.isNotEmpty()) {
if (modifiedValueCount != 0) return outputAndExitsError if (modifiedValueCount != 0) return outputAndExitsError
if (valuedReturnExits.size() != 1) return multipleExitsError if (valuedReturnExits.size != 1) return multipleExitsError
val element = valuedReturnExits.first().element as KtExpression val element = valuedReturnExits.first().element as KtExpression
return controlFlow.copy(outputValues = Collections.singletonList(Jump(listOf(element), element, true, module.builtIns))) to null return controlFlow.copy(outputValues = Collections.singletonList(Jump(listOf(element), element, true, module.builtIns))) to null
@@ -345,15 +344,15 @@ private fun ExtractionData.analyzeControlFlow(
outDeclarations.mapTo(outputValues) { outDeclarations.mapTo(outputValues) {
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? CallableDescriptor val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? CallableDescriptor
Initializer(it as KtProperty, descriptor?.getReturnType() ?: module.builtIns.defaultParameterType) Initializer(it as KtProperty, descriptor?.returnType ?: module.builtIns.defaultParameterType)
} }
outParameters.mapTo(outputValues) { ParameterUpdate(it, modifiedVarDescriptors[it.originalDescriptor]!!) } outParameters.mapTo(outputValues) { ParameterUpdate(it, modifiedVarDescriptors.getRaw(it.originalDescriptor)!!) }
if (outputValues.isNotEmpty()) { if (outputValues.isNotEmpty()) {
if (jumpExits.isNotEmpty()) return outputAndExitsError if (jumpExits.isNotEmpty()) return outputAndExitsError
val boxerFactory: (List<OutputValue>) -> OutputValueBoxer = when { val boxerFactory: (List<OutputValue>) -> OutputValueBoxer = when {
outputValues.size() > 3 -> { outputValues.size > 3 -> {
if (!options.enableListBoxing) { if (!options.enableListBoxing) {
val outValuesStr = val outValuesStr =
(outParameters.map { it.originalDescriptor.renderForMessage() } (outParameters.map { it.originalDescriptor.renderForMessage() }
@@ -370,8 +369,7 @@ private fun ExtractionData.analyzeControlFlow(
} }
if (jumpExits.isNotEmpty()) { if (jumpExits.isNotEmpty()) {
val jumpTarget = getCommonNonTrivialSuccessorIfAny(jumpExits) val jumpTarget = getCommonNonTrivialSuccessorIfAny(jumpExits) ?: return multipleExitsError
if (jumpTarget == null) return multipleExitsError
val singleExit = getCommonNonTrivialSuccessorIfAny(defaultExits) == jumpTarget val singleExit = getCommonNonTrivialSuccessorIfAny(defaultExits) == jumpTarget
val conditional = !singleExit && defaultExits.isNotEmpty() val conditional = !singleExit && defaultExits.isNotEmpty()
@@ -384,18 +382,18 @@ private fun ExtractionData.analyzeControlFlow(
} }
fun ExtractionData.createTemporaryDeclaration(functionText: String): KtNamedDeclaration { fun ExtractionData.createTemporaryDeclaration(functionText: String): KtNamedDeclaration {
val textRange = targetSibling.getTextRange()!! val textRange = targetSibling.textRange!!
val insertText: String val insertText: String
val insertPosition: Int val insertPosition: Int
val lookupPosition: Int val lookupPosition: Int
if (insertBefore) { if (insertBefore) {
insertPosition = textRange.getStartOffset() insertPosition = textRange.startOffset
lookupPosition = insertPosition lookupPosition = insertPosition
insertText = functionText insertText = functionText
} }
else { else {
insertPosition = textRange.getEndOffset() insertPosition = textRange.endOffset
lookupPosition = insertPosition + 1 lookupPosition = insertPosition + 1
insertText = "\n$functionText" insertText = "\n$functionText"
} }
@@ -407,14 +405,14 @@ fun ExtractionData.createTemporaryDeclaration(functionText: String): KtNamedDecl
} }
private fun ExtractionData.createTemporaryCodeBlock(): KtBlockExpression = private fun ExtractionData.createTemporaryCodeBlock(): KtBlockExpression =
(createTemporaryDeclaration("fun() {\n$codeFragmentText\n}\n") as KtNamedFunction).getBodyExpression() as KtBlockExpression (createTemporaryDeclaration("fun() {\n$codeFragmentText\n}\n") as KtNamedFunction).bodyExpression as KtBlockExpression
private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): List<KotlinType> { private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): List<KotlinType> {
if (!processTypeArguments) return Collections.singletonList(this) if (!processTypeArguments) return Collections.singletonList(this)
return DFS.dfsFromNode( return DFS.dfsFromNode(
this, this,
object: Neighbors<KotlinType> { object: Neighbors<KotlinType> {
override fun getNeighbors(current: KotlinType): Iterable<KotlinType> = current.getArguments().map { it.getType() } override fun getNeighbors(current: KotlinType): Iterable<KotlinType> = current.arguments.map { it.type }
}, },
VisitedWithSet(), VisitedWithSet(),
object: CollectingNodeHandler<KotlinType, KotlinType, ArrayList<KotlinType>>(ArrayList()) { object: CollectingNodeHandler<KotlinType, KotlinType, ArrayList<KotlinType>>(ArrayList()) {
@@ -426,16 +424,15 @@ private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): Li
} }
fun KtTypeParameter.collectRelevantConstraints(): List<KtTypeConstraint> { fun KtTypeParameter.collectRelevantConstraints(): List<KtTypeConstraint> {
val typeConstraints = getNonStrictParentOfType<KtTypeParameterListOwner>()?.getTypeConstraints() val typeConstraints = getNonStrictParentOfType<KtTypeParameterListOwner>()?.typeConstraints ?: return Collections.emptyList()
if (typeConstraints == null) return Collections.emptyList() return typeConstraints.filter { it.subjectTypeParameterName?.mainReference?.resolve() == this}
return typeConstraints.filter { it.getSubjectTypeParameterName()?.mainReference?.resolve() == this}
} }
fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List<KotlinType> { fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List<KotlinType> {
val typeRefs = ArrayList<KtTypeReference>() val typeRefs = ArrayList<KtTypeReference>()
originalDeclaration.getExtendsBound()?.let { typeRefs.add(it) } originalDeclaration.extendsBound?.let { typeRefs.add(it) }
originalConstraints originalConstraints
.map { it.getBoundTypeReference() } .map { it.boundTypeReference }
.filterNotNullTo(typeRefs) .filterNotNullTo(typeRefs)
return typeRefs return typeRefs
@@ -445,7 +442,7 @@ fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List<K
private fun KotlinType.isExtractable(targetScope: LexicalScope?): Boolean { private fun KotlinType.isExtractable(targetScope: LexicalScope?): Boolean {
return collectReferencedTypes(true).fold(true) { extractable, typeToCheck -> return collectReferencedTypes(true).fold(true) { extractable, typeToCheck ->
val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor val parameterTypeDescriptor = typeToCheck.constructor.declarationDescriptor as? TypeParameterDescriptor
val typeParameter = parameterTypeDescriptor?.let { val typeParameter = parameterTypeDescriptor?.let {
DescriptorToSourceUtils.descriptorToDeclaration(it) DescriptorToSourceUtils.descriptorToDeclaration(it)
} as? KtTypeParameter } as? KtTypeParameter
@@ -462,7 +459,7 @@ private fun KotlinType.processTypeIfExtractable(
processTypeArguments: Boolean = true processTypeArguments: Boolean = true
): Boolean { ): Boolean {
return collectReferencedTypes(processTypeArguments).fold(true) { extractable, typeToCheck -> return collectReferencedTypes(processTypeArguments).fold(true) { extractable, typeToCheck ->
val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor val parameterTypeDescriptor = typeToCheck.constructor.declarationDescriptor as? TypeParameterDescriptor
val typeParameter = parameterTypeDescriptor?.let { val typeParameter = parameterTypeDescriptor?.let {
DescriptorToSourceUtils.descriptorToDeclaration(it) DescriptorToSourceUtils.descriptorToDeclaration(it)
} as? KtTypeParameter } as? KtTypeParameter
@@ -479,7 +476,7 @@ private fun KotlinType.processTypeIfExtractable(
options.allowSpecialClassNames && typeToCheck.isSpecial() -> options.allowSpecialClassNames && typeToCheck.isSpecial() ->
extractable extractable
typeToCheck.isError() -> typeToCheck.isError ->
false false
else -> { else -> {
@@ -537,7 +534,7 @@ private class MutableParameter(
val typePredicate = and(typePredicates) val typePredicate = and(typePredicates)
val typeSet = if (defaultType.isFlexible()) { val typeSet = if (defaultType.isFlexible()) {
val bounds = defaultType.getCapability(javaClass<Flexibility>())!! val bounds = defaultType.getCapability(Flexibility::class.java)!!
LinkedHashSet<KotlinType>().apply { LinkedHashSet<KotlinType>().apply {
if (typePredicate(bounds.upperBound)) add(bounds.upperBound) if (typePredicate(bounds.upperBound)) add(bounds.upperBound)
if (typePredicate(bounds.lowerBound)) add(bounds.lowerBound) if (typePredicate(bounds.lowerBound)) add(bounds.lowerBound)
@@ -545,7 +542,7 @@ private class MutableParameter(
} }
else linkedSetOf(defaultType) else linkedSetOf(defaultType)
val addNullableTypes = defaultType.isNullabilityFlexible() && typeSet.size() > 1 val addNullableTypes = defaultType.isNullabilityFlexible() && typeSet.size > 1
val superTypes = TypeUtils.getAllSupertypes(defaultType).filter(typePredicate) val superTypes = TypeUtils.getAllSupertypes(defaultType).filter(typePredicate)
for (superType in superTypes) { for (superType in superTypes) {
@@ -615,28 +612,28 @@ private fun ExtractionData.inferParametersInfo(
extractFunctionRef -> { extractFunctionRef -> {
originalDescriptor as FunctionDescriptor originalDescriptor as FunctionDescriptor
builtIns.getFunctionType(Annotations.EMPTY, builtIns.getFunctionType(Annotations.EMPTY,
originalDescriptor.getExtensionReceiverParameter()?.getType(), originalDescriptor.extensionReceiverParameter?.type,
originalDescriptor.getValueParameters().map { it.getType() }, originalDescriptor.valueParameters.map { it.type },
originalDescriptor.getReturnType() ?: builtIns.defaultReturnType) originalDescriptor.returnType ?: builtIns.defaultReturnType)
} }
parameterExpression != null -> parameterExpression != null ->
(if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression] else null) (if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression] else null)
?: bindingContext.getType(parameterExpression) ?: bindingContext.getType(parameterExpression)
?: (parameterExpression as? KtReferenceExpression)?.let { ?: (parameterExpression as? KtReferenceExpression)?.let {
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.getReturnType() (bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.returnType
} }
?: if (receiverToExtract.exists()) receiverToExtract.getType() else null ?: if (receiverToExtract.exists()) receiverToExtract.type else null
receiverToExtract is ThisReceiver -> { receiverToExtract is ThisReceiver -> {
val calleeExpression = resolvedCall!!.getCall().getCalleeExpression() val calleeExpression = resolvedCall!!.call.calleeExpression
val typeByDataFlowInfo = if (useSmartCastsIfPossible) { val typeByDataFlowInfo = if (useSmartCastsIfPossible) {
bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo -> bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo ->
val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract)) val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract))
if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null
} }
} else null } else null
typeByDataFlowInfo ?: receiverToExtract.getType() typeByDataFlowInfo ?: receiverToExtract.type
} }
receiverToExtract.exists() -> receiverToExtract.getType() receiverToExtract.exists() -> receiverToExtract.type
else -> null else -> null
} ?: builtIns.defaultParameterType } ?: builtIns.defaultParameterType
} }
@@ -645,23 +642,23 @@ private fun ExtractionData.inferParametersInfo(
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
val ref = refInfo.refExpr val ref = refInfo.refExpr
val selector = (ref.getParent() as? KtCallExpression) ?: ref val selector = (ref.parent as? KtCallExpression) ?: ref
val superExpr = (selector.getParent() as? KtQualifiedExpression)?.getReceiverExpression() as? KtSuperExpression val superExpr = (selector.parent as? KtQualifiedExpression)?.receiverExpression as? KtSuperExpression
if (superExpr != null) { if (superExpr != null) {
info.errorMessage = ErrorMessage.SUPER_CALL info.errorMessage = ErrorMessage.SUPER_CALL
return info return info
} }
val extensionReceiver = resolvedCall?.getExtensionReceiver() val extensionReceiver = resolvedCall?.extensionReceiver
val receiverToExtract = when { val receiverToExtract = when {
extensionReceiver == ReceiverValue.NO_RECEIVER, extensionReceiver == ReceiverValue.NO_RECEIVER,
isSynthesizedInvoke(originalDescriptor) -> resolvedCall?.getDispatchReceiver() isSynthesizedInvoke(originalDescriptor) -> resolvedCall?.dispatchReceiver
else -> extensionReceiver else -> extensionReceiver
} ?: ReceiverValue.NO_RECEIVER } ?: ReceiverValue.NO_RECEIVER
val thisDescriptor = (receiverToExtract as? ThisReceiver)?.getDeclarationDescriptor() val thisDescriptor = (receiverToExtract as? ThisReceiver)?.declarationDescriptor
val hasThisReceiver = thisDescriptor != null val hasThisReceiver = thisDescriptor != null
val thisExpr = ref.getParent() as? KtThisExpression val thisExpr = ref.parent as? KtThisExpression
if (hasThisReceiver if (hasThisReceiver
&& DescriptorToSourceUtilsIde.getAllDeclarations(project, thisDescriptor!!).all { it.isInsideOf(originalElements) }) { && DescriptorToSourceUtilsIde.getAllDeclarations(project, thisDescriptor!!).all { it.isInsideOf(originalElements) }) {
@@ -671,22 +668,22 @@ private fun ExtractionData.inferParametersInfo(
val referencedClassifierDescriptor: ClassifierDescriptor? = (thisDescriptor ?: originalDescriptor).let { val referencedClassifierDescriptor: ClassifierDescriptor? = (thisDescriptor ?: originalDescriptor).let {
when (it) { when (it) {
is ClassDescriptor -> is ClassDescriptor ->
when(it.getKind()) { when(it.kind) {
ClassKind.OBJECT, ClassKind.ENUM_CLASS -> it as ClassifierDescriptor ClassKind.OBJECT, ClassKind.ENUM_CLASS -> it
ClassKind.ENUM_ENTRY -> it.getContainingDeclaration() as? ClassDescriptor ClassKind.ENUM_ENTRY -> it.containingDeclaration as? ClassDescriptor
else -> if (ref.getNonStrictParentOfType<KtTypeReference>() != null) it as ClassifierDescriptor else null else -> if (ref.getNonStrictParentOfType<KtTypeReference>() != null) it else null
} }
is TypeParameterDescriptor -> it as ClassifierDescriptor is TypeParameterDescriptor -> it
is ConstructorDescriptor -> it.getContainingDeclaration() is ConstructorDescriptor -> it.containingDeclaration
else -> null else -> null
} } as? ClassifierDescriptor
} }
if (referencedClassifierDescriptor != null) { if (referencedClassifierDescriptor != null) {
if (!referencedClassifierDescriptor.getDefaultType().processTypeIfExtractable( if (!referencedClassifierDescriptor.defaultType.processTypeIfExtractable(
info.typeParameters, info.nonDenotableTypes, options, targetScope, referencedClassifierDescriptor is TypeParameterDescriptor info.typeParameters, info.nonDenotableTypes, options, targetScope, referencedClassifierDescriptor is TypeParameterDescriptor
)) continue )) continue
@@ -703,8 +700,8 @@ private fun ExtractionData.inferParametersInfo(
val extractFunctionRef = val extractFunctionRef =
options.captureLocalFunctions options.captureLocalFunctions
&& originalRef.getReferencedName() == originalDescriptor.getName().asString() // to forbid calls by convention && originalRef.getReferencedName() == originalDescriptor.name.asString() // to forbid calls by convention
&& originalDeclaration is KtNamedFunction && originalDeclaration.isLocal() && originalDeclaration is KtNamedFunction && originalDeclaration.isLocal
&& targetScope.findFunction(originalDescriptor.name, NoLookupLocation.FROM_IDE) { it == originalDescriptor } == null && targetScope.findFunction(originalDescriptor.name, NoLookupLocation.FROM_IDE) { it == originalDescriptor } == null
val descriptorToExtract = (if (extractThis) thisDescriptor else null) ?: originalDescriptor val descriptorToExtract = (if (extractThis) thisDescriptor else null) ?: originalDescriptor
@@ -713,12 +710,12 @@ private fun ExtractionData.inferParametersInfo(
if (extractParameter) { if (extractParameter) {
val parameterExpression = when { val parameterExpression = when {
receiverToExtract is ExpressionReceiver -> { receiverToExtract is ExpressionReceiver -> {
val receiverExpression = receiverToExtract.getExpression() val receiverExpression = receiverToExtract.expression
// If p.q has a smart-cast, then extract entire qualified expression // If p.q has a smart-cast, then extract entire qualified expression
if (refInfo.smartCast != null) receiverExpression.getParent() as KtExpression else receiverExpression if (refInfo.smartCast != null) receiverExpression.parent as KtExpression else receiverExpression
} }
receiverToExtract.exists() && refInfo.smartCast == null -> null receiverToExtract.exists() && refInfo.smartCast == null -> null
else -> (originalRef.getParent() as? KtThisExpression) ?: originalRef else -> (originalRef.parent as? KtThisExpression) ?: originalRef
} }
val parameterType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, true) val parameterType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, true)
@@ -726,7 +723,7 @@ private fun ExtractionData.inferParametersInfo(
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) { val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
var argumentText = var argumentText =
if (hasThisReceiver && extractThis) { if (hasThisReceiver && extractThis) {
val label = if (descriptorToExtract is ClassDescriptor) "@${descriptorToExtract.getName().asString()}" else "" val label = if (descriptorToExtract is ClassDescriptor) "@${descriptorToExtract.name.asString()}" else ""
"this$label" "this$label"
} }
else { else {
@@ -736,13 +733,13 @@ private fun ExtractionData.inferParametersInfo(
val nameElementType = nameElement.node.elementType val nameElementType = nameElement.node.elementType
(nameElementType as? KtToken)?.let { (nameElementType as? KtToken)?.let {
OperatorConventions.getNameForOperationSymbol(it)?.asString() OperatorConventions.getNameForOperationSymbol(it)?.asString()
} ?: nameElement.getText() } ?: nameElement.text
} }
else argumentExpr.getText() else argumentExpr.text
?: throw AssertionError("reference shouldn't be empty: code fragment = $codeFragmentText") ?: throw AssertionError("reference shouldn't be empty: code fragment = $codeFragmentText")
} }
if (extractFunctionRef) { if (extractFunctionRef) {
val receiverTypeText = (originalDeclaration as KtCallableDeclaration).getReceiverTypeReference()?.getText() ?: "" val receiverTypeText = (originalDeclaration as KtCallableDeclaration).receiverTypeReference?.text ?: ""
argumentText = "$receiverTypeText::$argumentText" argumentText = "$receiverTypeText::$argumentText"
} }
@@ -752,7 +749,7 @@ private fun ExtractionData.inferParametersInfo(
} }
if (!extractThis) { if (!extractThis) {
parameter.currentName = originalDeclaration.getNameIdentifier()?.getText() parameter.currentName = originalDeclaration.nameIdentifier?.text
} }
parameter.refCount++ parameter.refCount++
@@ -761,9 +758,9 @@ private fun ExtractionData.inferParametersInfo(
parameter.addDefaultType(parameterType) parameter.addDefaultType(parameterType)
if (extractThis && thisExpr == null) { if (extractThis && thisExpr == null) {
val callElement = resolvedCall!!.getCall().getCallElement() val callElement = resolvedCall!!.call.callElement
val instruction = pseudocode.getElementValue(callElement)?.createdAt as? InstructionWithReceivers val instruction = pseudocode.getElementValue(callElement)?.createdAt as? InstructionWithReceivers
val receiverValue = instruction?.receiverValues?.entrySet()?.singleOrNull { it.getValue() == receiverToExtract }?.getKey() val receiverValue = instruction?.receiverValues?.entries?.singleOrNull { it.value == receiverToExtract }?.key
if (receiverValue != null) { if (receiverValue != null) {
parameter.addTypePredicate(getExpectedTypePredicate(receiverValue, bindingContext, targetScope.ownerDescriptor.builtIns)) parameter.addTypePredicate(getExpectedTypePredicate(receiverValue, bindingContext, targetScope.ownerDescriptor.builtIns))
} }
@@ -798,7 +795,7 @@ private fun ExtractionData.inferParametersInfo(
if (currentName == null) { if (currentName == null) {
currentName = KotlinNameSuggester.suggestNamesByType(getParameterType(options.allowSpecialClassNames), varNameValidator, "p").first() currentName = KotlinNameSuggester.suggestNamesByType(getParameterType(options.allowSpecialClassNames), varNameValidator, "p").first()
} }
mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) KotlinNameSuggester.suggestNameByName(name, varNameValidator) else null mirrorVarName = if (modifiedVarDescriptors.containsRaw(descriptorToExtract)) KotlinNameSuggester.suggestNameByName(name, varNameValidator) else null
info.parameters.add(this) info.parameters.add(this)
} }
} }
@@ -849,7 +846,7 @@ private fun ExtractionData.getLocalInstructions(pseudocode: Pseudocode): List<In
} }
fun ExtractionData.isVisibilityApplicable(): Boolean { fun ExtractionData.isVisibilityApplicable(): Boolean {
return when (targetSibling.getParent()) { return when (targetSibling.parent) {
is KtClassBody, is KtFile -> true is KtClassBody, is KtFile -> true
else -> false else -> false
} }
@@ -880,7 +877,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
val modifiedVarDescriptorsWithExpressions = localInstructions.getModifiedVarDescriptors(bindingContext) val modifiedVarDescriptorsWithExpressions = localInstructions.getModifiedVarDescriptors(bindingContext)
val targetScope = targetSibling.getResolutionScope(bindingContext, commonParent.getResolutionFacade()) val targetScope = targetSibling.getResolutionScope(bindingContext, commonParent.getResolutionFacade())
val paramsInfo = inferParametersInfo(commonParent, pseudocode, bindingContext, targetScope, modifiedVarDescriptorsWithExpressions.keySet()) val paramsInfo = inferParametersInfo(commonParent, pseudocode, bindingContext, targetScope, modifiedVarDescriptorsWithExpressions.keys)
if (paramsInfo.errorMessage != null) { if (paramsInfo.errorMessage != null) {
return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(paramsInfo.errorMessage!!)) return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(paramsInfo.errorMessage!!))
} }
@@ -888,7 +885,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
val messages = ArrayList<ErrorMessage>() val messages = ArrayList<ErrorMessage>()
val modifiedVarDescriptorsForControlFlow = HashMap(modifiedVarDescriptorsWithExpressions) val modifiedVarDescriptorsForControlFlow = HashMap(modifiedVarDescriptorsWithExpressions)
modifiedVarDescriptorsForControlFlow.keySet().retainAll(localInstructions.getVarDescriptorsAccessedAfterwards(bindingContext)) modifiedVarDescriptorsForControlFlow.keys.retainAll(localInstructions.getVarDescriptorsAccessedAfterwards(bindingContext))
val (controlFlow, controlFlowMessage) = val (controlFlow, controlFlowMessage) =
analyzeControlFlow( analyzeControlFlow(
localInstructions, localInstructions,
@@ -927,7 +924,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
val adjustedParameters = paramsInfo.parameters.filterTo(HashSet<Parameter>()) { it.refCount > 0 } val adjustedParameters = paramsInfo.parameters.filterTo(HashSet<Parameter>()) { it.refCount > 0 }
val receiverCandidates = adjustedParameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate } val receiverCandidates = adjustedParameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate }
val receiverParameter = if (receiverCandidates.size() == 1) receiverCandidates.first() else null val receiverParameter = if (receiverCandidates.size == 1) receiverCandidates.first() else null
receiverParameter?.let { adjustedParameters.remove(it) } receiverParameter?.let { adjustedParameters.remove(it) }
return AnalysisResult( return AnalysisResult(
@@ -938,7 +935,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
getDefaultVisibility(), getDefaultVisibility(),
adjustedParameters.sortedBy { it.name }, adjustedParameters.sortedBy { it.name },
receiverParameter, receiverParameter,
paramsInfo.typeParameters.sortedBy { it.originalDeclaration.getName()!! }, paramsInfo.typeParameters.sortedBy { it.originalDeclaration.name!! },
paramsInfo.replacementMap, paramsInfo.replacementMap,
if (messages.isEmpty()) controlFlow else controlFlow.toDefault(), if (messages.isEmpty()) controlFlow else controlFlow.toDefault(),
returnType returnType
@@ -953,8 +950,8 @@ private fun ExtractionData.suggestFunctionNames(returnType: KotlinType): List<St
val validator = val validator =
NewDeclarationNameValidator( NewDeclarationNameValidator(
targetSibling.getParent(), targetSibling.parent,
if (targetSibling is KtClassInitializer) targetSibling.getParent() else targetSibling, if (targetSibling is KtClassInitializer) targetSibling.parent else targetSibling,
if (options.extractAsProperty) NewDeclarationNameValidator.Target.VARIABLES else NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES if (options.extractAsProperty) NewDeclarationNameValidator.Target.VARIABLES else NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES
) )
if (!returnType.isDefault()) { if (!returnType.isDefault()) {
@@ -963,8 +960,8 @@ private fun ExtractionData.suggestFunctionNames(returnType: KotlinType): List<St
getExpressions().singleOrNull()?.let { expr -> getExpressions().singleOrNull()?.let { expr ->
val property = expr.getStrictParentOfType<KtProperty>() val property = expr.getStrictParentOfType<KtProperty>()
if (property?.getInitializer() == expr) { if (property?.initializer == expr) {
property?.getName()?.let { functionNames.add(KotlinNameSuggester.suggestNameByName("get" + it.capitalize(), validator)) } property?.name?.let { functionNames.add(KotlinNameSuggester.suggestNameByName("get" + it.capitalize(), validator)) }
} }
} }
@@ -973,16 +970,16 @@ private fun ExtractionData.suggestFunctionNames(returnType: KotlinType): List<St
internal fun KtNamedDeclaration.getGeneratedBody() = internal fun KtNamedDeclaration.getGeneratedBody() =
when (this) { when (this) {
is KtNamedFunction -> getBodyExpression() is KtNamedFunction -> bodyExpression
else -> { else -> {
val property = this as KtProperty val property = this as KtProperty
property.getGetter()?.getBodyExpression()?.let { return it } property.getter?.bodyExpression?.let { return it }
property.getInitializer()?.let { return it } property.initializer?.let { return it }
// We assume lazy property here with delegate expression 'by Delegates.lazy { body }' // We assume lazy property here with delegate expression 'by Delegates.lazy { body }'
property.getDelegateExpression()?.let { property.delegateExpression?.let {
val call = it.getCalleeExpressionIfAny()?.getParent() as? KtCallExpression val call = it.getCalleeExpressionIfAny()?.parent as? KtCallExpression
call?.getFunctionLiteralArguments()?.singleOrNull()?.getFunctionLiteral()?.getBodyExpression() call?.functionLiteralArguments?.singleOrNull()?.getFunctionLiteral()?.bodyExpression
} }
} }
} ?: throw AssertionError("Couldn't get block body for this declaration: ${getElementTextWithContext()}") } ?: throw AssertionError("Couldn't get block body for this declaration: ${getElementTextWithContext()}")
@@ -1000,8 +997,8 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false) ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false)
).generateDeclaration() ).generateDeclaration()
val valueParameterList = (result.declaration as? KtNamedFunction)?.getValueParameterList() val valueParameterList = (result.declaration as? KtNamedFunction)?.valueParameterList
val typeParameterList = (result.declaration as? KtNamedFunction)?.getTypeParameterList() val typeParameterList = (result.declaration as? KtNamedFunction)?.typeParameterList
val body = result.declaration.getGeneratedBody() val body = result.declaration.getGeneratedBody()
val bindingContext = body.analyzeFully() val bindingContext = body.analyzeFully()
@@ -1013,19 +1010,19 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
(it as? KtThisExpression)?.instanceReference ?: it as? KtSimpleNameExpression (it as? KtThisExpression)?.instanceReference ?: it as? KtSimpleNameExpression
} ?: continue } ?: continue
if (currentRefExpr.getParent() is KtThisExpression) continue if (currentRefExpr.parent is KtThisExpression) continue
val diagnostics = bindingContext.getDiagnostics().forElement(currentRefExpr) val diagnostics = bindingContext.diagnostics.forElement(currentRefExpr)
val currentDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, currentRefExpr] val currentDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, currentRefExpr]
val currentTarget = val currentTarget =
currentDescriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(extractionData.project, it) } as? PsiNamedElement currentDescriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(extractionData.project, it) } as? PsiNamedElement
if (currentTarget is KtParameter && currentTarget.getParent() == valueParameterList) continue if (currentTarget is KtParameter && currentTarget.parent == valueParameterList) continue
if (currentTarget is KtTypeParameter && currentTarget.getParent() == typeParameterList) continue if (currentTarget is KtTypeParameter && currentTarget.parent == typeParameterList) continue
if (currentDescriptor is LocalVariableDescriptor if (currentDescriptor is LocalVariableDescriptor
&& parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue && parameters.any { it.mirrorVarName == currentDescriptor.name.asString() }) continue
if (diagnostics.any { it.getFactory() in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS } if (diagnostics.any { it.factory in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS }
|| (currentDescriptor != null || (currentDescriptor != null
&& !ErrorUtils.isError(currentDescriptor) && !ErrorUtils.isError(currentDescriptor)
&& !compareDescriptors(extractionData.project, currentDescriptor, resolveResult.descriptor))) { && !compareDescriptors(extractionData.project, currentDescriptor, resolveResult.descriptor))) {
@@ -1036,8 +1033,8 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
continue continue
} }
diagnostics.firstOrNull { it.getFactory() in Errors.INVISIBLE_REFERENCE_DIAGNOSTICS }?.let { diagnostics.firstOrNull { it.factory in Errors.INVISIBLE_REFERENCE_DIAGNOSTICS }?.let {
val message = when (it.getFactory()) { val message = when (it.factory) {
Errors.INVISIBLE_SETTER -> Errors.INVISIBLE_SETTER ->
getDeclarationMessage(resolveResult.declaration, "setter.of.0.will.become.invisible.after.extraction", false) getDeclarationMessage(resolveResult.declaration, "setter.of.0.will.become.invisible.after.extraction", false)
else -> else ->
@@ -1051,10 +1048,10 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
result.declaration.accept( result.declaration.accept(
object : KtTreeVisitorVoid() { object : KtTreeVisitorVoid() {
override fun visitUserType(userType: KtUserType) { override fun visitUserType(userType: KtUserType) {
val refExpr = userType.getReferenceExpression() ?: return val refExpr = userType.referenceExpression ?: return
val declaration = refExpr.mainReference.resolve() as? PsiNamedElement ?: return val declaration = refExpr.mainReference.resolve() as? PsiNamedElement ?: return
val diagnostics = bindingContext.getDiagnostics().forElement(refExpr) val diagnostics = bindingContext.diagnostics.forElement(refExpr)
diagnostics.firstOrNull { it.getFactory() == Errors.INVISIBLE_REFERENCE }?.let { diagnostics.firstOrNull { it.factory == Errors.INVISIBLE_REFERENCE }?.let {
conflicts.putValue(declaration, getDeclarationMessage(declaration, "0.will.become.invisible.after.extraction")) conflicts.putValue(declaration, getDeclarationMessage(declaration, "0.will.become.invisible.after.extraction"))
} }
} }
@@ -1072,4 +1069,4 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
return ExtractableCodeDescriptorWithConflicts(this, conflicts) return ExtractableCodeDescriptorWithConflicts(this, conflicts)
} }
private val LOG = Logger.getInstance(javaClass<ExtractionEngine>()) private val LOG = Logger.getInstance(ExtractionEngine::class.java)
@@ -98,14 +98,14 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
} }
with(descriptor.returnType) { with(descriptor.returnType) {
if (isDefault() || isError() || extractionTarget == ExtractionTarget.PROPERTY_WITH_INITIALIZER) { if (isDefault() || isError || extractionTarget == ExtractionTarget.PROPERTY_WITH_INITIALIZER) {
builder.noReturnType() builder.noReturnType()
} else { } else {
builder.returnType(typeAsString()) builder.returnType(typeAsString())
} }
} }
builder.typeConstraints(descriptor.typeParameters.flatMap { it.originalConstraints }.map { it.getText()!! }) builder.typeConstraints(descriptor.typeParameters.flatMap { it.originalConstraints }.map { it.text!! })
if (withBody) { if (withBody) {
val bodyText = descriptor.extractionData.codeFragmentText val bodyText = descriptor.extractionData.codeFragmentText
@@ -130,13 +130,13 @@ fun KotlinType.isSpecial(): Boolean {
fun createNameCounterpartMap(from: KtElement, to: KtElement): Map<KtSimpleNameExpression, KtSimpleNameExpression> { fun createNameCounterpartMap(from: KtElement, to: KtElement): Map<KtSimpleNameExpression, KtSimpleNameExpression> {
val map = HashMap<KtSimpleNameExpression, KtSimpleNameExpression>() val map = HashMap<KtSimpleNameExpression, KtSimpleNameExpression>()
val fromOffset = from.getTextRange()!!.getStartOffset() val fromOffset = from.textRange!!.startOffset
from.accept( from.accept(
object : KtTreeVisitorVoid() { object : KtTreeVisitorVoid() {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val offset = expression.getTextRange()!!.getStartOffset() - fromOffset val offset = expression.textRange!!.startOffset - fromOffset
val newExpression = to.findElementAt(offset)?.getNonStrictParentOfType<KtSimpleNameExpression>() val newExpression = to.findElementAt(offset)?.getNonStrictParentOfType<KtSimpleNameExpression>()
assert(newExpression != null) { "Couldn't find expression at $offset in '${to.getText()}'" } assert(newExpression != null) { "Couldn't find expression at $offset in '${to.text}'" }
map[expression] = newExpression!! map[expression] = newExpression!!
} }
@@ -154,7 +154,7 @@ class DuplicateInfo(
fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> { fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
fun processWeakMatch(match: Match, newControlFlow: ControlFlow): Boolean { fun processWeakMatch(match: Match, newControlFlow: ControlFlow): Boolean {
val valueCount = controlFlow.outputValues.size() val valueCount = controlFlow.outputValues.size
val weakMatches = HashMap((match.result as WeaklyMatched).weakMatches) val weakMatches = HashMap((match.result as WeaklyMatched).weakMatches)
val currentValuesToNew = HashMap<OutputValue, OutputValue>() val currentValuesToNew = HashMap<OutputValue, OutputValue>()
@@ -163,7 +163,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
if ((currentValue is Jump) != (newValue is Jump)) return false if ((currentValue is Jump) != (newValue is Jump)) return false
if (currentValue.originalExpressions.zip(newValue.originalExpressions).all { weakMatches[it.first] == it.second }) { if (currentValue.originalExpressions.zip(newValue.originalExpressions).all { weakMatches[it.first] == it.second }) {
currentValuesToNew[currentValue] = newValue currentValuesToNew[currentValue] = newValue
weakMatches.keySet().removeAll(currentValue.originalExpressions) weakMatches.keys.removeAll(currentValue.originalExpressions)
return true return true
} }
return false return false
@@ -180,7 +180,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
} }
} }
return currentValuesToNew.size() == valueCount && weakMatches.isEmpty() return currentValuesToNew.size == valueCount && weakMatches.isEmpty()
} }
fun getControlFlowIfMatched(match: Match): ControlFlow? { fun getControlFlowIfMatched(match: Match): ControlFlow? {
@@ -189,7 +189,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
val newControlFlow = analysisResult.descriptor!!.controlFlow val newControlFlow = analysisResult.descriptor!!.controlFlow
if (newControlFlow.outputValues.isEmpty()) return newControlFlow if (newControlFlow.outputValues.isEmpty()) return newControlFlow
if (controlFlow.outputValues.size() != newControlFlow.outputValues.size()) return null if (controlFlow.outputValues.size != newControlFlow.outputValues.size) return null
val matched = when (match.result) { val matched = when (match.result) {
is StronglyMatched -> true is StronglyMatched -> true
@@ -213,14 +213,14 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
.filter { !(it.range.getTextRange() intersects originalTextRange) } .filter { !(it.range.getTextRange() intersects originalTextRange) }
.map { match -> .map { match ->
val controlFlow = getControlFlowIfMatched(match) val controlFlow = getControlFlowIfMatched(match)
controlFlow?.let { DuplicateInfo(match.range, it, unifierParameters.map { match.result.substitution[it]!!.getText()!! }) } controlFlow?.let { DuplicateInfo(match.range, it, unifierParameters.map { match.result.substitution[it]!!.text!! }) }
} }
.filterNotNull() .filterNotNull()
.toList() .toList()
} }
private fun ExtractableCodeDescriptor.getOccurrenceContainer(): PsiElement? { private fun ExtractableCodeDescriptor.getOccurrenceContainer(): PsiElement? {
return extractionData.duplicateContainer ?: extractionData.targetSibling.getParent() return extractionData.duplicateContainer ?: extractionData.targetSibling.parent
} }
private fun makeCall( private fun makeCall(
@@ -256,16 +256,16 @@ private fun makeCall(
if (rangeToReplace !is KotlinPsiRange.ListRange) return if (rangeToReplace !is KotlinPsiRange.ListRange) return
val anchor = rangeToReplace.startElement val anchor = rangeToReplace.startElement
val anchorParent = anchor.getParent()!! val anchorParent = anchor.parent!!
anchor.getNextSibling()?.let { from -> anchor.nextSibling?.let { from ->
val to = rangeToReplace.endElement val to = rangeToReplace.endElement
if (to != anchor) { if (to != anchor) {
anchorParent.deleteChildRange(from, to); anchorParent.deleteChildRange(from, to);
} }
} }
val calleeName = declaration.getName() val calleeName = declaration.name
val callText = when (declaration) { val callText = when (declaration) {
is KtNamedFunction -> { is KtNamedFunction -> {
val argumentsText = arguments.joinToString(separator = ", ", prefix = "(", postfix = ")") val argumentsText = arguments.joinToString(separator = ", ", prefix = "(", postfix = ")")
@@ -278,22 +278,22 @@ private fun makeCall(
else -> calleeName else -> calleeName
} }
val anchorInBlock = sequence(anchor) { it.getParent() }.firstOrNull { it.getParent() is KtBlockExpression } val anchorInBlock = sequence(anchor) { it.parent }.firstOrNull { it.parent is KtBlockExpression }
val block = (anchorInBlock?.getParent() as? KtBlockExpression) ?: anchorParent val block = (anchorInBlock?.parent as? KtBlockExpression) ?: anchorParent
val psiFactory = KtPsiFactory(anchor.getProject()) val psiFactory = KtPsiFactory(anchor.project)
val newLine = psiFactory.createNewLine() val newLine = psiFactory.createNewLine()
if (controlFlow.outputValueBoxer is AsTuple && controlFlow.outputValues.size() > 1 && controlFlow.outputValues.all { it is Initializer }) { if (controlFlow.outputValueBoxer is AsTuple && controlFlow.outputValues.size > 1 && controlFlow.outputValues.all { it is Initializer }) {
val declarationsToMerge = controlFlow.outputValues.map { (it as Initializer).initializedDeclaration } val declarationsToMerge = controlFlow.outputValues.map { (it as Initializer).initializedDeclaration }
val isVar = declarationsToMerge.first().isVar() val isVar = declarationsToMerge.first().isVar
if (declarationsToMerge.all { it.isVar() == isVar }) { if (declarationsToMerge.all { it.isVar == isVar }) {
controlFlow.declarationsToCopy.subtract(declarationsToMerge).forEach { controlFlow.declarationsToCopy.subtract(declarationsToMerge).forEach {
block.addBefore(psiFactory.createDeclaration<KtDeclaration>(it.getText()!!), anchorInBlock) as KtDeclaration block.addBefore(psiFactory.createDeclaration<KtDeclaration>(it.text!!), anchorInBlock) as KtDeclaration
block.addBefore(newLine, anchorInBlock) block.addBefore(newLine, anchorInBlock)
} }
val entries = declarationsToMerge.map { p -> p.getName() + (p.getTypeReference()?.let { ": ${it.getText()}" } ?: "") } val entries = declarationsToMerge.map { p -> p.name + (p.typeReference?.let { ": ${it.text}" } ?: "") }
anchorInBlock?.replace( anchorInBlock?.replace(
psiFactory.createDeclaration("${if (isVar) "var" else "val"} (${entries.joinToString()}) = $callText") psiFactory.createDeclaration("${if (isVar) "var" else "val"} (${entries.joinToString()}) = $callText")
) )
@@ -302,7 +302,7 @@ private fun makeCall(
} }
} }
val inlinableCall = controlFlow.outputValues.size() <= 1 val inlinableCall = controlFlow.outputValues.size <= 1
val unboxingExpressions = val unboxingExpressions =
if (inlinableCall) { if (inlinableCall) {
controlFlow.outputValueBoxer.getUnboxingExpressions(callText!!) controlFlow.outputValueBoxer.getUnboxingExpressions(callText!!)
@@ -317,7 +317,7 @@ private fun makeCall(
val copiedDeclarations = HashMap<KtDeclaration, KtDeclaration>() val copiedDeclarations = HashMap<KtDeclaration, KtDeclaration>()
for (decl in controlFlow.declarationsToCopy) { for (decl in controlFlow.declarationsToCopy) {
val declCopy = psiFactory.createDeclaration<KtDeclaration>(decl.getText()!!) val declCopy = psiFactory.createDeclaration<KtDeclaration>(decl.text!!)
copiedDeclarations[decl] = block.addBefore(declCopy, anchorInBlock) as KtDeclaration copiedDeclarations[decl] = block.addBefore(declCopy, anchorInBlock) as KtDeclaration
block.addBefore(newLine, anchorInBlock) block.addBefore(newLine, anchorInBlock)
} }
@@ -332,7 +332,7 @@ private fun makeCall(
is OutputValue.ExpressionValue -> { is OutputValue.ExpressionValue -> {
val exprText = if (outputValue.callSiteReturn) { val exprText = if (outputValue.callSiteReturn) {
val firstReturn = outputValue.originalExpressions.filterIsInstance<KtReturnExpression>().firstOrNull() val firstReturn = outputValue.originalExpressions.filterIsInstance<KtReturnExpression>().firstOrNull()
val label = firstReturn?.getTargetLabel()?.getText() ?: "" val label = firstReturn?.getTargetLabel()?.text ?: ""
"return$label $callText" "return$label $callText"
} }
else { else {
@@ -352,14 +352,14 @@ private fun makeCall(
} }
else if (outputValue.conditional) { else if (outputValue.conditional) {
Collections.singletonList( Collections.singletonList(
psiFactory.createExpression("if ($callText) ${outputValue.elementToInsertAfterCall.getText()}") psiFactory.createExpression("if ($callText) ${outputValue.elementToInsertAfterCall.text}")
) )
} }
else { else {
listOf( listOf(
psiFactory.createExpression(callText), psiFactory.createExpression(callText),
newLine, newLine,
psiFactory.createExpression(outputValue.elementToInsertAfterCall.getText()!!) psiFactory.createExpression(outputValue.elementToInsertAfterCall.text!!)
) )
} }
} }
@@ -396,7 +396,7 @@ private fun makeCall(
insertCall(anchor, wrapCall(it, unboxingExpressions[it]!!).first() as KtExpression) insertCall(anchor, wrapCall(it, unboxingExpressions[it]!!).first() as KtExpression)
} }
if (anchor.isValid()) { if (anchor.isValid) {
anchor.delete() anchor.delete()
} }
} }
@@ -422,10 +422,10 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
return descriptor.controlFlow.outputValues return descriptor.controlFlow.outputValues
.map { .map {
when (it) { when (it) {
is ExpressionValue -> resultExpression?.getText() is ExpressionValue -> resultExpression?.text
is Jump -> if (it.conditional) "false" else null is Jump -> if (it.conditional) "false" else null
is ParameterUpdate -> it.parameter.nameForRef is ParameterUpdate -> it.parameter.nameForRef
is Initializer -> it.initializedDeclaration.getName() is Initializer -> it.initializedDeclaration.name
else -> throw IllegalArgumentException("Unknown output value: $it") else -> throw IllegalArgumentException("Unknown output value: $it")
} }
} }
@@ -438,19 +438,20 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
expressionToUnifyWith: KtExpression? expressionToUnifyWith: KtExpression?
) { ) {
val currentResultExpression = val currentResultExpression =
if (originalExpression is KtReturnExpression) originalExpression.getReturnedExpression() else originalExpression (if (originalExpression is KtReturnExpression) originalExpression.returnedExpression else originalExpression) ?: return
if (currentResultExpression == null) return
val newResultExpression = descriptor.controlFlow.defaultOutputValue?.let { val newResultExpression = descriptor.controlFlow.defaultOutputValue?.let {
val boxedExpression = originalExpression.replaced(replacingExpression).getReturnedExpression()!! val boxedExpression = originalExpression.replaced(replacingExpression).returnedExpression!!
descriptor.controlFlow.outputValueBoxer.extractExpressionByValue(boxedExpression, it) descriptor.controlFlow.outputValueBoxer.extractExpressionByValue(boxedExpression, it)
} }
@Suppress
if (newResultExpression == null) { if (newResultExpression == null) {
throw AssertionError("Can' replace '${originalExpression.getText()}' with '${replacingExpression.getText()}'") throw AssertionError("Can' replace '${originalExpression.text}' with '${replacingExpression.text}'")
} }
val counterpartMap = createNameCounterpartMap(currentResultExpression, expressionToUnifyWith ?: newResultExpression) val counterpartMap = createNameCounterpartMap(currentResultExpression, expressionToUnifyWith ?: newResultExpression)
nameByOffset.entrySet().forEach { e -> counterpartMap[e.getValue()]?.let { e.setValue(it) } } nameByOffset.entries.forEach { e -> counterpartMap.getRaw(e.value)?.let { e.setValue(it) } }
} }
fun getCounterparts<T : KtExpression>(originalExpressions: Collection<T>, fun getCounterparts<T : KtExpression>(originalExpressions: Collection<T>,
@@ -458,9 +459,9 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
bodyOffset: Int, bodyOffset: Int,
file: PsiFile): List<T> { file: PsiFile): List<T> {
return originalExpressions.map { originalExpression -> return originalExpressions.map { originalExpression ->
val offsetInBody = originalExpression.getTextRange()!!.getStartOffset() - descriptor.extractionData.originalStartOffset!! val offsetInBody = originalExpression.textRange!!.startOffset - descriptor.extractionData.originalStartOffset!!
file.findElementAt(bodyOffset + offsetInBody)?.getNonStrictParentOfType(originalExpression.javaClass) file.findElementAt(bodyOffset + offsetInBody)?.getNonStrictParentOfType(originalExpression.javaClass)
?: throw AssertionError("Couldn't find expression at $offsetInBody in '${body.getText()}'") ?: throw AssertionError("Couldn't find expression at $offsetInBody in '${body.text}'")
} }
} }
@@ -471,15 +472,15 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val originalOffsetByExpr = LinkedHashMap<KtElement, Int>() val originalOffsetByExpr = LinkedHashMap<KtElement, Int>()
val bodyOffset = body.getBlockContentOffset() val bodyOffset = body.getBlockContentOffset()
val file = body.getContainingFile()!! val file = body.containingFile!!
/* /*
* Sort by descending position so that internals of value/type arguments in calls and qualified types are replaced * Sort by descending position so that internals of value/type arguments in calls and qualified types are replaced
* before calls/types themselves * before calls/types themselves
*/ */
for ((offsetInBody, resolveResult) in descriptor.extractionData.refOffsetToDeclaration.entrySet().sortedByDescending { it.key }) { for ((offsetInBody, resolveResult) in descriptor.extractionData.refOffsetToDeclaration.entries.sortedByDescending { it.key }) {
val expr = file.findElementAt(bodyOffset + offsetInBody)?.getNonStrictParentOfType<KtSimpleNameExpression>() val expr = file.findElementAt(bodyOffset + offsetInBody)?.getNonStrictParentOfType<KtSimpleNameExpression>()
assert(expr != null) { "Couldn't find expression at $offsetInBody in '${body.getText()}'" } assert(expr != null) { "Couldn't find expression at $offsetInBody in '${body.text}'" }
originalOffsetByExpr[expr!!] = offsetInBody originalOffsetByExpr[expr!!] = offsetInBody
@@ -497,7 +498,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val jumpValue = descriptor.controlFlow.jumpOutputValue val jumpValue = descriptor.controlFlow.jumpOutputValue
if (jumpValue != null) { if (jumpValue != null) {
replacingReturn = psiFactory.createExpression(if (jumpValue.conditional) "return true" else "return") replacingReturn = psiFactory.createExpression(if (jumpValue.conditional) "return true" else "return")
returnsForLabelRemoval.removeAll(jumpValue.elementsToReplace) returnsForLabelRemoval.removeAllRaw(jumpValue.elementsToReplace)
expressionsToReplaceWithReturn = getCounterparts(jumpValue.elementsToReplace, body, bodyOffset, file) expressionsToReplaceWithReturn = getCounterparts(jumpValue.elementsToReplace, body, bodyOffset, file)
} }
else { else {
@@ -514,7 +515,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
getCounterparts(returnsForLabelRemoval, body, bodyOffset, file).forEach { it.getTargetLabel()?.delete() } getCounterparts(returnsForLabelRemoval, body, bodyOffset, file).forEach { it.getTargetLabel()?.delete() }
for ((expr, originalOffset) in originalOffsetByExpr) { for ((expr, originalOffset) in originalOffsetByExpr) {
if (expr.isValid()) { if (expr.isValid) {
nameByOffset.put(originalOffset, exprReplacementMap[expr]?.invoke(descriptor, expr) ?: expr) nameByOffset.put(originalOffset, exprReplacementMap[expr]?.invoke(descriptor, expr) ?: expr)
} }
} }
@@ -523,7 +524,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
if (body !is KtBlockExpression) throw AssertionError("Block body expected: ${descriptor.extractionData.codeFragmentText}") if (body !is KtBlockExpression) throw AssertionError("Block body expected: ${descriptor.extractionData.codeFragmentText}")
val firstExpression = body.getStatements().firstOrNull() val firstExpression = body.statements.firstOrNull()
if (firstExpression != null) { if (firstExpression != null) {
for (param in descriptor.parameters) { for (param in descriptor.parameters) {
param.mirrorVarName?.let { varName -> param.mirrorVarName?.let { varName ->
@@ -535,16 +536,16 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val defaultValue = descriptor.controlFlow.defaultOutputValue val defaultValue = descriptor.controlFlow.defaultOutputValue
val lastExpression = body.getStatements().lastOrNull() val lastExpression = body.statements.lastOrNull()
if (lastExpression is KtReturnExpression) return if (lastExpression is KtReturnExpression) return
val (defaultExpression, expressionToUnifyWith) = val (defaultExpression, expressionToUnifyWith) =
if (!generatorOptions.inTempFile && defaultValue != null && descriptor.controlFlow.outputValueBoxer.boxingRequired && lastExpression!!.isMultiLine()) { if (!generatorOptions.inTempFile && defaultValue != null && descriptor.controlFlow.outputValueBoxer.boxingRequired && lastExpression!!.isMultiLine()) {
val varNameValidator = NewDeclarationNameValidator(body, lastExpression, NewDeclarationNameValidator.Target.VARIABLES) val varNameValidator = NewDeclarationNameValidator(body, lastExpression, NewDeclarationNameValidator.Target.VARIABLES)
val resultVal = KotlinNameSuggester.suggestNamesByType(defaultValue.valueType, varNameValidator, null).first() val resultVal = KotlinNameSuggester.suggestNamesByType(defaultValue.valueType, varNameValidator, null).first()
val newDecl = body.addBefore(psiFactory.createDeclaration("val $resultVal = ${lastExpression!!.getText()}"), lastExpression) as KtProperty val newDecl = body.addBefore(psiFactory.createDeclaration("val $resultVal = ${lastExpression!!.text}"), lastExpression) as KtProperty
body.addBefore(psiFactory.createNewLine(), lastExpression) body.addBefore(psiFactory.createNewLine(), lastExpression)
psiFactory.createExpression(resultVal) to newDecl.getInitializer()!! psiFactory.createExpression(resultVal) to newDecl.initializer!!
} }
else { else {
lastExpression to null lastExpression to null
@@ -557,7 +558,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
// In the case of lazy property absence of default value means that output values are of OutputValue.Initializer type // In the case of lazy property absence of default value means that output values are of OutputValue.Initializer type
// We just add resulting expressions without return, since returns are prohibited in the body of lazy property // We just add resulting expressions without return, since returns are prohibited in the body of lazy property
if (defaultValue == null) { if (defaultValue == null) {
body.appendElement(returnExpression.getReturnedExpression()!!) body.appendElement(returnExpression.returnedExpression!!)
} }
return return
} }
@@ -573,8 +574,8 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
if (generatorOptions.allowExpressionBody) { if (generatorOptions.allowExpressionBody) {
val convertToExpressionBody = ConvertToExpressionBodyIntention() val convertToExpressionBody = ConvertToExpressionBodyIntention()
val bodyExpression = body.getStatements().singleOrNull() val bodyExpression = body.statements.singleOrNull()
val bodyOwner = body.getParent() as KtDeclarationWithBody val bodyOwner = body.parent as KtDeclarationWithBody
if (bodyExpression != null && !bodyExpression.isMultiLine() && convertToExpressionBody.isApplicableTo(bodyOwner)) { if (bodyExpression != null && !bodyExpression.isMultiLine() && convertToExpressionBody.isApplicableTo(bodyOwner)) {
convertToExpressionBody.applyTo(bodyOwner, !descriptor.returnType.isFlexible()) convertToExpressionBody.applyTo(bodyOwner, !descriptor.returnType.isFlexible())
} }
@@ -585,7 +586,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
declarationToReplace?.let { return it.replace(declaration) as KtNamedDeclaration } declarationToReplace?.let { return it.replace(declaration) as KtNamedDeclaration }
return with(descriptor.extractionData) { return with(descriptor.extractionData) {
val targetContainer = anchor.getParent()!! val targetContainer = anchor.parent!!
// TODO: Get rid of explicit new-lines in favor of formatter rules // TODO: Get rid of explicit new-lines in favor of formatter rules
val emptyLines = psiFactory.createWhiteSpace("\n\n") val emptyLines = psiFactory.createWhiteSpace("\n\n")
if (insertBefore) { if (insertBefore) {
@@ -630,14 +631,14 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
adjustDeclarationBody(declaration) adjustDeclarationBody(declaration)
if (declaration is KtNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) { if (declaration is KtNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) {
declaration.getReceiverTypeReference()?.debugTypeInfo = descriptor.receiverParameter?.getParameterType(true) declaration.receiverTypeReference?.debugTypeInfo = descriptor.receiverParameter?.getParameterType(true)
for ((i, param) in declaration.getValueParameters().withIndex()) { for ((i, param) in declaration.valueParameters.withIndex()) {
param.getTypeReference()?.debugTypeInfo = descriptor.parameters[i].getParameterType(true) param.typeReference?.debugTypeInfo = descriptor.parameters[i].getParameterType(true)
} }
if (declaration.getTypeReference() != null) { if (declaration.typeReference != null) {
declaration.getTypeReference()?.debugTypeInfo = descriptor.returnType.builtIns.anyType declaration.typeReference?.debugTypeInfo = descriptor.returnType.builtIns.anyType
} }
} }