1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package com.code_intelligence.jazzer.instrumentor
16
isPrimitiveTypenull17 internal fun isPrimitiveType(typeDescriptor: String): Boolean {
18 return typeDescriptor in arrayOf("B", "C", "D", "F", "I", "J", "S", "V", "Z")
19 }
20
isPrimitiveTypenull21 private fun isPrimitiveType(typeDescriptor: Char) = isPrimitiveType(typeDescriptor.toString())
22
23 internal fun getWrapperTypeDescriptor(typeDescriptor: String): String = when (typeDescriptor) {
24 "B" -> "Ljava/lang/Byte;"
25 "C" -> "Ljava/lang/Character;"
26 "D" -> "Ljava/lang/Double;"
27 "F" -> "Ljava/lang/Float;"
28 "I" -> "Ljava/lang/Integer;"
29 "J" -> "Ljava/lang/Long;"
30 "S" -> "Ljava/lang/Short;"
31 "V" -> "Ljava/lang/Void;"
32 "Z" -> "Ljava/lang/Boolean;"
33 else -> typeDescriptor
34 }
35
36 // Removes the 'L' and ';' prefix/suffix from signatures to get the full class name.
37 // Note that array signatures '[Ljava/lang/String;' already have the correct form.
extractInternalClassNamenull38 internal fun extractInternalClassName(typeDescriptor: String): String {
39 return if (typeDescriptor.startsWith("L") && typeDescriptor.endsWith(";")) {
40 typeDescriptor.substring(1, typeDescriptor.length - 1)
41 } else {
42 typeDescriptor
43 }
44 }
45
extractParameterTypeDescriptorsnull46 internal fun extractParameterTypeDescriptors(methodDescriptor: String): List<String> {
47 require(methodDescriptor.startsWith('(')) { "Method descriptor must start with '('" }
48 val endOfParameterPart = methodDescriptor.indexOf(')') - 1
49 require(endOfParameterPart >= 0) { "Method descriptor must contain ')'" }
50 var remainingDescriptorList = methodDescriptor.substring(1..endOfParameterPart)
51 val parameterDescriptors = mutableListOf<String>()
52 while (remainingDescriptorList.isNotEmpty()) {
53 val nextDescriptor = extractNextTypeDescriptor(remainingDescriptorList)
54 parameterDescriptors.add(nextDescriptor)
55 remainingDescriptorList = remainingDescriptorList.removePrefix(nextDescriptor)
56 }
57 return parameterDescriptors
58 }
59
extractReturnTypeDescriptornull60 internal fun extractReturnTypeDescriptor(methodDescriptor: String): String {
61 require(methodDescriptor.startsWith('(')) { "Method descriptor must start with '('" }
62 val endBracketPos = methodDescriptor.indexOf(')')
63 require(endBracketPos >= 0) { "Method descriptor must contain ')'" }
64 val startOfReturnValue = endBracketPos + 1
65 return extractNextTypeDescriptor(methodDescriptor.substring(startOfReturnValue))
66 }
67
extractNextTypeDescriptornull68 private fun extractNextTypeDescriptor(input: String): String {
69 require(input.isNotEmpty()) { "Type descriptor must not be empty" }
70 // Skip over arbitrarily many '[' to support multi-dimensional arrays.
71 val firstNonArrayPrefixCharPos = input.indexOfFirst { it != '[' }
72 require(firstNonArrayPrefixCharPos >= 0) { "Array descriptor must contain type" }
73 val firstTypeChar = input[firstNonArrayPrefixCharPos]
74 return when {
75 // Primitive type
76 isPrimitiveType(firstTypeChar) -> {
77 input.substring(0..firstNonArrayPrefixCharPos)
78 }
79 // Object type
80 firstTypeChar == 'L' -> {
81 val endOfClassNamePos = input.indexOf(';')
82 require(endOfClassNamePos > 0) { "Class type indicated by L must end with ;" }
83 input.substring(0..endOfClassNamePos)
84 }
85 // Invalid type
86 else -> {
87 throw IllegalArgumentException("Invalid type: $firstTypeChar")
88 }
89 }
90 }
91