From 368dd193acadb45f2dd0b402a81f071fff1bd946 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 11 Jan 2018 20:13:05 +0300 Subject: [PATCH] 172: Revert "Fix compilation after moving to idea 173" This reverts commit fe121cc6aeadf63ca2c2819c9c7df59cc81caf5d. --- .../mock/MockFileManager.java.172 | 115 ++++++ ...tLightClassForDecompiledDeclaration.kt.172 | 71 ++++ .../gradle/GradleInspectionTest.kt.172 | 362 ++++++++++++++++++ .../NoStrataPositionManagerHelper.kt.172 | 334 ++++++++++++++++ .../AbstractKotlinMavenInspectionTest.kt.172 | 190 +++++++++ .../kotlin/console/ReplOutputHandler.kt.172 | 138 +++++++ .../MockParameterInfoUIContext.java.172 | 5 - .../MockUpdateParameterInfoContext.java.172 | 109 ++++++ 8 files changed, 1319 insertions(+), 5 deletions(-) create mode 100644 compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/mock/MockFileManager.java.172 create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtLightClassForDecompiledDeclaration.kt.172 create mode 100644 idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleInspectionTest.kt.172 create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt.172 create mode 100644 idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/AbstractKotlinMavenInspectionTest.kt.172 create mode 100644 idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt.172 create mode 100644 idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockUpdateParameterInfoContext.java.172 diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/mock/MockFileManager.java.172 b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/mock/MockFileManager.java.172 new file mode 100644 index 00000000000..3156769b134 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/mock/MockFileManager.java.172 @@ -0,0 +1,115 @@ +/* + * Copyright 2010-2016 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.test.testFramework.mock; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.SingleRootFileViewProvider; +import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.file.impl.FileManager; +import com.intellij.util.containers.ConcurrentWeakFactoryMap; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class MockFileManager implements FileManager { + private final PsiManagerEx myManager; + // in mock tests it's LightVirtualFile, they're only alive when they're referenced, + // and there can not be several instances representing the same file + private final FactoryMap myViewProviders = new ConcurrentWeakFactoryMap() { + @Override + protected Map createMap() { + return ContainerUtil.createConcurrentWeakKeyWeakValueMap(); + } + + @Override + protected FileViewProvider create(VirtualFile key) { + return new SingleRootFileViewProvider(myManager, key); + } + }; + + @Override + @NotNull + public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, boolean eventSystemEnabled) { + return new SingleRootFileViewProvider(myManager, file, eventSystemEnabled); + } + + public MockFileManager(PsiManagerEx manager) { + myManager = manager; + } + + @Override + public void dispose() { + throw new UnsupportedOperationException("Method dispose is not yet implemented in " + getClass().getName()); + } + + @Override + @Nullable + public PsiFile findFile(@NotNull VirtualFile vFile) { + return getCachedPsiFile(vFile); + } + + @Override + @Nullable + public PsiDirectory findDirectory(@NotNull VirtualFile vFile) { + throw new UnsupportedOperationException("Method findDirectory is not yet implemented in " + getClass().getName()); + } + + @Override + public void reloadFromDisk(@NotNull PsiFile file) //Q: move to PsiFile(Impl)? + { + throw new UnsupportedOperationException("Method reloadFromDisk is not yet implemented in " + getClass().getName()); + } + + @Override + @Nullable + public PsiFile getCachedPsiFile(@NotNull VirtualFile vFile) { + FileViewProvider provider = findCachedViewProvider(vFile); + return provider.getPsi(provider.getBaseLanguage()); + } + + @Override + public void cleanupForNextTest() { + myViewProviders.clear(); + } + + @Override + public FileViewProvider findViewProvider(@NotNull VirtualFile file) { + throw new UnsupportedOperationException("Method findViewProvider is not yet implemented in " + getClass().getName()); + } + + @Override + public FileViewProvider findCachedViewProvider(@NotNull VirtualFile file) { + return myViewProviders.get(file); + } + + @Override + public void setViewProvider(@NotNull VirtualFile virtualFile, FileViewProvider fileViewProvider) { + myViewProviders.put(virtualFile, fileViewProvider); + } + + @Override + @NotNull + public List getAllCachedFiles() { + throw new UnsupportedOperationException("Method getAllCachedFiles is not yet implemented in " + getClass().getName()); + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtLightClassForDecompiledDeclaration.kt.172 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtLightClassForDecompiledDeclaration.kt.172 new file mode 100644 index 00000000000..02450ec3318 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtLightClassForDecompiledDeclaration.kt.172 @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2017 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.caches.lightClasses + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod +import com.intellij.psi.impl.compiled.ClsClassImpl +import org.jetbrains.kotlin.asJava.classes.KtLightClassBase +import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl +import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl +import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtClassOrObject + +class KtLightClassForDecompiledDeclaration( + override val clsDelegate: ClsClassImpl, + override val kotlinOrigin: KtClassOrObject?, + private val file: KtClsFile +) : KtLightClassBase(clsDelegate.manager) { + val fqName = kotlinOrigin?.fqName ?: FqName(clsDelegate.qualifiedName) + + override fun copy() = this + + override fun getOwnInnerClasses(): List { + val nestedClasses = kotlinOrigin?.declarations?.filterIsInstance() ?: emptyList() + return clsDelegate.ownInnerClasses.map { innerClsClass -> + KtLightClassForDecompiledDeclaration(innerClsClass as ClsClassImpl, + nestedClasses.firstOrNull { innerClsClass.name == it.name }, file + ) + } + } + + override fun getOwnFields(): List { + return clsDelegate.ownFields.map { KtLightFieldImpl.create(LightMemberOriginForCompiledField(it, file), it, this) } + } + + override fun getOwnMethods(): List { + return clsDelegate.ownMethods.map { KtLightMethodImpl.create(it, LightMemberOriginForCompiledMethod(it, file), this) } + } + + override fun getNavigationElement() = kotlinOrigin?.navigationElement ?: file + + override fun getParent() = clsDelegate.parent + + override fun equals(other: Any?): Boolean = + other is KtLightClassForDecompiledDeclaration && + fqName == other.fqName + + override fun hashCode(): Int = + fqName.hashCode() + + override val originKind: LightClassOriginKind + get() = LightClassOriginKind.BINARY +} + diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleInspectionTest.kt.172 b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleInspectionTest.kt.172 new file mode 100644 index 00000000000..2b5bfbb1dcd --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleInspectionTest.kt.172 @@ -0,0 +1,362 @@ +/* + * Copyright 2010-2016 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.codeInsight.gradle + +import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.codeInspection.ProblemDescriptorBase +import com.intellij.openapi.util.Ref +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.inspections.gradle.DeprecatedGradleDependencyInspection +import org.jetbrains.kotlin.idea.inspections.gradle.DifferentKotlinGradleVersionInspection +import org.jetbrains.kotlin.idea.inspections.gradle.DifferentStdlibGradleVersionInspection +import org.jetbrains.kotlin.idea.inspections.runInspection +import org.junit.Assert +import org.junit.Test + +class GradleInspectionTest : GradleImportingTestCase() { + @Test + fun testDifferentStdlibGradleVersion() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.2") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.3" + } + """ + ) + importProject() + + val tool = DifferentStdlibGradleVersionInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals("Plugin version (1.0.2) is not the same as library version (1.0.3)", problems.single()) + } + + @Test + fun testDifferentStdlibGradleVersionWithImplementation() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.2") + } + } + + apply plugin: 'kotlin' + + dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:1.0.3" + } + """ + ) + importProject() + + val tool = DifferentStdlibGradleVersionInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals("Plugin version (1.0.2) is not the same as library version (1.0.3)", problems.single()) + } + + @Test + fun testDifferentStdlibJre7GradleVersion() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + maven { + url 'http://dl.bintray.com/kotlin/kotlin-eap-1.1' + } + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0-beta-17") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.0-beta-22" + } + """ + ) + importProject() + + val tool = DifferentStdlibGradleVersionInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals("Plugin version (1.1.0-beta-17) is not the same as library version (1.1.0-beta-22)", problems.single()) + } + + @Test + fun testDifferentStdlibJdk7GradleVersion() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + maven { + url 'http://dl.bintray.com/kotlin/kotlin-eap-1.1' + } + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0-beta-17") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.1.0-beta-22" + } + """ + ) + importProject() + + val tool = DifferentStdlibGradleVersionInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals("Plugin version (1.1.0-beta-17) is not the same as library version (1.1.0-beta-22)", problems.single()) + } + + + @Test + fun testDifferentStdlibGradleVersionWithVariables() { + createProjectSubFile( + "gradle.properties", """ + |kotlin=1.0.1 + |lib_version=1.0.3""".trimMargin() + ) + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}kotlin") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: lib_version + } + """ + ) + importProject() + + val tool = DifferentStdlibGradleVersionInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals("Plugin version (1.0.1) is not the same as library version (1.0.3)", problems.single()) + } + + @Test + fun testDifferentKotlinGradleVersion() { + createProjectSubFile("gradle.properties", """test=1.0.1""") + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}{test}") + } + } + + apply plugin: 'kotlin' + """ + ) + importProject() + + val tool = DifferentKotlinGradleVersionInspection() + tool.testVersionMessage = "\$PLUGIN_VERSION" + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals( + "Kotlin version that is used for building with Gradle (1.0.1) differs from the one bundled into the IDE plugin (\$PLUGIN_VERSION)", + problems.single() + ) + } + + @Test + fun testJreInOldVersion() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.60" + } + """ + ) + importProject() + + val tool = DeprecatedGradleDependencyInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.isEmpty()) + } + + @Test + fun testJreIsDeprecated() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60") + } + } + + apply plugin: 'kotlin' + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0" + } + """ + ) + importProject() + + val tool = DeprecatedGradleDependencyInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals( + "kotlin-stdlib-jre7 is deprecated since 1.2.0 and should be replaced with kotlin-stdlib-jdk7", + problems.single() + ) + } + + @Test + fun testJreIsDeprecatedWithImplementation() { + val localFile = createProjectSubFile( + "build.gradle", """ + group 'Again' + version '1.0-SNAPSHOT' + + buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0") + } + } + + apply plugin: 'kotlin' + + dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0" + } + """ + ) + importProject() + + val tool = DeprecatedGradleDependencyInspection() + val problems = getInspectionResult(tool, localFile) + + Assert.assertTrue(problems.size == 1) + Assert.assertEquals( + "kotlin-stdlib-jre7 is deprecated since 1.2.0 and should be replaced with kotlin-stdlib-jdk7", + problems.single() + ) + } + + fun getInspectionResult(tool: LocalInspectionTool, file: VirtualFile): List { + val resultRef = Ref>() + invokeTestRunnable { + val presentation = runInspection(tool, myProject, listOf(file)) + + val foundProblems = presentation.problemElements + .values + .flatMap { it.toList() } + .mapNotNull { it as? ProblemDescriptorBase } + .map { it.descriptionTemplate } + + resultRef.set(foundProblems) + } + + return resultRef.get() + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt.172 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt.172 new file mode 100644 index 00000000000..b82231ec367 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt.172 @@ -0,0 +1,334 @@ +/* + * Copyright 2010-2016 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.debugger.SourcePosition +import com.intellij.debugger.engine.DebugProcess +import com.intellij.debugger.jdi.VirtualMachineProxyImpl +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.compiler.CompilerPaths +import com.intellij.openapi.compiler.ex.CompilerPathsEx +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ProjectFileIndex +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.containers.ConcurrentWeakFactoryMap +import com.intellij.util.containers.ContainerUtil +import com.sun.jdi.Location +import com.sun.jdi.ReferenceType +import org.jetbrains.kotlin.codegen.inline.API +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches +import org.jetbrains.kotlin.idea.refactoring.getLineCount +import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset +import org.jetbrains.kotlin.idea.refactoring.toPsiFile +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.tail +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.getOrPutNullable +import org.jetbrains.org.objectweb.asm.* +import java.io.File +import java.util.* + +fun isInlineFunctionLineNumber(file: VirtualFile, lineNumber: Int, project: Project): Boolean { + if (ProjectRootsUtil.isProjectSourceFile(project, file)) { + val linesInFile = file.toPsiFile(project)?.getLineCount() ?: return false + return lineNumber > linesInFile + } + + return true +} + +fun readBytecodeInfo(project: Project, + jvmName: JvmClassName, + file: VirtualFile): BytecodeDebugInfo? { + return KotlinDebuggerCaches.getOrReadDebugInfoFromBytecode(project, jvmName, file) +} + +fun ktLocationInfo(location: Location, isDexDebug: Boolean, project: Project, + preferInlined: Boolean = false, locationFile: KtFile? = null): Pair { + if (isDexDebug && (locationFile == null || location.lineNumber() > locationFile.getLineCount())) { + if (!preferInlined) { + val thisFunLine = runReadAction { getLastLineNumberForLocation(location, project) } + if (thisFunLine != null && thisFunLine != location.lineNumber()) { + return thisFunLine to locationFile + } + } + + val inlinePosition = runReadAction { getOriginalPositionOfInlinedLine(location, project) } + if (inlinePosition != null) { + val (file, line) = inlinePosition + return line + 1 to file + } + } + + return location.lineNumber() to locationFile +} + +/** + * Only the first line number is stored for instruction in dex. It can be obtained through location.lineNumber(). + * This method allows to get last stored linenumber for instruction. + */ +fun getLastLineNumberForLocation(location: Location, project: Project, searchScope: GlobalSearchScope = GlobalSearchScope.allScope(project)): Int? { + val lineNumber = location.lineNumber() + val fqName = FqName(location.declaringType().name()) + val fileName = location.sourceName() + + val method = location.method() ?: return null + val name = method.name() ?: return null + val signature = method.signature() ?: return null + + val debugInfo = findAndReadClassFile(fqName, fileName, project, searchScope, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null + + val lineMapping = debugInfo.lineTableMapping[BytecodeMethodKey(name, signature)] ?: return null + return lineMapping.values.firstOrNull { it.contains(lineNumber) }?.last() +} + +class WeakBytecodeDebugInfoStorage : ConcurrentWeakFactoryMap() { + override fun create(key: BinaryCacheKey): BytecodeDebugInfo? { + val bytes = readClassFileImpl(key.project, key.jvmName, key.file) ?: return null + + val smapData = readDebugInfo(bytes) + val lineNumberMapping = readLineNumberTableMapping(bytes) + + return BytecodeDebugInfo(smapData, lineNumberMapping) + } + override fun createMap(): Map { + return ContainerUtil.createConcurrentWeakKeyWeakValueMap() + } +} + +class BytecodeDebugInfo(val smapData: SmapData?, val lineTableMapping: Map>>) + +data class BytecodeMethodKey(val methodName: String, val signature: String) + +data class BinaryCacheKey(val project: Project, val jvmName: JvmClassName, val file: VirtualFile) + +private fun readClassFileImpl(project: Project, + jvmName: JvmClassName, + file: VirtualFile): ByteArray? { + val fqNameWithInners = jvmName.fqNameForClassNameWithoutDollars.tail(jvmName.packageFqName) + + fun readFromLibrary(): ByteArray? { + if (!ProjectRootsUtil.isLibrarySourceFile(project, file)) return null + + val classId = ClassId(jvmName.packageFqName, Name.identifier(fqNameWithInners.asString())) + + val fileFinder = VirtualFileFinder.getInstance(project) + val classFile = fileFinder.findVirtualFileWithHeader(classId) ?: return null + return classFile.contentsToByteArray(false) + } + + fun readFromOutput(isForTestClasses: Boolean): ByteArray? { + if (!ProjectRootsUtil.isProjectSourceFile(project, file)) return null + + val module = ProjectFileIndex.SERVICE.getInstance(project).getModuleForFile(file) ?: return null + + val outputPaths = CompilerPathsEx.getOutputPaths(arrayOf(module)).toList() + val className = fqNameWithInners.asString().replace('.', '$') + var classFile = findClassFileByPaths(jvmName.packageFqName.asString(), className, outputPaths) + + if (classFile == null) { + if (!isForTestClasses) { + return null + } + + val outputDir = CompilerPaths.getModuleOutputDirectory(module, /*forTests = */ isForTestClasses) ?: return null + + val outputModeDirName = outputDir.name + // FIXME: It looks like this doesn't work anymore after Kotlin gradle plugin have stopped generating Kotlin classes in java output dir + // Originally this code did mapping like 'path/classes/test/debug' -> 'path/classes/androidTest/debug' + val androidTestOutputDir = outputDir.parent?.parent?.findChild("androidTest")?.findChild(outputModeDirName) ?: return null + + classFile = findClassFileByPath(jvmName.packageFqName.asString(), className, androidTestOutputDir.path) ?: return null + } + + return classFile.readBytes() + } + + fun readFromSourceOutput(): ByteArray? = readFromOutput(false) + + fun readFromTestOutput(): ByteArray? = readFromOutput(true) + + return readFromLibrary() ?: + readFromSourceOutput() ?: + readFromTestOutput() +} + +private fun findClassFileByPaths(packageName: String, className: String, paths: List): File? = + paths.mapNotNull { path -> findClassFileByPath(packageName, className, path) }.maxBy { it.lastModified() } + +private fun findClassFileByPath(packageName: String, className: String, outputDirPath: String): File? { + val outDirFile = File(outputDirPath).takeIf(File::exists) ?: return null + + val parentDirectory = File(outDirFile, packageName.replace(".", File.separator)) + if (!parentDirectory.exists()) return null + + if (ApplicationManager.getApplication().isUnitTestMode) { + val beforeDexFileClassFile = File(parentDirectory, className + ".class.before_dex") + if (beforeDexFileClassFile.exists()) { + return beforeDexFileClassFile + } + } + + val classFile = File(parentDirectory, className + ".class") + if (classFile.exists()) { + return classFile + } + + return null +} + +private fun readLineNumberTableMapping(bytes: ByteArray): Map>> { + val lineNumberMapping = HashMap>>() + + ClassReader(bytes).accept(object : ClassVisitor(API) { + override fun visitMethod(access: Int, name: String?, desc: String?, signature: String?, exceptions: Array?): MethodVisitor? { + if (name == null || desc == null) { + return null + } + + val methodKey = BytecodeMethodKey(name, desc) + val methodLinesMapping = HashMap>() + lineNumberMapping[methodKey] = methodLinesMapping + + return object : MethodVisitor(Opcodes.ASM5, null) { + override fun visitLineNumber(line: Int, start: Label?) { + if (start != null) { + methodLinesMapping.getOrPutNullable(start.toString(), { LinkedHashSet() }).add(line) + } + } + } + } + }, ClassReader.SKIP_FRAMES and ClassReader.SKIP_CODE) + + return lineNumberMapping +} + +internal fun getOriginalPositionOfInlinedLine(location: Location, project: Project): Pair? { + val lineNumber = location.lineNumber() + val fqName = FqName(location.declaringType().name()) + val fileName = location.sourceName() + val searchScope = GlobalSearchScope.allScope(project) + + val debugInfo = findAndReadClassFile(fqName, fileName, project, searchScope, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: + return null + val smapData = debugInfo.smapData ?: return null + + return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope) +} + +private fun findAndReadClassFile( + fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope, + fileFilter: (VirtualFile) -> Boolean): BytecodeDebugInfo? { + val internalName = fqName.asString().replace('.', '/') + val jvmClassName = JvmClassName.byInternalName(internalName) + + val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, searchScope, jvmClassName, fileName) ?: return null + + val virtualFile = file.virtualFile ?: return null + if (!fileFilter(virtualFile)) return null + + return readBytecodeInfo(project, jvmClassName, virtualFile) +} + +internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosition, sourceSearchScope: GlobalSearchScope): List { + val line = position.line + val file = position.file + val project = position.file.project + + val lineStartOffset = file.getLineStartOffset(line) ?: return listOf() + val element = file.findElementAt(lineStartOffset) ?: return listOf() + val ktElement = element.parents.firstIsInstanceOrNull() ?: return listOf() + + val isInInline = runReadAction { element.parents.any { it is KtFunction && it.hasModifier(KtTokens.INLINE_KEYWORD) } } + + if (!isInInline) { + // Lambdas passed to crossinline arguments are inlined when they are used in non-inlined lambdas + val isInCrossinlineArgument = isInCrossinlineArgument(ktElement) + if (!isInCrossinlineArgument) { + return listOf() + } + } + + val lines = inlinedLinesNumbers(line + 1, position.file.name, FqName(type.name()), type.sourceName(), project, sourceSearchScope) + + return lines.flatMap { type.locationsOfLine(it) } +} + +fun isInCrossinlineArgument(ktElement: KtElement): Boolean { + val argumentFunctions = runReadAction { + ktElement.parents.filter { + when (it) { + is KtFunctionLiteral -> it.parent is KtLambdaExpression && (it.parent.parent is KtValueArgument || it.parent.parent is KtLambdaArgument) + is KtFunction -> it.parent is KtValueArgument + else -> false + } + }.filterIsInstance() + } + + val bindingContext = ktElement.analyze(BodyResolveMode.PARTIAL) + return argumentFunctions.any { + val argumentDescriptor = InlineUtil.getInlineArgumentDescriptor(it, bindingContext) + argumentDescriptor?.isCrossinline ?: false + } +} + + +private fun inlinedLinesNumbers( + inlineLineNumber: Int, inlineFileName: String, + destinationTypeFqName: FqName, destinationFileName: String, + project: Project, sourceSearchScope: GlobalSearchScope): List { + val internalName = destinationTypeFqName.asString().replace('.', '/') + val jvmClassName = JvmClassName.byInternalName(internalName) + + val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, sourceSearchScope, jvmClassName, destinationFileName) ?: + return listOf() + + val virtualFile = file.virtualFile ?: return listOf() + + val debugInfo = readBytecodeInfo(project, jvmClassName, virtualFile) ?: return listOf() + val smapData = debugInfo.smapData ?: return listOf() + + val smap = smapData.kotlinStrata ?: return listOf() + + val mappingsToInlinedFile = smap.fileMappings.filter { it.name == inlineFileName } + val mappingIntervals = mappingsToInlinedFile.flatMap { it.lineMappings } + + return mappingIntervals.asSequence(). + filter { rangeMapping -> rangeMapping.hasMappingForSource(inlineLineNumber) }. + map { rangeMapping -> rangeMapping.mapSourceToDest(inlineLineNumber) }. + filter { line -> line != -1 }. + toList() +} + +@Volatile var emulateDexDebugInTests: Boolean = false + +fun DebugProcess.isDexDebug() = + (emulateDexDebugInTests && ApplicationManager.getApplication().isUnitTestMode) || + (this.virtualMachineProxy as? VirtualMachineProxyImpl)?.virtualMachine?.name() == "Dalvik" // TODO: check other machine names \ No newline at end of file diff --git a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/AbstractKotlinMavenInspectionTest.kt.172 b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/AbstractKotlinMavenInspectionTest.kt.172 new file mode 100644 index 00000000000..e97c7b2f871 --- /dev/null +++ b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/AbstractKotlinMavenInspectionTest.kt.172 @@ -0,0 +1,190 @@ +/* + * Copyright 2010-2016 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.maven + +import com.intellij.codeInspection.CommonProblemDescriptor +import com.intellij.codeInspection.ProblemDescriptorBase +import com.intellij.codeInspection.QuickFix +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.Result +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiManager +import com.intellij.psi.search.FileTypeIndex +import org.jetbrains.jps.model.java.JavaSourceRootType +import org.jetbrains.kotlin.idea.inspections.runInspection +import org.jetbrains.kotlin.idea.maven.inspections.KotlinMavenPluginPhaseInspection +import org.jetbrains.kotlin.idea.refactoring.toPsiDirectory +import org.jetbrains.kotlin.idea.util.projectStructure.allModules +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.utils.keysToMap +import java.io.File + +abstract class AbstractKotlinMavenInspectionTest : MavenImportingTestCase() { + + override fun setUp() { + super.setUp() + repositoryPath = File(myDir, "repo").path + createStdProjectFolders() + } + + fun doTest(fileName: String) { + val pomFile = File(fileName) + val pomText = pomFile.readText() + + createPomFile(fileName) + importProject() + myProject.allModules().forEach { + setupJdkForModule(it.name) + } + + if (pomText.contains("".toRegex(RegexOption.MULTILINE))) { + mkJavaFile() + } + + val inspectionClassName = "".toRegex().find(pomText)?.groups?.get(1)?.value + ?: KotlinMavenPluginPhaseInspection::class.qualifiedName!! + val inspectionClass = Class.forName(inspectionClassName) + + val matcher = "".toRegex() + val expectedProblemsText = pomText.lines() + .filter { matcher.matches(it) } + .joinToString("\n") + + val problemElements = runInspection(inspectionClass, myProject).problemElements + val actualProblems = problemElements + .filter { it.key.name == "pom.xml" } + .values + .flatMap { it.toList() } + .mapNotNull { it as? ProblemDescriptorBase } + + val actual = actualProblems + .map { SimplifiedProblemDescription(it.descriptionTemplate, it.psiElement.text.replace("\\s+".toRegex(), "")) to it } + .sortedBy { it.first.text } + + val actualProblemsText = actual + .map { it.first } + .joinToString("\n") { ""} + + assertEquals(expectedProblemsText, actualProblemsText) + + val suggestedFixes = actual.flatMap { p -> p.second.fixes?.sortedBy { it.familyName }?.map { p.second to it } ?: emptyList() } + + val filenamePrefix = pomFile.nameWithoutExtension + ".fixed." + val fixFiles = + pomFile.parentFile.listFiles { _, name -> name.startsWith(filenamePrefix) && name.endsWith(".xml") }.sortedBy { it.name } + + val rangesToFixFiles: Map = fixFiles.keysToMap { + val fixFileName = it.name + val fixRangeStr = fixFileName.substringBeforeLast('.').substringAfterLast('.') + val numbers = fixRangeStr.split('-').map { it.toInt() } + when (numbers.size) { + 0 -> error("No number in fix file $fixFileName") + 1 -> IntRange(numbers[0], numbers[0]) + 2 -> IntRange(numbers[0], numbers[1]) + else -> error("Bad range `$fixRangeStr` in fix file $fixFileName") + } + } + + val sortedFixRanges = rangesToFixFiles.values.sortedBy { it.start } + sortedFixRanges.forEachIndexed { i, range -> + if (i > 0) { + val previous = sortedFixRanges[i - 1] + if (previous.endInclusive + 1 != range.start) { + error("Bad ranges in fix files: $previous and $range") + } + } + } + + val numberOfFixDataFiles = sortedFixRanges.lastOrNull()?.endInclusive ?: 0 + if (numberOfFixDataFiles > suggestedFixes.size) { + fail("Not all fixes were suggested by the inspection: expected count: ${fixFiles.size}, actual fixes count: ${suggestedFixes.size}") + } + if (numberOfFixDataFiles < suggestedFixes.size) { + fail("Not all fixes covered by *.fixed.N.xml files") + } + + val documentManager = PsiDocumentManager.getInstance(myProject) + val document = documentManager.getDocument(PsiManager.getInstance(myProject).findFile(myProjectPom)!!)!! + val originalText = document.text + + suggestedFixes.forEachIndexed { index, suggestedFix -> + val (problem, quickfix) = suggestedFix + val file = rangesToFixFiles.entries.first { (_, range) -> index + 1 in range }.key + + quickfix.applyFix(problem) + + KotlinTestUtils.assertEqualsToFile(file, document.text.trim()) + + ApplicationManager.getApplication().runWriteAction { + document.setText(originalText) + documentManager.commitDocument(document) + } + } + } + + private fun createPomFile(fileName: String) { + myProjectPom = myProjectRoot.findChild("pom.xml") + if (myProjectPom == null) { + myProjectPom = object : WriteAction() { + override fun run(result: Result) { + val res = myProjectRoot.createChildData(null, "pom.xml") + result.setResult(res) + } + }.execute().resultObject + } + myAllPoms.add(myProjectPom!!) + + ApplicationManager.getApplication().runWriteAction { + myProjectPom!!.setBinaryContent(File(fileName).readBytes()) + } + } + + private fun QuickFix.applyFix(desc: ProblemDescriptorBase) { + CommandProcessor.getInstance().executeCommand(myProject, { + ApplicationManager.getApplication().runWriteAction { + applyFix(myProject, desc) + + val manager = PsiDocumentManager.getInstance(myProject) + val document = manager.getDocument(PsiManager.getInstance(myProject).findFile(myProjectPom)!!)!! + manager.doPostponedOperationsAndUnblockDocument(document) + manager.commitDocument(document) + FileDocumentManager.getInstance().saveDocument(document) + + } + + println(myProjectPom.contentsToByteArray().toString(Charsets.UTF_8)) + }, "quick-fix-$name", "Kotlin") + } + + private fun mkJavaFile() { + val sourceFolder = + getContentRoots(myProject.allModules().single().name).single().getSourceFolders(JavaSourceRootType.SOURCE).single() + ApplicationManager.getApplication().runWriteAction { + val javaFile = sourceFolder.file?.toPsiDirectory(myProject)?.createFile("Test.java") ?: throw IllegalStateException() + javaFile.viewProvider.document!!.setText("class Test {}\n") + } + + assertTrue(FileTypeIndex.containsFileOfType(JavaFileType.INSTANCE, myProject.allModules().single().moduleScope)) + } + + private data class SimplifiedProblemDescription(val text: String, val elementText: String) +} \ No newline at end of file diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt.172 b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt.172 new file mode 100644 index 00000000000..8ad35941123 --- /dev/null +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ReplOutputHandler.kt.172 @@ -0,0 +1,138 @@ +/* + * Copyright 2010-2016 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.console + +import com.intellij.execution.process.OSProcessHandler +import com.intellij.execution.process.ProcessOutputTypes +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.console.actions.logError +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.utils.repl.ReplEscapeType +import org.w3c.dom.Element +import org.xml.sax.InputSource +import java.io.ByteArrayInputStream +import java.nio.charset.Charset +import javax.xml.parsers.DocumentBuilderFactory +import org.jetbrains.kotlin.utils.repl.ReplEscapeType.* + +val XML_REPLACEMENTS: Array = arrayOf("#n", "#diez") +val SOURCE_CHARS: Array = arrayOf("\n", "#") + +data class SeverityDetails(val severity: Severity, val description: String, val range: TextRange) + +class ReplOutputHandler( + private val runner: KotlinConsoleRunner, + process: Process, + commandLine: String +) : OSProcessHandler(process, commandLine) { + + private var isBuildInfoChecked = false + private val factory = DocumentBuilderFactory.newInstance() + private val outputProcessor = ReplOutputProcessor(runner) + private val inputBuffer = StringBuilder() + + override fun isSilentlyDestroyOnClose() = true + + override fun notifyTextAvailable(text: String, key: Key<*>?) { + // hide warning about adding test folder to classpath + if (text.startsWith("warning: classpath entry points to a non-existent location")) return + + if (key == ProcessOutputTypes.STDOUT) { + inputBuffer.append(text) + val resultingText = inputBuffer.toString() + if (resultingText.endsWith("\n")) { + handleReplMessage(resultingText) + inputBuffer.setLength(0) + } + } + else { + super.notifyTextAvailable(text, key) + } + } + + private fun handleReplMessage(text: String) { + if (text.isBlank()) return + val output = try { + factory.newDocumentBuilder().parse(strToSource(text)) + } + catch (e: Exception) { + logError(ReplOutputHandler::class.java, "Couldn't parse REPL output: $text") + return + } + + val root = output.firstChild as Element + val outputType = ReplEscapeType.valueOfOrNull(root.getAttribute("type")) + val content = StringUtil.replace(root.textContent, XML_REPLACEMENTS, SOURCE_CHARS) + + when (outputType) { + INITIAL_PROMPT -> buildWarningIfNeededBeforeInit(content) + HELP_PROMPT -> outputProcessor.printHelp(content) + USER_OUTPUT -> outputProcessor.printUserOutput(content) + REPL_RESULT -> outputProcessor.printResultWithGutterIcon(content) + READLINE_START -> runner.isReadLineMode = true + READLINE_END -> runner.isReadLineMode = false + REPL_INCOMPLETE, + COMPILE_ERROR -> outputProcessor.highlightCompilerErrors(createCompilerMessages(content)) + RUNTIME_ERROR -> outputProcessor.printRuntimeError("${content.trim()}\n") + INTERNAL_ERROR -> outputProcessor.printInternalErrorMessage(content) + SUCCESS -> runner.commandHistory.lastUnprocessedEntry()?.entryText?.let { runner.successfulLine(it) } + null -> logError(ReplOutputHandler::class.java, "Unexpected output type:\n$outputType") + } + + if (outputType in setOf(SUCCESS, COMPILE_ERROR, INTERNAL_ERROR, RUNTIME_ERROR, READLINE_END)) { + runner.commandHistory.entryProcessed() + } + } + + private fun buildWarningIfNeededBeforeInit(content: String) { + if (!isBuildInfoChecked) { + outputProcessor.printBuildInfoWarningIfNeeded() + isBuildInfoChecked = true + } + outputProcessor.printInitialPrompt(content) + } + + private fun strToSource(s: String, encoding: Charset = Charsets.UTF_8) = InputSource(ByteArrayInputStream(s.toByteArray(encoding))) + + private fun createCompilerMessages(runtimeErrorsReport: String): List { + val compilerMessages = arrayListOf() + + val report = factory.newDocumentBuilder().parse(strToSource(runtimeErrorsReport, Charsets.UTF_16)) + val entries = report.getElementsByTagName("reportEntry") + for (i in 0..entries.length - 1) { + val reportEntry = entries.item(i) as Element + + val severityLevel = reportEntry.getAttribute("severity").toSeverity() + val rangeStart = reportEntry.getAttribute("rangeStart").toInt() + val rangeEnd = reportEntry.getAttribute("rangeEnd").toInt() + val description = reportEntry.textContent + + compilerMessages.add(SeverityDetails(severityLevel, description, TextRange(rangeStart, rangeEnd))) + } + + return compilerMessages + } + + private fun String.toSeverity() = when (this) { + "ERROR" -> Severity.ERROR + "WARNING" -> Severity.WARNING + "INFO" -> Severity.INFO + else -> throw IllegalArgumentException("Unsupported Severity: '$this'") // this case shouldn't occur + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockParameterInfoUIContext.java.172 b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockParameterInfoUIContext.java.172 index ea8503d6535..0fe69d29d45 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockParameterInfoUIContext.java.172 +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockParameterInfoUIContext.java.172 @@ -68,11 +68,6 @@ public class MockParameterInfoUIContext implements ParameterInfoUIContext { return myParameterOwner; } - @Override - public boolean isSingleParameterInfo() { - return false; - } - @Override public Color getDefaultParameterColor() { return null; diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockUpdateParameterInfoContext.java.172 b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockUpdateParameterInfoContext.java.172 new file mode 100644 index 00000000000..fdee5439b1c --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/MockUpdateParameterInfoContext.java.172 @@ -0,0 +1,109 @@ +/* + * 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.parameterInfo; + +import com.intellij.lang.parameterInfo.UpdateParameterInfoContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +public class MockUpdateParameterInfoContext implements UpdateParameterInfoContext { + private int myCurrentParameter = -1; + private PsiFile myFile; + private JavaCodeInsightTestFixture myFixture; + + MockUpdateParameterInfoContext(PsiFile file, JavaCodeInsightTestFixture fixture) { + myFile = file; + myFixture = fixture; + } + + + @Override + public void removeHint() { + } + + @Override + public void setParameterOwner(PsiElement o) { + } + + @Override + public PsiElement getParameterOwner() { + return null; + } + + @Override + public void setHighlightedParameter(Object parameter) { + } + + @Override + public Object getHighlightedParameter() { + return null; + } + + @Override + public void setCurrentParameter(int index) { + myCurrentParameter = index; + } + + public int getCurrentParameter() { + return myCurrentParameter; + } + + @Override + public boolean isUIComponentEnabled(int index) { + return false; + } + + @Override + public void setUIComponentEnabled(int index, boolean b) { + } + + @Override + public int getParameterListStart() { + return 0; + } + + @Override + public Object[] getObjectsToView() { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + + @Override + public Project getProject() { + return null; + } + + @Override + public PsiFile getFile() { + return myFile; + } + + @Override + public int getOffset() { + return myFixture.getCaretOffset(); + } + + @NotNull + @Override + public Editor getEditor() { + return myFixture.getEditor(); + } +}