Add SKIP_INLINE_CHECK_IN directive to inline test framework

This commit is contained in:
Mikhael Bogdanov
2017-05-09 14:22:57 +02:00
parent daf6768181
commit b7af4ac882
@@ -30,20 +30,20 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.* import java.util.*
object InlineTestUtil { object InlineTestUtil {
fun checkNoCallsToInline(files: Iterable<OutputFile>, sourceFiles: List<KtFile>) { fun checkNoCallsToInline(outputFiles: Iterable<OutputFile>, sourceFiles: List<KtFile>) {
val inlineInfo = obtainInlineInfo(files) val inlineInfo = obtainInlineInfo(outputFiles)
val inlineMethods = inlineInfo.inlineMethods val inlineMethods = inlineInfo.inlineMethods
assert(!inlineMethods.isEmpty()) { "There are no inline methods" } assert(!inlineMethods.isEmpty()) { "There are no inline methods" }
val notInlinedCalls = checkInlineMethodNotInvoked(files, inlineMethods) val notInlinedCalls = checkInlineMethodNotInvoked(outputFiles, inlineMethods)
assert(notInlinedCalls.isEmpty()) { "All inline methods should be inlined but:\n" + notInlinedCalls.joinToString("\n") } assert(notInlinedCalls.isEmpty()) { "All inline methods should be inlined but:\n" + notInlinedCalls.joinToString("\n") }
val skipParameterChecking = sourceFiles.any { val skipParameterChecking = sourceFiles.any {
InTextDirectivesUtils.isDirectiveDefined(it.text, "NO_CHECK_LAMBDA_INLINING") InTextDirectivesUtils.isDirectiveDefined(it.text, "NO_CHECK_LAMBDA_INLINING")
} || !doLambdaInliningCheck(files, inlineInfo) } || !doLambdaInliningCheck(outputFiles, inlineInfo)
if (!skipParameterChecking) { if (!skipParameterChecking) {
val notInlinedParameters = checkParametersInlined(files, inlineInfo) val notInlinedParameters = checkParametersInlined(outputFiles, inlineInfo, sourceFiles)
assert(notInlinedParameters.isEmpty()) { assert(notInlinedParameters.isEmpty()) {
"All inline parameters should be inlined but:\n${notInlinedParameters.joinToString("\n")}\n" + "All inline parameters should be inlined but:\n${notInlinedParameters.joinToString("\n")}\n" +
"but if you have not inlined lambdas or anonymous objects enable NO_CHECK_LAMBDA_INLINING directive" "but if you have not inlined lambdas or anonymous objects enable NO_CHECK_LAMBDA_INLINING directive"
@@ -80,6 +80,7 @@ object InlineTestUtil {
val binaryClass = loadBinaryClass(file) val binaryClass = loadBinaryClass(file)
val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader)
//if inline function creates anonymous object then do not try to check that all lambdas are inlined
val classVisitor = object : ClassVisitorWithName() { val classVisitor = object : ClassVisitorWithName() {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? {
if (name + desc in inlineFunctions) { if (name + desc in inlineFunctions) {
@@ -149,20 +150,30 @@ object InlineTestUtil {
return notInlined return notInlined
} }
private fun checkParametersInlined(files: Iterable<OutputFile>, inlineInfo: InlineInfo): ArrayList<NotInlinedParameter> { private fun checkParametersInlined(outputFiles: Iterable<OutputFile>, inlineInfo: InlineInfo, sourceFiles: List<KtFile>): ArrayList<NotInlinedParameter> {
val skipMethods =
sourceFiles.flatMap {
InTextDirectivesUtils.findLinesWithPrefixesRemoved(it.text, "// SKIP_INLINE_CHECK_IN: ")
}.toSet()
val inlinedMethods = inlineInfo.inlineMethods val inlinedMethods = inlineInfo.inlineMethods
val notInlinedParameters = ArrayList<NotInlinedParameter>() val notInlinedParameters = ArrayList<NotInlinedParameter>()
for (file in files) { for (file in outputFiles) {
if (!isClassOrPackagePartKind(loadBinaryClass(file))) continue if (!isClassOrPackagePartKind(loadBinaryClass(file))) continue
ClassReader(file.asByteArray()).accept(object : ClassVisitorWithName() { ClassReader(file.asByteArray()).accept(object : ClassVisitorWithName() {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? {
val declaration = MethodInfo(className, name, desc) val declaration = MethodInfo(className, name, desc)
//do not check anonymous object creation in inline functions and in package facades //do not check anonymous object creation in inline functions and in package facades
if (declaration in inlinedMethods) { if (declaration in inlinedMethods) {
return null return null
} }
if (skipMethods.contains(name)) {
return null
}
return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) {
override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) {
val fromCall = MethodInfo(className, this.name, this.desc) val fromCall = MethodInfo(className, this.name, this.desc)