convert JetPositionManager to Kotlin
This commit is contained in:
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,428 +14,383 @@
|
|||||||
* limitations under the License.
|
* 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.NoDataException
|
||||||
import com.intellij.debugger.PositionManager;
|
import com.intellij.debugger.PositionManager
|
||||||
import com.intellij.debugger.SourcePosition;
|
import com.intellij.debugger.SourcePosition
|
||||||
import com.intellij.debugger.engine.DebugProcess;
|
import com.intellij.debugger.engine.DebugProcess
|
||||||
import com.intellij.debugger.requests.ClassPrepareRequestor;
|
import com.intellij.debugger.requests.ClassPrepareRequestor
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.project.DumbService;
|
import com.intellij.openapi.project.DumbService
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.roots.libraries.LibraryUtil;
|
import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair
|
||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.util.*;
|
import com.intellij.psi.util.*
|
||||||
import com.sun.jdi.AbsentInformationException;
|
import com.sun.jdi.AbsentInformationException
|
||||||
import com.sun.jdi.Location;
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.ReferenceType;
|
import com.sun.jdi.ReferenceType
|
||||||
import com.sun.jdi.request.ClassPrepareRequest;
|
import com.sun.jdi.request.ClassPrepareRequest
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.jet.analyzer.AnalysisResult
|
||||||
import org.jetbrains.annotations.TestOnly;
|
import org.jetbrains.jet.codegen.AsmUtil
|
||||||
import org.jetbrains.jet.analyzer.AnalysisResult;
|
import org.jetbrains.jet.codegen.ClassBuilderFactories
|
||||||
import org.jetbrains.jet.codegen.AsmUtil;
|
import org.jetbrains.jet.codegen.state.GenerationState
|
||||||
import org.jetbrains.jet.codegen.ClassBuilderFactories;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.psi.*
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.resolve.calls.callUtil.*
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.java.JvmClassName
|
||||||
import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension;
|
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||||
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
|
import org.jetbrains.jet.lang.types.lang.InlineStrategy
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.types.lang.InlineUtil
|
||||||
import org.jetbrains.jet.lang.types.lang.InlineStrategy;
|
import org.jetbrains.jet.plugin.caches.resolve.IdeaModuleInfo
|
||||||
import org.jetbrains.jet.lang.types.lang.InlineUtil;
|
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheService
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.IdeaModuleInfo;
|
import org.jetbrains.jet.plugin.caches.resolve.*
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheService;
|
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
import org.jetbrains.jet.plugin.util.DebuggerUtils
|
||||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
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 org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
|
||||||
import static org.jetbrains.jet.plugin.stubindex.PackageIndexUtil.findFilesWithExactPackage;
|
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 {
|
public class JetPositionManager(private val myDebugProcess: DebugProcess) : PositionManager {
|
||||||
private final DebugProcess myDebugProcess;
|
private val myTypeMappers = WeakHashMap<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>>()
|
||||||
private final WeakHashMap<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>> myTypeMappers = new WeakHashMap<Pair<FqName, IdeaModuleInfo>, CachedValue<JetTypeMapper>>();
|
|
||||||
|
|
||||||
public JetPositionManager(DebugProcess debugProcess) {
|
override fun getSourcePosition(location: Location?): SourcePosition? {
|
||||||
myDebugProcess = debugProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException {
|
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
throw new NoDataException();
|
throw NoDataException()
|
||||||
}
|
}
|
||||||
PsiFile psiFile = getPsiFileByLocation(location);
|
val psiFile = getPsiFileByLocation(location)
|
||||||
if (psiFile == null) {
|
if (psiFile == null) {
|
||||||
throw new NoDataException();
|
throw NoDataException()
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineNumber;
|
val lineNumber: Int
|
||||||
try {
|
try {
|
||||||
lineNumber = location.lineNumber() - 1;
|
lineNumber = location.lineNumber() - 1
|
||||||
}
|
}
|
||||||
catch (InternalError e) {
|
catch (e: InternalError) {
|
||||||
lineNumber = -1;
|
lineNumber = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (lineNumber >= 0) {
|
if (lineNumber >= 0) {
|
||||||
JetFunctionLiteral lambdaIfInside = getLambdaIfInside(location, (JetFile) psiFile, lineNumber);
|
val lambdaIfInside = getLambdaIfInside(location, psiFile as JetFile, lineNumber)
|
||||||
if (lambdaIfInside != null) {
|
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) {
|
private fun getLambdaIfInside(location: Location, file: JetFile, lineNumber: Int): JetFunctionLiteral? {
|
||||||
String currentLocationFqName = location.declaringType().name();
|
val currentLocationFqName = location.declaringType().name()
|
||||||
if (currentLocationFqName == null) return null;
|
if (currentLocationFqName == null) return null
|
||||||
|
|
||||||
Integer start = CodeInsightUtils.getStartLineOffset(file, lineNumber);
|
val start = CodeInsightUtils.getStartLineOffset(file, lineNumber)
|
||||||
Integer end = CodeInsightUtils.getEndLineOffset(file, lineNumber);
|
val end = CodeInsightUtils.getEndLineOffset(file, lineNumber)
|
||||||
if (start == null || end == null) return null;
|
if (start == null || end == null) return null
|
||||||
|
|
||||||
PsiElement[] literals = CodeInsightUtils.findElementsOfClassInRange(file, start, end, JetFunctionLiteral.class);
|
val literals = CodeInsightUtils.findElementsOfClassInRange(file, start, end, javaClass<JetFunctionLiteral>())
|
||||||
if (literals == null || literals.length == 0) return null;
|
if (literals == null || literals.size() == 0) return null
|
||||||
|
|
||||||
boolean isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null;
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null
|
||||||
JetTypeMapper typeMapper = !isInLibrary
|
val typeMapper = if (!isInLibrary)
|
||||||
? prepareTypeMapper(file)
|
prepareTypeMapper(file)
|
||||||
: createTypeMapperForLibraryFile(file.findElementAt(start), file);
|
else
|
||||||
|
createTypeMapperForLibraryFile(file.findElementAt(start), file)
|
||||||
|
|
||||||
String currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(new FqName(currentLocationFqName)).getInternalName();
|
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).getInternalName()
|
||||||
for (PsiElement literal : literals) {
|
for (literal in literals) {
|
||||||
JetFunctionLiteral functionLiteral = (JetFunctionLiteral) literal;
|
val functionLiteral = literal as JetFunctionLiteral
|
||||||
if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) {
|
if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
String internalClassName = getClassNameForElement(literal.getFirstChild(), typeMapper, file, isInLibrary);
|
val internalClassName = getClassNameForElement(literal.getFirstChild(), typeMapper, file, isInLibrary)
|
||||||
if (internalClassName.equals(currentLocationClassName)) {
|
if (internalClassName == currentLocationClassName) {
|
||||||
return functionLiteral;
|
return functionLiteral
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun getPsiFileByLocation(location: Location): PsiFile? {
|
||||||
private PsiFile getPsiFileByLocation(@NotNull Location location) {
|
val sourceName: String
|
||||||
String sourceName;
|
|
||||||
try {
|
try {
|
||||||
sourceName = location.sourceName();
|
sourceName = location.sourceName()
|
||||||
}
|
}
|
||||||
catch (AbsentInformationException e) {
|
catch (e: AbsentInformationException) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// JDI names are of form "package.Class$InnerClass"
|
// JDI names are of form "package.Class$InnerClass"
|
||||||
String referenceFqName = location.declaringType().name();
|
val referenceFqName = location.declaringType().name()
|
||||||
String referenceInternalName = referenceFqName.replace('.', '/');
|
val referenceInternalName = referenceFqName.replace('.', '/')
|
||||||
JvmClassName className = JvmClassName.byInternalName(referenceInternalName);
|
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 fun getAllClasses(sourcePosition: SourcePosition): List<ReferenceType> {
|
||||||
@Override
|
if (sourcePosition.getFile() !is JetFile) {
|
||||||
public List<ReferenceType> getAllClasses(SourcePosition sourcePosition) throws NoDataException {
|
throw NoDataException()
|
||||||
if (!(sourcePosition.getFile() instanceof JetFile)) {
|
|
||||||
throw new NoDataException();
|
|
||||||
}
|
}
|
||||||
String name = classNameForPosition(sourcePosition);
|
val name = classNameForPosition(sourcePosition)
|
||||||
List<ReferenceType> result = new ArrayList<ReferenceType>();
|
val result = ArrayList<ReferenceType>()
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name));
|
result.addAll(myDebugProcess.getVirtualMachineProxy().classesByName(name))
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun classNameForPosition(sourcePosition: SourcePosition): String? {
|
||||||
private String classNameForPosition(final SourcePosition sourcePosition) {
|
val result = Ref.create<String>()
|
||||||
final Ref<String> result = Ref.create();
|
|
||||||
|
|
||||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
ApplicationManager.getApplication().runReadAction {
|
||||||
@Override
|
val file = sourcePosition.getFile() as JetFile
|
||||||
@SuppressWarnings("unchecked")
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null
|
||||||
public void run() {
|
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(sourcePosition.getElementAt(), file)
|
||||||
JetFile file = (JetFile) sourcePosition.getFile();
|
result.set(getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file, isInLibrary))
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
return result.get()
|
||||||
|
|
||||||
return result.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private fun prepareTypeMapper(file: JetFile): JetTypeMapper {
|
||||||
public static String getClassNameForElement(
|
val key = createKeyForTypeMapper(file)
|
||||||
@Nullable PsiElement notPositionedElement,
|
|
||||||
@NotNull JetTypeMapper typeMapper,
|
|
||||||
@NotNull JetFile file,
|
|
||||||
boolean isInLibrary
|
|
||||||
) {
|
|
||||||
PsiElement element = getElementToCalculateClassName(notPositionedElement);
|
|
||||||
|
|
||||||
if (element instanceof JetClassOrObject) {
|
var value: CachedValue<JetTypeMapper>? = myTypeMappers.get(key)
|
||||||
return getJvmInternalNameForImpl(typeMapper, (JetClassOrObject) element);
|
if (value == null) {
|
||||||
}
|
value = CachedValuesManager.getManager(file.getProject()).createCachedValue<JetTypeMapper>(object : CachedValueProvider<JetTypeMapper> {
|
||||||
else if (element instanceof JetFunctionLiteral) {
|
override fun compute(): CachedValueProvider.Result<JetTypeMapper>? {
|
||||||
if (isInlinedLambda((JetFunctionLiteral) element, typeMapper.getBindingContext())) {
|
val project = file.getProject()
|
||||||
return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary);
|
val packageFacadeScope = key.second.contentScope()
|
||||||
} else {
|
val packageFiles = PackageIndexUtil.findFilesWithExactPackage(key.first, packageFacadeScope, project)
|
||||||
Type asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), ((JetFunctionLiteral) element));
|
|
||||||
return asmType.getInternalName();
|
val analysisResult = KotlinCacheService.getInstance(project).getAnalysisResults(packageFiles)
|
||||||
}
|
analysisResult.throwIfError()
|
||||||
}
|
|
||||||
else if (element instanceof JetClassInitializer) {
|
val state = GenerationState(project, ClassBuilderFactories.THROW_EXCEPTION, analysisResult.moduleDescriptor,
|
||||||
PsiElement parent = getElementToCalculateClassName(element.getParent());
|
analysisResult.bindingContext, ArrayList(packageFiles))
|
||||||
// Class-object initializer
|
state.beforeCompile()
|
||||||
if (parent instanceof JetObjectDeclaration && ((JetObjectDeclaration) parent).isClassObject()) {
|
return CachedValueProvider.Result<JetTypeMapper>(state.getTypeMapper(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}, false)
|
||||||
|
|
||||||
VariableDescriptor descriptor = (VariableDescriptor) typeMapper.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
myTypeMappers.put(key, value)
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInLibrary) {
|
return value!!.getValue()
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
|
||||||
private static JetDeclaration getElementToCalculateClassName(@Nullable PsiElement notPositionedElement) {
|
if (position.getFile() !is JetFile) {
|
||||||
//noinspection unchecked
|
throw NoDataException()
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int line = position.getLine() + 1;
|
val line = position.getLine() + 1
|
||||||
List<Location> locations = myDebugProcess.getVirtualMachineProxy().versionHigher("1.4")
|
val locations = if (myDebugProcess.getVirtualMachineProxy().versionHigher("1.4"))
|
||||||
? type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line)
|
type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line)
|
||||||
: type.locationsOfLine(line);
|
else
|
||||||
if (locations == null || locations.isEmpty()) throw new NoDataException();
|
type.locationsOfLine(line)
|
||||||
return locations;
|
if (locations == null || locations.isEmpty()) throw NoDataException()
|
||||||
|
return locations
|
||||||
}
|
}
|
||||||
catch (AbsentInformationException e) {
|
catch (e: AbsentInformationException) {
|
||||||
throw new NoDataException();
|
throw NoDataException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun createPrepareRequest(classPrepareRequestor: ClassPrepareRequestor, sourcePosition: SourcePosition): ClassPrepareRequest? {
|
||||||
public ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor classPrepareRequestor,
|
if (sourcePosition.getFile() !is JetFile) {
|
||||||
SourcePosition sourcePosition) throws NoDataException {
|
throw NoDataException()
|
||||||
if (!(sourcePosition.getFile() instanceof JetFile)) {
|
|
||||||
throw new NoDataException();
|
|
||||||
}
|
}
|
||||||
String className = classNameForPosition(sourcePosition);
|
val className = classNameForPosition(sourcePosition)
|
||||||
if (className == null) {
|
if (className == null) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
return myDebugProcess.getRequestsManager().createClassPrepareRequest(classPrepareRequestor, className.replace('/', '.'));
|
return myDebugProcess.getRequestsManager().createClassPrepareRequest(classPrepareRequestor, className.replace('/', '.'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOnly
|
TestOnly
|
||||||
public void addTypeMapper(JetFile file, final JetTypeMapper typeMapper) {
|
public fun addTypeMapper(file: JetFile, typeMapper: JetTypeMapper) {
|
||||||
CachedValue<JetTypeMapper> value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<JetTypeMapper>() {
|
val value = CachedValuesManager.getManager(file.getProject()).createCachedValue<JetTypeMapper>(object : CachedValueProvider<JetTypeMapper> {
|
||||||
@Override
|
override fun compute() = CachedValueProvider.Result<JetTypeMapper>(typeMapper, PsiModificationTracker.MODIFICATION_COUNT)
|
||||||
public Result<JetTypeMapper> compute() {
|
}, false)
|
||||||
return new Result<JetTypeMapper>(typeMapper, PsiModificationTracker.MODIFICATION_COUNT);
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
Pair<FqName, IdeaModuleInfo> key = createKeyForTypeMapper(file);
|
val key = createKeyForTypeMapper(file)
|
||||||
myTypeMappers.put(key, value);
|
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) {
|
val descriptor = typeMapper.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element)
|
||||||
PsiElement functionLiteralExpression = functionLiteral.getParent();
|
if (descriptor !is PropertyDescriptor) {
|
||||||
if (functionLiteralExpression == null) return false;
|
return getClassNameForElement(element.getParent(), typeMapper, file, isInLibrary)
|
||||||
|
}
|
||||||
|
|
||||||
PsiElement parent = functionLiteralExpression.getParent();
|
return getJvmInternalNameForPropertyOwner(typeMapper, descriptor)
|
||||||
|
}
|
||||||
PsiElement valueArgument = functionLiteralExpression;
|
element is JetNamedFunction -> {
|
||||||
while (parent instanceof JetParenthesizedExpression ||
|
val parent = getElementToCalculateClassName(element)
|
||||||
parent instanceof JetBinaryExpressionWithTypeRHS ||
|
if (parent is JetClassOrObject) {
|
||||||
parent instanceof JetLabeledExpression) {
|
return getJvmInternalNameForImpl(typeMapper, parent)
|
||||||
valueArgument = parent;
|
}
|
||||||
parent = parent.getParent();
|
else if (parent != null) {
|
||||||
}
|
val asmType = asmTypeForAnonymousClass(typeMapper.getBindingContext(), element)
|
||||||
|
return asmType.getInternalName()
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private fun getElementToCalculateClassName(notPositionedElement: PsiElement?) =
|
||||||
return new Pair<FqName, IdeaModuleInfo>(file.getPackageFqName(), ResolvePackage.getModuleInfo(file));
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user