From 16481a4144915c6290fa1ba7de9d4dbe4ed028ba Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 5 Dec 2014 20:17:32 +0100 Subject: [PATCH] convert JetPositionManager to Kotlin --- .../jet/plugin/debugger/JetPositionManager.kt | 645 ++++++++---------- 1 file changed, 300 insertions(+), 345 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt index c72fb74f455..b1c71a6a0ae 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt @@ -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. @@ -14,428 +14,383 @@ * limitations under the License. */ -package org.jetbrains.jet.plugin.debugger; +package org.jetbrains.jet.plugin.debugger -import com.intellij.debugger.NoDataException; -import com.intellij.debugger.PositionManager; -import com.intellij.debugger.SourcePosition; -import com.intellij.debugger.engine.DebugProcess; -import com.intellij.debugger.requests.ClassPrepareRequestor; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.libraries.LibraryUtil; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.*; -import com.sun.jdi.AbsentInformationException; -import com.sun.jdi.Location; -import com.sun.jdi.ReferenceType; -import com.sun.jdi.request.ClassPrepareRequest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; -import org.jetbrains.jet.analyzer.AnalysisResult; -import org.jetbrains.jet.codegen.AsmUtil; -import org.jetbrains.jet.codegen.ClassBuilderFactories; -import org.jetbrains.jet.codegen.state.GenerationState; -import org.jetbrains.jet.codegen.state.JetTypeMapper; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; -import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension; -import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils; -import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.types.lang.InlineStrategy; -import org.jetbrains.jet.lang.types.lang.InlineUtil; -import org.jetbrains.jet.plugin.caches.resolve.IdeaModuleInfo; -import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheService; -import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; -import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils; -import org.jetbrains.jet.plugin.util.DebuggerUtils; -import org.jetbrains.org.objectweb.asm.Type; +import com.intellij.debugger.NoDataException +import com.intellij.debugger.PositionManager +import com.intellij.debugger.SourcePosition +import com.intellij.debugger.engine.DebugProcess +import com.intellij.debugger.requests.ClassPrepareRequestor +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.libraries.LibraryUtil +import com.intellij.openapi.util.Pair +import com.intellij.openapi.util.Ref +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.* +import com.sun.jdi.AbsentInformationException +import com.sun.jdi.Location +import com.sun.jdi.ReferenceType +import com.sun.jdi.request.ClassPrepareRequest +import org.jetbrains.annotations.TestOnly +import org.jetbrains.jet.analyzer.AnalysisResult +import org.jetbrains.jet.codegen.AsmUtil +import org.jetbrains.jet.codegen.ClassBuilderFactories +import org.jetbrains.jet.codegen.state.GenerationState +import org.jetbrains.jet.codegen.state.JetTypeMapper +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lang.descriptors.VariableDescriptor +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.calls.callUtil.* +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument +import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension +import org.jetbrains.jet.lang.resolve.java.JvmClassName +import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils +import org.jetbrains.jet.lang.resolve.name.FqName +import org.jetbrains.jet.lang.types.lang.InlineStrategy +import org.jetbrains.jet.lang.types.lang.InlineUtil +import org.jetbrains.jet.plugin.caches.resolve.IdeaModuleInfo +import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheService +import org.jetbrains.jet.plugin.caches.resolve.* +import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils +import org.jetbrains.jet.plugin.util.DebuggerUtils +import org.jetbrains.org.objectweb.asm.Type -import java.util.*; +import java.util.* -import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; -import static org.jetbrains.jet.plugin.stubindex.PackageIndexUtil.findFilesWithExactPackage; +import org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass +import org.jetbrains.jet.plugin.stubindex.PackageIndexUtil +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import com.intellij.psi.stubs.StubElement -public class JetPositionManager implements PositionManager { - private final DebugProcess myDebugProcess; - private final WeakHashMap, CachedValue> myTypeMappers = new WeakHashMap, CachedValue>(); +public class JetPositionManager(private val myDebugProcess: DebugProcess) : PositionManager { + private val myTypeMappers = WeakHashMap, CachedValue>() - public JetPositionManager(DebugProcess debugProcess) { - myDebugProcess = debugProcess; - } - - @Override - @Nullable - public SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException { + override fun getSourcePosition(location: Location?): SourcePosition? { if (location == null) { - throw new NoDataException(); + throw NoDataException() } - PsiFile psiFile = getPsiFileByLocation(location); + val psiFile = getPsiFileByLocation(location) if (psiFile == null) { - throw new NoDataException(); + throw NoDataException() } - int lineNumber; + val lineNumber: Int try { - lineNumber = location.lineNumber() - 1; + lineNumber = location.lineNumber() - 1 } - catch (InternalError e) { - lineNumber = -1; + catch (e: InternalError) { + lineNumber = -1 } + if (lineNumber >= 0) { - JetFunctionLiteral lambdaIfInside = getLambdaIfInside(location, (JetFile) psiFile, lineNumber); + val lambdaIfInside = getLambdaIfInside(location, psiFile as JetFile, lineNumber) if (lambdaIfInside != null) { - return SourcePosition.createFromElement(lambdaIfInside.getBodyExpression().getStatements().get(0)); + return SourcePosition.createFromElement(lambdaIfInside.getBodyExpression().getStatements().get(0)) } - return SourcePosition.createFromLine(psiFile, lineNumber); + return SourcePosition.createFromLine(psiFile, lineNumber) } - throw new NoDataException(); + throw NoDataException() } - private JetFunctionLiteral getLambdaIfInside(@NotNull Location location, @NotNull JetFile file, int lineNumber) { - String currentLocationFqName = location.declaringType().name(); - if (currentLocationFqName == null) return null; + private fun getLambdaIfInside(location: Location, file: JetFile, lineNumber: Int): JetFunctionLiteral? { + val currentLocationFqName = location.declaringType().name() + if (currentLocationFqName == null) return null - Integer start = CodeInsightUtils.getStartLineOffset(file, lineNumber); - Integer end = CodeInsightUtils.getEndLineOffset(file, lineNumber); - if (start == null || end == null) return null; + val start = CodeInsightUtils.getStartLineOffset(file, lineNumber) + val end = CodeInsightUtils.getEndLineOffset(file, lineNumber) + if (start == null || end == null) return null - PsiElement[] literals = CodeInsightUtils.findElementsOfClassInRange(file, start, end, JetFunctionLiteral.class); - if (literals == null || literals.length == 0) return null; + val literals = CodeInsightUtils.findElementsOfClassInRange(file, start, end, javaClass()) + if (literals == null || literals.size() == 0) return null - boolean isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null; - JetTypeMapper typeMapper = !isInLibrary - ? prepareTypeMapper(file) - : createTypeMapperForLibraryFile(file.findElementAt(start), file); + val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null + val typeMapper = if (!isInLibrary) + prepareTypeMapper(file) + else + createTypeMapperForLibraryFile(file.findElementAt(start), file) - String currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(new FqName(currentLocationFqName)).getInternalName(); - for (PsiElement literal : literals) { - JetFunctionLiteral functionLiteral = (JetFunctionLiteral) literal; + val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).getInternalName() + for (literal in literals) { + val functionLiteral = literal as JetFunctionLiteral if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) { - continue; + continue } - String internalClassName = getClassNameForElement(literal.getFirstChild(), typeMapper, file, isInLibrary); - if (internalClassName.equals(currentLocationClassName)) { - return functionLiteral; + val internalClassName = getClassNameForElement(literal.getFirstChild(), typeMapper, file, isInLibrary) + if (internalClassName == currentLocationClassName) { + return functionLiteral } } - return null; + return null } - @Nullable - private PsiFile getPsiFileByLocation(@NotNull Location location) { - String sourceName; + private fun getPsiFileByLocation(location: Location): PsiFile? { + val sourceName: String try { - sourceName = location.sourceName(); + sourceName = location.sourceName() } - catch (AbsentInformationException e) { - return null; + catch (e: AbsentInformationException) { + return null } + // JDI names are of form "package.Class$InnerClass" - String referenceFqName = location.declaringType().name(); - String referenceInternalName = referenceFqName.replace('.', '/'); - JvmClassName className = JvmClassName.byInternalName(referenceInternalName); + val referenceFqName = location.declaringType().name() + val referenceInternalName = referenceFqName.replace('.', '/') + val className = JvmClassName.byInternalName(referenceInternalName) - Project project = myDebugProcess.getProject(); + val project = myDebugProcess.getProject() - if (DumbService.getInstance(project).isDumb()) return null; + if (DumbService.getInstance(project).isDumb()) return null - return DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), className, sourceName, location.lineNumber() - 1); + return DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), className, sourceName, location.lineNumber() - 1) } - @NotNull - @Override - public List getAllClasses(SourcePosition sourcePosition) throws NoDataException { - if (!(sourcePosition.getFile() instanceof JetFile)) { - throw new NoDataException(); + override fun getAllClasses(sourcePosition: SourcePosition): List { + if (sourcePosition.getFile() !is JetFile) { + throw NoDataException() } - String name = classNameForPosition(sourcePosition); - List result = new ArrayList(); + val name = classNameForPosition(sourcePosition) + val result = ArrayList() if (name != null) { - result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name)); + result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name)) } - return result; + return result } - @Nullable - private String classNameForPosition(final SourcePosition sourcePosition) { - final Ref result = Ref.create(); + private fun classNameForPosition(sourcePosition: SourcePosition): String? { + val result = Ref.create() - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - @SuppressWarnings("unchecked") - public void run() { - JetFile file = (JetFile) sourcePosition.getFile(); - boolean isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null; - JetTypeMapper typeMapper = !isInLibrary ? prepareTypeMapper(file) : createTypeMapperForLibraryFile(sourcePosition.getElementAt(), file); - result.set(getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file, isInLibrary)); - } + ApplicationManager.getApplication().runReadAction { + val file = sourcePosition.getFile() as JetFile + val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null + val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(sourcePosition.getElementAt(), file) + result.set(getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file, isInLibrary)) + } - }); - - return result.get(); + return result.get() } - @SuppressWarnings("unchecked") - public static String getClassNameForElement( - @Nullable PsiElement notPositionedElement, - @NotNull JetTypeMapper typeMapper, - @NotNull JetFile file, - boolean isInLibrary - ) { - PsiElement element = getElementToCalculateClassName(notPositionedElement); + private fun prepareTypeMapper(file: JetFile): JetTypeMapper { + val key = createKeyForTypeMapper(file) - if (element instanceof JetClassOrObject) { - return getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) element); - } - else if (element instanceof JetFunctionLiteral) { - if (isInlinedLambda((JetFunctionLiteral) element, typeMapper.getBindingContext())) { - return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary); - } else { - Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), ((JetFunctionLiteral) element)); - return asmType.getInternalName(); - } - } - else if (element instanceof JetClassInitializer) { - PsiElement parent = getElementToCalculateClassName(element.getParent()); - // Class-object initializer - if (parent instanceof JetObjectDeclaration && ((JetObjectDeclaration) parent).isClassObject()) { - return getClassNameForElement(parent.getParent(), typeMapper, file, isInLibrary); - } - return getClassNameForElement(element, typeMapper, file, isInLibrary); - } - else if (element instanceof JetProperty && (!((JetProperty) element).isTopLevel() || !isInLibrary)) { - if (isInPropertyAccessor(notPositionedElement)) { - JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class); - if (classOrObject != null) { - return getJvmInternalNameForImpl(typeMapper, classOrObject); + var value: CachedValue? = myTypeMappers.get(key) + if (value == null) { + value = CachedValuesManager.getManager(file.getProject()).createCachedValue(object : CachedValueProvider { + override fun compute(): CachedValueProvider.Result? { + val project = file.getProject() + val packageFacadeScope = key.second.contentScope() + val packageFiles = PackageIndexUtil.findFilesWithExactPackage(key.first, packageFacadeScope, project) + + val analysisResult = KotlinCacheService.getInstance(project).getAnalysisResults(packageFiles) + analysisResult.throwIfError() + + val state = GenerationState(project, ClassBuilderFactories.THROW_EXCEPTION, analysisResult.moduleDescriptor, + analysisResult.bindingContext, ArrayList(packageFiles)) + state.beforeCompile() + return CachedValueProvider.Result(state.getTypeMapper(), PsiModificationTracker.MODIFICATION_COUNT) } - } + }, false) - VariableDescriptor descriptor = (VariableDescriptor) typeMapper.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); - if (!(descriptor instanceof PropertyDescriptor)) { - return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary); - } - - return getJvmInternalNameForPropertyOwner(typeMapper, (PropertyDescriptor) descriptor); - } - else if (element instanceof JetNamedFunction) { - PsiElement parent = getElementToCalculateClassName(element); - if (parent instanceof JetClassOrObject) { - return getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) parent); - } - else if (parent != null) { - Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), (JetElement) element); - return asmType.getInternalName(); - } + myTypeMappers.put(key, value) } - if (isInLibrary) { - JetElement elementAtForLibraryFile = getElementToCreateTypeMapperForLibraryFile(notPositionedElement); - assert elementAtForLibraryFile != null : "Couldn't find element at breakpoint for library file " + file.getName() - + (notPositionedElement == null ? "" : ", notPositionedElement = " + JetPsiUtil.getElementTextWithContext( (JetElement) notPositionedElement)); - return DebuggerPackage.findPackagePartInternalNameForLibraryFile(elementAtForLibraryFile); - } - - return PackagePartClassUtils.getPackagePartInternalName(file); + return value!!.getValue() } - @Nullable - private static JetDeclaration getElementToCalculateClassName(@Nullable PsiElement notPositionedElement) { - //noinspection unchecked - return PsiTreeUtil.getParentOfType(notPositionedElement, - JetClassOrObject.class, - JetFunctionLiteral.class, JetNamedFunction.class, - JetProperty.class, - JetClassInitializer.class); - } - - @NotNull - public static String getJvmInternalNameForPropertyOwner(@NotNull JetTypeMapper typeMapper, @NotNull PropertyDescriptor descriptor) { - return typeMapper.mapOwner( - AsmUtil.isPropertyWithBackingFieldInOuterClass(descriptor) ? descriptor.getContainingDeclaration() : descriptor, - true) - .getInternalName(); - } - - private static boolean isInPropertyAccessor(@Nullable PsiElement element) { - //noinspection unchecked - return element instanceof JetPropertyAccessor || ((JetElement) PsiTreeUtil.getParentOfType(element, JetProperty.class, JetPropertyAccessor.class)) instanceof JetPropertyAccessor; - } - - @Nullable - private static JetElement getElementToCreateTypeMapperForLibraryFile(@Nullable PsiElement element) { - return element instanceof JetElement ? (JetElement) element : PsiTreeUtil.getParentOfType(element, JetElement.class); - } - - @Nullable - private static String getJvmInternalNameForImpl(JetTypeMapper typeMapper, JetClassOrObject jetClass) { - ClassDescriptor classDescriptor = typeMapper.getBindingContext().get(BindingContext.CLASS, jetClass); - if (classDescriptor == null) { - return null; - } - - if (jetClass instanceof JetClass && ((JetClass) jetClass).isTrait()) { - return typeMapper.mapTraitImpl(classDescriptor).getInternalName(); - } - - return typeMapper.mapClass(classDescriptor).getInternalName(); - } - - private static JetTypeMapper createTypeMapperForLibraryFile(@Nullable PsiElement notPositionedElement, @NotNull JetFile file) { - JetElement element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement); - AnalysisResult analysisResult = ResolvePackage.analyzeAndGetResult(element); - - GenerationState state = new GenerationState(file.getProject(), ClassBuilderFactories.THROW_EXCEPTION, - analysisResult.getModuleDescriptor(), - analysisResult.getBindingContext(), - Collections.singletonList(file) - ); - state.beforeCompile(); - return state.getTypeMapper(); - } - - private JetTypeMapper prepareTypeMapper(final JetFile file) { - final Pair key = createKeyForTypeMapper(file); - - CachedValue value = myTypeMappers.get(key); - if(value == null) { - value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - Project project = file.getProject(); - GlobalSearchScope packageFacadeScope = key.second.contentScope(); - Collection packageFiles = findFilesWithExactPackage(key.first, packageFacadeScope, project); - - AnalysisResult analysisResult = KotlinCacheService.OBJECT$.getInstance(project).getAnalysisResults(packageFiles); - analysisResult.throwIfError(); - - GenerationState state = new GenerationState(project, ClassBuilderFactories.THROW_EXCEPTION, - analysisResult.getModuleDescriptor(), analysisResult.getBindingContext(), - new ArrayList(packageFiles) - ); - state.beforeCompile(); - return new Result(state.getTypeMapper(), PsiModificationTracker.MODIFICATION_COUNT); - } - }, false); - - myTypeMappers.put(key, value); - } - - return value.getValue(); - } - - @NotNull - @Override - public List locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException { - if (!(position.getFile() instanceof JetFile)) { - throw new NoDataException(); + override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List { + if (position.getFile() !is JetFile) { + throw NoDataException() } try { - int line = position.getLine() + 1; - List locations = myDebugProcess.getVirtualMachineProxy().versionHigher("1.4") - ? type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line) - : type.locationsOfLine(line); - if (locations == null || locations.isEmpty()) throw new NoDataException(); - return locations; + val line = position.getLine() + 1 + val locations = if (myDebugProcess.getVirtualMachineProxy().versionHigher("1.4")) + type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line) + else + type.locationsOfLine(line) + if (locations == null || locations.isEmpty()) throw NoDataException() + return locations } - catch (AbsentInformationException e) { - throw new NoDataException(); + catch (e: AbsentInformationException) { + throw NoDataException() } } - @Override - public ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor classPrepareRequestor, - SourcePosition sourcePosition) throws NoDataException { - if (!(sourcePosition.getFile() instanceof JetFile)) { - throw new NoDataException(); + override fun createPrepareRequest(classPrepareRequestor: ClassPrepareRequestor, sourcePosition: SourcePosition): ClassPrepareRequest? { + if (sourcePosition.getFile() !is JetFile) { + throw NoDataException() } - String className = classNameForPosition(sourcePosition); + val className = classNameForPosition(sourcePosition) if (className == null) { - return null; + return null } - return myDebugProcess.getRequestsManager().createClassPrepareRequest(classPrepareRequestor, className.replace('/', '.')); + return myDebugProcess.getRequestsManager().createClassPrepareRequest(classPrepareRequestor, className.replace('/', '.')) } - @TestOnly - public void addTypeMapper(JetFile file, final JetTypeMapper typeMapper) { - CachedValue value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - return new Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT); - } - }, false); + TestOnly + public fun addTypeMapper(file: JetFile, typeMapper: JetTypeMapper) { + val value = CachedValuesManager.getManager(file.getProject()).createCachedValue(object : CachedValueProvider { + override fun compute() = CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) + }, false) - Pair key = createKeyForTypeMapper(file); - myTypeMappers.put(key, value); + val key = createKeyForTypeMapper(file) + myTypeMappers.put(key, value) } + class object { + public fun getClassNameForElement(notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: JetFile, isInLibrary: Boolean): String? { + val element = getElementToCalculateClassName(notPositionedElement) + when { + element is JetClassOrObject -> return getJvmInternalNameForImpl(typeMapper, element) + element is JetFunctionLiteral -> { + if (isInlinedLambda(element, typeMapper.getBindingContext())) { + return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary) + } + else { + val asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), element) + return asmType.getInternalName() + } + } + element is JetClassInitializer -> { + val parent = getElementToCalculateClassName(element.getParent()) + // Class-object initializer + if (parent is JetObjectDeclaration && parent.isClassObject()) { + return getClassNameForElement(parent.getParent(), typeMapper, file, isInLibrary) + } + return getClassNameForElement(element, typeMapper, file, isInLibrary) + } + element is JetProperty && (!element.isTopLevel() || !isInLibrary) -> { + if (isInPropertyAccessor(notPositionedElement)) { + val classOrObject = PsiTreeUtil.getParentOfType(element, javaClass()) + if (classOrObject != null) { + return getJvmInternalNameForImpl(typeMapper, classOrObject) + } + } - public static boolean isInlinedLambda(@NotNull JetFunctionLiteral functionLiteral, @NotNull BindingContext context) { - PsiElement functionLiteralExpression = functionLiteral.getParent(); - if (functionLiteralExpression == null) return false; + val descriptor = typeMapper.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + if (descriptor !is PropertyDescriptor) { + return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary) + } - PsiElement parent = functionLiteralExpression.getParent(); - - PsiElement valueArgument = functionLiteralExpression; - while (parent instanceof JetParenthesizedExpression || - parent instanceof JetBinaryExpressionWithTypeRHS || - parent instanceof JetLabeledExpression) { - valueArgument = parent; - parent = parent.getParent(); - } - - while (parent instanceof ValueArgument || - parent instanceof JetValueArgumentList) { - parent = parent.getParent(); - } - - if (!(parent instanceof JetElement)) return false; - - ResolvedCall call = CallUtilPackage.getResolvedCall((JetElement) parent, context); - if (call == null) return false; - - InlineStrategy inlineType = InlineUtil.getInlineType(call.getResultingDescriptor()); - if (!inlineType.isInline()) return false; - - for (Map.Entry entry : call.getValueArguments().entrySet()) { - ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); - ResolvedValueArgument resolvedValueArgument = entry.getValue(); - - for (ValueArgument next : resolvedValueArgument.getArguments()) { - JetExpression expression = next.getArgumentExpression(); - if (valueArgument == expression) { - return InlineAnalyzerExtension.checkInlinableParameter( - valueParameterDescriptor, expression, - call.getResultingDescriptor(), null - ); + return getJvmInternalNameForPropertyOwner(typeMapper, descriptor) + } + element is JetNamedFunction -> { + val parent = getElementToCalculateClassName(element) + if (parent is JetClassOrObject) { + return getJvmInternalNameForImpl(typeMapper, parent) + } + else if (parent != null) { + val asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), element) + return asmType.getInternalName() + } } } + + if (isInLibrary) { + val elementAtForLibraryFile = getElementToCreateTypeMapperForLibraryFile(notPositionedElement) + assert(elementAtForLibraryFile != null) { + "Couldn't find element at breakpoint for library file " + file.getName() + + (if (notPositionedElement == null) "" else ", notPositionedElement = " + JetPsiUtil.getElementTextWithContext(notPositionedElement)) + } + return findPackagePartInternalNameForLibraryFile(elementAtForLibraryFile!!) + } + + return PackagePartClassUtils.getPackagePartInternalName(file) } - return false; - } - private static Pair createKeyForTypeMapper(@NotNull JetFile file) { - return new Pair(file.getPackageFqName(), ResolvePackage.getModuleInfo(file)); - } + private fun getElementToCalculateClassName(notPositionedElement: PsiElement?) = + PsiTreeUtil.getParentOfType(notPositionedElement, + javaClass(), + javaClass(), + javaClass(), + javaClass(), + javaClass()) + public fun getJvmInternalNameForPropertyOwner(typeMapper: JetTypeMapper, descriptor: PropertyDescriptor): String { + return typeMapper.mapOwner( + if (AsmUtil.isPropertyWithBackingFieldInOuterClass(descriptor)) descriptor.getContainingDeclaration() else descriptor, + true).getInternalName() + } + + private fun isInPropertyAccessor(element: PsiElement?) = + element is JetPropertyAccessor || + PsiTreeUtil.getParentOfType(element, javaClass(), javaClass()) is JetPropertyAccessor + + private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) = + if (element is JetElement) element else PsiTreeUtil.getParentOfType(element, javaClass()) + + private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, jetClass: JetClassOrObject): String? { + val classDescriptor = typeMapper.getBindingContext().get(BindingContext.CLASS, jetClass) + if (classDescriptor == null) { + return null + } + + if (jetClass is JetClass && jetClass.isTrait()) { + return typeMapper.mapTraitImpl(classDescriptor).getInternalName() + } + + return typeMapper.mapClass(classDescriptor).getInternalName() + } + + private fun createTypeMapperForLibraryFile(notPositionedElement: PsiElement?, file: JetFile): JetTypeMapper { + val element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement) + val analysisResult = element!!.analyzeAndGetResult() + + val state = GenerationState(file.getProject(), ClassBuilderFactories.THROW_EXCEPTION, + analysisResult.moduleDescriptor, analysisResult.bindingContext, listOf(file)) + state.beforeCompile() + return state.getTypeMapper() + } + + public fun isInlinedLambda(functionLiteral: JetFunctionLiteral, context: BindingContext): Boolean { + val functionLiteralExpression = functionLiteral.getParent() + if (functionLiteralExpression == null) return false + + var parent = functionLiteralExpression.getParent() + + var valueArgument: PsiElement = functionLiteralExpression + while (parent is JetParenthesizedExpression || parent is JetBinaryExpressionWithTypeRHS || parent is JetLabeledExpression) { + valueArgument = parent + parent = parent.getParent() + } + + while (parent is ValueArgument || parent is JetValueArgumentList) { + parent = parent.getParent() + } + + if (parent !is JetElement) return false + + val call = (parent as JetElement).getResolvedCall(context) + if (call == null) return false + + val inlineType = InlineUtil.getInlineType(call.getResultingDescriptor()) + if (!inlineType.isInline()) return false + + for (entry in call.getValueArguments().entrySet()) { + val valueParameterDescriptor = entry.getKey() + val resolvedValueArgument = entry.getValue() + + for (next in resolvedValueArgument.getArguments()) { + val expression = next.getArgumentExpression() + if (valueArgument == expression) { + return InlineAnalyzerExtension.checkInlinableParameter(valueParameterDescriptor, expression, call.getResultingDescriptor(), null) + } + } + } + return false + } + + private fun createKeyForTypeMapper(file: JetFile) = Pair(file.getPackageFqName(), file.getModuleInfo()) + } }