diff --git a/idea/src/org/jetbrains/kotlin/idea/coverage/KotlinCoverageExtension.kt b/idea/src/org/jetbrains/kotlin/idea/coverage/KotlinCoverageExtension.kt index fe2d4b206bc..552a0643ae3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/coverage/KotlinCoverageExtension.kt +++ b/idea/src/org/jetbrains/kotlin/idea/coverage/KotlinCoverageExtension.kt @@ -50,7 +50,7 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { override fun suggestQualifiedName(sourceFile: PsiFile, classes: Array, names: MutableSet): Boolean { if (sourceFile is JetFile) { - val qNames = collectGeneratedClassQualifiedNames(sourceFile) + val qNames = collectGeneratedClassQualifiedNames(findOutputRoot(sourceFile), sourceFile) if (qNames != null) { names.addAll(qNames) return true @@ -67,78 +67,10 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { } LOG.info("Retrieving coverage for " + element.getName()) - val qualifiedNames = collectGeneratedClassQualifiedNames(element) + val qualifiedNames = collectGeneratedClassQualifiedNames(findOutputRoot(element), element) return if (qualifiedNames == null) null else totalCoverageForQualifiedNames(coverageAnnotator, qualifiedNames) } - private fun collectGeneratedClassQualifiedNames(file: JetFile): List? { - val outputRoot = findOutputRoot(file) - val existingClassFiles = getClassesGeneratedFromFile(outputRoot, file) - if (existingClassFiles.isEmpty()) { - return null - } - LOG.debug("Classfiles: [${existingClassFiles.map { it.getName() }.join()}]") - return existingClassFiles.map { - val relativePath = VfsUtilCore.getRelativePath(it, outputRoot) - StringUtil.trimEnd(relativePath, ".class").replace("/", ".") - } - } - - private fun getClassesGeneratedFromFile(outputRoot: VirtualFile?, file: JetFile): List { - val relativePath = file.getPackageFqName().asString().replace('.', '/') - val packageOutputDir = outputRoot?.findFileByRelativePath(relativePath) - if (packageOutputDir == null) return listOf() - - val prefixes = collectClassFilePrefixes(file) - LOG.debug("Classfile prefixes: [${prefixes.join(", ")}]") - return packageOutputDir.getChildren().filter { - file -> prefixes.any { - (file.getName().startsWith(it + "$") && FileUtilRt.getExtension(file.getName()) == "class") || - file.getName() == it + ".class" - } - } - } - - private fun totalCoverageForQualifiedNames(coverageAnnotator: JavaCoverageAnnotator, - qualifiedNames: List): PackageAnnotator.ClassCoverageInfo { - val result = PackageAnnotator.ClassCoverageInfo() - result.totalClassCount = 0 - qualifiedNames.forEach { - val classInfo = coverageAnnotator.getClassCoverageInfo(it) - if (classInfo != null) { - result.totalClassCount += classInfo.totalClassCount - result.coveredClassCount += classInfo.coveredClassCount - result.totalMethodCount += classInfo.totalMethodCount - result.coveredMethodCount += classInfo.coveredMethodCount - result.totalLineCount += classInfo.totalLineCount - result.fullyCoveredLineCount += classInfo.fullyCoveredLineCount - result.partiallyCoveredLineCount += classInfo.partiallyCoveredLineCount - } - else { - LOG.debug("Found no coverage for ${it}") - } - } - return result - } - - private fun findOutputRoot(file: JetFile): VirtualFile? { - val module = ModuleUtilCore.findModuleForPsiElement(file) - if (module == null) return null - val fileIndex = ProjectRootManager.getInstance(file.getProject()).getFileIndex() - val inTests = fileIndex.isInTestSourceContent(file.getVirtualFile()) - val compilerOutputExtension = CompilerModuleExtension.getInstance(module) - return if (inTests) - compilerOutputExtension.getCompilerOutputPathForTests() - else - compilerOutputExtension.getCompilerOutputPath() - } - - private fun collectClassFilePrefixes(file: JetFile): Collection { - val result = file.getChildren().filter { it is JetClassOrObject }.map { (it as JetClassOrObject).getName() } - val packagePartFqName = PackagePartClassUtils.getPackagePartFqName(file) - return result.union(arrayListOf(packagePartFqName.shortName().asString())) - } - // Implements API added in IDEA 14.1 fun keepCoverageInfoForClassWithoutSource(bundle: CoverageSuitesBundle, classFile: File): Boolean { // TODO check scope and source roots @@ -177,10 +109,81 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() { runReadAction { val outputRoot = findOutputRoot(srcFile) val existingClassFiles = getClassesGeneratedFromFile(outputRoot, srcFile) - existingClassFiles.mapTo(classFiles) { File(it.getPath())} + existingClassFiles.mapTo(classFiles) { File(it.getPath()) } } return true } return false } + + class object { + private val LOG = Logger.getInstance(javaClass()) + + fun collectGeneratedClassQualifiedNames(outputRoot: VirtualFile?, file: JetFile): List? { + val existingClassFiles = getClassesGeneratedFromFile(outputRoot, file) + if (existingClassFiles.isEmpty()) { + return null + } + LOG.debug("Classfiles: [${existingClassFiles.map { it.getName() }.join()}]") + return existingClassFiles.map { + val relativePath = VfsUtilCore.getRelativePath(it, outputRoot) + StringUtil.trimEnd(relativePath, ".class").replace("/", ".") + } + } + + private fun totalCoverageForQualifiedNames(coverageAnnotator: JavaCoverageAnnotator, + qualifiedNames: List): PackageAnnotator.ClassCoverageInfo { + val result = PackageAnnotator.ClassCoverageInfo() + result.totalClassCount = 0 + qualifiedNames.forEach { + val classInfo = coverageAnnotator.getClassCoverageInfo(it) + if (classInfo != null) { + result.totalClassCount += classInfo.totalClassCount + result.coveredClassCount += classInfo.coveredClassCount + result.totalMethodCount += classInfo.totalMethodCount + result.coveredMethodCount += classInfo.coveredMethodCount + result.totalLineCount += classInfo.totalLineCount + result.fullyCoveredLineCount += classInfo.fullyCoveredLineCount + result.partiallyCoveredLineCount += classInfo.partiallyCoveredLineCount + } + else { + LOG.debug("Found no coverage for ${it}") + } + } + return result + } + + private fun getClassesGeneratedFromFile(outputRoot: VirtualFile?, file: JetFile): List { + val relativePath = file.getPackageFqName().asString().replace('.', '/') + val packageOutputDir = outputRoot?.findFileByRelativePath(relativePath) + if (packageOutputDir == null) return listOf() + + val prefixes = collectClassFilePrefixes(file) + LOG.debug("Classfile prefixes: [${prefixes.join(", ")}]") + return packageOutputDir.getChildren().filter { + file -> prefixes.any { + (file.getName().startsWith(it + "$") && FileUtilRt.getExtension(file.getName()) == "class") || + file.getName() == it + ".class" + } + } + } + + private fun findOutputRoot(file: JetFile): VirtualFile? { + val module = ModuleUtilCore.findModuleForPsiElement(file) + if (module == null) return null + val fileIndex = ProjectRootManager.getInstance(file.getProject()).getFileIndex() + val inTests = fileIndex.isInTestSourceContent(file.getVirtualFile()) + val compilerOutputExtension = CompilerModuleExtension.getInstance(module) + return if (inTests) + compilerOutputExtension.getCompilerOutputPathForTests() + else + compilerOutputExtension.getCompilerOutputPath() + } + + private fun collectClassFilePrefixes(file: JetFile): Collection { + val result = file.getChildren().filter { it is JetClassOrObject }.map { (it as JetClassOrObject).getName() } + val packagePartFqName = PackagePartClassUtils.getPackagePartFqName(file) + return result.union(arrayListOf(packagePartFqName.shortName().asString())) + } + } } diff --git a/idea/testData/coverage/outputFiles/NotInlinedLambda.expected.txt b/idea/testData/coverage/outputFiles/NotInlinedLambda.expected.txt index 39ea5e49821..f8aef9ad97a 100644 --- a/idea/testData/coverage/outputFiles/NotInlinedLambda.expected.txt +++ b/idea/testData/coverage/outputFiles/NotInlinedLambda.expected.txt @@ -1,2 +1,2 @@ -org/demo/coverage/Foo -org/demo/coverage/Foo$bar$1 +org.demo.coverage.Foo +org.demo.coverage.Foo$bar$1 diff --git a/idea/testData/coverage/outputFiles/NotInlinedLambda.kt b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt index 3007ac1e940..56f67a65c1f 100644 --- a/idea/testData/coverage/outputFiles/NotInlinedLambda.kt +++ b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt @@ -2,6 +2,7 @@ package org.demo.coverage public class Foo { public fun forEach(fn: (Any?) -> Unit): Unit { + fn(1) } public fun bar() { diff --git a/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo$bar$1.class b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo$bar$1.class new file mode 100644 index 00000000000..175d65c2751 Binary files /dev/null and b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo$bar$1.class differ diff --git a/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo.class b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo.class new file mode 100644 index 00000000000..d6b80fbdbb9 Binary files /dev/null and b/idea/testData/coverage/outputFiles/NotInlinedLambda.kt.out/org/demo/coverage/Foo.class differ diff --git a/idea/tests/org/jetbrains/kotlin/idea/coverage/AbstractKotlinCoverageOutputFilesTest.kt b/idea/tests/org/jetbrains/kotlin/idea/coverage/AbstractKotlinCoverageOutputFilesTest.kt index 478f8f4ee85..1e61f26a57c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/coverage/AbstractKotlinCoverageOutputFilesTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/coverage/AbstractKotlinCoverageOutputFilesTest.kt @@ -18,6 +18,11 @@ package org.jetbrains.kotlin.idea.coverage import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.PluginTestCaseBase +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.test.JetTestUtils +import java.io.File +import com.intellij.openapi.vfs.LocalFileSystem +import kotlin.test.assertNotNull public abstract class AbstractKotlinCoverageOutputFilesTest(): JetLightCodeInsightFixtureTestCase() { private val TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/coverage/outputFiles" @@ -25,8 +30,10 @@ public abstract class AbstractKotlinCoverageOutputFilesTest(): JetLightCodeInsig override fun getTestDataPath(): String? = TEST_DATA_PATH public fun doTest(path: String) { -// val kotlinFile = myFixture.configureByFile(path) as JetFile -// val actualClasses = KotlinCoverageExtension.collectOutputClassNames(kotlinFile) -// JetTestUtils.assertEqualsToFile(File(path.replace(".kt", ".expected.txt")), actualClasses.join("\n")) + val kotlinFile = myFixture.configureByFile(path) as JetFile + val outputRoot = LocalFileSystem.getInstance().findFileByPath("$path.out") + assertNotNull(outputRoot) + val actualClasses = KotlinCoverageExtension.collectGeneratedClassQualifiedNames(outputRoot, kotlinFile) + JetTestUtils.assertEqualsToFile(File(path.replace(".kt", ".expected.txt")), actualClasses!!.join("\n")) } }