• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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