convert JetPositionManager to Kotlin

This commit is contained in:
Dmitry Jemerov
2014-12-05 20:17:32 +01:00
parent 6d7b4ad721
commit 16481a4144
@@ -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<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>> myTypeMappers = new WeakHashMap<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>>();
public class JetPositionManager(private val myDebugProcess: DebugProcess) : PositionManager {
private val myTypeMappers = WeakHashMap<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>>()
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<JetFunctionLiteral>())
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<ReferenceType> getAllClasses(SourcePosition sourcePosition) throws NoDataException {
if (!(sourcePosition.getFile() instanceof JetFile)) {
throw new NoDataException();
override fun getAllClasses(sourcePosition: SourcePosition): List<ReferenceType> {
if (sourcePosition.getFile() !is JetFile) {
throw NoDataException()
}
String name = classNameForPosition(sourcePosition);
List<ReferenceType> result = new ArrayList<ReferenceType>();
val name = classNameForPosition(sourcePosition)
val result = ArrayList<ReferenceType>()
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<String> result = Ref.create();
private fun classNameForPosition(sourcePosition: SourcePosition): String? {
val result = Ref.create<String>()
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<JetTypeMapper>? = myTypeMappers.get(key)
if (value == null) {
value = CachedValuesManager.getManager(file.getProject()).createCachedValue<JetTypeMapper>(object : CachedValueProvider<JetTypeMapper> {
override fun compute(): CachedValueProvider.Result<JetTypeMapper>? {
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<JetTypeMapper>(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<FqName, IdeaModuleInfo> key = createKeyForTypeMapper(file);
CachedValue<JetTypeMapper> value = myTypeMappers.get(key);
if(value == null) {
value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<JetTypeMapper>() {
@Override
public Result<JetTypeMapper> compute() {
Project project = file.getProject();
GlobalSearchScope packageFacadeScope = key.second.contentScope();
Collection<JetFile> 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<JetFile>(packageFiles)
);
state.beforeCompile();
return new Result<JetTypeMapper>(state.getTypeMapper(), PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
myTypeMappers.put(key, value);
}
return value.getValue();
}
@NotNull
@Override
public List<Location> locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException {
if (!(position.getFile() instanceof JetFile)) {
throw new NoDataException();
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
if (position.getFile() !is JetFile) {
throw NoDataException()
}
try {
int line = position.getLine() + 1;
List<Location> 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<JetTypeMapper> value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<JetTypeMapper>() {
@Override
public Result<JetTypeMapper> compute() {
return new Result<JetTypeMapper>(typeMapper, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
TestOnly
public fun addTypeMapper(file: JetFile, typeMapper: JetTypeMapper) {
val value = CachedValuesManager.getManager(file.getProject()).createCachedValue<JetTypeMapper>(object : CachedValueProvider<JetTypeMapper> {
override fun compute() = CachedValueProvider.Result<JetTypeMapper>(typeMapper, PsiModificationTracker.MODIFICATION_COUNT)
}, false)
Pair<FqName, IdeaModuleInfo> 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<JetClassOrObject>())
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<ValueParameterDescriptor, ResolvedValueArgument> 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<FqName, IdeaModuleInfo> createKeyForTypeMapper(@NotNull JetFile file) {
return new Pair<FqName, IdeaModuleInfo>(file.getPackageFqName(), ResolvePackage.getModuleInfo(file));
}
private fun getElementToCalculateClassName(notPositionedElement: PsiElement?) =
PsiTreeUtil.getParentOfType(notPositionedElement,
javaClass<JetClassOrObject>(),
javaClass<JetFunctionLiteral>(),
javaClass<JetNamedFunction>(),
javaClass<JetProperty>(),
javaClass<JetClassInitializer>())
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<JetProperty>(), javaClass<JetPropertyAccessor>()) is JetPropertyAccessor
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =
if (element is JetElement) element else PsiTreeUtil.getParentOfType(element, javaClass<JetElement>())
private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, jetClass: JetClassOrObject): String? {
val classDescriptor = typeMapper.getBindingContext().get<PsiElement, ClassDescriptor>(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())
}
}