From 6d7b4ad7216db09ca2da8f77a2e393ca32bed835 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 5 Dec 2014 19:17:57 +0100 Subject: [PATCH 1/6] rename JetPositionManager to Kotlin --- .../debugger/{JetPositionManager.java => JetPositionManager.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename idea/src/org/jetbrains/jet/plugin/debugger/{JetPositionManager.java => JetPositionManager.kt} (100%) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt similarity index 100% rename from idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java rename to idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt From 16481a4144915c6290fa1ba7de9d4dbe4ed028ba Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 5 Dec 2014 20:17:32 +0100 Subject: [PATCH 2/6] 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()) + } } From 8f2092fe792d6db51b6c2c197654c04cb71ea16a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 5 Dec 2014 20:23:23 +0100 Subject: [PATCH 3/6] extract method for creating type mapper for a file --- .../jet/plugin/debugger/JetPositionManager.kt | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt index b1c71a6a0ae..4543bec6c92 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt @@ -189,17 +189,8 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi 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) + val typeMapper = createTypeMapper(file, key.second) + return CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) } }, false) @@ -249,6 +240,21 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi } class object { + public fun createTypeMapper(file: JetFile, moduleInfo: IdeaModuleInfo): JetTypeMapper { + val project = file.getProject() + val packageFacadeScope = moduleInfo.contentScope() + val packageFiles = PackageIndexUtil.findFilesWithExactPackage(file.getPackageFqName(), 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() + val typeMapper = state.getTypeMapper() + return typeMapper + } + public fun getClassNameForElement(notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: JetFile, isInLibrary: Boolean): String? { val element = getElementToCalculateClassName(notPositionedElement) when { From 052c0e60a4ef2aa2a99460b27442559347e49a1a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 5 Dec 2014 21:29:09 +0100 Subject: [PATCH 4/6] initial implementation of showing coverage data in IDE --- .idea/libraries/coverage_plugin.xml | 11 +++ idea/idea.iml | 1 + idea/src/META-INF/coverage.xml | 5 ++ idea/src/META-INF/plugin.xml | 1 + .../coverage/KotlinCoverageExtension.kt | 85 +++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 .idea/libraries/coverage_plugin.xml create mode 100644 idea/src/META-INF/coverage.xml create mode 100644 idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt diff --git a/.idea/libraries/coverage_plugin.xml b/.idea/libraries/coverage_plugin.xml new file mode 100644 index 00000000000..91df8c11739 --- /dev/null +++ b/.idea/libraries/coverage_plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/idea/idea.iml b/idea/idea.iml index 21412d50803..ea77e4c848e 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -44,5 +44,6 @@ + \ No newline at end of file diff --git a/idea/src/META-INF/coverage.xml b/idea/src/META-INF/coverage.xml new file mode 100644 index 00000000000..ce1756d8453 --- /dev/null +++ b/idea/src/META-INF/coverage.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 2f695c90203..c34aef03115 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -15,6 +15,7 @@ com.intellij.copyright JavaScriptDebugger org.jetbrains.android + Coverage diff --git a/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt new file mode 100644 index 00000000000..3e29c7bf705 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.coverage + +import com.intellij.coverage.JavaCoverageEngineExtension +import com.intellij.execution.configurations.RunConfigurationBase +import org.jetbrains.jet.plugin.run.JetRunConfiguration +import com.intellij.psi.PsiFile +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.coverage.CoverageSuitesBundle +import java.io.File +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.plugin.debugger.JetPositionManager +import org.jetbrains.jet.plugin.caches.resolve.getModuleInfo +import java.util.HashSet +import org.jetbrains.jet.lang.psi.JetTreeVisitor +import org.jetbrains.jet.lang.psi.JetDeclaration +import com.intellij.openapi.roots.ProjectRootManager +import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid +import org.jetbrains.annotations.TestOnly +import com.intellij.openapi.application.ApplicationManager + +public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { + override fun isApplicableTo(conf: RunConfigurationBase?): Boolean = conf is JetRunConfiguration + + override fun collectOutputFiles(srcFile: PsiFile, + output: VirtualFile?, + testoutput: VirtualFile?, + suite: CoverageSuitesBundle, + classFiles: MutableSet): Boolean { + if (srcFile is JetFile) { + val fileIndex = ProjectRootManager.getInstance(srcFile.getProject()).getFileIndex() + if (fileIndex.isInLibraryClasses(srcFile.getVirtualFile()) || + fileIndex.isInLibrarySource(srcFile.getVirtualFile())) { + return false + } + + val classNames = ApplicationManager.getApplication().runReadAction> { collectOutputClassNames(srcFile) } + + fun findUnder(name: String, root: VirtualFile?): File? { + if (root != null) { + val outputFile = File(root.getPath(), name + ".class") + if (outputFile.exists()) { + return outputFile + } + } + return null + } + + classNames.map { findUnder(it, output) ?: findUnder(it, testoutput) }.filterNotNullTo(classFiles) + return true + } + return false + } + + class object { + TestOnly public fun collectOutputClassNames(srcFile: JetFile): Set { + val typeMapper = JetPositionManager.createTypeMapper(srcFile, srcFile.getModuleInfo()) + val classNames = HashSet() + srcFile.acceptChildren(object: JetTreeVisitorVoid() { + override fun visitDeclaration(dcl: JetDeclaration) { + val className = JetPositionManager.getClassNameForElement(dcl.getFirstChild(), typeMapper, srcFile, false) + if (className != null) { + classNames.add(className) + } + } + }) + return classNames + } + } +} \ No newline at end of file From 0512b8ce1a7ead32f301e5bf397bb3c4ed735327 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 8 Dec 2014 12:51:08 +0100 Subject: [PATCH 5/6] add test to verify output files; correctly handle lambdas --- .../jet/generators/tests/GenerateTests.kt | 5 +++ .../coverage/KotlinCoverageExtension.kt | 14 +++++- .../coverage/outputFiles/lambda.expected.txt | 2 + idea/testData/coverage/outputFiles/lambda.kt | 12 +++++ .../AbstractKotlinCoverageOutputFilesTest.kt | 40 +++++++++++++++++ ...otlinCoverageOutputFilesTestGenerated.java | 44 +++++++++++++++++++ 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 idea/testData/coverage/outputFiles/lambda.expected.txt create mode 100644 idea/testData/coverage/outputFiles/lambda.kt create mode 100644 idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt create mode 100644 idea/tests/org/jetbrains/jet/plugin/coverage/KotlinCoverageOutputFilesTestGenerated.java diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index 84a6fe9d568..6ce34f21539 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -133,6 +133,7 @@ import org.jetbrains.jet.checkers.AbstractJetDiagnosticsTestWithJsStdLib import org.jetbrains.jet.renderer.AbstractDescriptorRendererTest import org.jetbrains.jet.types.AbstractJetTypeBindingTest import org.jetbrains.jet.plugin.debugger.evaluate.AbstractCodeFragmentCompletionHandlerTest +import org.jetbrains.jet.plugin.coverage.AbstractKotlinCoverageOutputFilesTest fun main(args: Array) { System.setProperty("java.awt.headless", "true") @@ -638,6 +639,10 @@ fun main(args: Array) { testClass(javaClass()) { model("debugger/selectExpression") } + + testClass(javaClass()) { + model("coverage/outputFiles") + } } testGroup("idea/tests", "compiler/testData") { diff --git a/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt index 3e29c7bf705..28f8f144290 100644 --- a/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt +++ b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt @@ -33,6 +33,8 @@ import com.intellij.openapi.roots.ProjectRootManager import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid import org.jetbrains.annotations.TestOnly import com.intellij.openapi.application.ApplicationManager +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression +import com.intellij.psi.PsiElement public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { override fun isApplicableTo(conf: RunConfigurationBase?): Boolean = conf is JetRunConfiguration @@ -73,7 +75,17 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { val classNames = HashSet() srcFile.acceptChildren(object: JetTreeVisitorVoid() { override fun visitDeclaration(dcl: JetDeclaration) { - val className = JetPositionManager.getClassNameForElement(dcl.getFirstChild(), typeMapper, srcFile, false) + super.visitDeclaration(dcl) + collectClassName(dcl.getFirstChild()) + } + + override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression) { + super.visitFunctionLiteralExpression(expression) + collectClassName(expression.getFunctionLiteral().getFirstChild()) + } + + private fun collectClassName(element: PsiElement) { + val className = JetPositionManager.getClassNameForElement(element, typeMapper, srcFile, false) if (className != null) { classNames.add(className) } diff --git a/idea/testData/coverage/outputFiles/lambda.expected.txt b/idea/testData/coverage/outputFiles/lambda.expected.txt new file mode 100644 index 00000000000..39ea5e49821 --- /dev/null +++ b/idea/testData/coverage/outputFiles/lambda.expected.txt @@ -0,0 +1,2 @@ +org/demo/coverage/Foo +org/demo/coverage/Foo$bar$1 diff --git a/idea/testData/coverage/outputFiles/lambda.kt b/idea/testData/coverage/outputFiles/lambda.kt new file mode 100644 index 00000000000..3007ac1e940 --- /dev/null +++ b/idea/testData/coverage/outputFiles/lambda.kt @@ -0,0 +1,12 @@ +package org.demo.coverage + +public class Foo { + public fun forEach(fn: (Any?) -> Unit): Unit { + } + + public fun bar() { + forEach { + println("foo") + } + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt b/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt new file mode 100644 index 00000000000..c5551c86c85 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.coverage + +import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase +import org.jetbrains.jet.plugin.PluginTestCaseBase +import org.jetbrains.jet.lang.psi.JetFile +import kotlin.test.assertNotNull +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.fileEditor.impl.LoadTextUtil +import kotlin.test.assertEquals +import java.io.File +import com.intellij.testFramework.UsefulTestCase + +public abstract class AbstractKotlinCoverageOutputFilesTest(): JetLightCodeInsightFixtureTestCase() { + private val TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/coverage/outputFiles" + + override fun getTestDataPath(): String? = TEST_DATA_PATH + + public fun doTest(path: String) { + var kotlinFile = myFixture.configureByFile(path) as JetFile + val actualClasses = KotlinCoverageExtension.collectOutputClassNames(kotlinFile) + val expectedClasses = FileUtil.loadLines(path.replace(".kt", ".expected.txt")) + UsefulTestCase.assertSameElements(actualClasses, expectedClasses) + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/coverage/KotlinCoverageOutputFilesTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/coverage/KotlinCoverageOutputFilesTestGenerated.java new file mode 100644 index 00000000000..ec317bac214 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/coverage/KotlinCoverageOutputFilesTestGenerated.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.coverage; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.jet.JUnit3RunnerWithInners; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/coverage/outputFiles") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class KotlinCoverageOutputFilesTestGenerated extends AbstractKotlinCoverageOutputFilesTest { + public void testAllFilesPresentInOutputFiles() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/coverage/outputFiles"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("lambda.kt") + public void testLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/coverage/outputFiles/lambda.kt"); + doTest(fileName); + } +} From 274e529b90a4a1fd43c38e6ceacfe47b0729c4f5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 9 Dec 2014 12:36:44 +0100 Subject: [PATCH 6/6] code review --- .../coverage/KotlinCoverageExtension.kt | 5 ++- .../jet/plugin/debugger/JetPositionManager.kt | 43 +++++++------------ .../AbstractKotlinCoverageOutputFilesTest.kt | 6 +-- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt index 28f8f144290..1bdb6aea475 100644 --- a/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt +++ b/idea/src/org/jetbrains/jet/plugin/coverage/KotlinCoverageExtension.kt @@ -35,6 +35,7 @@ import org.jetbrains.annotations.TestOnly import com.intellij.openapi.application.ApplicationManager import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression import com.intellij.psi.PsiElement +import java.util.LinkedHashSet public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { override fun isApplicableTo(conf: RunConfigurationBase?): Boolean = conf is JetRunConfiguration @@ -70,9 +71,9 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { } class object { - TestOnly public fun collectOutputClassNames(srcFile: JetFile): Set { + public fun collectOutputClassNames(srcFile: JetFile): Set { val typeMapper = JetPositionManager.createTypeMapper(srcFile, srcFile.getModuleInfo()) - val classNames = HashSet() + val classNames = LinkedHashSet() srcFile.acceptChildren(object: JetTreeVisitorVoid() { override fun visitDeclaration(dcl: JetDeclaration) { super.visitDeclaration(dcl) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt index 4543bec6c92..2f784819d8d 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.kt @@ -69,6 +69,7 @@ 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 +import org.jetbrains.jet.plugin.util.application.runReadAction public class JetPositionManager(private val myDebugProcess: DebugProcess) : PositionManager { private val myTypeMappers = WeakHashMap, CachedValue>() @@ -82,12 +83,11 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi throw NoDataException() } - val lineNumber: Int - try { - lineNumber = location.lineNumber() - 1 + val lineNumber = try { + location.lineNumber() - 1 } catch (e: InternalError) { - lineNumber = -1 + -1 } @@ -170,16 +170,12 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi } private fun classNameForPosition(sourcePosition: SourcePosition): String? { - val result = Ref.create() - - ApplicationManager.getApplication().runReadAction { + return 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)) + getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file, isInLibrary) } - - return result.get() } private fun prepareTypeMapper(file: JetFile): JetTypeMapper { @@ -187,12 +183,11 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi var value: CachedValue? = myTypeMappers.get(key) if (value == null) { - value = CachedValuesManager.getManager(file.getProject()).createCachedValue(object : CachedValueProvider { - override fun compute(): CachedValueProvider.Result? { - val typeMapper = createTypeMapper(file, key.second) - return CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) - } - }, false) + value = CachedValuesManager.getManager(file.getProject()).createCachedValue( + {() -> + val typeMapper = createTypeMapper(file, key.second) + CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) + }, false) myTypeMappers.put(key, value) } @@ -231,10 +226,8 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi 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) - + val value = CachedValuesManager.getManager(file.getProject()).createCachedValue( + { () -> CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) }, false) val key = createKeyForTypeMapper(file) myTypeMappers.put(key, value) } @@ -249,10 +242,9 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi analysisResult.throwIfError() val state = GenerationState(project, ClassBuilderFactories.THROW_EXCEPTION, analysisResult.moduleDescriptor, - analysisResult.bindingContext, ArrayList(packageFiles)) + analysisResult.bindingContext, packageFiles.toList()) state.beforeCompile() - val typeMapper = state.getTypeMapper() - return typeMapper + return state.getTypeMapper() } public fun getClassNameForElement(notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: JetFile, isInLibrary: Boolean): String? { @@ -383,10 +375,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Posi 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 ((valueParameterDescriptor, resolvedValueArgument) in call.getValueArguments()) { for (next in resolvedValueArgument.getArguments()) { val expression = next.getArgumentExpression() if (valueArgument == expression) { diff --git a/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt b/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt index c5551c86c85..09f0fc81dae 100644 --- a/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/coverage/AbstractKotlinCoverageOutputFilesTest.kt @@ -25,6 +25,7 @@ import com.intellij.openapi.fileEditor.impl.LoadTextUtil import kotlin.test.assertEquals import java.io.File import com.intellij.testFramework.UsefulTestCase +import org.jetbrains.jet.JetTestUtils public abstract class AbstractKotlinCoverageOutputFilesTest(): JetLightCodeInsightFixtureTestCase() { private val TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/coverage/outputFiles" @@ -32,9 +33,8 @@ public abstract class AbstractKotlinCoverageOutputFilesTest(): JetLightCodeInsig override fun getTestDataPath(): String? = TEST_DATA_PATH public fun doTest(path: String) { - var kotlinFile = myFixture.configureByFile(path) as JetFile + val kotlinFile = myFixture.configureByFile(path) as JetFile val actualClasses = KotlinCoverageExtension.collectOutputClassNames(kotlinFile) - val expectedClasses = FileUtil.loadLines(path.replace(".kt", ".expected.txt")) - UsefulTestCase.assertSameElements(actualClasses, expectedClasses) + JetTestUtils.assertEqualsToFile(File(path.replace(".kt", ".expected.txt")), actualClasses.join("\n")) } }