Merge master into idea14
Conflicts: .idea/runConfigurations/All_Tests.xml idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt
This commit is contained in:
@@ -155,6 +155,9 @@
|
||||
<projectService serviceInterface="org.jetbrains.jet.asJava.KotlinLightClassForPackage$FileStubCache"
|
||||
serviceImplementation="org.jetbrains.jet.asJava.KotlinLightClassForPackage$FileStubCache"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.jet.plugin.debugger.evaluate.KotlinEvaluateExpressionCache"
|
||||
serviceImplementation="org.jetbrains.jet.plugin.debugger.evaluate.KotlinEvaluateExpressionCache"/>
|
||||
|
||||
<errorHandler implementation="org.jetbrains.jet.plugin.reporter.KotlinReportSubmitter"/>
|
||||
|
||||
<internalFileTemplate name="Kotlin File"/>
|
||||
@@ -287,6 +290,7 @@
|
||||
<typedHandler implementation="org.jetbrains.jet.plugin.editor.KotlinTypedHandler"/>
|
||||
<enterHandlerDelegate implementation="org.jetbrains.jet.plugin.editor.KotlinEnterHandler"
|
||||
id="KotlinEnterHandler" order="before EnterBetweenBracesHandler"/>
|
||||
<lang.smartEnterProcessor language="jet" implementationClass="org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler"/>
|
||||
<backspaceHandlerDelegate implementation="org.jetbrains.jet.plugin.editor.KotlinBackspaceHandler"/>
|
||||
|
||||
<copyPastePostProcessor implementation="org.jetbrains.jet.plugin.conversion.copy.ConvertJavaCopyPastePostProcessor"/>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.actions;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -25,10 +24,11 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.j2k.Converter;
|
||||
import org.jetbrains.jet.j2k.ConverterSettings;
|
||||
import org.jetbrains.jet.j2k.FilesConversionScope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class JavaToKotlinAction extends AnAction {
|
||||
assert virtualFiles != null;
|
||||
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
|
||||
assert project != null;
|
||||
final List<PsiFile> selectedJavaFiles = getAllJavaFiles(virtualFiles, project);
|
||||
final List<PsiJavaFile> selectedJavaFiles = getAllJavaFiles(virtualFiles, project);
|
||||
if (selectedJavaFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class JavaToKotlinAction extends AnAction {
|
||||
return;
|
||||
}
|
||||
|
||||
final Converter converter = prepareConverter(project, selectedJavaFiles);
|
||||
final Converter converter = Converter.object$.create(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles));
|
||||
CommandProcessor.getInstance().executeCommand(
|
||||
project,
|
||||
new Runnable() {
|
||||
@@ -76,18 +76,6 @@ public class JavaToKotlinAction extends AnAction {
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Converter prepareConverter(@NotNull Project project, @NotNull List<PsiFile> selectedJavaFiles) {
|
||||
Converter converter = new Converter(project, ConverterSettings.defaultSettings);
|
||||
converter.clearClassIdentifiers();
|
||||
for (PsiFile f : selectedJavaFiles) {
|
||||
if (f.getFileType() instanceof JavaFileType) {
|
||||
setClassIdentifiers(converter, f);
|
||||
}
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
private static enum DialogResult {
|
||||
BACKUP_FILES,
|
||||
DELETE_FILES,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.actions;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ex.MessagesEx;
|
||||
@@ -29,19 +28,11 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.j2k.Converter;
|
||||
import org.jetbrains.jet.j2k.visitors.ClassVisitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class JavaToKotlinActionUtil {
|
||||
|
||||
static void setClassIdentifiers(@NotNull Converter converter, @NotNull PsiFile psiFile) {
|
||||
ClassVisitor c = new ClassVisitor();
|
||||
psiFile.accept(c);
|
||||
converter.setClassIdentifiers(new HashSet<String>(c.getClassIdentifiers()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<VirtualFile> getChildrenRecursive(@Nullable VirtualFile baseDir) {
|
||||
List<VirtualFile> result = new LinkedList<VirtualFile>();
|
||||
@@ -53,14 +44,14 @@ public class JavaToKotlinActionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static List<PsiFile> getAllJavaFiles(@NotNull VirtualFile[] vFiles, Project project) {
|
||||
/*package*/ static List<PsiJavaFile> getAllJavaFiles(@NotNull VirtualFile[] vFiles, Project project) {
|
||||
Set<VirtualFile> filesSet = allVirtualFiles(vFiles);
|
||||
PsiManager manager = PsiManager.getInstance(project);
|
||||
List<PsiFile> res = new ArrayList<PsiFile>();
|
||||
List<PsiJavaFile> res = new ArrayList<PsiJavaFile>();
|
||||
for (VirtualFile file : filesSet) {
|
||||
PsiFile psiFile = manager.findFile(file);
|
||||
if (psiFile != null && psiFile.getFileType() instanceof JavaFileType) {
|
||||
res.add(psiFile);
|
||||
if (psiFile != null && psiFile instanceof PsiJavaFile) {
|
||||
res.add((PsiJavaFile)psiFile);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@@ -92,7 +83,7 @@ public class JavaToKotlinActionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static List<VirtualFile> convertFiles(final Converter converter, List<PsiFile> allJavaFilesNear) {
|
||||
static List<VirtualFile> convertFiles(final Converter converter, List<PsiJavaFile> allJavaFilesNear) {
|
||||
final List<VirtualFile> result = new LinkedList<VirtualFile>();
|
||||
for (final PsiFile f : allJavaFilesNear) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@@ -108,7 +99,7 @@ public class JavaToKotlinActionUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
static void deleteFiles(List<PsiFile> allJavaFilesNear) {
|
||||
static void deleteFiles(List<PsiJavaFile> allJavaFilesNear) {
|
||||
for (final PsiFile f : allJavaFilesNear) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
@@ -133,7 +124,7 @@ public class JavaToKotlinActionUtil {
|
||||
if (psiFile instanceof PsiJavaFile && virtualFile != null) {
|
||||
String result = "";
|
||||
try {
|
||||
result = converter.convertFile((PsiJavaFile) psiFile).toKotlin();
|
||||
result = converter.elementToKotlin(psiFile);
|
||||
} catch (Exception e) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.printStackTrace();
|
||||
@@ -150,7 +141,7 @@ public class JavaToKotlinActionUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static void renameFiles(@NotNull List<PsiFile> psiFiles) {
|
||||
static void renameFiles(@NotNull List<PsiJavaFile> psiFiles) {
|
||||
for (final PsiFile f : psiFiles) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -97,7 +97,7 @@ public class CodeInsightUtils {
|
||||
}
|
||||
if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
ArrayList<PsiElement> array = new ArrayList<PsiElement>();
|
||||
List<PsiElement> array = new ArrayList<PsiElement>();
|
||||
PsiElement stopElement = element2.getNextSibling();
|
||||
for (PsiElement currentElement = element1; currentElement != stopElement; currentElement = currentElement.getNextSibling()) {
|
||||
if (!(currentElement instanceof PsiWhiteSpace)) {
|
||||
|
||||
@@ -33,9 +33,11 @@ import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentForJavaClass
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer.FQ_NAMES_IN_TYPES
|
||||
|
||||
public object ShortenReferences {
|
||||
public fun process(element: JetElement) {
|
||||
@@ -100,6 +102,8 @@ public object ShortenReferences {
|
||||
|
||||
private fun process(elements: Iterable<JetElement>, elementFilter: (PsiElement) -> FilterResult) {
|
||||
for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) {
|
||||
ImportInsertHelper.optimizeImportsIfNeeded(file)
|
||||
|
||||
// first resolve all qualified references - optimization
|
||||
val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false)
|
||||
|
||||
@@ -313,7 +317,13 @@ public object ShortenReferences {
|
||||
|
||||
private fun resolveState(referenceExpression: JetReferenceExpression, bindingContext: BindingContext): Any? {
|
||||
val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpression]
|
||||
if (target != null) return target.asString()
|
||||
if (target != null) {
|
||||
val resolvedCallKey = (referenceExpression.getParent() as? JetThisExpression) ?: referenceExpression
|
||||
val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, resolvedCallKey]
|
||||
if (resolvedCall != null) return resolvedCall.asString()
|
||||
|
||||
return target.asString()
|
||||
}
|
||||
|
||||
val targets = bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression]
|
||||
if (targets != null) return HashSet(targets.map{it.asString()})
|
||||
@@ -334,8 +344,12 @@ public object ShortenReferences {
|
||||
|
||||
private fun DeclarationDescriptor.asString() = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(this)
|
||||
|
||||
private fun ResolvedCall<*>.asString(): String {
|
||||
return "${getReceiverArgument()}, ${getThisObject()} -> ${getResultingDescriptor()?.let {FQ_NAMES_IN_TYPES.render(it)}}"
|
||||
}
|
||||
|
||||
//TODO: do we need this "IfNeeded" check?
|
||||
private fun addImportIfNeeded(descriptor: DeclarationDescriptor, file: JetFile) {
|
||||
ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file)
|
||||
ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ fun createLookupElement(descriptor: DeclarationDescriptor, resolveSession: Resol
|
||||
return if (descriptor is FunctionDescriptor && descriptor.getValueParameters().isNotEmpty()) element.keepOldArgumentListOnTab() else element
|
||||
}
|
||||
|
||||
fun JetType.isSubtypeOf(expectedType: JetType) = !isError() && JetTypeChecker.INSTANCE.isSubtypeOf(this, expectedType)
|
||||
fun JetType.isSubtypeOf(expectedType: JetType) = !isError() && JetTypeChecker.DEFAULT.isSubtypeOf(this, expectedType)
|
||||
|
||||
fun <T : Any> T?.toList(): List<T> = if (this != null) listOf(this) else listOf()
|
||||
fun <T : Any> T?.toSet(): Set<T> = if (this != null) setOf(this) else setOf()
|
||||
|
||||
+12
-17
@@ -49,9 +49,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
||||
}
|
||||
|
||||
public override fun collectTransferableData(file: PsiFile, editor: Editor, startOffsets: IntArray, endOffsets: IntArray): List<TextBlockTransferableData> {
|
||||
if (file !is PsiJavaFile) {
|
||||
return listOf()
|
||||
}
|
||||
if (file !is PsiJavaFile) return listOf()
|
||||
|
||||
val lightFile = PsiFileFactory.getInstance(file.getProject())!!.createFileFromText(file.getText()!!, file)
|
||||
return listOf(CopiedCode(lightFile as? PsiJavaFile, startOffsets, endOffsets))
|
||||
@@ -61,36 +59,33 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
||||
assert(values.size() == 1)
|
||||
|
||||
val value = values.first()
|
||||
|
||||
if (value !is CopiedCode) return
|
||||
|
||||
if (value !is CopiedCode)
|
||||
return
|
||||
val sourceFile = value.getFile() ?: return
|
||||
|
||||
if (value.getFile() == null)
|
||||
return
|
||||
|
||||
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument())
|
||||
if (file !is JetFile)
|
||||
return
|
||||
val targetFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument())
|
||||
if (targetFile !is JetFile) return
|
||||
|
||||
val jetEditorOptions = JetEditorOptions.getInstance()!!
|
||||
val needConvert = jetEditorOptions.isEnableJavaToKotlinConversion() && (jetEditorOptions.isDonTShowConversionDialog() || okFromDialog(project))
|
||||
if (needConvert) {
|
||||
val text = convertCopiedCodeToKotlin(value, file.getProject())
|
||||
val text = convertCopiedCodeToKotlin(value, sourceFile)
|
||||
if (text.isNotEmpty()) {
|
||||
ApplicationManager.getApplication()!!.runWriteAction {
|
||||
val startOffset = bounds.getStartOffset()
|
||||
editor.getDocument().replaceString(bounds.getStartOffset(), bounds.getEndOffset(), text)
|
||||
val endOffsetAfterCopy = startOffset + text.length()
|
||||
editor.getCaretModel().moveToOffset(endOffsetAfterCopy)
|
||||
CodeStyleManager.getInstance(project)!!.reformatText(file, startOffset, endOffsetAfterCopy)
|
||||
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument())
|
||||
CodeStyleManager.getInstance(project)!!.reformatText(targetFile, startOffset, endOffsetAfterCopy)
|
||||
PsiDocumentManager.getInstance(targetFile.getProject()).commitDocument(editor.getDocument())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertCopiedCodeToKotlin(code: CopiedCode, project: Project): String {
|
||||
val converter = Converter(project, ConverterSettings.defaultSettings)
|
||||
private fun convertCopiedCodeToKotlin(code: CopiedCode, file: PsiJavaFile): String {
|
||||
val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)))
|
||||
val startOffsets = code.getStartOffsets()
|
||||
val endOffsets = code.getEndOffsets()
|
||||
assert(startOffsets.size == endOffsets.size) { "Must have the same size" }
|
||||
@@ -98,7 +93,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
||||
for (i in startOffsets.indices) {
|
||||
val startOffset = startOffsets[i]
|
||||
val endOffset = endOffsets[i]
|
||||
result.append(convertRangeToKotlin(code.getFile()!!, TextRange(startOffset, endOffset), converter))
|
||||
result.append(convertRangeToKotlin(file, TextRange(startOffset, endOffset), converter))
|
||||
}
|
||||
return StringUtil.convertLineSeparators(result.toString())
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
|
||||
override fun isContextAccepted(contextElement: PsiElement?): Boolean {
|
||||
if (contextElement is PsiCodeBlock) {
|
||||
return contextElement.getContext()?.getContext()?.getLanguage() == JetFileType.INSTANCE.getLanguage()
|
||||
return isContextAccepted(contextElement.getContext())
|
||||
}
|
||||
return contextElement?.getLanguage() == JetFileType.INSTANCE.getLanguage()
|
||||
}
|
||||
@@ -63,6 +63,10 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
||||
if (elementAt == null) return null
|
||||
|
||||
if (elementAt is PsiCodeBlock) {
|
||||
return getContextElement(elementAt.getContext())
|
||||
}
|
||||
|
||||
val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
|
||||
if (expressionAtOffset != null) {
|
||||
return expressionAtOffset
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.plugin.debugger.evaluate
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import java.util.ArrayList
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.jet.lang.types.JetType
|
||||
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName
|
||||
import org.jetbrains.jet.codegen.AsmUtil
|
||||
import org.apache.log4j.Logger
|
||||
|
||||
class KotlinEvaluateExpressionCache(val project: Project) {
|
||||
|
||||
private val cachedCompiledData = CachedValuesManager.getManager(project).createCachedValue(
|
||||
{
|
||||
CachedValueProvider.Result<MultiMap<String, CompiledDataDescriptor>>(
|
||||
MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||
}, false)
|
||||
|
||||
class object {
|
||||
private val LOG = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
|
||||
|
||||
fun getInstance(project: Project) = ServiceManager.getService(project, javaClass<KotlinEvaluateExpressionCache>())!!
|
||||
|
||||
fun getOrCreateCompiledData(
|
||||
codeFragment: JetCodeFragment,
|
||||
sourcePosition: SourcePosition,
|
||||
evaluationContext: EvaluationContextImpl,
|
||||
create: (JetCodeFragment, SourcePosition) -> CompiledDataDescriptor
|
||||
): CompiledDataDescriptor {
|
||||
val evaluateExpressionCache = getInstance(codeFragment.getProject())
|
||||
|
||||
return synchronized(evaluateExpressionCache.cachedCompiledData) {
|
||||
(): CompiledDataDescriptor ->
|
||||
val cache = evaluateExpressionCache.cachedCompiledData.getValue()!!
|
||||
val text = "${codeFragment.importsToString()}\n${codeFragment.getText()}"
|
||||
|
||||
val answer = cache[text].firstOrNull {
|
||||
it.sourcePosition == sourcePosition || evaluateExpressionCache.canBeEvaluatedInThisContext(it, evaluationContext)
|
||||
}
|
||||
if (answer != null) return@synchronized answer
|
||||
|
||||
val newCompiledData = create(codeFragment, sourcePosition)
|
||||
LOG.debug("Compile bytecode for ${codeFragment.getText()}")
|
||||
|
||||
cache.putValue(text, newCompiledData)
|
||||
return@synchronized newCompiledData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun canBeEvaluatedInThisContext(compiledData: CompiledDataDescriptor, context: EvaluationContextImpl): Boolean {
|
||||
return compiledData.parameters.all { (p): Boolean ->
|
||||
val (name, jetType) = p
|
||||
val value = context.getFrameProxy()?.getStackFrame()?.findLocalVariable(name, failIfNotFound = false)
|
||||
if (value == null) return@all false
|
||||
|
||||
val thisDescriptor = value.asmType.getClassDescriptor()
|
||||
val superClassDescriptor = jetType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor
|
||||
return@all thisDescriptor != null && superClassDescriptor != null && DescriptorUtils.isSubclass(thisDescriptor, superClassDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Type.getClassDescriptor(): ClassDescriptor? {
|
||||
if (AsmUtil.isPrimitive(this)) return null
|
||||
|
||||
val jvmName = JvmClassName.byInternalName(getInternalName()).getFqNameForClassNameWithoutDollars()
|
||||
|
||||
val platformClasses = JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmName)
|
||||
if (platformClasses.notEmpty) return platformClasses.first()
|
||||
|
||||
return ApplicationManager.getApplication()?.runReadAction<ClassDescriptor> {
|
||||
val classes = JavaPsiFacade.getInstance(project).findClasses(jvmName.asString(), GlobalSearchScope.allScope(project))
|
||||
if (classes.isEmpty()) null else JavaResolveExtension[project].resolveClass(JavaClassImpl(classes.first()))
|
||||
}
|
||||
}
|
||||
|
||||
data class CompiledDataDescriptor(val bytecodes: ByteArray, val sourcePosition: SourcePosition, val funName: String, val parameters: ParametersDescriptor)
|
||||
|
||||
class ParametersDescriptor : Iterable<Pair<String, JetType>> {
|
||||
private val list = ArrayList<Pair<String, JetType>>()
|
||||
|
||||
fun add(name: String, jetType: JetType) {
|
||||
list.add(name to jetType)
|
||||
}
|
||||
|
||||
fun getParameterNames() = list.map { it.first }
|
||||
|
||||
override fun iterator() = list.iterator()
|
||||
}
|
||||
}
|
||||
@@ -43,35 +43,24 @@ import org.jetbrains.eval4j.jdi.asJdiValue
|
||||
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||
import org.jetbrains.eval4j.jdi.asValue
|
||||
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory
|
||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.jet.OutputFileCollection
|
||||
import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||
import org.jetbrains.jet.lang.psi.JetImportList
|
||||
import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck
|
||||
import org.jetbrains.jet.lang.psi.JetExpression
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.jet.codegen.CompilationErrorHandler
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||
import org.jetbrains.jet.lang.diagnostics.Severity
|
||||
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages
|
||||
import com.sun.jdi.request.EventRequest
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.intellij.debugger.engine.SuspendContext
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder
|
||||
import org.jetbrains.jet.plugin.debugger.evaluate.KotlinEvaluateExpressionCache.*
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import com.sun.jdi.StackFrame
|
||||
import com.sun.jdi.VirtualMachine
|
||||
|
||||
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
||||
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
||||
@@ -98,52 +87,24 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
val sourcePosition: SourcePosition
|
||||
) : Evaluator {
|
||||
override fun evaluate(context: EvaluationContextImpl): Any? {
|
||||
var isCompiledDataFromCache = true
|
||||
try {
|
||||
val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine())
|
||||
if (extractedFunction == null) {
|
||||
throw IllegalStateException("Code fragment cannot be extracted to function: ${sourcePosition.getFile().getText()}:${sourcePosition.getLine()},\ncodeFragment = ${codeFragment.getText()}")
|
||||
val compiledData = KotlinEvaluateExpressionCache.getOrCreateCompiledData(codeFragment, sourcePosition, context) {
|
||||
fragment, position ->
|
||||
isCompiledDataFromCache = false
|
||||
extractAndCompile(fragment, position)
|
||||
}
|
||||
|
||||
val classFileFactory = createClassFileFactory(extractedFunction)
|
||||
|
||||
// KT-4509
|
||||
val outputFiles = (classFileFactory : OutputFileCollection).asList().filter { it.relativePath != "$packageInternalName.class" }
|
||||
if (outputFiles.size() != 1) exception("Expression compiles to more than one class file. Note that lambdas, classes and objects are unsupported yet. List of files: ${outputFiles.makeString(",")}")
|
||||
val args = context.getArgumentsByNames(compiledData.parameters.getParameterNames())
|
||||
val result = runEval4j(context, compiledData, args)
|
||||
|
||||
val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine()
|
||||
|
||||
var resultValue: Value? = null
|
||||
ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) {
|
||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
if (name == extractedFunction.getName()) {
|
||||
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
|
||||
override fun visitEnd() {
|
||||
val value = interpreterLoop(
|
||||
this,
|
||||
makeInitialFrame(this, context.getArgumentsByNames(extractedFunction.getParameterNamesForDebugger())),
|
||||
JDIEval(virtualMachine,
|
||||
context.getClassLoader()!!,
|
||||
context.getSuspendContext().getThread()?.getThreadReference()!!, context.getSuspendContext().getInvokePolicy())
|
||||
)
|
||||
|
||||
resultValue = when (value) {
|
||||
is ValueReturned -> value.result
|
||||
is ExceptionThrown -> exception(value.exception.toString())
|
||||
is AbnormalTermination -> exception(value.message)
|
||||
else -> throw IllegalStateException("Unknown result value produced by eval4j")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitMethod(access, name, desc, signature, exceptions)
|
||||
}
|
||||
}, 0)
|
||||
|
||||
if (resultValue == null) {
|
||||
throw IllegalStateException("resultValue is null: cannot find method ${extractedFunction.getName()} in ${outputFiles.first().relativePath}")
|
||||
// If bytecode was taken from cache and exception was thrown - recompile bytecode and run eval4j again
|
||||
if (isCompiledDataFromCache && result is ExceptionThrown && result.kind == ExceptionThrown.ExceptionKind.BROKEN_CODE) {
|
||||
return runEval4j(context, extractAndCompile(codeFragment, sourcePosition), args).toJdiValue(virtualMachine)
|
||||
}
|
||||
|
||||
return resultValue!!.asJdiValue(virtualMachine, resultValue!!.asmType)
|
||||
return result.toJdiValue(virtualMachine)
|
||||
}
|
||||
catch(e: EvaluateException) {
|
||||
throw e
|
||||
@@ -159,85 +120,145 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
return null
|
||||
}
|
||||
|
||||
private fun SuspendContext.getInvokePolicy(): Int {
|
||||
return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.getParameterNamesForDebugger(): List<String> {
|
||||
val result = arrayListOf<String>()
|
||||
if (getReceiverTypeRef() != null) {
|
||||
result.add("this")
|
||||
}
|
||||
for (param in getValueParameters()) {
|
||||
result.add(param.getName()!!)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List<String>): List<Value> {
|
||||
val frames = getFrameProxy()?.getStackFrame()
|
||||
if (frames != null) {
|
||||
fun getValue(name: String): Value {
|
||||
return try {
|
||||
when (name) {
|
||||
"this" -> frames.thisObject().asValue()
|
||||
else -> frames.getValue(frames.visibleVariableByName(name)).asValue()
|
||||
}
|
||||
}
|
||||
catch(e: Exception) {
|
||||
exception("Cannot get parameter value from local variables table: parameterName = ${name}. Note that captured parameters are unsupported yet.")
|
||||
}
|
||||
class object {
|
||||
private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition): CompiledDataDescriptor {
|
||||
val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine())
|
||||
if (extractedFunction == null) {
|
||||
throw IllegalStateException("Code fragment cannot be extracted to function: ${sourcePosition.getFile().getText()}:${sourcePosition.getLine()},\ncodeFragment = ${codeFragment.getText()}")
|
||||
}
|
||||
|
||||
return parameterNames.map { getValue(it) }
|
||||
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction)
|
||||
|
||||
// KT-4509
|
||||
val outputFiles = (classFileFactory : OutputFileCollection).asList().filter { it.relativePath != "$packageInternalName.class" }
|
||||
if (outputFiles.size() != 1) exception("Expression compiles to more than one class file. Note that lambdas, classes and objects are unsupported yet. List of files: ${outputFiles.makeString(",")}")
|
||||
|
||||
val funName = extractedFunction.getName()
|
||||
if (funName == null) {
|
||||
throw IllegalStateException("Extracted function should have a name: ${extractedFunction.getText()}")
|
||||
}
|
||||
return CompiledDataDescriptor(outputFiles.first().asByteArray(), sourcePosition, funName, extractedFunction.getParametersForDebugger())
|
||||
}
|
||||
return Collections.emptyList()
|
||||
}
|
||||
|
||||
private fun createClassFileFactory(extractedFunction: JetNamedFunction): ClassFileFactory {
|
||||
return ApplicationManager.getApplication()?.runReadAction(object: Computable<ClassFileFactory> {
|
||||
override fun compute(): ClassFileFactory? {
|
||||
val file = createFileForDebugger(codeFragment, extractedFunction)
|
||||
private fun runEval4j(
|
||||
context: EvaluationContextImpl,
|
||||
compiledData: CompiledDataDescriptor,
|
||||
args: List<Value>
|
||||
): InterpreterResult {
|
||||
val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine()
|
||||
|
||||
checkForSyntacticErrors(file)
|
||||
var resultValue: InterpreterResult? = null
|
||||
ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) {
|
||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
if (name == compiledData.funName) {
|
||||
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
|
||||
override fun visitEnd() {
|
||||
resultValue = interpreterLoop(
|
||||
this,
|
||||
makeInitialFrame(this, args),
|
||||
JDIEval(virtualMachine,
|
||||
context.getClassLoader()!!,
|
||||
context.getSuspendContext().getThread()?.getThreadReference()!!,
|
||||
context.getSuspendContext().getInvokePolicy())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val analyzeExhaust = file.getAnalysisResults()
|
||||
if (analyzeExhaust.isError()) {
|
||||
exception(analyzeExhaust.getError())
|
||||
return super.visitMethod(access, name, desc, signature, exceptions)
|
||||
}
|
||||
}, 0)
|
||||
|
||||
val bindingContext = analyzeExhaust.getBindingContext()
|
||||
bindingContext.getDiagnostics().forEach {
|
||||
diagnostic ->
|
||||
if (diagnostic.getSeverity() == Severity.ERROR) {
|
||||
exception(DefaultErrorMessages.RENDERER.render(diagnostic))
|
||||
return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}")
|
||||
}
|
||||
|
||||
private fun InterpreterResult.toJdiValue(vm: VirtualMachine): com.sun.jdi.Value? {
|
||||
val jdiValue = when (this) {
|
||||
is ValueReturned -> result
|
||||
is ExceptionThrown -> exception(exception.toString())
|
||||
is AbnormalTermination -> exception(message)
|
||||
else -> throw IllegalStateException("Unknown result value produced by eval4j")
|
||||
}
|
||||
return jdiValue.asJdiValue(vm, jdiValue.asmType)
|
||||
}
|
||||
|
||||
private fun SuspendContext.getInvokePolicy(): Int {
|
||||
return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.getParametersForDebugger(): ParametersDescriptor {
|
||||
return ApplicationManager.getApplication()?.runReadAction(Computable {
|
||||
val parameters = ParametersDescriptor()
|
||||
val bindingContext = getAnalysisResults().getBindingContext()
|
||||
val descriptor = bindingContext[BindingContext.FUNCTION, this]
|
||||
if (descriptor != null) {
|
||||
val receiver = descriptor.getReceiverParameter()
|
||||
if (receiver != null) {
|
||||
parameters.add("this", receiver.getType())
|
||||
}
|
||||
|
||||
descriptor.getValueParameters().forEach {
|
||||
param ->
|
||||
parameters.add(param.getName().asString(), param.getType())
|
||||
}
|
||||
}
|
||||
|
||||
val state = GenerationState(
|
||||
file.getProject(),
|
||||
ClassBuilderFactories.BINARIES,
|
||||
analyzeExhaust.getModuleDescriptor(),
|
||||
bindingContext,
|
||||
listOf(file)
|
||||
)
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
return state.getFactory()
|
||||
}
|
||||
})!!
|
||||
|
||||
}
|
||||
|
||||
private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
||||
|
||||
private fun exception(e: Throwable) {
|
||||
val message = e.getMessage()
|
||||
if (message != null) {
|
||||
exception(message)
|
||||
parameters
|
||||
})!!
|
||||
}
|
||||
|
||||
private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List<String>): List<Value> {
|
||||
val frames = getFrameProxy()?.getStackFrame()
|
||||
if (frames != null) {
|
||||
return parameterNames.map { frames.findLocalVariable(it)!! }
|
||||
}
|
||||
return Collections.emptyList()
|
||||
}
|
||||
|
||||
private fun createClassFileFactory(codeFragment: JetCodeFragment, extractedFunction: JetNamedFunction): ClassFileFactory {
|
||||
return ApplicationManager.getApplication()?.runReadAction(object : Computable<ClassFileFactory> {
|
||||
override fun compute(): ClassFileFactory? {
|
||||
val file = createFileForDebugger(codeFragment, extractedFunction)
|
||||
|
||||
checkForSyntacticErrors(file)
|
||||
|
||||
val analyzeExhaust = file.getAnalysisResults()
|
||||
if (analyzeExhaust.isError()) {
|
||||
exception(analyzeExhaust.getError())
|
||||
}
|
||||
|
||||
val bindingContext = analyzeExhaust.getBindingContext()
|
||||
bindingContext.getDiagnostics().forEach {
|
||||
diagnostic ->
|
||||
if (diagnostic.getSeverity() == Severity.ERROR) {
|
||||
exception(DefaultErrorMessages.RENDERER.render(diagnostic))
|
||||
}
|
||||
}
|
||||
|
||||
val state = GenerationState(
|
||||
file.getProject(),
|
||||
ClassBuilderFactories.BINARIES,
|
||||
analyzeExhaust.getModuleDescriptor(),
|
||||
bindingContext,
|
||||
listOf(file)
|
||||
)
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
return state.getFactory()
|
||||
}
|
||||
})!!
|
||||
|
||||
}
|
||||
|
||||
private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
||||
|
||||
private fun exception(e: Throwable) {
|
||||
val message = e.getMessage()
|
||||
if (message != null) {
|
||||
exception(message)
|
||||
}
|
||||
throw EvaluateExceptionUtil.createEvaluateException(e)
|
||||
}
|
||||
throw EvaluateExceptionUtil.createEvaluateException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,38 +292,6 @@ private fun createFileForDebugger(codeFragment: JetCodeFragment,
|
||||
return jetFile
|
||||
}
|
||||
|
||||
fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) {
|
||||
if (newImportList != null) {
|
||||
val tmpFileImportList = tmpFile.getImportList()
|
||||
val packageDirective = tmpFile.getPackageDirective()
|
||||
if (tmpFileImportList == null) {
|
||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||
tmpFile.addAfter(newImportList, tmpFile.getPackageDirective())
|
||||
}
|
||||
else {
|
||||
tmpFileImportList.replace(newImportList)
|
||||
}
|
||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||
}
|
||||
}
|
||||
|
||||
fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? {
|
||||
val parent = contextElement.getParent()
|
||||
if (parent == null) return null
|
||||
|
||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||
|
||||
val debugExpression = codeFragment.getContentElement()
|
||||
if (debugExpression == null) return null
|
||||
|
||||
val newDebugExpression = parent.addBefore(debugExpression, contextElement)
|
||||
if (newDebugExpression == null) return null
|
||||
|
||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||
|
||||
return newDebugExpression as JetExpression
|
||||
}
|
||||
|
||||
fun checkForSyntacticErrors(file: JetFile) {
|
||||
try {
|
||||
AnalyzingUtils.checkForSyntacticErrors(file)
|
||||
@@ -312,69 +301,22 @@ fun checkForSyntacticErrors(file: JetFile) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFunctionForExtractedFragment(
|
||||
codeFragment: JetCodeFragment,
|
||||
breakpointFile: PsiFile,
|
||||
breakpointLine: Int
|
||||
): JetNamedFunction? {
|
||||
|
||||
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String {
|
||||
return analysisResult.messages.map {
|
||||
errorMessage ->
|
||||
val message = when(errorMessage) {
|
||||
ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression"
|
||||
ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}"
|
||||
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.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable"
|
||||
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
||||
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
||||
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
||||
ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
||||
}
|
||||
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
||||
}.makeString(", ")
|
||||
}
|
||||
|
||||
return ApplicationManager.getApplication()?.runReadAction(object: Computable<JetNamedFunction> {
|
||||
override fun compute(): JetNamedFunction? {
|
||||
checkForSyntacticErrors(codeFragment)
|
||||
|
||||
val originalFile = breakpointFile as JetFile
|
||||
|
||||
val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine)
|
||||
if (lineStart == null) return null
|
||||
|
||||
val tmpFile = originalFile.createTempCopy { it }
|
||||
tmpFile.skipVisibilityCheck = true
|
||||
|
||||
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
||||
if (elementAtOffset == null) return null
|
||||
|
||||
val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||
|
||||
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
||||
|
||||
val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
||||
if (newDebugExpression == null) return null
|
||||
|
||||
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
||||
if (targetSibling == null) return null
|
||||
|
||||
val analysisResult = ExtractionData(
|
||||
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false)
|
||||
).performAnalysis()
|
||||
if (analysisResult.status != Status.SUCCESS) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||
}
|
||||
|
||||
val validationResult = analysisResult.descriptor!!.validate()
|
||||
if (!validationResult.conflicts.isEmpty()) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}")
|
||||
}
|
||||
|
||||
return validationResult.descriptor.generateFunction(true)
|
||||
fun StackFrame.findLocalVariable(name: String, failIfNotFound: Boolean = true): Value? {
|
||||
return try {
|
||||
when (name) {
|
||||
"this" -> thisObject().asValue()
|
||||
else -> getValue(visibleVariableByName(name)).asValue()
|
||||
}
|
||||
})
|
||||
}
|
||||
catch(e: Exception) {
|
||||
if (failIfNotFound) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(
|
||||
"Cannot find local variable: name = ${name}. Note that captured variables are unsupported yet.")
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.plugin.debugger.evaluate
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.util.Computable
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
||||
import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData
|
||||
import java.util.Collections
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction
|
||||
import org.jetbrains.jet.lang.psi.JetImportList
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||
import org.jetbrains.jet.lang.psi.JetExpression
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||
|
||||
fun getFunctionForExtractedFragment(
|
||||
codeFragment: JetCodeFragment,
|
||||
breakpointFile: PsiFile,
|
||||
breakpointLine: Int
|
||||
): JetNamedFunction? {
|
||||
|
||||
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String {
|
||||
return analysisResult.messages.map {
|
||||
errorMessage ->
|
||||
val message = when(errorMessage) {
|
||||
ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression"
|
||||
ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}"
|
||||
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.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable"
|
||||
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
||||
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
||||
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
||||
ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
||||
}
|
||||
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
||||
}.makeString(", ")
|
||||
}
|
||||
|
||||
return ApplicationManager.getApplication()?.runReadAction(object: Computable<JetNamedFunction> {
|
||||
override fun compute(): JetNamedFunction? {
|
||||
checkForSyntacticErrors(codeFragment)
|
||||
|
||||
val originalFile = breakpointFile as JetFile
|
||||
|
||||
val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine)
|
||||
if (lineStart == null) return null
|
||||
|
||||
val tmpFile = originalFile.createTempCopy { it }
|
||||
tmpFile.skipVisibilityCheck = true
|
||||
|
||||
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
||||
if (elementAtOffset == null) return null
|
||||
|
||||
val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||
|
||||
addImportsToFile(codeFragment.importsAsImportList(), tmpFile)
|
||||
|
||||
val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement)
|
||||
if (newDebugExpression == null) return null
|
||||
|
||||
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
||||
if (targetSibling == null) return null
|
||||
|
||||
val analysisResult = ExtractionData(
|
||||
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false)
|
||||
).performAnalysis()
|
||||
if (analysisResult.status != Status.SUCCESS) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||
}
|
||||
|
||||
val validationResult = analysisResult.descriptor!!.validate()
|
||||
if (!validationResult.conflicts.isEmpty()) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}")
|
||||
}
|
||||
|
||||
return validationResult.descriptor.generateFunction(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) {
|
||||
if (newImportList != null) {
|
||||
val tmpFileImportList = tmpFile.getImportList()
|
||||
val packageDirective = tmpFile.getPackageDirective()
|
||||
if (tmpFileImportList == null) {
|
||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||
tmpFile.addAfter(newImportList, tmpFile.getPackageDirective())
|
||||
}
|
||||
else {
|
||||
tmpFileImportList.replace(newImportList)
|
||||
}
|
||||
tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? {
|
||||
val parent = contextElement.getParent()
|
||||
if (parent == null) return null
|
||||
|
||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||
|
||||
val debugExpression = codeFragment.getContentElement()
|
||||
if (debugExpression == null) return null
|
||||
|
||||
val newDebugExpression = parent.addBefore(debugExpression, contextElement)
|
||||
if (newDebugExpression == null) return null
|
||||
|
||||
parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement)
|
||||
|
||||
return newDebugExpression as JetExpression
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.plugin.editor
|
||||
|
||||
import org.jetbrains.jet.plugin.editor.fixers.*
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.text.CharArrayUtil
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
||||
import org.jetbrains.jet.lang.psi.JetExpression
|
||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
||||
import org.jetbrains.jet.lang.psi.JetIfExpression
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression
|
||||
import org.jetbrains.jet.lang.psi.JetParameter
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.jet.JetNodeTypes
|
||||
import org.jetbrains.jet.lang.psi.JetLoopExpression
|
||||
|
||||
public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() {
|
||||
{
|
||||
addFixers(
|
||||
KotlinIfConditionFixer(),
|
||||
KotlinMissingIfBranchFixer(),
|
||||
|
||||
KotlinWhileConditionFixer(),
|
||||
KotlinForConditionFixer(),
|
||||
KotlinMissingForOrWhileBodyFixer(),
|
||||
|
||||
KotlinWhenSubjectCaretFixer(),
|
||||
KotlinMissingWhenBodyFixer(),
|
||||
|
||||
KotlinDoWhileFixer(),
|
||||
|
||||
KotlinFunctionParametersFixer(),
|
||||
KotlinFunctionDeclarationBodyFixer()
|
||||
)
|
||||
|
||||
addEnterProcessors(KotlinPlainEnterProcessor())
|
||||
}
|
||||
|
||||
override fun getStatementAtCaret(editor: Editor?, psiFile: PsiFile?): PsiElement? {
|
||||
var atCaret = super.getStatementAtCaret(editor, psiFile)
|
||||
|
||||
if (atCaret is PsiWhiteSpace) return null
|
||||
|
||||
while (atCaret != null) {
|
||||
when {
|
||||
atCaret?.isJetStatement() == true -> return atCaret
|
||||
atCaret?.getParent() is JetFunctionLiteral -> return atCaret
|
||||
atCaret is JetDeclaration -> {
|
||||
val declaration = atCaret!!
|
||||
when {
|
||||
declaration is JetParameter && !declaration.isInLambdaExpression() -> {/* proceed to function declaration */}
|
||||
declaration.getParent() is JetForExpression -> {/* skip variable declaration in 'for' expression */}
|
||||
else -> return atCaret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
atCaret = atCaret?.getParent()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun moveCaretInsideBracesIfAny(editor: Editor, file: PsiFile) {
|
||||
var caretOffset = editor.getCaretModel().getOffset()
|
||||
val chars = editor.getDocument().getCharsSequence()
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset, "{}")) {
|
||||
caretOffset += 2
|
||||
}
|
||||
else {
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset, "{\n}")) {
|
||||
caretOffset += 3
|
||||
}
|
||||
}
|
||||
|
||||
caretOffset = CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t") + 1
|
||||
|
||||
if (CharArrayUtil.regionMatches(chars, caretOffset - "{}".length(), "{}") ||
|
||||
CharArrayUtil.regionMatches(chars, caretOffset - "{\n}".length(), "{\n}")) {
|
||||
commit(editor)
|
||||
val settings = CodeStyleSettingsManager.getSettings(file.getProject())
|
||||
val old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false
|
||||
val elt = PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset - 1), javaClass<JetBlockExpression>())
|
||||
if (elt != null) {
|
||||
reformat(elt)
|
||||
}
|
||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old
|
||||
editor.getCaretModel().moveToOffset(caretOffset - 1)
|
||||
}
|
||||
}
|
||||
|
||||
public fun registerUnresolvedError(offset: Int) {
|
||||
if (myFirstErrorOffset > offset) {
|
||||
myFirstErrorOffset = offset
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isJetStatement() =
|
||||
getParent() is JetBlockExpression || (getParent()?.getNode()?.getElementType() in BRANCH_CONTAINERS)
|
||||
|
||||
class KotlinPlainEnterProcessor : SmartEnterProcessorWithFixers.FixEnterProcessor() {
|
||||
private fun getControlStatementBlock(caret: Int, element: PsiElement): JetExpression? {
|
||||
when (element) {
|
||||
is JetDeclarationWithBody -> return element.getBodyExpression()
|
||||
is JetIfExpression -> {
|
||||
if (element.getThen().isWithCaret(caret)) return element.getThen()
|
||||
if (element.getElse().isWithCaret(caret)) return element.getElse()
|
||||
}
|
||||
is JetLoopExpression -> return element.getBody()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun doEnter(atCaret: PsiElement, file: PsiFile?, editor: Editor, modified: Boolean): Boolean {
|
||||
val block = getControlStatementBlock(editor.getCaretModel().getOffset(), atCaret) as? JetBlockExpression
|
||||
if (block != null) {
|
||||
val firstElement = block.getFirstChild()?.getNextSibling()
|
||||
|
||||
val offset = if (firstElement != null) {
|
||||
firstElement.getTextRange()!!.getStartOffset() - 1
|
||||
} else {
|
||||
block.getTextRange()!!.getEndOffset()
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(offset)
|
||||
}
|
||||
|
||||
plainEnter(editor)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val BRANCH_CONTAINERS = TokenSet.create(JetNodeTypes.THEN, JetNodeTypes.ELSE, JetNodeTypes.BODY)
|
||||
private fun JetParameter.isInLambdaExpression() = this.getParent()?.getParent() is JetFunctionLiteral
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetDoWhileExpression
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
||||
|
||||
public class KotlinDoWhileFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
|
||||
if (psiElement !is JetDoWhileExpression) return
|
||||
|
||||
val doc = editor.getDocument()
|
||||
val stmt = psiElement as JetDoWhileExpression
|
||||
val start = stmt.range.start
|
||||
val body = stmt.getBody()
|
||||
|
||||
val whileKeyword = stmt.getWhileKeywordElement()
|
||||
if (body == null) {
|
||||
if (whileKeyword == null) {
|
||||
doc.replaceString(start, start + "do".length(), "do {} while()")
|
||||
}
|
||||
else {
|
||||
doc.insertString(start + "do".length(), "{}")
|
||||
}
|
||||
return
|
||||
}
|
||||
else if (whileKeyword != null && body !is JetBlockExpression && body.startLine(doc) > stmt.startLine(doc)) {
|
||||
doc.insertString(start + "do".length(), "{")
|
||||
doc.insertString(whileKeyword.range.start - 1, "}")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (stmt.getCondition() == null) {
|
||||
val lParen = stmt.getLeftParenthesis()
|
||||
val rParen = stmt.getRightParenthesis()
|
||||
|
||||
when {
|
||||
whileKeyword == null -> doc.insertString(stmt.range.end, "while()")
|
||||
lParen == null && rParen == null -> {
|
||||
doc.replaceString(whileKeyword.range.start, whileKeyword.range.end, "while()")
|
||||
}
|
||||
lParen != null -> processor.registerUnresolvedError(lParen.range.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetWhileExpression
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression
|
||||
|
||||
public class KotlinForConditionFixer: MissingConditionFixer<JetForExpression>() {
|
||||
override val keyword = "for"
|
||||
override fun getElement(element: PsiElement?) = element as? JetForExpression
|
||||
override fun getCondition(element: JetForExpression) =
|
||||
element.getLoopRange() ?: element.getLoopParameter() ?: element.getMultiParameter()
|
||||
override fun getLeftParenthesis(element: JetForExpression) = element.getLeftParenthesis()
|
||||
override fun getRightParenthesis(element: JetForExpression) = element.getRightParenthesis()
|
||||
override fun getBody(element: JetForExpression) = element.getBody()
|
||||
}
|
||||
@@ -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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetFunction
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
|
||||
|
||||
public class KotlinFunctionDeclarationBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
|
||||
if (psiElement !is JetNamedFunction) return
|
||||
if (psiElement.getBodyExpression() != null|| psiElement.getEqualsToken() != null) return
|
||||
|
||||
val parentDeclaration = PsiTreeUtil.getParentOfType(psiElement, javaClass<JetDeclaration>())
|
||||
if (parentDeclaration is JetClassOrObject) {
|
||||
if (JetPsiUtil.isTrait(parentDeclaration) || psiElement.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val doc = editor.getDocument()
|
||||
var endOffset = psiElement.range.end
|
||||
|
||||
if (psiElement.getText()?.last() == ';') {
|
||||
doc.deleteString(endOffset - 1, endOffset)
|
||||
endOffset--
|
||||
}
|
||||
|
||||
doc.insertString(endOffset, "{}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
|
||||
|
||||
public class KotlinFunctionParametersFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
|
||||
if (psiElement !is JetNamedFunction) return;
|
||||
|
||||
val parameterList = psiElement.getValueParameterList()
|
||||
if (parameterList == null) {
|
||||
val identifier = psiElement.getNameIdentifier()
|
||||
if (identifier == null) return
|
||||
|
||||
// Insert () after name or after type parameters list when it placed after name
|
||||
val offset = Math.max(identifier.range.end, psiElement.getTypeParameterList()?.range?.end ?: psiElement.range.start)
|
||||
editor.getDocument().insertString(offset, "()")
|
||||
processor.registerUnresolvedError(offset + 1)
|
||||
}
|
||||
else {
|
||||
val rParen = parameterList.getLastChild()
|
||||
if (rParen == null) return
|
||||
|
||||
if (")" != rParen.getText()) {
|
||||
val params = parameterList.getParameters()
|
||||
val offset = if (params.isEmpty()) parameterList.range.start + 1 else params.last().range.end
|
||||
editor.getDocument().insertString(offset, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetIfExpression
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.openapi.util.TextRange
|
||||
|
||||
public class KotlinIfConditionFixer : MissingConditionFixer<JetIfExpression>() {
|
||||
override val keyword = "if"
|
||||
override fun getElement(element: PsiElement?) = element as? JetIfExpression
|
||||
override fun getCondition(element: JetIfExpression) = element.getCondition()
|
||||
override fun getLeftParenthesis(element: JetIfExpression) = element.getLeftParenthesis()
|
||||
override fun getRightParenthesis(element: JetIfExpression) = element.getRightParenthesis()
|
||||
override fun getBody(element: JetIfExpression) = element.getThen()
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetWhileExpression
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
||||
import org.jetbrains.jet.lang.psi.JetLoopExpression
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression
|
||||
|
||||
public class KotlinMissingForOrWhileBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
|
||||
if (!(element is JetForExpression || element is JetWhileExpression)) return
|
||||
val loopExpression = element as JetLoopExpression
|
||||
|
||||
val doc = editor.getDocument()
|
||||
|
||||
val body = loopExpression.getBody()
|
||||
if (body is JetBlockExpression) return
|
||||
|
||||
if (!loopExpression.isValidLoopCondition()) return
|
||||
|
||||
if (body != null && body.startLine(doc) == loopExpression.startLine(doc)) return
|
||||
|
||||
val rParen = loopExpression.getRightParenthesis()
|
||||
if (rParen == null) return
|
||||
|
||||
doc.insertString(rParen.range.end, "{}")
|
||||
}
|
||||
|
||||
fun JetLoopExpression.isValidLoopCondition() = getLeftParenthesis() != null && getRightParenthesis() != null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.psi.JetIfExpression
|
||||
import org.jetbrains.jet.plugin.formatter.JetBlock
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
||||
|
||||
public class KotlinMissingIfBranchFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
|
||||
if (element !is JetIfExpression) return
|
||||
val ifExpression = element as JetIfExpression
|
||||
|
||||
val document = editor.getDocument()
|
||||
val elseBranch = ifExpression.getElse()
|
||||
val elseKeyword = ifExpression.getElseKeyword()
|
||||
|
||||
if (elseKeyword != null) {
|
||||
if (elseBranch == null || elseBranch !is JetBlockExpression && elseBranch.startLine(editor.getDocument()) > elseKeyword.startLine(editor.getDocument())) {
|
||||
document.insertString(elseKeyword.range.end, "{}")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val thenBranch = ifExpression.getThen()
|
||||
if (thenBranch is JetBlockExpression) return
|
||||
|
||||
val rParen = ifExpression.getRightParenthesis()
|
||||
if (rParen == null) return
|
||||
|
||||
var transformingOneLiner = false
|
||||
if (thenBranch != null && thenBranch.startLine(editor.getDocument()) == ifExpression.startLine(editor.getDocument())) {
|
||||
if (ifExpression.getCondition() != null) return
|
||||
transformingOneLiner = true
|
||||
}
|
||||
|
||||
val probablyNextStatementParsedAsThen = elseKeyword == null && elseBranch == null && !transformingOneLiner
|
||||
|
||||
if (thenBranch == null || probablyNextStatementParsedAsThen) {
|
||||
document.insertString(rParen.range.end, "{}")
|
||||
}
|
||||
else {
|
||||
document.insertString(rParen.range.end, "{")
|
||||
document.insertString(thenBranch.range.end + 1, "}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetWhenExpression
|
||||
|
||||
public class KotlinMissingWhenBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
|
||||
if (element !is JetWhenExpression) return
|
||||
val whenExpression = element as JetWhenExpression
|
||||
|
||||
val doc = editor.getDocument()
|
||||
|
||||
val openBrace = whenExpression.getOpenBrace()
|
||||
val closeBrace = whenExpression.getCloseBrace()
|
||||
|
||||
if (openBrace == null && closeBrace == null && whenExpression.getEntries().isEmpty()) {
|
||||
val openBraceAfter = whenExpression.insertOpenBraceAfter()
|
||||
if (openBraceAfter != null) {
|
||||
doc.insertString(openBraceAfter.range.end, "{}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun JetWhenExpression.insertOpenBraceAfter(): PsiElement? = when {
|
||||
getRightParenthesis() != null -> getRightParenthesis()
|
||||
getSubjectExpression() != null -> null
|
||||
getLeftParenthesis() != null -> null
|
||||
else -> getWhenKeywordElement()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.jet.lang.psi.JetWhenExpression
|
||||
|
||||
public class KotlinWhenSubjectCaretFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
|
||||
if (element !is JetWhenExpression) return
|
||||
|
||||
val lParen = element.getLeftParenthesis()
|
||||
val rParen = element.getRightParenthesis()
|
||||
val subject = element.getSubjectExpression()
|
||||
|
||||
if (subject == null && lParen != null && rParen != null) {
|
||||
processor.registerUnresolvedError(lParen.range.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetIfExpression
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.psi.JetWhileExpression
|
||||
|
||||
public class KotlinWhileConditionFixer: MissingConditionFixer<JetWhileExpression>() {
|
||||
override val keyword = "while"
|
||||
override fun getElement(element: PsiElement?) = element as? JetWhileExpression
|
||||
override fun getCondition(element: JetWhileExpression) = element.getCondition()
|
||||
override fun getLeftParenthesis(element: JetWhileExpression) = element.getLeftParenthesis()
|
||||
override fun getRightParenthesis(element: JetWhileExpression) = element.getRightParenthesis()
|
||||
override fun getBody(element: JetWhileExpression) = element.getBody()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.lang.SmartEnterProcessorWithFixers
|
||||
import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
abstract class MissingConditionFixer<T: PsiElement>() : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
|
||||
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
|
||||
val workElement = getElement(element)
|
||||
if (workElement == null) return
|
||||
|
||||
val doc = editor.getDocument()
|
||||
val lParen = getLeftParenthesis(workElement)
|
||||
val rParen = getRightParenthesis(workElement)
|
||||
val condition = getCondition(workElement)
|
||||
|
||||
if (condition == null) {
|
||||
if (lParen == null || rParen == null) {
|
||||
var stopOffset = doc.getLineEndOffset(doc.getLineNumber(workElement.range.start))
|
||||
val then = getBody(workElement)
|
||||
if (then != null) {
|
||||
stopOffset = Math.min(stopOffset, then.range.start)
|
||||
}
|
||||
|
||||
stopOffset = Math.min(stopOffset, workElement.range.end)
|
||||
|
||||
doc.replaceString(workElement.range.start, stopOffset, "$keyword ()")
|
||||
processor.registerUnresolvedError(workElement.range.start + "$keyword (".length())
|
||||
}
|
||||
else {
|
||||
processor.registerUnresolvedError(lParen.range.end)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rParen == null) {
|
||||
doc.insertString(condition.range.end, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract val keyword: String
|
||||
abstract fun getElement(element: PsiElement?): T?
|
||||
abstract fun getCondition(element: T): PsiElement?
|
||||
abstract fun getLeftParenthesis(element: T): PsiElement?
|
||||
abstract fun getRightParenthesis(element: T): PsiElement?
|
||||
abstract fun getBody(element: T): PsiElement?
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.plugin.editor.fixers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.editor.Document
|
||||
|
||||
val PsiElement.range: TextRange get() = getTextRange()!!
|
||||
val TextRange.start: Int get() = getStartOffset()
|
||||
val TextRange.end: Int get() = getEndOffset()
|
||||
|
||||
fun PsiElement.startLine(doc: Document): Int = doc.getLineNumber(range.start)
|
||||
fun PsiElement?.isWithCaret(caret: Int) = this?.getTextRange()?.contains(caret) == true
|
||||
@@ -259,6 +259,7 @@ fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder {
|
||||
afterInside(LBRACE, BLOCK).lineBreakInCode()
|
||||
beforeInside(RBRACE, CLASS_BODY).lineBreakInCode()
|
||||
beforeInside(RBRACE, BLOCK).lineBreakInCode()
|
||||
beforeInside(RBRACE, WHEN).lineBreakInCode()
|
||||
between(RPAR, BODY).spaces(1)
|
||||
|
||||
// if when entry has block, spacing after arrow should be set by lbrace rule
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ public open class ReplaceContainsIntention : AttributeCallReplacementIntention("
|
||||
val ret = call.resolved.getResultingDescriptor().getReturnType()
|
||||
?: return intentionFailed(editor, "undefined.returntype")
|
||||
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(ret, KotlinBuiltIns.getInstance().getBooleanType())) {
|
||||
if (!JetTypeChecker.DEFAULT.isSubtypeOf(ret, KotlinBuiltIns.getInstance().getBooleanType())) {
|
||||
return intentionFailed(editor, "contains.returns.boolean")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -327,7 +327,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
|
||||
if (argument.getArgumentExpression() != null) {
|
||||
JetType paramType = getActualParameterType(param);
|
||||
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
|
||||
return exprType == null || JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType);
|
||||
return exprType == null || JetTypeChecker.DEFAULT.isSubtypeOf(exprType, paramType);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -127,7 +127,7 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix {
|
||||
JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null;
|
||||
JetType parameterType = parameters.get(i).getType();
|
||||
|
||||
if (argumentType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType))
|
||||
if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType))
|
||||
changeSignatureData.getParameters().get(i).setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(argumentType));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -76,10 +76,10 @@ public class AddFunctionToSupertypeFix extends JetHintAction<JetNamedFunction> {
|
||||
if (o1.equals(o2)) {
|
||||
return 0;
|
||||
}
|
||||
if (JetTypeChecker.INSTANCE.isSubtypeOf(o1, o2)) {
|
||||
if (JetTypeChecker.DEFAULT.isSubtypeOf(o1, o2)) {
|
||||
return -1;
|
||||
}
|
||||
if (JetTypeChecker.INSTANCE.isSubtypeOf(o2, o1)) {
|
||||
if (JetTypeChecker.DEFAULT.isSubtypeOf(o2, o1)) {
|
||||
return 1;
|
||||
}
|
||||
return o1.toString().compareTo(o2.toString());
|
||||
|
||||
@@ -76,7 +76,7 @@ public class AddNameToArgumentFix extends JetIntentionAction<JetValueArgument> {
|
||||
for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) {
|
||||
String name = parameter.getName().asString();
|
||||
if (usedParameters.contains(name)) continue;
|
||||
if (type == null || JetTypeChecker.INSTANCE.isSubtypeOf(type, parameter.getType())) {
|
||||
if (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType())) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -55,12 +55,12 @@ public class AddWhenElseBranchFix extends JetIntentionAction<JetWhenExpression>
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
return super.isAvailable(project, editor, file) && element.getCloseBraceNode() != null;
|
||||
return super.isAvailable(project, editor, file) && element.getCloseBrace() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
|
||||
PsiElement whenCloseBrace = element.getCloseBraceNode();
|
||||
PsiElement whenCloseBrace = element.getCloseBrace();
|
||||
assert (whenCloseBrace != null) : "isAvailable should check if close brace exist";
|
||||
|
||||
JetWhenEntry entry = JetPsiFactory.createWhenEntry(project, ELSE_ENTRY_TEXT);
|
||||
|
||||
@@ -61,7 +61,7 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
|
||||
if (!super.isAvailable(project, editor, file)) return false;
|
||||
BindingContext context = ResolvePackage.getBindingContext((JetFile) file);
|
||||
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, element);
|
||||
return expressionType != null && JetTypeChecker.INSTANCE.isSubtypeOf(type, expressionType);
|
||||
return expressionType != null && JetTypeChecker.DEFAULT.isSubtypeOf(type, expressionType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
|
||||
if (correspondingProperty != null && QuickFixUtil.canEvaluateTo(correspondingProperty.getInitializer(), element)) {
|
||||
JetTypeReference correspondingPropertyTypeRef = correspondingProperty.getTypeRef();
|
||||
JetType propertyType = context.get(BindingContext.TYPE, correspondingPropertyTypeRef);
|
||||
if (propertyType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(eventualFunctionLiteralType, propertyType)) {
|
||||
if (propertyType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, propertyType)) {
|
||||
appropriateQuickFix = new ChangeVariableTypeFix(correspondingProperty, eventualFunctionLiteralType);
|
||||
}
|
||||
return;
|
||||
@@ -78,7 +78,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
|
||||
if (correspondingParameter != null) {
|
||||
JetTypeReference correspondingParameterTypeRef = correspondingParameter.getTypeReference();
|
||||
JetType parameterType = context.get(BindingContext.TYPE, correspondingParameterTypeRef);
|
||||
if (parameterType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(eventualFunctionLiteralType, parameterType)) {
|
||||
if (parameterType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parameterType)) {
|
||||
appropriateQuickFix = new ChangeParameterTypeFix(correspondingParameter, eventualFunctionLiteralType);
|
||||
}
|
||||
return;
|
||||
@@ -88,7 +88,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
|
||||
if (parentFunction != null && QuickFixUtil.canFunctionOrGetterReturnExpression(parentFunction, element)) {
|
||||
JetTypeReference parentFunctionReturnTypeRef = parentFunction.getReturnTypeRef();
|
||||
JetType parentFunctionReturnType = context.get(BindingContext.TYPE, parentFunctionReturnTypeRef);
|
||||
if (parentFunctionReturnType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType)) {
|
||||
if (parentFunctionReturnType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType)) {
|
||||
appropriateQuickFix = new ChangeFunctionReturnTypeFix(parentFunction, eventualFunctionLiteralType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
|
||||
for (FunctionDescriptor overriddenFunction: descriptor.getOverriddenDescriptors()) {
|
||||
JetType overriddenFunctionType = overriddenFunction.getReturnType();
|
||||
if (overriddenFunctionType == null) continue;
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(functionType, overriddenFunctionType)) {
|
||||
if (!JetTypeChecker.DEFAULT.isSubtypeOf(functionType, overriddenFunctionType)) {
|
||||
overriddenMismatchingFunctions.add(overriddenFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction<PsiE
|
||||
argumentExpression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, argumentExpression) : null;
|
||||
JetType parameterType = parameters.get(i).getType();
|
||||
|
||||
if (argumentType == null || !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) {
|
||||
if (argumentType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public class ChangeMemberFunctionSignatureFix extends JetHintAction<JetNamedFunc
|
||||
@NotNull ValueParameterDescriptor superParameter
|
||||
) {
|
||||
// TODO: support for generic functions
|
||||
if (JetTypeChecker.INSTANCE.equalTypes(parameter.getType(), superParameter.getType())) {
|
||||
if (JetTypeChecker.DEFAULT.equalTypes(parameter.getType(), superParameter.getType())) {
|
||||
return superParameter.copy(parameter.getContainingDeclaration(), parameter.getName());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -150,14 +150,14 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
|
||||
for (PropertyDescriptor overriddenProperty: propertyDescriptor.getOverriddenDescriptors()) {
|
||||
JetType overriddenPropertyType = overriddenProperty.getReturnType();
|
||||
if (overriddenPropertyType != null) {
|
||||
if (!JetTypeChecker.INSTANCE.isSubtypeOf(propertyType, overriddenPropertyType)) {
|
||||
if (!JetTypeChecker.DEFAULT.isSubtypeOf(propertyType, overriddenPropertyType)) {
|
||||
overriddenMismatchingProperties.add(overriddenProperty);
|
||||
}
|
||||
else if (overriddenProperty.isVar() && !JetTypeChecker.INSTANCE.equalTypes(overriddenPropertyType, propertyType)) {
|
||||
else if (overriddenProperty.isVar() && !JetTypeChecker.DEFAULT.equalTypes(overriddenPropertyType, propertyType)) {
|
||||
canChangeOverriddenPropertyType = false;
|
||||
}
|
||||
if (overriddenProperty.isVar() && lowerBoundOfOverriddenPropertiesTypes != null &&
|
||||
!JetTypeChecker.INSTANCE.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)) {
|
||||
!JetTypeChecker.DEFAULT.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)) {
|
||||
lowerBoundOfOverriddenPropertiesTypes = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ private fun JetNamedDeclaration.guessType(context: BindingContext): Array<JetTyp
|
||||
if (expectedTypes.isEmpty() || expectedTypes.any { expectedType -> ErrorUtils.containsErrorType(expectedType) }) {
|
||||
return array<JetType>()
|
||||
}
|
||||
val theType = TypeUtils.intersect(JetTypeChecker.INSTANCE, expectedTypes)
|
||||
val theType = TypeUtils.intersect(JetTypeChecker.DEFAULT, expectedTypes)
|
||||
if (theType != null) {
|
||||
return array<JetType>(theType)
|
||||
}
|
||||
@@ -494,8 +494,8 @@ private class JetTypeSubstitution(public val forType: JetType, public val byType
|
||||
private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType {
|
||||
if (when (variance) {
|
||||
Variance.INVARIANT -> this == substitution.forType
|
||||
Variance.IN_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(this, substitution.forType)
|
||||
Variance.OUT_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(substitution.forType, this)
|
||||
Variance.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(this, substitution.forType)
|
||||
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this)
|
||||
}) {
|
||||
return substitution.byType
|
||||
}
|
||||
|
||||
@@ -43,12 +43,21 @@ public class ImportInsertHelper {
|
||||
*
|
||||
* @param importFqn full name of the import
|
||||
* @param file File where directive should be added.
|
||||
* @param optimize Optimize existing imports before adding new one.
|
||||
*/
|
||||
public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) {
|
||||
addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file);
|
||||
public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file, boolean optimize) {
|
||||
addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file, optimize);
|
||||
}
|
||||
|
||||
public static void addImportDirectiveOrChangeToFqName(@NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) {
|
||||
public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) {
|
||||
addImportDirectiveIfNeeded(importFqn, file, true);
|
||||
}
|
||||
|
||||
public static void addImportDirectiveOrChangeToFqName(
|
||||
@NotNull FqName importFqn,
|
||||
@NotNull JetFile file,
|
||||
int refOffset,
|
||||
@NotNull PsiElement targetElement) {
|
||||
PsiReference reference = file.findReferenceAt(refOffset);
|
||||
if (reference instanceof JetReference) {
|
||||
PsiElement target = reference.resolve();
|
||||
@@ -80,12 +89,12 @@ public class ImportInsertHelper {
|
||||
return;
|
||||
}
|
||||
}
|
||||
addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file);
|
||||
addImportDirectiveIfNeeded(importFqn, file);
|
||||
}
|
||||
|
||||
public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file) {
|
||||
if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) {
|
||||
new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress();
|
||||
public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file, boolean optimize) {
|
||||
if (optimize) {
|
||||
optimizeImportsIfNeeded(file);
|
||||
}
|
||||
|
||||
if (!needImport(importPath, file)) {
|
||||
@@ -95,6 +104,16 @@ public class ImportInsertHelper {
|
||||
writeImportToFile(importPath, file);
|
||||
}
|
||||
|
||||
public static void optimizeImportsIfNeeded(JetFile file) {
|
||||
if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) {
|
||||
optimizeImports(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static void optimizeImports(JetFile file) {
|
||||
new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress();
|
||||
}
|
||||
|
||||
public static void writeImportToFile(@NotNull ImportPath importPath, @NotNull JetFile file) {
|
||||
if (file instanceof JetCodeFragment) {
|
||||
JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath);
|
||||
@@ -105,6 +124,7 @@ public class ImportInsertHelper {
|
||||
JetImportList importList = file.getImportList();
|
||||
if (importList != null) {
|
||||
JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath);
|
||||
importList.add(JetPsiFactory.createNewLine(file.getProject()));
|
||||
importList.add(newDirective);
|
||||
}
|
||||
else {
|
||||
|
||||
+20
-10
@@ -20,12 +20,12 @@ import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
//TODO: should use change signature to deal with cases of multiple overridden descriptors
|
||||
public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -71,9 +72,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
|
||||
ResolvedCall<?> resolvedCall =
|
||||
context.get(BindingContext.RESOLVED_CALL, ((JetOperationExpression) expression).getOperationReference());
|
||||
if (resolvedCall != null) {
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor());
|
||||
if (declaration instanceof JetFunction) {
|
||||
actions.add(new ChangeFunctionReturnTypeFix((JetFunction) declaration, expectedType));
|
||||
JetFunction declaration = getFunctionDeclaration(context, resolvedCall);
|
||||
if (declaration != null) {
|
||||
actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,9 +83,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
|
||||
if (parentBinary.getRight() == expression) {
|
||||
ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, parentBinary.getOperationReference());
|
||||
if (resolvedCall != null) {
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor());
|
||||
if (declaration instanceof JetFunction) {
|
||||
JetParameter binaryOperatorParameter = ((JetFunction) declaration).getValueParameterList().getParameters().get(0);
|
||||
JetFunction declaration = getFunctionDeclaration(context, resolvedCall);
|
||||
if (declaration != null) {
|
||||
JetParameter binaryOperatorParameter = declaration.getValueParameterList().getParameters().get(0);
|
||||
actions.add(new ChangeParameterTypeFix(binaryOperatorParameter, expressionType));
|
||||
}
|
||||
}
|
||||
@@ -96,9 +97,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
|
||||
ResolvedCall<?> resolvedCall =
|
||||
context.get(BindingContext.RESOLVED_CALL, ((JetCallExpression) expression).getCalleeExpression());
|
||||
if (resolvedCall != null) {
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor());
|
||||
if (declaration instanceof JetFunction) {
|
||||
actions.add(new ChangeFunctionReturnTypeFix((JetFunction) declaration, expectedType));
|
||||
JetFunction declaration = getFunctionDeclaration(context, resolvedCall);
|
||||
if (declaration != null) {
|
||||
actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,4 +129,13 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetFunction getFunctionDeclaration(@NotNull BindingContext context, @NotNull ResolvedCall<?> resolvedCall) {
|
||||
PsiElement result = QuickFixUtil.safeGetDeclaration(context, resolvedCall);
|
||||
if (result instanceof JetFunction) {
|
||||
return (JetFunction) result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,10 +90,10 @@ public class QuickFixUtil {
|
||||
if (overriddenReturnType == null) {
|
||||
return null;
|
||||
}
|
||||
if (matchingReturnType == null || JetTypeChecker.INSTANCE.isSubtypeOf(overriddenReturnType, matchingReturnType)) {
|
||||
if (matchingReturnType == null || JetTypeChecker.DEFAULT.isSubtypeOf(overriddenReturnType, matchingReturnType)) {
|
||||
matchingReturnType = overriddenReturnType;
|
||||
}
|
||||
else if (!JetTypeChecker.INSTANCE.isSubtypeOf(matchingReturnType, overriddenReturnType)) {
|
||||
else if (!JetTypeChecker.DEFAULT.isSubtypeOf(matchingReturnType, overriddenReturnType)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ public class QuickFixUtil {
|
||||
BindingContext context = ResolvePackage.getBindingContext(callExpression.getContainingJetFile());
|
||||
ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
|
||||
if (resolvedCall == null) return null;
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor());
|
||||
PsiElement declaration = safeGetDeclaration(context, resolvedCall);
|
||||
if (declaration instanceof JetFunction) {
|
||||
return ((JetFunction) declaration).getValueParameterList();
|
||||
}
|
||||
@@ -119,6 +119,16 @@ public class QuickFixUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement safeGetDeclaration(@NotNull BindingContext context, @NotNull ResolvedCall<?> resolvedCall) {
|
||||
List<PsiElement> declarations = BindingContextUtils.descriptorToDeclarations(context, resolvedCall.getResultingDescriptor());
|
||||
//do not create fix if descriptor has more than one overridden declaration
|
||||
if (declarations.size() == 1) {
|
||||
return declarations.iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetParameter getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
|
||||
if (!(functionLiteralExpression.getParent() instanceof JetCallExpression)) {
|
||||
|
||||
@@ -22,9 +22,11 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.JetBundle;
|
||||
|
||||
@@ -40,7 +42,7 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) {
|
||||
//noinspection unchecked
|
||||
JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetProperty.class, JetNamedFunction.class);
|
||||
JetType type = getTypeForDeclaration(declaration);
|
||||
@@ -51,12 +53,12 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction {
|
||||
addTypeAnnotation(project, editor, (JetNamedFunction) declaration, type);
|
||||
}
|
||||
else {
|
||||
assert false : "Couldn't find property or function";
|
||||
assert false : "Couldn't find property or function " + JetPsiUtil.getElementTextWithContext((JetElement) element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) {
|
||||
//noinspection unchecked
|
||||
JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetProperty.class, JetNamedFunction.class);
|
||||
if (declaration instanceof JetProperty) {
|
||||
@@ -66,7 +68,7 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction {
|
||||
setText(JetBundle.message("specify.type.explicitly.add.return.type.action.name"));
|
||||
}
|
||||
else {
|
||||
assert false : "Couldn't find property or function";
|
||||
assert false : "Couldn't find property or function " + JetPsiUtil.getElementTextWithContext((JetElement) element);
|
||||
}
|
||||
|
||||
return !getTypeForDeclaration(declaration).isError();
|
||||
|
||||
@@ -98,7 +98,7 @@ public class JetNameSuggester {
|
||||
|
||||
private static void addNamesForType(ArrayList<String> result, JetType jetType, JetNameValidator validator) {
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||
JetTypeChecker typeChecker = JetTypeChecker.DEFAULT;
|
||||
jetType = TypeUtils.makeNotNullable(jetType); // wipe out '?'
|
||||
if (ErrorUtils.containsErrorType(jetType)) return;
|
||||
if (typeChecker.equalTypes(builtIns.getBooleanType(), jetType)) {
|
||||
|
||||
@@ -440,7 +440,7 @@ public class JetRefactoringUtil {
|
||||
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(expression);
|
||||
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
if (expressionType == null || !(expressionType instanceof PackageType) &&
|
||||
!JetTypeChecker.INSTANCE.equalTypes(KotlinBuiltIns.
|
||||
!JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns.
|
||||
getInstance().getUnitType(), expressionType)) {
|
||||
expressions.add(expression);
|
||||
}
|
||||
|
||||
+3
-2
@@ -59,7 +59,8 @@ public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boole
|
||||
editor: Editor,
|
||||
file: JetFile,
|
||||
elements: List<PsiElement>,
|
||||
targetSibling: PsiElement
|
||||
targetSibling: PsiElement,
|
||||
preprocessor: ((ExtractionDescriptor) -> Unit)? = null
|
||||
) {
|
||||
val project = file.getProject()
|
||||
|
||||
@@ -83,7 +84,7 @@ public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boole
|
||||
|
||||
dialog.getCurrentDescriptor()
|
||||
}
|
||||
|
||||
preprocessor?.invoke(descriptor)
|
||||
project.executeWriteCommand(EXTRACT_FUNCTION) { descriptor.generateFunction() }
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
||||
import org.jetbrains.jet.lang.psi.JetUserType
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.jet.lang.psi.JetParameter
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral
|
||||
|
||||
data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) {
|
||||
class object {
|
||||
@@ -95,20 +101,31 @@ class ExtractionData(
|
||||
|
||||
val originalStartOffset = originalElements.first?.let { e -> e.getTextRange()!!.getStartOffset() }
|
||||
|
||||
private val itFakeDeclaration by Delegates.lazy { JetPsiFactory.createParameter(project, "it", null) }
|
||||
|
||||
val refOffsetToDeclaration by Delegates.lazy {
|
||||
fun isExtractableIt(descriptor: DeclarationDescriptor, context: BindingContext): Boolean {
|
||||
if (!(descriptor is ValueParameterDescriptor && (context[BindingContext.AUTO_CREATED_IT, descriptor] ?: false))) return false
|
||||
val function = BindingContextUtils.descriptorToDeclaration(context, descriptor.getContainingDeclaration()) as? JetFunctionLiteral
|
||||
return function == null || !function.isInsideOf(originalElements)
|
||||
}
|
||||
|
||||
if (originalStartOffset != null) {
|
||||
val resultMap = HashMap<Int, ResolveResult>()
|
||||
|
||||
for ((ref, context) in JetFileReferencesResolver.resolve(originalFile, getExpressions())) {
|
||||
if (ref !is JetSimpleNameExpression) continue
|
||||
|
||||
val resolvedCallKey = (ref.getParent() as? JetThisExpression) ?: ref
|
||||
val resolvedCall = context[BindingContext.RESOLVED_CALL, resolvedCallKey]
|
||||
val resolvedCall = context[BindingContext.RESOLVED_CALL, resolvedCallKey]?.let {
|
||||
(it as? VariableAsFunctionResolvedCall)?.functionCall ?: it
|
||||
}
|
||||
|
||||
val descriptor = context[BindingContext.REFERENCE_TARGET, ref]
|
||||
if (descriptor == null) continue
|
||||
|
||||
val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, context) as? PsiNamedElement
|
||||
if (declaration == null) continue
|
||||
?: if (isExtractableIt(descriptor, context)) itFakeDeclaration else continue
|
||||
|
||||
val offset = ref.getTextRange()!!.getStartOffset() - originalStartOffset
|
||||
resultMap[offset] = ResolveResult(ref, declaration, descriptor, resolvedCall)
|
||||
|
||||
+11
-9
@@ -31,19 +31,21 @@ import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
||||
import org.jetbrains.jet.lang.psi.JetTypeParameter
|
||||
import org.jetbrains.jet.lang.psi.JetTypeConstraint
|
||||
import kotlin.properties.Delegates
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||
|
||||
data class Parameter(
|
||||
val argumentText: String,
|
||||
val name: String,
|
||||
var mirrorVarName: String?,
|
||||
val parameterType: JetType,
|
||||
val receiverCandidate: Boolean
|
||||
) {
|
||||
trait Parameter {
|
||||
val argumentText: String
|
||||
val name: String
|
||||
val mirrorVarName: String?
|
||||
val parameterType: JetType
|
||||
val parameterTypeCandidates: List<JetType>
|
||||
val receiverCandidate: Boolean
|
||||
|
||||
val nameForRef: String get() = mirrorVarName ?: name
|
||||
|
||||
fun copy(name: String, parameterType: JetType): Parameter
|
||||
}
|
||||
|
||||
data class TypeParameter(
|
||||
@@ -165,7 +167,7 @@ class AnalysisResult (
|
||||
|
||||
fun renderMessage(): String {
|
||||
val message = JetRefactoringBundle.message(when(this) {
|
||||
NO_EXPRESSION -> "cannot.refactor.no.expresson"
|
||||
NO_EXPRESSION -> "cannot.refactor.no.expression"
|
||||
NO_CONTAINER -> "cannot.refactor.no.container"
|
||||
SUPER_CALL -> "cannot.extract.super.call"
|
||||
DENOTABLE_TYPES -> "parameter.types.are.not.denotable"
|
||||
|
||||
+161
-89
@@ -38,7 +38,6 @@ import org.jetbrains.jet.lang.psi.JetPsiFactory.FunctionBuilder
|
||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl
|
||||
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
|
||||
import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
||||
@@ -56,18 +55,16 @@ import org.jetbrains.jet.lang.diagnostics.Errors
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.*
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.WriteValueInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.CallInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.JetElementInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.OperationInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.ReadValueInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.*
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.*
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.*
|
||||
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.getNextInstructions
|
||||
import kotlin.properties.Delegates
|
||||
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverse
|
||||
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
||||
|
||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||
private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()
|
||||
@@ -84,7 +81,10 @@ private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingC
|
||||
private fun List<Instruction>.getExitPoints(): List<Instruction> =
|
||||
filter { localInstruction -> localInstruction.nextInstructions.any { it !in this } }
|
||||
|
||||
private fun List<Instruction>.getResultType(bindingContext: BindingContext, options: ExtractionOptions): JetType {
|
||||
private fun List<Instruction>.getResultType(
|
||||
pseudocode: Pseudocode,
|
||||
bindingContext: BindingContext,
|
||||
options: ExtractionOptions): JetType {
|
||||
fun instructionToType(instruction: Instruction): JetType? {
|
||||
val expression = when (instruction) {
|
||||
is ReturnValueInstruction -> {
|
||||
@@ -101,10 +101,7 @@ private fun List<Instruction>.getResultType(bindingContext: BindingContext, opti
|
||||
}
|
||||
|
||||
if (expression == null) return null
|
||||
if (options.inferUnitTypeForUnusedValues) {
|
||||
val pseudocode = firstOrNull()?.owner
|
||||
if (pseudocode != null && expression.isStatement(pseudocode)) return null
|
||||
}
|
||||
if (options.inferUnitTypeForUnusedValues && expression.isStatement(pseudocode)) return null
|
||||
|
||||
return bindingContext[BindingContext.EXPRESSION_TYPE, expression]
|
||||
}
|
||||
@@ -123,10 +120,17 @@ private fun JetType.isMeaningful(): Boolean {
|
||||
}
|
||||
|
||||
private fun List<Instruction>.analyzeControlFlow(
|
||||
pseudocode: Pseudocode,
|
||||
bindingContext: BindingContext,
|
||||
options: ExtractionOptions,
|
||||
parameters: Set<Parameter>
|
||||
): Pair<ControlFlow, ErrorMessage?> {
|
||||
fun isCurrentFunctionReturn(expression: JetReturnExpression): Boolean {
|
||||
val functionDescriptor = expression.getTargetFunctionDescriptor(bindingContext)
|
||||
val currentDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()]
|
||||
return currentDescriptor == functionDescriptor
|
||||
}
|
||||
|
||||
val exitPoints = getExitPoints()
|
||||
|
||||
val valuedReturnExits = ArrayList<ReturnValueInstruction>()
|
||||
@@ -135,19 +139,26 @@ private fun List<Instruction>.analyzeControlFlow(
|
||||
exitPoints.forEach {
|
||||
val e = (it as? UnconditionalJumpInstruction)?.element
|
||||
val insn =
|
||||
if (e != null && e !is JetBreakExpression && e !is JetContinueExpression) {
|
||||
it.previousInstructions.firstOrNull()
|
||||
when {
|
||||
it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode ->
|
||||
null
|
||||
e != null && e !is JetBreakExpression && e !is JetContinueExpression ->
|
||||
it.previousInstructions.firstOrNull()
|
||||
else ->
|
||||
it
|
||||
}
|
||||
else it
|
||||
|
||||
when (insn) {
|
||||
is ReturnValueInstruction -> valuedReturnExits.add(insn)
|
||||
is ReturnValueInstruction ->
|
||||
if (isCurrentFunctionReturn(insn.element as JetReturnExpression)) {
|
||||
valuedReturnExits.add(insn)
|
||||
}
|
||||
|
||||
is AbstractJumpInstruction -> {
|
||||
val element = insn.element
|
||||
if (element is JetReturnExpression
|
||||
|| element is JetBreakExpression
|
||||
|| element is JetContinueExpression) {
|
||||
if ((element is JetReturnExpression && isCurrentFunctionReturn(element))
|
||||
|| element is JetBreakExpression
|
||||
|| element is JetContinueExpression) {
|
||||
jumpExits.add(insn)
|
||||
}
|
||||
else if (element !is JetThrowExpression) {
|
||||
@@ -161,8 +172,8 @@ private fun List<Instruction>.analyzeControlFlow(
|
||||
}
|
||||
}
|
||||
|
||||
val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options)
|
||||
val returnValueType = valuedReturnExits.getResultType(bindingContext, options)
|
||||
val typeOfDefaultFlow = defaultExits.getResultType(pseudocode, bindingContext, options)
|
||||
val returnValueType = valuedReturnExits.getResultType(pseudocode, bindingContext, options)
|
||||
val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow)
|
||||
|
||||
val outParameters = parameters.filterTo(HashSet<Parameter>()) { it.mirrorVarName != null }
|
||||
@@ -204,7 +215,7 @@ private fun List<Instruction>.analyzeControlFlow(
|
||||
}
|
||||
|
||||
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
||||
return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext, options)), null)
|
||||
return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(pseudocode, bindingContext, options)), null)
|
||||
}
|
||||
|
||||
if (jumpExits.isNotEmpty()) {
|
||||
@@ -307,8 +318,51 @@ private fun JetType.processTypeIfExtractable(
|
||||
}
|
||||
}
|
||||
|
||||
private class MutableParameter(
|
||||
override val argumentText: String,
|
||||
override val name: String,
|
||||
override val mirrorVarName: String?,
|
||||
override val receiverCandidate: Boolean
|
||||
): Parameter {
|
||||
// All modifications happen in the same thread
|
||||
private var writable: Boolean = true
|
||||
private val defaultTypes = HashSet<JetType>()
|
||||
private val typePredicates = HashSet<TypePredicate>()
|
||||
|
||||
fun addDefaultType(jetType: JetType) {
|
||||
assert(writable, "Can't add type to non-writable parameter $name")
|
||||
defaultTypes.add(jetType)
|
||||
}
|
||||
|
||||
fun addTypePredicate(predicate: TypePredicate) {
|
||||
assert(writable, "Can't add type predicate to non-writable parameter $name")
|
||||
typePredicates.add(predicate)
|
||||
}
|
||||
|
||||
override val parameterTypeCandidates: List<JetType> by Delegates.lazy {
|
||||
writable = false
|
||||
listOf(parameterType) + TypeUtils.getAllSupertypes(parameterType).filter(and(typePredicates))
|
||||
}
|
||||
|
||||
override val parameterType: JetType by Delegates.lazy {
|
||||
writable = false
|
||||
CommonSupertypes.commonSupertype(defaultTypes)
|
||||
}
|
||||
|
||||
override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(this, name, parameterType)
|
||||
}
|
||||
|
||||
private class DelegatingParameter(
|
||||
val original: Parameter,
|
||||
override val name: String,
|
||||
override val parameterType: JetType
|
||||
): Parameter by original {
|
||||
override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(original, name, parameterType)
|
||||
}
|
||||
|
||||
private fun ExtractionData.inferParametersInfo(
|
||||
commonParent: PsiElement,
|
||||
pseudocode: Pseudocode,
|
||||
localInstructions: List<Instruction>,
|
||||
bindingContext: BindingContext,
|
||||
replacementMap: MutableMap<Int, Replacement>,
|
||||
@@ -323,7 +377,9 @@ private fun ExtractionData.inferParametersInfo(
|
||||
)
|
||||
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
||||
|
||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
||||
|
||||
val valueUsageMap = pseudocode.collectValueUsages()
|
||||
|
||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||
@@ -379,64 +435,42 @@ private fun ExtractionData.inferParametersInfo(
|
||||
|
||||
val extractParameter = extractThis || extractLocalVar
|
||||
if (extractParameter) {
|
||||
val parameterType =
|
||||
if (hasThisReceiver) {
|
||||
when (descriptorToExtract) {
|
||||
is ClassDescriptor -> descriptorToExtract.getDefaultType()
|
||||
is CallableDescriptor -> descriptorToExtract.getReceiverParameter()?.getType()
|
||||
else -> null
|
||||
} ?: DEFAULT_PARAMETER_TYPE
|
||||
}
|
||||
else bindingContext[BindingContext.EXPRESSION_TYPE, originalRef] ?: DEFAULT_PARAMETER_TYPE
|
||||
val parameterType = when {
|
||||
receiver.exists() -> receiver.getType()
|
||||
else -> bindingContext[BindingContext.AUTOCAST, originalRef]
|
||||
?: bindingContext[BindingContext.EXPRESSION_TYPE, originalRef]
|
||||
?: DEFAULT_PARAMETER_TYPE
|
||||
}
|
||||
|
||||
if (!parameterType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)) continue
|
||||
|
||||
val existingParameter = extractedDescriptorToParameter[descriptorToExtract]
|
||||
val parameter: Parameter =
|
||||
if (existingParameter != null) {
|
||||
if (!JetTypeChecker.INSTANCE.equalTypes(existingParameter.parameterType, parameterType)) {
|
||||
val newParameter = existingParameter.copy(
|
||||
parameterType = CommonSupertypes.commonSupertype(listOf(existingParameter.parameterType, parameterType))
|
||||
)
|
||||
val parameterTypePredicate =
|
||||
pseudocode.getElementValue(originalRef)?.let { getExpectedTypePredicate(it, valueUsageMap, bindingContext) } ?: AllTypes
|
||||
|
||||
extractedDescriptorToParameter[descriptorToExtract] = newParameter
|
||||
|
||||
for ((offset, replacement) in replacementMap) {
|
||||
if (replacement is ParameterReplacement && replacement.parameter == existingParameter) {
|
||||
replacementMap[offset] = replacement.copy(newParameter)
|
||||
}
|
||||
}
|
||||
|
||||
newParameter
|
||||
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
||||
val parameterName =
|
||||
if (extractThis) {
|
||||
JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first()
|
||||
}
|
||||
else existingParameter
|
||||
}
|
||||
else {
|
||||
val parameterName =
|
||||
if (extractThis) {
|
||||
JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first()
|
||||
}
|
||||
else originalDeclaration.getName()!!
|
||||
else originalDeclaration.getName()!!
|
||||
|
||||
val mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors)
|
||||
varNameValidator.validateName(parameterName)!!
|
||||
else null
|
||||
val mirrorVarName =
|
||||
if (descriptorToExtract in modifiedVarDescriptors) varNameValidator.validateName(parameterName)!! else null
|
||||
|
||||
val argumentText =
|
||||
if (hasThisReceiver && extractThis)
|
||||
"this@${parameterType.getConstructor().getDeclarationDescriptor()!!.getName().asString()}"
|
||||
else
|
||||
(thisExpr ?: ref).getText() ?: throw AssertionError("'this' reference shouldn't be empty: code fragment = ${getCodeFragmentText()}")
|
||||
val argumentText =
|
||||
if (hasThisReceiver && extractThis)
|
||||
"this@${parameterType.getConstructor().getDeclarationDescriptor()!!.getName().asString()}"
|
||||
else
|
||||
(thisExpr ?: ref).getText() ?: throw AssertionError("'this' reference shouldn't be empty: code fragment = ${getCodeFragmentText()}")
|
||||
|
||||
val parameter = Parameter(argumentText, parameterName, mirrorVarName, parameterType, extractThis)
|
||||
MutableParameter(argumentText, parameterName, mirrorVarName, extractThis)
|
||||
}
|
||||
|
||||
extractedDescriptorToParameter[descriptorToExtract] = parameter
|
||||
|
||||
parameter
|
||||
}
|
||||
parameter.addDefaultType(parameterType)
|
||||
parameter.addTypePredicate(parameterTypePredicate)
|
||||
|
||||
replacementMap[refInfo.offsetInBody] =
|
||||
if (hasThisReceiver && extractThis) AddPrefixReplacement(parameter) else RenameReplacement(parameter)
|
||||
if (hasThisReceiver && extractThis) AddPrefixReplacement(parameter) else RenameReplacement(parameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,20 +485,20 @@ private fun ExtractionData.inferParametersInfo(
|
||||
}
|
||||
|
||||
private fun ExtractionData.checkLocalDeclarationsWithNonLocalUsages(
|
||||
allInstructions: List<Instruction>,
|
||||
pseudocode: Pseudocode,
|
||||
localInstructions: List<Instruction>,
|
||||
bindingContext: BindingContext
|
||||
): ErrorMessage? {
|
||||
// todo: non-locally used declaration can be turned into the output value
|
||||
|
||||
val declarations = ArrayList<JetNamedDeclaration>()
|
||||
for (instruction in allInstructions) {
|
||||
if (instruction in localInstructions) continue
|
||||
|
||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor ->
|
||||
val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext)
|
||||
if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) {
|
||||
declarations.add(declaration)
|
||||
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
|
||||
if (instruction !in localInstructions) {
|
||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor ->
|
||||
val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext)
|
||||
if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) {
|
||||
declarations.add(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,6 +534,16 @@ private fun ExtractionData.checkDeclarationsMovingOutOfScope(controlFlow: Contro
|
||||
return null
|
||||
}
|
||||
|
||||
private fun ExtractionData.getLocalInstructions(pseudocode: Pseudocode): List<Instruction> {
|
||||
val instructions = ArrayList<Instruction>()
|
||||
pseudocode.traverse(TraversalOrder.FORWARD) {
|
||||
if (it is JetElementInstruction && it.element.isInsideOf(originalElements)) {
|
||||
instructions.add(it)
|
||||
}
|
||||
}
|
||||
return instructions
|
||||
}
|
||||
|
||||
fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
if (originalElements.empty) {
|
||||
return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(ErrorMessage.NO_EXPRESSION))
|
||||
@@ -516,16 +560,14 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
val bindingContext = resolveSession.resolveToElement(enclosingDeclaration.getBodyExpression())
|
||||
|
||||
val pseudocode = PseudocodeUtil.generatePseudocode(enclosingDeclaration, bindingContext)
|
||||
val localInstructions = pseudocode.getInstructions().filter {
|
||||
it is JetElementInstruction && it.element.isInsideOf(originalElements)
|
||||
}
|
||||
val localInstructions = getLocalInstructions(pseudocode)
|
||||
|
||||
val replacementMap = HashMap<Int, Replacement>()
|
||||
val parameters = HashSet<Parameter>()
|
||||
val typeParameters = HashSet<TypeParameter>()
|
||||
val nonDenotableTypes = HashSet<JetType>()
|
||||
val parameterError = inferParametersInfo(
|
||||
commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes
|
||||
commonParent, pseudocode, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes
|
||||
)
|
||||
if (parameterError != null) {
|
||||
return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError))
|
||||
@@ -533,7 +575,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
|
||||
val messages = ArrayList<ErrorMessage>()
|
||||
|
||||
val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, options, parameters)
|
||||
val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(pseudocode, bindingContext, options, parameters)
|
||||
controlFlowMessage?.let { messages.add(it) }
|
||||
|
||||
controlFlow.returnType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)
|
||||
@@ -547,7 +589,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
)
|
||||
}
|
||||
|
||||
checkLocalDeclarationsWithNonLocalUsages(pseudocode.getInstructions(), localInstructions, bindingContext)?.let { messages.add(it) }
|
||||
checkLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)?.let { messages.add(it) }
|
||||
checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) }
|
||||
|
||||
val functionNameValidator =
|
||||
@@ -607,7 +649,7 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
||||
if (diagnostics.any { it.getFactory() == Errors.UNRESOLVED_REFERENCE }
|
||||
|| (currentDescriptor != null
|
||||
&& !ErrorUtils.isError(currentDescriptor)
|
||||
&& !compareDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||
&& !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||
conflicts.putValue(
|
||||
currentRefExpr,
|
||||
JetRefactoringBundle.message(
|
||||
@@ -632,6 +674,15 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
||||
return ExtractionDescriptorWithConflicts(this, conflicts)
|
||||
}
|
||||
|
||||
private fun comparePossiblyOverridingDescriptors(currentDescriptor: DeclarationDescriptor?, originalDescriptor: DeclarationDescriptor?): Boolean {
|
||||
if (compareDescriptors(currentDescriptor, originalDescriptor)) return true
|
||||
if (originalDescriptor is CallableDescriptor) {
|
||||
if (!OverridingUtil.traverseOverridenDescriptors(originalDescriptor) { !compareDescriptors(currentDescriptor, it) }) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun ExtractionDescriptor.getFunctionText(
|
||||
withBody: Boolean = true,
|
||||
descriptorRenderer: DescriptorRenderer = DescriptorRenderer.FQ_NAMES_IN_TYPES
|
||||
@@ -795,6 +846,27 @@ fun ExtractionDescriptor.generateFunction(
|
||||
}
|
||||
}
|
||||
|
||||
fun insertCall(anchor: PsiElement, wrappedCall: JetExpression) {
|
||||
val firstExpression = extractionData.getExpressions().firstOrNull()
|
||||
val enclosingCall = firstExpression?.getParent() as? JetCallExpression
|
||||
if (enclosingCall == null || firstExpression !in enclosingCall.getFunctionLiteralArguments()) {
|
||||
anchor.replace(wrappedCall)
|
||||
return
|
||||
}
|
||||
|
||||
val argumentListExt = JetPsiFactory.createCallArguments(project, "(${wrappedCall.getText()})")
|
||||
val argumentList = enclosingCall.getValueArgumentList()
|
||||
if (argumentList == null) {
|
||||
(anchor.getPrevSibling() as? PsiWhiteSpace)?.let { it.delete() }
|
||||
anchor.replace(argumentListExt)
|
||||
return
|
||||
}
|
||||
|
||||
val newArgText = (argumentList.getArguments() + argumentListExt.getArguments()).map { it.getText() }.joinToString(", ", "(", ")")
|
||||
argumentList.replace(JetPsiFactory.createCallArguments(project, newArgText))
|
||||
anchor.delete()
|
||||
}
|
||||
|
||||
fun makeCall(function: JetNamedFunction): JetNamedFunction {
|
||||
val anchor = extractionData.originalElements.first
|
||||
if (anchor == null) return function
|
||||
@@ -808,7 +880,7 @@ fun ExtractionDescriptor.generateFunction(
|
||||
|
||||
val callText = parameters
|
||||
.map { it.argumentText }
|
||||
.makeString(separator = ", ", prefix = "$name(", postfix = ")")
|
||||
.joinToString(separator = ", ", prefix = "$name(", postfix = ")")
|
||||
val wrappedCall = when (controlFlow) {
|
||||
is ExpressionEvaluationWithCallSiteReturn ->
|
||||
JetPsiFactory.createReturn(project, callText)
|
||||
@@ -833,7 +905,7 @@ fun ExtractionDescriptor.generateFunction(
|
||||
else ->
|
||||
JetPsiFactory.createExpression(project, callText)
|
||||
}
|
||||
anchor.replace(wrappedCall)
|
||||
insertCall(anchor, wrappedCall)
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
+6
-8
@@ -63,7 +63,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
setModal(true);
|
||||
setTitle(JetRefactoringBundle.message("extract.function"));
|
||||
init();
|
||||
update(false);
|
||||
update();
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
@@ -94,10 +94,8 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void update(boolean recreateDescriptor) {
|
||||
if (recreateDescriptor) {
|
||||
this.currentDescriptor = createDescriptor();
|
||||
}
|
||||
private void update() {
|
||||
this.currentDescriptor = createDescriptor();
|
||||
|
||||
setOKActionEnabled(checkNames());
|
||||
signaturePreviewField.setText(
|
||||
@@ -116,7 +114,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
new DocumentAdapter() {
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
update(true);
|
||||
update();
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -130,7 +128,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(@NotNull ItemEvent e) {
|
||||
update(true);
|
||||
update();
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -138,7 +136,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
parameterTablePanel = new KotlinParameterTablePanel() {
|
||||
@Override
|
||||
protected void updateSignature() {
|
||||
KotlinExtractFunctionDialog.this.update(true);
|
||||
KotlinExtractFunctionDialog.this.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+83
-35
@@ -19,18 +19,25 @@ package org.jetbrains.jet.plugin.refactoring.extractFunction.ui;
|
||||
import com.intellij.ui.BooleanTableCellRenderer;
|
||||
import com.intellij.ui.TableUtil;
|
||||
import com.intellij.ui.ToolbarDecorator;
|
||||
import com.intellij.ui.components.JBComboBoxLabel;
|
||||
import com.intellij.ui.components.editors.JBComboBoxTableCellEditorComponent;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ui.AbstractTableCellEditor;
|
||||
import com.intellij.util.ui.EditableModel;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.Parameter;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.*;
|
||||
@@ -42,11 +49,13 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
public static class ParameterInfo {
|
||||
private final Parameter originalParameter;
|
||||
private String name;
|
||||
private JetType type;
|
||||
private boolean enabled = true;
|
||||
|
||||
public ParameterInfo(Parameter originalParameter) {
|
||||
this.originalParameter = originalParameter;
|
||||
this.name = originalParameter.getName();
|
||||
this.type = originalParameter.getParameterType();
|
||||
}
|
||||
|
||||
public Parameter getOriginalParameter() {
|
||||
@@ -69,18 +78,16 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTypeAsString() {
|
||||
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getOriginalParameter().getParameterType());
|
||||
public JetType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(JetType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Parameter toParameter() {
|
||||
return new Parameter(
|
||||
originalParameter.getArgumentText(),
|
||||
name,
|
||||
originalParameter.getMirrorVarName(),
|
||||
originalParameter.getParameterType(),
|
||||
originalParameter.getReceiverCandidate()
|
||||
);
|
||||
return originalParameter.copy(name, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +118,7 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
|
||||
myTable.setTableHeader(null);
|
||||
myTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myTable.setCellSelectionEnabled(true);
|
||||
|
||||
TableColumn checkBoxColumn = myTable.getColumnModel().getColumn(MyTableModel.CHECKMARK_COLUMN);
|
||||
TableUtil.setupCheckboxColumn(checkBoxColumn);
|
||||
@@ -128,6 +136,55 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
}
|
||||
);
|
||||
|
||||
myTable.getColumnModel().getColumn(MyTableModel.PARAMETER_TYPE_COLUMN).setCellRenderer(new DefaultTableCellRenderer() {
|
||||
private final JBComboBoxLabel myLabel = new JBComboBoxLabel();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Component getTableCellRendererComponent(
|
||||
@NotNull JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column
|
||||
) {
|
||||
myLabel.setText(String.valueOf(value));
|
||||
myLabel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
|
||||
myLabel.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
|
||||
if (isSelected) {
|
||||
myLabel.setSelectionIcon();
|
||||
} else {
|
||||
myLabel.setRegularIcon();
|
||||
}
|
||||
return myLabel;
|
||||
}
|
||||
});
|
||||
|
||||
myTable.getColumnModel().getColumn(MyTableModel.PARAMETER_TYPE_COLUMN).setCellEditor(new AbstractTableCellEditor() {
|
||||
final JBComboBoxTableCellEditorComponent myEditorComponent = new JBComboBoxTableCellEditorComponent();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getCellEditorValue() {
|
||||
return myEditorComponent.getEditorValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellEditorComponent(
|
||||
JTable table, Object value, boolean isSelected, int row, int column
|
||||
) {
|
||||
ParameterInfo info = parameterInfos.get(row);
|
||||
|
||||
myEditorComponent.setCell(table, row, column);
|
||||
myEditorComponent.setOptions(info.getOriginalParameter().getParameterTypeCandidates().toArray());
|
||||
myEditorComponent.setDefaultValue(info.getType());
|
||||
myEditorComponent.setToString(new Function<Object, String>() {
|
||||
@Override
|
||||
public String fun(Object o) {
|
||||
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType((JetType) o);
|
||||
}
|
||||
});
|
||||
|
||||
return myEditorComponent;
|
||||
}
|
||||
});
|
||||
|
||||
myTable.setPreferredScrollableViewportSize(new Dimension(250, myTable.getRowHeight() * 5));
|
||||
myTable.setShowGrid(false);
|
||||
myTable.setIntercellSpacing(new Dimension(0, 0));
|
||||
@@ -159,20 +216,6 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
// F2: edit parameter name
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "edit_parameter_name");
|
||||
actionMap.put("edit_parameter_name", new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull ActionEvent e) {
|
||||
if (!myTable.isEditing()) {
|
||||
int row = myTable.getSelectedRow();
|
||||
if (row >= 0 && row < myTableModel.getRowCount()) {
|
||||
TableUtil.editCellAt(myTable, row, MyTableModel.PARAMETER_NAME_COLUMN);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// make ENTER work when the table has focus
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "invoke_impl");
|
||||
actionMap.put("invoke_impl", new AbstractAction() {
|
||||
@@ -266,32 +309,29 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case CHECKMARK_COLUMN: {
|
||||
case CHECKMARK_COLUMN:
|
||||
return parameterInfos.get(rowIndex).isEnabled();
|
||||
}
|
||||
case PARAMETER_NAME_COLUMN: {
|
||||
case PARAMETER_NAME_COLUMN:
|
||||
return parameterInfos.get(rowIndex).getName();
|
||||
}
|
||||
case PARAMETER_TYPE_COLUMN: {
|
||||
return parameterInfos.get(rowIndex).getTypeAsString();
|
||||
}
|
||||
case PARAMETER_TYPE_COLUMN:
|
||||
return parameterInfos.get(rowIndex).getType();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
ParameterInfo info = parameterInfos.get(rowIndex);
|
||||
switch (columnIndex) {
|
||||
case CHECKMARK_COLUMN: {
|
||||
parameterInfos.get(rowIndex).setEnabled((Boolean) aValue);
|
||||
info.setEnabled((Boolean) aValue);
|
||||
fireTableRowsUpdated(rowIndex, rowIndex);
|
||||
myTable.getSelectionModel().setSelectionInterval(rowIndex, rowIndex);
|
||||
updateSignature();
|
||||
break;
|
||||
}
|
||||
case PARAMETER_NAME_COLUMN: {
|
||||
ParameterInfo info = parameterInfos.get(rowIndex);
|
||||
String name = (String) aValue;
|
||||
if (JetNameSuggester.isIdentifier(name)) {
|
||||
info.setName(name);
|
||||
@@ -299,16 +339,24 @@ public class KotlinParameterTablePanel extends JPanel {
|
||||
updateSignature();
|
||||
break;
|
||||
}
|
||||
case PARAMETER_TYPE_COLUMN: {
|
||||
info.setType((JetType) aValue);
|
||||
updateSignature();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
ParameterInfo info = parameterInfos.get(rowIndex);
|
||||
switch (columnIndex) {
|
||||
case CHECKMARK_COLUMN:
|
||||
return isEnabled();
|
||||
case PARAMETER_NAME_COLUMN:
|
||||
return isEnabled() && parameterInfos.get(rowIndex).isEnabled();
|
||||
return isEnabled() && info.isEnabled();
|
||||
case PARAMETER_TYPE_COLUMN:
|
||||
return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates().size() > 1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
+2
-5
@@ -31,11 +31,8 @@ import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import kotlin.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.analyzer.AnalyzerPackage;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
@@ -139,7 +136,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
JetType typeNoExpectedType = AnalyzerPackage.computeTypeInfoInContext(
|
||||
expression, scope, bindingTrace, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, resolveSession.getModuleDescriptor()
|
||||
).getType();
|
||||
if (expressionType != null && typeNoExpectedType != null && !JetTypeChecker.INSTANCE.equalTypes(expressionType,
|
||||
if (expressionType != null && typeNoExpectedType != null && !JetTypeChecker.DEFAULT.equalTypes(expressionType,
|
||||
typeNoExpectedType)) {
|
||||
noTypeInference = true;
|
||||
}
|
||||
@@ -149,7 +146,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
return;
|
||||
}
|
||||
if (expressionType != null &&
|
||||
JetTypeChecker.INSTANCE.equalTypes(KotlinBuiltIns.getInstance().getUnitType(), expressionType)) {
|
||||
JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns.getInstance().getUnitType(), expressionType)) {
|
||||
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.expression.has.unit.type"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ fun blockAndAndMismatch1() : Int {
|
||||
return <error>true && false</error>
|
||||
}
|
||||
fun blockAndAndMismatch2() : Int {
|
||||
<warning>(return <error>true</error>) && (return <error>false</error>)</warning>
|
||||
(return <error>true</error>) <warning>&& (return <error>false</error>)</warning>
|
||||
}
|
||||
|
||||
fun blockAndAndMismatch3() : Int {
|
||||
@@ -58,7 +58,7 @@ fun blockAndAndMismatch4() : Int {
|
||||
return <error>true || false</error>
|
||||
}
|
||||
fun blockAndAndMismatch5() : Int {
|
||||
<warning>(return <error>true</error>) || (return <error>false</error>)</warning>
|
||||
(return <error>true</error>) <warning>|| (return <error>false</error>)</warning>
|
||||
}
|
||||
fun blockReturnValueTypeMatch1() : Int {
|
||||
return if (1 > 2) <error>1.0</error> else <error>2.0</error>
|
||||
|
||||
@@ -126,17 +126,17 @@ fun t8() : Int {
|
||||
}
|
||||
|
||||
fun blockAndAndMismatch() : Boolean {
|
||||
<warning>(return true) || (return false)</warning>
|
||||
(return true) <warning>|| (return false)</warning>
|
||||
<warning>return true</warning>
|
||||
}
|
||||
|
||||
fun tf() : Int {
|
||||
try {<warning>return 1</warning>} finally{return 1}
|
||||
try {<warning>return</warning> 1} finally{return 1}
|
||||
<warning>return 1</warning>
|
||||
}
|
||||
|
||||
fun failtest(<warning>a</warning> : Int) : Int {
|
||||
if (fail() || <warning>true</warning>) <warning>{
|
||||
if (fail() <warning>|| true</warning>) <warning>{
|
||||
|
||||
}</warning>
|
||||
<warning>return 1</warning>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package bar;
|
||||
|
||||
public interface Bar {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package bar;
|
||||
|
||||
public interface Other {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package foo;
|
||||
|
||||
import bar.Bar;
|
||||
import bar.Other;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Foo {
|
||||
abstract public Bar foo(ArrayList<Integer> list, Other other);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package foo
|
||||
|
||||
class Impl: Foo() {
|
||||
<caret>
|
||||
}
|
||||
|
||||
// KT-4732 Override/Implement action does not add all imports when "Optimize imports on the fly" is enabled
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package foo
|
||||
|
||||
import java.util.ArrayList
|
||||
import bar.Other
|
||||
import bar.Bar
|
||||
|
||||
class Impl: Foo() {
|
||||
|
||||
override fun foo(list: ArrayList<Int>?, other: Other?): Bar? {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
// KT-4732 Override/Implement action does not add all imports when "Optimize imports on the fly" is enabled
|
||||
-2
@@ -1,11 +1,9 @@
|
||||
package foo;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class JavaClass {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void bar(@Nullable String price) {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ LineBreakpoint created at abstractFunCall.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! abstractFunCall.AbstractFunCallPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
abstractFunCall.kt:4
|
||||
Compile bytecode for (1 as java.lang.Number).intValue()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,15 @@ LineBreakpoint created at arrays.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! arrays.ArraysPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
arrays.kt:4
|
||||
Compile bytecode for array(1, 2).map { it.toString() }
|
||||
Compile bytecode for array(1, 2, 101, 102).filter { it > 100 }
|
||||
Compile bytecode for array(1, 2).none()
|
||||
Compile bytecode for array(1, 2).count()
|
||||
Compile bytecode for array(1, 2).size
|
||||
Compile bytecode for array(1, 2).first()
|
||||
Compile bytecode for array(1, 2).last()
|
||||
Compile bytecode for intArray(1, 2).max()
|
||||
Compile bytecode for array(1, 2).max()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,8 @@ LineBreakpoint created at classFromAnotherPackage.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classFromAnotherPackage.ClassFromAnotherPackagePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
classFromAnotherPackage.kt:6
|
||||
Compile bytecode for MyJavaClass()
|
||||
Compile bytecode for stepInto.MyJavaClass()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,8 @@ LineBreakpoint created at classObjectVal.kt:10
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classObjectVal.ClassObjectValPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
classObjectVal.kt:9
|
||||
Compile bytecode for coProp
|
||||
Compile bytecode for MyClass.coProp
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
LineBreakpoint created at clearCache.kt:12
|
||||
LineBreakpoint created at clearCache.kt:20
|
||||
LineBreakpoint created at clearCache.kt:31
|
||||
LineBreakpoint created at clearCache.kt:42
|
||||
LineBreakpoint created at clearCache.kt:52
|
||||
LineBreakpoint created at clearCache.kt:60
|
||||
LineBreakpoint created at clearCache.kt:78
|
||||
LineBreakpoint created at clearCache.kt:86
|
||||
LineBreakpoint created at clearCache.kt:95
|
||||
LineBreakpoint created at clearCache.kt:105
|
||||
LineBreakpoint created at clearCache.kt:113
|
||||
LineBreakpoint created at clearCache.kt:123
|
||||
LineBreakpoint created at clearCache.kt:131
|
||||
LineBreakpoint created at clearCache.kt:149
|
||||
LineBreakpoint created at clearCache.kt:154
|
||||
LineBreakpoint created at clearCache.kt:161
|
||||
LineBreakpoint created at clearCache.kt:169
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! clearCache.ClearCachePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
clearCache.kt:11
|
||||
Compile bytecode for a
|
||||
clearCache.kt:19
|
||||
Compile bytecode for a
|
||||
clearCache.kt:30
|
||||
Compile bytecode for i
|
||||
clearCache.kt:30
|
||||
clearCache.kt:41
|
||||
Compile bytecode for i
|
||||
clearCache.kt:41
|
||||
clearCache.kt:51
|
||||
Compile bytecode for o.test()
|
||||
clearCache.kt:59
|
||||
clearCache.kt:77
|
||||
Compile bytecode for c.size()
|
||||
clearCache.kt:85
|
||||
clearCache.kt:94
|
||||
clearCache.kt:104
|
||||
clearCache.kt:112
|
||||
Compile bytecode for c.size()
|
||||
clearCache.kt:122
|
||||
Compile bytecode for o.test()
|
||||
clearCache.kt:130
|
||||
clearCache.kt:148
|
||||
Compile bytecode for obj.test()
|
||||
clearCache.kt:153
|
||||
clearCache.kt:160
|
||||
Compile bytecode for o.test()
|
||||
clearCache.kt:168
|
||||
Compile bytecode for o.test()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -2,6 +2,17 @@ LineBreakpoint created at collections.kt:6
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! collections.CollectionsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
collections.kt:5
|
||||
Compile bytecode for arrayListOf(1, 2).map { it.toString() }
|
||||
Compile bytecode for arrayListOf(1, 2, 101, 102).filter { it > 100 }
|
||||
Compile bytecode for arrayListOf(1, 2).max()
|
||||
Compile bytecode for arrayListOf(1, 2).count()
|
||||
Compile bytecode for arrayListOf(1, 2).size
|
||||
Compile bytecode for arrayListOf(1, 2).drop(1)
|
||||
Compile bytecode for ar.map { if (it > 50) "big" else "small" }
|
||||
.filter { it == "small" }
|
||||
.size
|
||||
|
||||
// RESULT: 2: I
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,14 @@ LineBreakpoint created at dependentOnFile.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! dependentOnFile.DependentOnFilePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
dependentOnFile.kt:4
|
||||
Compile bytecode for TestClass().testFun()
|
||||
Compile bytecode for testFun()
|
||||
Compile bytecode for TestObject.p
|
||||
Compile bytecode for TestClass.p
|
||||
Compile bytecode for 1.testExtFun()
|
||||
Compile bytecode for testVal
|
||||
Compile bytecode for 1.testExtVal
|
||||
Compile bytecode for testDelVal
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at doubles.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! doubles.DoublesPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
doubles.kt:6
|
||||
Compile bytecode for d1 + d2
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -2,6 +2,7 @@ LineBreakpoint created at enums.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! enums.EnumsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
enums.kt:6
|
||||
Compile bytecode for A == MyEnum.A
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
LineBreakpoint created at exceptions.kt:9
|
||||
LineBreakpoint created at exceptions.kt:14
|
||||
LineBreakpoint created at exceptions.kt:26
|
||||
LineBreakpoint created at exceptions.kt:31
|
||||
LineBreakpoint created at exceptions.kt:42
|
||||
LineBreakpoint created at exceptions.kt:51
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! exceptions.ExceptionsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
exceptions.kt:8
|
||||
Compile bytecode for fail()
|
||||
exceptions.kt:13
|
||||
exceptions.kt:25
|
||||
Compile bytecode for o as Derived
|
||||
exceptions.kt:30
|
||||
exceptions.kt:41
|
||||
Compile bytecode for c.get(0)
|
||||
exceptions.kt:50
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -2,6 +2,10 @@ LineBreakpoint created at extractLocalVariables.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractLocalVariables.ExtractLocalVariablesPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
extractLocalVariables.kt:6
|
||||
Compile bytecode for a
|
||||
Compile bytecode for klass.f1(1)
|
||||
Compile bytecode for args.size
|
||||
Compile bytecode for klass.b
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,9 @@ LineBreakpoint created at extractThis.kt:13
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractThis.ExtractThisPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
extractThis.kt:12
|
||||
Compile bytecode for prop
|
||||
Compile bytecode for this.prop
|
||||
Compile bytecode for prop + a
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,10 @@ LineBreakpoint created at extractVariablesFromCall.kt:8
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractVariablesFromCall.ExtractVariablesFromCallPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
extractVariablesFromCall.kt:7
|
||||
Compile bytecode for f1(a, s)
|
||||
Compile bytecode for a.f2(s)
|
||||
Compile bytecode for a f2 s
|
||||
Compile bytecode for klass.f1(a, s)
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,10 @@ LineBreakpoint created at imports.kt:10
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! imports.ImportsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
imports.kt:9
|
||||
Compile bytecode for Collections.emptyList<String>()
|
||||
Compile bytecode for ArrayList<Int>()
|
||||
Compile bytecode for HashSet<Int>()
|
||||
Compile bytecode for JHashMap<Int, Int>()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,7 @@ LineBreakpoint created at insertInBlock.kt:6
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! insertInBlock.InsertInBlockPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
insertInBlock.kt:5
|
||||
Compile bytecode for 1 + 1
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,7 @@ LineBreakpoint created at multilineExpressionAtBreakpoint.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! multilineExpressionAtBreakpoint.MultilineExpressionAtBreakpointPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
multilineExpressionAtBreakpoint.kt:4
|
||||
Compile bytecode for 1 + 1
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
LineBreakpoint created at privateMember.kt:5
|
||||
LineBreakpoint created at privateMember.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! privateMember.PrivateMemberPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
privateMember.kt:4
|
||||
privateMember.kt:8
|
||||
Compile bytecode for MyClass().privateFun()
|
||||
Compile bytecode for MyClass().privateVal
|
||||
Compile bytecode for MyClass.PrivateClass().a
|
||||
Compile bytecode for base.privateFun()
|
||||
Compile bytecode for derived.privateFun()
|
||||
Compile bytecode for derivedAsBase.privateFun()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,9 @@ LineBreakpoint created at protectedMember.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! protectedMember.ProtectedMemberPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
protectedMember.kt:4
|
||||
Compile bytecode for MyClass().protectedFun()
|
||||
Compile bytecode for MyClass().protectedVal
|
||||
Compile bytecode for MyClass.ProtectedClass().a
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,13 @@ LineBreakpoint created at simple.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! simple.SimplePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
simple.kt:4
|
||||
Compile bytecode for 1
|
||||
Compile bytecode for 1 + 1
|
||||
Compile bytecode for val a = 1
|
||||
a + args.size
|
||||
|
||||
// RESULT: 1: I
|
||||
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,13 @@ LineBreakpoint created at stdlib.kt:5
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! stdlib.StdlibPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stdlib.kt:4
|
||||
Compile bytecode for array(100, 101)
|
||||
Compile bytecode for array("a", "b", "c")
|
||||
Compile bytecode for intArray(1, 2)
|
||||
Compile bytecode for javaClass<String>()
|
||||
Compile bytecode for javaClass<Int>()
|
||||
Compile bytecode for 100.toInt()
|
||||
Compile bytecode for 100.toLong()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,6 +2,8 @@ LineBreakpoint created at vars.kt:7
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! vars.VarsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
vars.kt:6
|
||||
Compile bytecode for a
|
||||
Compile bytecode for a += 1
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
package clearCache
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
|
||||
fun primitiveTypes() {
|
||||
if (true) {
|
||||
val a: Any = 0
|
||||
// EXPRESSION: a
|
||||
// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer;
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val a = 1
|
||||
// EXPRESSION: a
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
for (i in 1..2) {
|
||||
// EXPRESSION: i
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: i
|
||||
// RESULT: 2: I
|
||||
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
for (i in 5.0..6.0) {
|
||||
// EXPRESSION: i
|
||||
// RESULT: 5.0: D
|
||||
|
||||
// EXPRESSION: i
|
||||
// RESULT: 6.0: D
|
||||
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
fun subType() {
|
||||
if (true) {
|
||||
val o = Base()
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 100: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val o = Derived()
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 200: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
open class Base {
|
||||
open fun test() = 100
|
||||
}
|
||||
|
||||
class Derived: Base() {
|
||||
override fun test() = 200
|
||||
}
|
||||
|
||||
fun subTypePlatform() {
|
||||
if (true) {
|
||||
val c: MutableList<String> = ArrayList<String>()
|
||||
// EXPRESSION: c.size()
|
||||
// RESULT: 0: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val c: List<String> = ArrayList<String>()
|
||||
// EXPRESSION: c.size()
|
||||
// RESULT: 0: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val c = ArrayList<String>()
|
||||
c.add("a")
|
||||
// EXPRESSION: c.size()
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val c = ArrayList<Int>()
|
||||
c.add(1)
|
||||
c.add(2)
|
||||
// EXPRESSION: c.size()
|
||||
// RESULT: 2: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val c = HashSet<Int>()
|
||||
// EXPRESSION: c.size()
|
||||
// RESULT: 0: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
fun innerClass() {
|
||||
if (true) {
|
||||
val o = TestInnerClasses.Base()
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 100: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val o = TestInnerClasses.Derived()
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 200: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
class TestInnerClasses {
|
||||
open class Base {
|
||||
open fun test() = 100
|
||||
}
|
||||
|
||||
class Derived: Base() {
|
||||
override fun test() = 200
|
||||
}
|
||||
}
|
||||
|
||||
fun objects() {
|
||||
// EXPRESSION: obj.test()
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val a1 = 1
|
||||
|
||||
// EXPRESSION: obj.test()
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val a2 = 1
|
||||
|
||||
if (true) {
|
||||
val o: BaseObject = obj
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val o = obj
|
||||
// EXPRESSION: o.test()
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
val obj = object: BaseObject() { }
|
||||
|
||||
open class BaseObject {
|
||||
fun test() = 1
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
primitiveTypes()
|
||||
subType()
|
||||
subTypePlatform()
|
||||
innerClass()
|
||||
objects()
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package exceptions
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
fun throwException() {
|
||||
// EXPRESSION: fail()
|
||||
// RESULT: instance of java.lang.UnsupportedOperationException(id=ID): Ljava/lang/UnsupportedOperationException;
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
|
||||
// EXPRESSION: fail()
|
||||
// RESULT: instance of java.lang.UnsupportedOperationException(id=ID): Ljava/lang/UnsupportedOperationException;
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
fun fail() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
fun classCast() {
|
||||
val o = Base()
|
||||
// EXPRESSION: o as Derived
|
||||
// RESULT: java.lang.ClassCastException: exceptions.Base cannot be cast to exceptions.Derived: Ljava/lang/ClassCastException;
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
|
||||
// EXPRESSION: o as Derived
|
||||
// RESULT: java.lang.ClassCastException: exceptions.Base cannot be cast to exceptions.Derived: Ljava/lang/ClassCastException;
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
|
||||
fun genericClassCast() {
|
||||
if (true) {
|
||||
val c = ArrayList<Int>()
|
||||
c.add(1)
|
||||
// EXPRESSION: c.get(0)
|
||||
// RESULT: 1: I
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
if (true) {
|
||||
val c = ArrayList<String>()
|
||||
c.add("a")
|
||||
// EXPRESSION: c.get(0)
|
||||
// RESULT: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number: Ljava/lang/ClassCastException;
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
}
|
||||
|
||||
open class Base {
|
||||
private fun test(): Int = 1
|
||||
}
|
||||
|
||||
class Derived: Base()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
throwException()
|
||||
classCast()
|
||||
genericClassCast()
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package privateMember
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
args.size
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
private fun privateFun() = 1
|
||||
private val privateVal = 1
|
||||
|
||||
private class PrivateClass {
|
||||
val a = 1
|
||||
}
|
||||
}
|
||||
|
||||
// EXPRESSION: MyClass().privateFun()
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: MyClass().privateVal
|
||||
// RESULT: 1: I
|
||||
|
||||
// EXPRESSION: MyClass.PrivateClass().a
|
||||
// RESULT: 1: I
|
||||
@@ -0,0 +1,11 @@
|
||||
package doubles
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val d1 = 1.0
|
||||
val d2 = 3.0
|
||||
//Breakpoint!
|
||||
args.size
|
||||
}
|
||||
|
||||
// EXPRESSION: d1 + d2
|
||||
// RESULT: 4.0: D
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user