Improve code coverage performance: always get the .class files corresponding to a source file by looking at the output directory, not by analyzing the source file.
This commit is contained in:
@@ -24,15 +24,7 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import com.intellij.coverage.CoverageSuitesBundle
|
import com.intellij.coverage.CoverageSuitesBundle
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.idea.debugger.JetPositionManager
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
|
|
||||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
|
||||||
import com.intellij.openapi.roots.ProjectRootManager
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
import org.jetbrains.kotlin.psi.JetTreeVisitorVoid
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import java.util.LinkedHashSet
|
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
@@ -49,6 +41,7 @@ import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
|||||||
import com.intellij.openapi.vfs.LocalFileSystem
|
import com.intellij.openapi.vfs.LocalFileSystem
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
import com.intellij.openapi.util.io.FileUtilRt
|
import com.intellij.openapi.util.io.FileUtilRt
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
|
||||||
public class KotlinCoverageExtension(): JavaCoverageEngineExtension() {
|
public class KotlinCoverageExtension(): JavaCoverageEngineExtension() {
|
||||||
private val LOG = Logger.getInstance(javaClass<KotlinCoverageExtension>())
|
private val LOG = Logger.getInstance(javaClass<KotlinCoverageExtension>())
|
||||||
@@ -57,8 +50,11 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() {
|
|||||||
|
|
||||||
override fun suggestQualifiedName(sourceFile: PsiFile, classes: Array<out PsiClass>, names: MutableSet<String>): Boolean {
|
override fun suggestQualifiedName(sourceFile: PsiFile, classes: Array<out PsiClass>, names: MutableSet<String>): Boolean {
|
||||||
if (sourceFile is JetFile) {
|
if (sourceFile is JetFile) {
|
||||||
names.addAll(collectOutputClassNames(sourceFile).map { StringUtil.replaceChar(it, '/', '.' )})
|
val qNames = collectGeneratedClassQualifiedNames(sourceFile)
|
||||||
return true
|
if (qNames != null) {
|
||||||
|
names.addAll(qNames)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -70,18 +66,22 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
LOG.info("Retrieving coverage for " + element.getName())
|
LOG.info("Retrieving coverage for " + element.getName())
|
||||||
val outputRoot = findOutputRoot(element)
|
|
||||||
val existingClassFiles = getClassesGeneratedFromFile(outputRoot, element)
|
val qualifiedNames = collectGeneratedClassQualifiedNames(element)
|
||||||
|
return if (qualifiedNames == null) null else totalCoverageForQualifiedNames(coverageAnnotator, qualifiedNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectGeneratedClassQualifiedNames(file: JetFile): List<String>? {
|
||||||
|
val outputRoot = findOutputRoot(file)
|
||||||
|
val existingClassFiles = getClassesGeneratedFromFile(outputRoot, file)
|
||||||
if (existingClassFiles.isEmpty()) {
|
if (existingClassFiles.isEmpty()) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
LOG.debug("Classfiles: [${existingClassFiles.map { it.getName() }.join()}]")
|
LOG.debug("Classfiles: [${existingClassFiles.map { it.getName() }.join()}]")
|
||||||
val qualifiedNames = existingClassFiles.map {
|
return existingClassFiles.map {
|
||||||
val relativePath = VfsUtilCore.getRelativePath(it, outputRoot)
|
val relativePath = VfsUtilCore.getRelativePath(it, outputRoot)
|
||||||
StringUtil.trimEnd(relativePath, ".class").replace("/", ".")
|
StringUtil.trimEnd(relativePath, ".class").replace("/", ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalCoverageForQualifiedNames(coverageAnnotator, qualifiedNames)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getClassesGeneratedFromFile(outputRoot: VirtualFile?, file: JetFile): List<VirtualFile> {
|
private fun getClassesGeneratedFromFile(outputRoot: VirtualFile?, file: JetFile): List<VirtualFile> {
|
||||||
@@ -174,47 +174,13 @@ public class KotlinCoverageExtension(): JavaCoverageEngineExtension() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val classNames = ApplicationManager.getApplication().runReadAction<Set<String>> { collectOutputClassNames(srcFile) }
|
runReadAction {
|
||||||
|
val outputRoot = findOutputRoot(srcFile)
|
||||||
fun findUnder(name: String, root: VirtualFile?): File? {
|
val existingClassFiles = getClassesGeneratedFromFile(outputRoot, srcFile)
|
||||||
if (root != null) {
|
existingClassFiles.mapTo(classFiles) { File(it.getPath())}
|
||||||
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 true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
class object {
|
|
||||||
public fun collectOutputClassNames(srcFile: JetFile): Set<String> {
|
|
||||||
val typeMapper = JetPositionManager.createTypeMapper(srcFile, srcFile.getModuleInfo())
|
|
||||||
val classNames = LinkedHashSet<String>()
|
|
||||||
srcFile.acceptChildren(object: JetTreeVisitorVoid() {
|
|
||||||
override fun visitDeclaration(dcl: JetDeclaration) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return classNames
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user