Debugger: fix breakpoints in files with JvmName annotation

Drop unnessecary logic about part classes with hashcodes
#KT-9480 Fixed
This commit is contained in:
Natalia Ukhorskaya
2015-10-07 16:05:35 +03:00
parent 11ea5f28e8
commit 7e356354e0
7 changed files with 58 additions and 222 deletions
@@ -41,6 +41,8 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.JetTypeMapper import org.jetbrains.kotlin.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
@@ -50,10 +52,8 @@ import org.jetbrains.kotlin.idea.util.DebuggerUtils
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
@@ -80,7 +80,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
val javaClassName = JvmClassName.byInternalName(defaultInternalName(location)) val javaClassName = JvmClassName.byInternalName(defaultInternalName(location))
val project = myDebugProcess.project val project = myDebugProcess.project
val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), javaClassName, javaSourceFileName, 0) val defaultPsiFile = DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), javaClassName, javaSourceFileName)
if (defaultPsiFile != null) { if (defaultPsiFile != null) {
return SourcePosition.createFromLine(defaultPsiFile, 0) return SourcePosition.createFromLine(defaultPsiFile, 0)
} }
@@ -178,7 +178,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
val project = myDebugProcess.project val project = myDebugProcess.project
return DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), className, sourceName, location.lineNumber() - 1) return DebuggerUtils.findSourceFileForClass(project, GlobalSearchScope.allScope(project), className, sourceName)
} }
private fun defaultInternalName(location: Location): String { private fun defaultInternalName(location: Location): String {
@@ -375,19 +375,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
} }
} }
if (isInLibrary) { return PositionedElement(NoResolveFileClassesProvider.getFileClassInternalName(file), element)
val elementAtForLibraryFile =
if (element is JetDeclaration) element
else PsiTreeUtil.getParentOfType(element, JetDeclaration::class.java)
assert(elementAtForLibraryFile != null) {
"Couldn't find element at breakpoint for library file " + file.name +
(if (notPositionedElement == null) "" else ", notPositionedElement = " + notPositionedElement.getElementTextWithContext())
}
return PositionedElement(findPackagePartInternalNameForLibraryFile(elementAtForLibraryFile!!), elementAtForLibraryFile)
}
return PositionedElement(PackagePartClassUtils.getPackagePartInternalName(file), element)
} }
private val TYPES_TO_CALCULATE_CLASSNAME: Array<Class<out JetElement>> = private val TYPES_TO_CALCULATE_CLASSNAME: Array<Class<out JetElement>> =
@@ -439,7 +427,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
return InlineUtil.isInlinedArgument(functionLiteral, context, false) return InlineUtil.isInlinedArgument(functionLiteral, context, false)
} }
private fun createKeyForTypeMapper(file: JetFile) = PackagePartClassUtils.getPackagePartInternalName(file) private fun createKeyForTypeMapper(file: JetFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
} }
private fun findInlinedCalls(element: PsiElement?, jetFile: PsiFile?): List<String> { private fun findInlinedCalls(element: PsiElement?, jetFile: PsiFile?): List<String> {
@@ -1,129 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.idea.debugger
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.impl.scopes.JdkScope
import com.intellij.openapi.module.impl.scopes.LibraryScope
import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.libraries.LibraryUtil
import com.intellij.psi.search.FilenameIndex
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
private val LOG = Logger.getInstance("org.jetbrains.kotlin.idea.debugger")
/**
* This method finds class name for top-level declaration in source file attached to library.
* The problem is that package-part class file has hash in className and it depends on machine where library was built,
* so we couldn't predict it.
* 1. find all .class files with package-part prefix, if there is one - return it
* 2. find all descriptors with same signature, if there is one - return it
* 3. else -> return null, because it means that there is more than one function with same signature in project
*/
fun findPackagePartInternalNameForLibraryFile(topLevelDeclaration: JetDeclaration): String? {
val packagePartFile = findPackagePartFileNamesForElement(topLevelDeclaration).singleOrNull()
if (packagePartFile != null) return packagePartFile
val descriptor = topLevelDeclaration.resolveToDescriptor()
if (descriptor !is CallableDescriptor) return null
val packageFqName = topLevelDeclaration.getContainingJetFile().getPackageFqName()
val packageDescriptor = descriptor.module.getPackage(packageFqName)
val descFromSourceText = render(descriptor)
val descriptors: Collection<CallableDescriptor> = when (descriptor) {
is FunctionDescriptor -> packageDescriptor.memberScope.getFunctions(descriptor.name, NoLookupLocation.FROM_IDE)
is PropertyDescriptor -> packageDescriptor.memberScope.getProperties(descriptor.name, NoLookupLocation.FROM_IDE)
else -> {
reportError(topLevelDeclaration, descriptor)
listOf()
}
}
val deserializedDescriptor = descriptors
.filterIsInstance<DeserializedCallableMemberDescriptor>()
.filter { render(it) == descFromSourceText }
.singleOrNull()
if (deserializedDescriptor == null) {
reportError(topLevelDeclaration, descriptor)
return null
}
val implClassName = JvmFileClassUtil.getImplClassName(deserializedDescriptor)
if (implClassName != null) {
return JvmClassName.byFqNameWithoutInnerClasses(packageFqName.child(implClassName)).getInternalName()
}
return null
}
private fun findPackagePartFileNamesForElement(elementAt: JetElement): List<String> {
val project = elementAt.getProject()
val file = elementAt.getContainingJetFile()
val packagePartName = PackagePartClassUtils.getPackagePartFqName(file).shortName().asString()
val packagePartNameWoHash = packagePartName.substring(0, packagePartName.lastIndexOf("$") + 1)
val libraryEntry = LibraryUtil.findLibraryEntry(file.getVirtualFile(), project)
val scope = if (libraryEntry is LibraryOrderEntry){
LibraryScope(project, libraryEntry.getLibrary() ?: throw AssertionError("Cannot find library for file ${file.getVirtualFile()?.getPath()}"))
}
else {
JdkScope(project, libraryEntry as JdkOrderEntry)
}
val packagePartFiles = FilenameIndex.getAllFilenames(project).asSequence().filter {
it.startsWith(packagePartNameWoHash) && it.endsWith(".class") &&
!it.substringAfter(packagePartNameWoHash).contains("\$")
}.flatMap {
FilenameIndex.getVirtualFilesByName(project, it, scope).asSequence()
}.map {
val packageFqName = file.getPackageFqName()
if (packageFqName.isRoot()) {
it.getNameWithoutExtension()
} else {
"${packageFqName.asString()}.${it.getNameWithoutExtension()}"
}
}
return packagePartFiles.toList()
}
private fun render(desc: DeclarationDescriptor) = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(desc)
private fun reportError(element: JetElement, descriptor: CallableDescriptor?) {
LOG.error("Couldn't calculate class name for element in library scope:\n" +
element.getElementTextWithContext() +
if (descriptor != null) "\ndescriptor = ${render(descriptor)}" else ""
)
}
@@ -63,7 +63,7 @@ public class JetExceptionFilter implements Filter {
String internalName = fullyQualifiedName.replace('.', '/'); String internalName = fullyQualifiedName.replace('.', '/');
JvmClassName jvmClassName = JvmClassName.byInternalName(internalName); JvmClassName jvmClassName = JvmClassName.byInternalName(internalName);
JetFile file = DebuggerUtils.findSourceFileForClass(project, searchScope, jvmClassName, fileName, lineNumber); JetFile file = DebuggerUtils.findSourceFileForClass(project, searchScope, jvmClassName, fileName);
if (file == null) return null; if (file == null) return null;
VirtualFile virtualFile = file.getVirtualFile(); VirtualFile virtualFile = file.getVirtualFile();
@@ -22,11 +22,9 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
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.util.io.FileUtilRt; import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.KotlinPackage; import kotlin.KotlinPackage;
import kotlin.Pair; import kotlin.Pair;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
@@ -35,13 +33,10 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils;
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde; import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde;
import org.jetbrains.kotlin.idea.debugger.DebuggerPackage;
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil; import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil;
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
@@ -66,9 +61,8 @@ public class DebuggerUtils {
public static JetFile findSourceFileForClass( public static JetFile findSourceFileForClass(
@NotNull Project project, @NotNull Project project,
@NotNull GlobalSearchScope searchScope, @NotNull GlobalSearchScope searchScope,
@NotNull final JvmClassName className, @NotNull JvmClassName className,
@NotNull final String fileName, @NotNull final String fileName
final int lineNumber
) { ) {
String extension = FileUtilRt.getExtension(fileName); String extension = FileUtilRt.getExtension(fileName);
if (!KOTLIN_EXTENSIONS.contains(extension)) return null; if (!KOTLIN_EXTENSIONS.contains(extension)) return null;
@@ -113,66 +107,15 @@ public class DebuggerUtils {
} }
} }
if (isPackagePartClassName(className)) {
JetFile file = getFileForPackagePartPrefixedName(filesWithExactName, className.getInternalName());
if (file != null) {
return file;
}
boolean isInLibrary = KotlinPackage.all(filesWithExactName, new Function1<JetFile, Boolean>() {
@Override
public Boolean invoke(JetFile file) {
return LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null;
}
});
if (isInLibrary) {
return KotlinPackage.singleOrNull(KotlinPackage.filter(filesWithExactName, new Function1<JetFile, Boolean>() {
@Override
public Boolean invoke(JetFile file) {
Integer startLineOffset = CodeInsightUtils.getStartLineOffset(file, lineNumber);
assert startLineOffset != null : "Cannot find start line offset for file " + file.getName() + ", line " +
lineNumber;
JetDeclaration elementAt = PsiTreeUtil.getParentOfType(file.findElementAt(startLineOffset), JetDeclaration.class);
return elementAt != null &&
className.getInternalName().equals(DebuggerPackage.findPackagePartInternalNameForLibraryFile(elementAt));
}
}));
}
return null;
}
return filesWithExactName.iterator().next(); return filesWithExactName.iterator().next();
} }
private static boolean isPackagePartClassName(JvmClassName className) {
String packageName = PackageClassUtils.getPackageClassInternalName(className.getPackageFqName());
String internalName = className.getInternalName();
return !internalName.equals(packageName) && internalName.startsWith(packageName);
}
private static boolean isPackageClassName(JvmClassName className) { private static boolean isPackageClassName(JvmClassName className) {
String packageName = PackageClassUtils.getPackageClassInternalName(className.getPackageFqName()); String packageName = PackageClassUtils.getPackageClassInternalName(className.getPackageFqName());
return packageName.equals(className.getInternalName()); return packageName.equals(className.getInternalName());
} }
@Nullable
private static JetFile getFileForPackagePartPrefixedName(
@NotNull Collection<JetFile> allPackageFiles,
@NotNull String classInternalName
) {
for (JetFile file : allPackageFiles) {
String packagePartInternalName = PackagePartClassUtils.getPackagePartInternalName(file);
if (classInternalName.startsWith(packagePartInternalName)) {
return file;
}
}
return null;
}
@NotNull @NotNull
public static Pair<BindingContext, List<JetFile>> analyzeInlinedFunctions( public static Pair<BindingContext, List<JetFile>> analyzeInlinedFunctions(
@NotNull ResolutionFacade resolutionFacadeForFile, @NotNull ResolutionFacade resolutionFacadeForFile,
@@ -0,0 +1,6 @@
@file:JvmName("ABC")
package a
fun foo() {
"" // a/ABC
}
@@ -28,23 +28,27 @@ import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.testFramework.PsiTestUtil;
import com.sun.jdi.Location; import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType; import com.sun.jdi.ReferenceType;
import kotlin.KotlinPackage; import kotlin.SequencesKt;
import kotlin.StringsKt;
import kotlin.Unit;
import kotlin.io.FilesKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection; import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider; import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider;
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.utils.UtilsPackage; import org.jetbrains.kotlin.utils.UtilsPackage;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -52,7 +56,7 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public abstract class AbstractJetPositionManagerTest extends KotlinMultiFileTestCase { public abstract class AbstractJetPositionManagerTest extends JetLightCodeInsightFixtureTestCase {
// Breakpoint is given as a line comment on a specific line, containing the regexp to match the name of the class where that line // Breakpoint is given as a line comment on a specific line, containing the regexp to match the name of the class where that line
// can be found. This pattern matches against these line comments and saves the class name in the first group // can be found. This pattern matches against these line comments and saves the class name in the first group
private static final Pattern BREAKPOINT_PATTERN = Pattern.compile("^.*//\\s*(.+)\\s*$"); private static final Pattern BREAKPOINT_PATTERN = Pattern.compile("^.*//\\s*(.+)\\s*$");
@@ -60,15 +64,21 @@ public abstract class AbstractJetPositionManagerTest extends KotlinMultiFileTest
@NotNull @NotNull
@Override @Override
protected String getTestDataPath() { protected String getTestDataPath() {
return PluginTestCaseBase.getTestDataPathBase(); return PluginTestCaseBase.getTestDataPathBase() + "/debugger/positionManager/";
}
@Override
public void setUp() {
super.setUp();
myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase());
} }
private DebugProcessImpl debugProcess; private DebugProcessImpl debugProcess;
@NotNull @NotNull
@Override @Override
protected String getTestRoot() { protected LightProjectDescriptor getProjectDescriptor() {
return "/debugger/positionManager/"; return JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE;
} }
@NotNull @NotNull
@@ -89,18 +99,30 @@ public abstract class AbstractJetPositionManagerTest extends KotlinMultiFileTest
protected void doTest(@NotNull String fileName) throws Exception { protected void doTest(@NotNull String fileName) throws Exception {
if (fileName.endsWith(".kt")) { if (fileName.endsWith(".kt")) {
String path = KotlinPackage.substringAfter(fileName, PluginTestCaseBase.TEST_DATA_PROJECT_RELATIVE.substring(1), fileName); String path = getPath(fileName);
configureByFile(path); myFixture.configureByFile(path);
} }
else { else {
VirtualFile rootDir = PsiTestUtil.createTestProjectStructure(myProject, myModule, fileName, myFilesToDelete, false); String path = getPath(fileName);
prepareProject(rootDir); SequencesKt.forEach(FilesKt.walkTopDown(new File(path)), new Function1<File, Unit>() {
PsiDocumentManager.getInstance(myProject).commitAllDocuments(); @Override
public Unit invoke(File file) {
String fileName = file.getName();
String path = getPath(fileName);
myFixture.configureByFile(path);
return null;
}
});
} }
performTest(); performTest();
} }
@NotNull
private static String getPath(@NotNull String fileName) {
return StringsKt.substringAfter(fileName, PluginTestCaseBase.TEST_DATA_PROJECT_RELATIVE.substring(1), fileName);
}
private void performTest() { private void performTest() {
Project project = getProject(); Project project = getProject();
List<JetFile> files = new ArrayList<JetFile>(PluginJetFilesProvider.allFilesInProject(project)); List<JetFile> files = new ArrayList<JetFile>(PluginJetFilesProvider.allFilesInProject(project));
@@ -91,6 +91,12 @@ public class JetPositionManagerTestGenerated extends AbstractJetPositionManagerT
doTest(fileName); doTest(fileName);
} }
@TestMetadata("JvmNameAnnotation.kt")
public void testJvmNameAnnotation() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/positionManager/JvmNameAnnotation.kt");
doTest(fileName);
}
@TestMetadata("localFunction.kt") @TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception { public void testLocalFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/positionManager/localFunction.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/positionManager/localFunction.kt");