refactor: remove unused ':subprojects:classfile' module

This commit is contained in:
Akash Yadav
2023-07-31 13:56:02 +05:30
parent 27c6ea8722
commit bd0bfe827f
51 changed files with 11 additions and 17138 deletions
+10 -7
View File
@@ -2,13 +2,6 @@
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Gradle Imported" enabled="true">
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.auto.value/auto-value/1.10.1/e0184c26c3a20257c6fb46eaea16fdd3d7b6d357/auto-value-1.10.1.jar" />
</processorPath>
<module name="AndroidIDE.subprojects.google-java-format.main" />
</profile>
<profile name="Gradle Imported" enabled="true">
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
@@ -27,6 +20,13 @@
</processorPath>
<module name="AndroidIDE.annotation-processors.main" />
</profile>
<profile name="Gradle Imported" enabled="true">
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.auto.value/auto-value/1.10.2/ec0b68a285b67ea83e54cd4cc0fb5652dcefc2e9/auto-value-1.10.2.jar" />
</processorPath>
<module name="AndroidIDE.subprojects.google-java-format.main" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel target="1.8">
<module name="AndroidIDE.annotation-ksp" target="17" />
@@ -117,6 +117,9 @@
<module name="AndroidIDE.ksp-processor.main" target="11" />
<module name="AndroidIDE.ksp-processor.test" target="11" />
<module name="AndroidIDE.sdk-info" target="11" />
<module name="AndroidIDE.subprojects.classfile" target="11" />
<module name="AndroidIDE.subprojects.classfile.main" target="11" />
<module name="AndroidIDE.subprojects.classfile.test" target="11" />
<module name="AndroidIDE.subprojects.java-compiler-utils.main" target="8" />
<module name="AndroidIDE.subprojects.java-compiler-utils.test" target="8" />
<module name="AndroidIDE.subprojects.jsonrpc" target="11" />
+1 -1
View File
@@ -216,7 +216,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
-1
View File
@@ -75,7 +75,6 @@ include(
":lsp:testing",
":subprojects:aaptcompiler",
":subprojects:builder-model-impl",
":subprojects:classfile",
":subprojects:flashbar",
":subprojects:framework-stubs",
":subprojects:fuzzysearch",
-1
View File
@@ -1 +0,0 @@
/build
-46
View File
@@ -1,46 +0,0 @@
# Class File Reader
This is a basic class file reader which supports reading class files with major version **61 and below**. Currently, we only read required information from the class file (up to the `super_class` entry).
## Usage
Create a `ClassFileReader` instance and call the `read()` method to start reading the class file.
```kotlin
// Kotlin
val reader = ClassFileReader(FileInputStream(File("/path/to/MyClass.class")))
val classFile = reader.read()
```
## Constant pool
The `IClassFile` provides access to the constant pool that is read from the class file.
The entries in the constant pool from class file is represented by the `IConstant` implementations. Each implementation has a `type` property which represents the type of the constant. It also contains the tag value of the constant type. The following table shows the constant type and its implementation in this class file reader.
| Constant type | Implementation |
| --------------------------- | ---------------------- |
| CONSTANT_Class | `ClassConstant` |
| CONSTANT_Fieldref | `ReferenceConstant` |
| CONSTANT_Methodref | `ReferenceConstant` |
| CONSTANT_InterfaceMethodref | `ReferenceConstant` |
| CONSTANT_String | `StringConstant` |
| CONSTANT_Integer | `IntegerConstant` |
| CONSTANT_Float | `FloatConstant` |
| CONSTANT_Double | `DoubleConstant` |
| CONSTANT_NameAndType | `NameAndTypeConstant` |
| CONSTANT_Utf8 | `Utf8Constant` |
| CONSTANT_MethodHandle | `MethodHandleConstant` |
| CONSTANT_MethodType | `MethodTypeConstant` |
| CONSTANT_Dynamic | `DynamicConstant` |
| CONSTANT_InvokeDynamic | `DynamicConstant` |
| CONSTANT_Module | `ModuleConstant` |
| CONSTANT_Package | `PackageConstant` |
## References
The following sections were referred from the JDK 17 JVM specifications :
- [Chapter 4 - The Class File Format](https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html).
- [Table 5.4.3.5-A. Bytecode Behaviors for Method Handles](https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-5.html#jvms-5.4.3.5).
-29
View File
@@ -1,29 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
@Suppress("JavaPluginLanguageLevel")
plugins {
id("java-library")
id("org.jetbrains.kotlin.jvm")
}
dependencies {
implementation(libs.common.jkotlin)
testImplementation(libs.tests.junit)
testImplementation(libs.tests.google.truth)
}
@@ -1,109 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile;
/**
* Constants in a class file.
*
* @author Akash Yadav
*/
public class ClassFileConstants {
/** Required magic number in the class files. */
public static final int MAGIC = 0xCAFEBABE;
/** Declared public; may be accessed from outside its package. */
public static final int ACC_PUBLIC = 0x0001;
/**
* Declared private; accessible only within the defining class and other classes belonging to the
* same nest
*/
public static final int ACC_PRIVATE = 0x0002;
/** Declared protected; may be accessed within subclasses. */
public static final int ACC_PROTECTED = 0x0004;
/** Declared static. */
public static final int ACC_STATIC = 0x0008;
/** Declared final; no subclasses allowed. */
public static final int ACC_FINAL = 0x0010;
/** Treat superclass methods specially when invoked by the invokespecial instruction. */
public static final int ACC_SUPER = 0x0020;
/** Declared volatile; cannot be cached */
public static final int ACC_VOLATILE = 0x0040;
/** Declared transient; not written or read by a persistent object manager. */
public static final int ACC_TRANSIENT = 0x0080;
/** Is an interface, not a class. */
public static final int ACC_INTERFACE = 0x0200;
/** Declared abstract; must not be instantiated. */
public static final int ACC_ABSTRACT = 0x0400;
/** Declared synthetic; Not present in the source code. */
public static final int ACC_SYNTHETIC = 0x1000;
/** Declared as an annotation type. */
public static final int ACC_ANNOTATION = 0x2000;
/** Declared as an enum type. */
public static final int ACC_ENUM = 0x4000;
/** Is a module, not a class or interface. */
public static final int ACC_MODULE = 0x8000;
public static final String ATTR_CONSTANT_VALUE = "ConstantValue";
public static final String ATTR_CODE = "Code";
public static final String ATTR_EXCEPTIONS = "Exceptions";
public static final String ATTR_SOURCE_FILE = "SourceFile";
public static final String ATTR_LINE_NUMBER_TABLE = "LineNumberTable";
public static final String ATTR_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
public static final String ATTR_INNER_CLASSES = "InnerClasses";
public static final String ATTR_SYNTHETIC = "Synthetic";
public static final String ATTR_DEPRECATED = "Deprecated";
public static final String ATTR_ENCLOSING_METHOD = "EnclosingMethod";
public static final String ATTR_SIGNATURE = "Signature";
public static final String ATTR_SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
public static final String ATTR_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
public static final String ATTR_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
public static final String ATTR_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
public static final String ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS =
"RuntimeVisibleParameterAnnotations";
public static final String ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
"RuntimeInvisibleParameterAnnotations";
public static final String ATTR_ANNOTATION_DEFAULT = "AnnotationDefault";
public static final String ATTR_STACK_MAP_TABLE = "StackMapTable";
public static final String ATTR_BOOTSTRAP_METHODS = "BootstrapMethods";
public static final String ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS =
"RuntimeVisibleTypeAnnotations";
public static final String ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS =
"RuntimeInvisibleTypeAnnotations";
public static final String ATTR_METHOD_PARAMETERS = "MethodParameters";
public static final String ATTR_MODULE = "Module";
public static final String ATTR_MODULE_PACKAGES = "ModulePackages";
public static final String ATTR_MAIN_CLASS = "ModuleMainClass";
public static final String ATTR_NEST_HOST = "NestHost";
public static final String ATTR_NEST_MEMBERS = "NestMembers";
public static final String ATTR_RECORD = "Record";
public static final String ATTR_PERMITTED_SUBCLASSES = "PermittedSubclasses";
}
@@ -1,109 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile
import com.itsaky.androidide.classfile.constants.IConstant
import com.itsaky.androidide.classfile.constants.IConstant.Type.DOUBLE
import com.itsaky.androidide.classfile.constants.IConstant.Type.LONG
import com.itsaky.androidide.classfile.internal.ClassFile
import com.itsaky.androidide.classfile.internal.NullConstant
import com.itsaky.androidide.classfile.internal.NullField
import java.io.DataInputStream
import java.io.InputStream
/**
* Reads class file from the given stream. This currently does not read the entire class file but
* only the things we need (upto the `super_class` entry).
*
* @author Akash Yadav
*/
class ClassFileReader(private val stream: InputStream) {
/**
* Read the class file.
*
* @return The info about the class file.
*/
fun read(): IClassFile {
val input = DataInputStream(stream)
val magic = input.readInt()
if (magic != ClassFileConstants.MAGIC) {
throw IllegalArgumentException(
"Not a class file. Expecting magic value ${ClassFileConstants.MAGIC} but found $magic."
)
}
val file = ClassFile()
val minorVersion = input.readUnsignedShort()
val majorVersion = input.readUnsignedShort()
if (majorVersion >= 56 && minorVersion != 0 && minorVersion != 65535) {
// When major version is >= 56, minor version must be 0 or 65535
throw IllegalStateException("Invalid class file minor version: '${minorVersion}'")
}
file.version = ClassFileVersion.get(majorVersion, minorVersion)
val poolCount = input.readUnsignedShort()
file.constantPool = Array(poolCount) { NullConstant }
var index = 1
while (index < poolCount) {
val constant = readPoolConstant(input)
file.constantPool[index] = constant
if (constant.type == LONG || constant.type == DOUBLE) {
++index
}
++index
}
file.accessFlags = input.readUnsignedShort()
file.thisClass = input.readUnsignedShort()
file.superClass = input.readUnsignedShort()
val interfaceCount = input.readUnsignedShort()
file.interfaces = IntArray(interfaceCount)
index = 0
while (index < interfaceCount) {
file.interfaces[index] = input.readUnsignedShort()
++index
}
val fieldCount = input.readUnsignedShort()
file.fields = Array(fieldCount) { NullField }
index = 0
while (index < fieldCount) {
file.fields[index] = IFieldInfo.read(input, file)
++index
}
return file
}
private fun readPoolConstant(input: DataInputStream): IConstant {
val tag = input.readUnsignedByte()
val type = IConstant.forTag(tag)
val constant = IConstant.forType(type)
constant.read(input)
return constant
}
}
@@ -1,51 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile
/**
* Version info for the class file.
*
* @author Akash Yadav
*/
enum class ClassFileVersion(val major: Int, val minor: Int) {
JAVA_1_0(45, 0),
JAVA_1_1(45, 3),
JAVA_1_2(46, 0),
JAVA_1_3(47, 0),
JAVA_1_4(48, 0),
JAVA_5(49, 0),
JAVA_6(50, 0),
JAVA_7(51, 0),
JAVA_8(52, 0),
JAVA_9(53, 0),
JAVA_10(54, 0),
JAVA_11(55, 0),
JAVA_12(56, 0),
JAVA_13(57, 0),
JAVA_14(58, 0),
JAVA_15(59, 0),
JAVA_16(60, 0),
JAVA_17(61, 0);
companion object {
internal fun get(major: Int, minor: Int): ClassFileVersion {
return values().firstOrNull { it.major == major && it.minor == minor }
?: throw IllegalArgumentException("Unknown class file version '${major}.${minor}'")
}
}
}
@@ -1,61 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile
import com.itsaky.androidide.classfile.constants.IConstant
/**
* Model class for holding information about class files.
*
* @author Akash Yadav
*/
interface IClassFile {
/** The class file version. */
val version: ClassFileVersion
/** The constant pool. */
val constantPool: Array<IConstant>
/** Access flags for the class. */
val accessFlags: Int
/**
* The index in the constant pool which corresponds to the internal representation of the name of
* this class.
*/
val thisClass: Int
/**
* The index in the constant pool which corresponds to the internal representation of the name of
* the super class of this class.
*/
val superClass: Int
/** The interfaces that this class implements. */
val interfaces: IntArray
/** The fields of this class. */
val fields: Array<IFieldInfo>
/** Get the string representation of this class' name. */
fun getName(): String
/** Get the string representation of the name of this class' super class. */
fun getSuperClassName(): String
}
@@ -1,66 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile
import com.itsaky.androidide.classfile.attributes.IAttribute
import com.itsaky.androidide.classfile.internal.ClassFile
import com.itsaky.androidide.classfile.internal.FieldInfo
import com.itsaky.androidide.classfile.internal.NullAttribute
import java.io.DataInputStream
/**
* Information about a field.
*
* @author Akash Yadav
*/
interface IFieldInfo {
/** Access flags for this field. */
val accessFlags: Int
/** The index in the constant pool which corresponds to the name of this field. */
val nameIndex: Int
/**
* The index in the constant pool which corresponds to the field descriptor string for this field.
*/
val descriptorIndex: Int
/** The attributes of this field. */
val attributes: Array<IAttribute>
companion object {
internal fun read(input: DataInputStream, file: ClassFile): IFieldInfo {
val field = FieldInfo()
field.accessFlags = input.readUnsignedShort()
field.nameIndex = input.readUnsignedShort()
field.descriptorIndex = input.readUnsignedShort()
val attrCount = input.readUnsignedShort()
field.attributes = Array(attrCount) { NullAttribute }
var index = 0
while (index < attrCount) {
field.attributes[index] = IAttribute.read(input, file)
++index
}
return field
}
}
}
@@ -1,52 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import java.io.DataInputStream
/**
* Annotation model for annotation based attributes in class files.
*
* @author Akash Yadav
*/
open class Annotation {
/**
* Index of the entry in the constant pool which corresponds to the type of the the annotation.
* The entry at this index is always an UTF-8 constant.
*/
var typeIndex: Int = -1
internal set
/** The element value pairs. */
open var elementValues: Array<Pair<Int, ElementValue>> = emptyArray()
internal set
companion object {
internal fun read(input: DataInputStream): Annotation {
val annotation = Annotation()
annotation.typeIndex = input.readUnsignedShort()
val valueCount = input.readUnsignedShort()
annotation.elementValues =
Array(valueCount) { input.readUnsignedShort() to ElementValue.read(input) }
return annotation
}
}
}
@@ -1,40 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_5
import com.itsaky.androidide.classfile.IClassFile
import java.io.DataInputStream
/**
* An attribute which stores information about annotations.
*
* @author Akash Yadav
*/
abstract class AnnotationAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
override val version: ClassFileVersion = JAVA_5
/** The annotations. */
var annotations: Array<Annotation> = emptyArray()
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
val count = input.readUnsignedShort()
this.annotations = Array(count) { Annotation.read(input) }
}
}
@@ -1,25 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
/**
* Base class for attrbutes.
*
* @author Akash Yadav
*/
abstract class BaseAttribute(override val nameIndex: Int): IAttribute
@@ -1,43 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_2
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.CONSTANT_VALUE
import java.io.DataInputStream
/**
* Constant value for a field.
*
* @author Akash Yadav
*/
class ConstantValueAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
override val version: ClassFileVersion = JAVA_1_2
override val type: Type = CONSTANT_VALUE
/** The index in the constant pool which corresponds to the value of this constant. */
var valueIndex: Int = -1
internal set
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
this.valueIndex = input.readUnsignedShort()
}
}
@@ -1,28 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_1
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.DEPRECATED
/**
* Indicates that a class, field or method is deprecated.
*
* @author Akash Yadav
*/
class DeprecatedAttr(nameIndex: Int) : MarkerAttribute(nameIndex, DEPRECATED, JAVA_1_1)
@@ -1,140 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ANNOTATION_INTERFACE
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ARRAY_TYPE
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.CLASS
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ENUM_CLASS
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.UNKNOWN
import java.io.DataInputStream
/**
* The element value in an annotation.
*
* @author Akash Yadav
*/
class ElementValue {
/** The element tag. */
var type: Type = UNKNOWN
internal set
/**
* The constant value if the [type] is one of the following :
*
* - [Type.BYTE]
* - [Type.CHAR]
* - [Type.DOUBLE]
* - [Type.FLOAT]
* - [Type.INT]
* - [Type.LONG]
* - [Type.SHORT]
* - [Type.BOOLEAN]
* - [Type.STRING]
*/
var constValIndex: Int = -1
internal set
/** The element constant value if the [type] is [Type.ENUM_CLASS]. */
var enumValue: EnumConstValue? = null
internal set
/** The class name index if the [type] is [Type.CLASS]. */
var classNameIndex: Int = -1
internal set
/** The annotation constant value if the [type] is [Type.ANNOTATION_INTERFACE]. */
var annotationValue: Annotation? = null
internal set
/** The array constant value if the [type] is [Type.ARRAY_TYPE]. */
var arrayValue: Array<ElementValue>? = null
internal set
companion object {
internal fun read(input: DataInputStream): ElementValue {
val value = ElementValue()
value.type = Type.forTag(input.readUnsignedByte())
when (value.type) {
ENUM_CLASS -> value.enumValue = EnumConstValue.read(input)
CLASS -> value.classNameIndex = input.readUnsignedShort()
ANNOTATION_INTERFACE -> value.annotationValue = Annotation.read(input)
ARRAY_TYPE -> {
val count = input.readUnsignedShort()
val nullElem = ElementValue()
value.arrayValue = Array(count) { nullElem }
var index = 0
while (index < count) {
value.arrayValue!![index] = read(input)
++index
}
}
else -> value.constValIndex = input.readUnsignedShort()
}
return value
}
}
/**
* The enum constant value.
*
* @property typeNameIndex The index of the entry in the constant pool which corresponds to the
* name of the type of this constant.
* @property constNameIndex The index of the entry in the constant pool which corresponds to the
* name of this constant.
*/
data class EnumConstValue(val typeNameIndex: Int, val constNameIndex: Int) {
companion object {
internal fun read(input: DataInputStream): EnumConstValue {
return EnumConstValue(input.readUnsignedShort(), input.readUnsignedShort())
}
}
}
/** The type of [ElementValue]. */
enum class Type(val tag: Int) {
BYTE('B'.code),
CHAR('C'.code),
DOUBLE('D'.code),
FLOAT('F'.code),
INT('I'.code),
LONG('J'.code),
SHORT('S'.code),
BOOLEAN('Z'.code),
STRING('s'.code),
ENUM_CLASS('e'.code),
CLASS('c'.code),
ANNOTATION_INTERFACE('@'.code),
ARRAY_TYPE('['.code),
/** **FOR INTERNAL USE ONLY** */
UNKNOWN('-'.code);
companion object {
/** Get the element type for the given tag value. */
internal fun forTag(tag: Int): Type {
return values().firstOrNull { it.tag == tag }
?: throw IllegalArgumentException("Invalid tag for element value type tag '$tag'")
}
}
}
}
@@ -1,106 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_CONSTANT_VALUE
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_DEPRECATED
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_SIGNATURE
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_SYNTHETIC
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.CONSTANT_VALUE
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.DEPRECATED
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_ANNOTATIONS
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_ANNOTATIONS
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SIGNATURE
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SYNTHETIC
import com.itsaky.androidide.classfile.constants.Utf8Constant
import com.itsaky.androidide.classfile.internal.ClassFile
import java.io.DataInputStream
/**
* Base class for all attributes in a class, field or method.
*
* @author Akash Yadav
*/
interface IAttribute {
/** The version of the class file in which this attribute appears. */
val version: ClassFileVersion
/** The index of the entry in the constant pool which represents the name of this attrbute. */
val nameIndex: Int
/** The type of attribute. */
val type: Type
/**
* **FOR INTERNAL USE ONLY**
*
* Read further information from the given input.
*/
fun read(attrLength: Int, file: IClassFile, input: DataInputStream)
enum class Type(val attrName: String) {
CONSTANT_VALUE(ATTR_CONSTANT_VALUE),
SYNTHETIC(ATTR_SYNTHETIC),
SIGNATURE(ATTR_SIGNATURE),
DEPRECATED(ATTR_DEPRECATED),
RUNTIME_VISIBLE_ANNOTATIONS(ATTR_RUNTIME_VISIBLE_ANNOTATIONS),
RUNTIME_INVISIBLE_ANNOTATIONS(ATTR_RUNTIME_INVISIBLE_ANNOTATIONS),
RUNTIME_VISIBLE_TYPE_ANNOTATIONS(ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS),
RUNTIME_INVISIBLE_TYPE_ANNOTATIONS(ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
companion object {
internal fun forName(name: String): Type {
return values().firstOrNull { it.attrName == name }
?: throw IllegalArgumentException("Unknown attribute '$name'")
}
}
}
companion object {
internal fun read(input: DataInputStream, file: ClassFile): IAttribute {
val nameIndex = input.readUnsignedShort()
val attrLength = input.readInt()
val name = (file.constantPool[nameIndex] as Utf8Constant).content()
val type = Type.forName(name)
return createForType(type, nameIndex).also { it.read(attrLength, file, input) }
}
private fun createForType(type: Type, nameIndex: Int): IAttribute {
return when (type) {
CONSTANT_VALUE -> ConstantValueAttr(nameIndex)
SYNTHETIC -> SyntheticAttr(nameIndex)
SIGNATURE -> SignatureAttr(nameIndex)
DEPRECATED -> DeprecatedAttr(nameIndex)
RUNTIME_VISIBLE_ANNOTATIONS -> RuntimeVisibleAnnotationsAttr(nameIndex)
RUNTIME_INVISIBLE_ANNOTATIONS -> RuntimeVisibleAnnotationsAttr(nameIndex)
RUNTIME_VISIBLE_TYPE_ANNOTATIONS -> RuntimeVisibleTypeAnnotations(nameIndex)
RUNTIME_INVISIBLE_TYPE_ANNOTATIONS -> RuntimeInvisibleTypeAnnotations(nameIndex)
else -> throw IllegalArgumentException("Unknown attribute type $type")
}
}
}
}
@@ -1,36 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import java.io.DataInputStream
/**
* An attribute which is simply a marker and does not contain any further information.
*
* @author Akash Yadav
*/
abstract class MarkerAttribute(
nameIndex: Int,
override val type: Type,
override val version: ClassFileVersion
) : BaseAttribute(nameIndex) {
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {}
}
@@ -1,31 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_ANNOTATIONS
/**
* Stores run-time invisible annotations on the declaration of the corresponding class, method,
* field, or record component.
*
* @author Akash Yadav
*/
class RuntimeInvisibleAnnotationsAttr(nameIndex: Int) : AnnotationAttr(nameIndex) {
override val type: Type = RUNTIME_INVISIBLE_ANNOTATIONS
}
@@ -1,37 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
/**
* Stores run-time invisible annotations on type parameter declarations of generic classes,
* interfaces, methods, and constructors.
*
* @author Akash Yadav
*/
class RuntimeInvisibleTypeAnnotations(nameIndex: Int) : AnnotationAttr(nameIndex) {
override val type: Type = RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
/**
* The annotations always of type [TypeAnnotation]
*/
var typeAnnotations: Array<TypeAnnotation> = emptyArray()
}
@@ -1,30 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_ANNOTATIONS
/**
* Stores run-time visible annotations on the declaration of the corresponding class, field, method,
* or record component.
* @author Akash Yadav
*/
class RuntimeVisibleAnnotationsAttr(nameIndex: Int) : AnnotationAttr(nameIndex) {
override val type: Type = RUNTIME_VISIBLE_ANNOTATIONS
}
@@ -1,36 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
/**
* Stores run-time visible annotations on type parameter declarations of generic classes,
* interfaces, methods, and constructors.
*
* @author Akash Yadav
*/
class RuntimeVisibleTypeAnnotations(nameIndex: Int) : AnnotationAttr(nameIndex) {
override val type: Type = RUNTIME_VISIBLE_TYPE_ANNOTATIONS
/**
* The annotations always of type [TypeAnnotation]
*/
var typeAnnotations: Array<TypeAnnotation> = emptyArray()
}
@@ -1,42 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_5
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SIGNATURE
import java.io.DataInputStream
/**
* Signature of a class, field or method.
*
* @author Akash Yadav
*/
class SignatureAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
override val version: ClassFileVersion = JAVA_5
override val type: Type = SIGNATURE
var signatureIndex: Int = -1
internal set
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
this.signatureIndex = input.readUnsignedShort()
}
}
@@ -1,28 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_1
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SYNTHETIC
/**
* Indicates that a class, field or method is synthetic.
*
* @author Akash Yadav
*/
class SyntheticAttr(nameIndex: Int) : MarkerAttribute(nameIndex, SYNTHETIC, JAVA_1_1)
@@ -1,59 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import java.io.DataInputStream
/**
* Annotation model for (in)visible type annotations.
*
* @author Akash Yadav
*/
class TypeAnnotation {
lateinit var targetInfo: TargetInfo
internal set
lateinit var typePath: TypePath
internal set
/**
* Index of the entry in the constant pool which corresponds to the type of the the annotation.
* The entry at this index is always an UTF-8 constant.
*/
var typeIndex: Int = -1
internal set
/** The element value pairs. */
var elementValues: Array<Pair<Int, ElementValue>> = emptyArray()
internal set
companion object {
internal fun read(input: DataInputStream): TypeAnnotation {
val annotation = TypeAnnotation()
val targetType = input.readUnsignedByte()
annotation.targetInfo = TargetInfo.forType(targetType).apply { read(input) }
annotation.typePath = TypePath().apply { read(input) }
annotation.typeIndex = input.readUnsignedShort()
val valueCount = input.readUnsignedShort()
annotation.elementValues =
Array(valueCount) { input.readUnsignedShort() to ElementValue.read(input) }
return annotation
}
}
}
@@ -1,54 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import java.io.DataInputStream
/**
* Wherever a type is used in a declaration or expression, the type_path structure identifies which
* part of the type is annotated. An annotation may appear on the type itself, but if the type is a
* reference type, then there are additional locations where an annotation may appear.
*
* @author Akash Yadav
*/
class TypePath {
var paths: Array<PathEntry> = emptyArray()
internal set
class PathEntry {
var typePathKind: Int = -1
internal set
var typeArgumentIndex: Int = -1
internal set
internal fun read(input: DataInputStream) {
this.typePathKind = input.readUnsignedByte()
this.typeArgumentIndex = input.readUnsignedByte()
}
}
internal fun read(input: DataInputStream) {
this.paths =
Array(input.readUnsignedByte()) {
val entry = PathEntry()
entry.read(input)
entry
}
}
}
@@ -1,210 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.attributes
import java.io.DataInputStream
/**
* Target information in a type annotation.
*
* @author Akash Yadav
*/
abstract class TargetInfo(val currentType: Int, val types: IntArray) {
/** The read the target info. */
internal abstract fun read(input: DataInputStream)
companion object {
internal fun forType(type: Int): TargetInfo {
return when (type) {
0x00,
0x01 -> TypeParameterTarget(type)
0x10 -> SupertypeTarget(type)
0x11,
0x12 -> TypeParameterBoundTarget(type)
0x13,
0x14,
0x15 -> EmptyTarget(type)
0x16 -> FormalParameterTarget(type)
0x17 -> ThrowsTarget(type)
0x40,
0x41 -> LocalVarTarget(type)
0x42 -> CatchTarget(type)
0x43,
0x44,
0x45,
0x46 -> OffsetTarget(type)
0x47,
0x48,
0x49,
0x4A,
0x4B -> TypeArgumentTarget(type)
else -> throw IllegalArgumentException("Unknown type parameter target")
}
}
}
}
open class TypeParameterTarget
@JvmOverloads
constructor(currentType: Int, types: IntArray = intArrayOf(0x00, 0x01)) :
TargetInfo(currentType, types) {
/**
* The value of the type_parameter_index item specifies which type parameter declaration is
* annotated. A type_parameter_index value of 0 specifies the first type parameter declaration.
*/
var typeParameterIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.typeParameterIndex = input.readUnsignedByte()
}
}
class SupertypeTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x10)) {
/**
* A supertype_index value of 65535 specifies that the annotation appears on the superclass in an
* extends clause of a class declaration.
*
* Any other supertype_index value is an index into the interfaces array of the enclosing
* ClassFile structure, and specifies that the annotation appears on that superinterface in either
* the implements clause of a class declaration or the extends clause of an interface declaration.
*/
var supertypeIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.supertypeIndex = input.readUnsignedShort()
}
}
class TypeParameterBoundTarget(currentType: Int) :
TypeParameterTarget(currentType, intArrayOf(0x11, 0x12)) {
/**
* The value of the bound_index item specifies which bound of the type parameter declaration
* indicated by type_parameter_index is annotated. A bound_index value of 0 specifies the first
* bound of a type parameter declaration.
*/
var boundIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
super.read(input)
this.boundIndex = input.readUnsignedShort()
}
}
class EmptyTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x13, 0x14, 0x15)) {
override fun read(input: DataInputStream) {}
}
class FormalParameterTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x16)) {
/**
* The value of the formal_parameter_index item specifies which formal parameter declaration has
* an annotated type. A formal_parameter_index value of i may, but is not required to, correspond
* to the i'th parameter descriptor in the method descriptor.
*/
var formalParameterIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.formalParameterIndex = input.readUnsignedByte()
}
}
class ThrowsTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x17)) {
/**
* The value of the throws_type_index item is an index into the exception_index_table array of the
* Exceptions attribute of the method_info structure enclosing the RuntimeVisibleTypeAnnotations
* attribute.
*/
var throwsTypeIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.throwsTypeIndex = input.readUnsignedShort()
}
}
class LocalVarTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x40, 0x41)) {
var table: Array<LocalVarTagetTableEntry> = emptyArray()
class LocalVarTagetTableEntry {
var startPc: Int = -1
internal set
var length: Int = -1
internal set
var index: Int = -1
internal set
}
override fun read(input: DataInputStream) {
val length = input.readUnsignedShort()
this.table =
Array(length) {
val entry = LocalVarTagetTableEntry()
entry.startPc = input.readUnsignedShort()
entry.length = input.readUnsignedShort()
entry.index = input.readUnsignedShort()
entry
}
}
}
class CatchTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x42)) {
var exceptionTableIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.exceptionTableIndex = input.readUnsignedShort()
}
}
class OffsetTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x43, 0x44, 0x45, 0x46)) {
var offset: Int = -1
internal set
override fun read(input: DataInputStream) {
this.offset = input.readUnsignedShort()
}
}
class TypeArgumentTarget(currentType: Int) :
TargetInfo(currentType, intArrayOf(0x47, 0x48, 0x49, 0x4A, 0x4B)) {
var offset: Int = -1
internal set
var typeArgumentIndex: Int = -1
internal set
override fun read(input: DataInputStream) {
this.offset = input.readUnsignedShort()
this.typeArgumentIndex = input.readUnsignedByte()
}
}
@@ -1,61 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.CLASS
import java.io.DataInputStream
/**
* A class name constant in the constant pool of class file.
*
* @property nameIndex The index of the name constant in the constant pool. The constant entry at
* this index is always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class ClassConstant() : IConstant {
var nameIndex: Int = -1
private set
override val type: Type = CLASS
override fun read(input: DataInputStream) {
this.nameIndex = input.readUnsignedShort()
}
override fun toString(): String {
return "ClassConstant(nameIndex=$nameIndex, type=$type)"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ClassConstant) return false
if (nameIndex != other.nameIndex) return false
if (type != other.type) return false
return true
}
override fun hashCode(): Int {
var result = nameIndex
result = 31 * result + type.hashCode()
return result
}
}
@@ -1,60 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.DOUBLE
import java.io.DataInputStream
/**
* A double constant in the constant pool of class file.
*
* @property value The value of this constant.
* @author Akash Yadav
*/
class DoubleConstant : IConstant {
override val type: Type = DOUBLE
var value: Double = 0.0
private set
override fun read(input: DataInputStream) {
this.value = input.readDouble()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is DoubleConstant) return false
if (type != other.type) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + value.hashCode()
return result
}
override fun toString(): String {
return "DoubleConstant(type=$type, value=$value)"
}
}
@@ -1,69 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import java.io.DataInputStream
/**
* **NOT SUPPORTED**
*
* A constant of type [IConstant.Type.DYNAMIC] or [IConstant.Type.INVOKE_DYNAMIC] in the constant
* pool of class file.
*
* @property bootstrapMethodAttrIndex The index into the bootstrap_methods array of the bootstrap
* method table of the class file.
* @property nameTypeIndex The index of the name and type constant in the constant pool. The entry
* at this index is always of type [IConstant.Type.NAME_AND_TYPE].
* @author Akash Yadav
*/
class DynamicConstant(override val type: Type) :
IConstant {
var bootstrapMethodAttrIndex: Int = -1
private set
var nameTypeIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.bootstrapMethodAttrIndex = input.readUnsignedShort()
this.nameTypeIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is DynamicConstant) return false
if (type != other.type) return false
if (bootstrapMethodAttrIndex != other.bootstrapMethodAttrIndex) return false
if (nameTypeIndex != other.nameTypeIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + bootstrapMethodAttrIndex
result = 31 * result + nameTypeIndex
return result
}
override fun toString(): String {
return "DynamicConstant(type=$type, bootstrapMethodAttrIndex=$bootstrapMethodAttrIndex, nameTypeIndex=$nameTypeIndex)"
}
}
@@ -1,60 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.FLOAT
import java.io.DataInputStream
/**
* A float constant in the constant pool of class file.
*
* @property value The value of this constant.
* @author Akash Yadav
*/
class FloatConstant : IConstant {
override val type: Type = FLOAT
var value: Float = 0f
private set
override fun read(input: DataInputStream) {
this.value = input.readFloat()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is FloatConstant) return false
if (type != other.type) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + value.hashCode()
return result
}
override fun toString(): String {
return "FloatConstant(type=$type, value=$value)"
}
}
@@ -1,116 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type.CLASS
import com.itsaky.androidide.classfile.constants.IConstant.Type.DOUBLE
import com.itsaky.androidide.classfile.constants.IConstant.Type.DYNAMIC
import com.itsaky.androidide.classfile.constants.IConstant.Type.FIELD_REF
import com.itsaky.androidide.classfile.constants.IConstant.Type.FLOAT
import com.itsaky.androidide.classfile.constants.IConstant.Type.INTEGER
import com.itsaky.androidide.classfile.constants.IConstant.Type.INTERFACE_METHOD_REF
import com.itsaky.androidide.classfile.constants.IConstant.Type.INVOKE_DYNAMIC
import com.itsaky.androidide.classfile.constants.IConstant.Type.LONG
import com.itsaky.androidide.classfile.constants.IConstant.Type.METHOD_HANDLE
import com.itsaky.androidide.classfile.constants.IConstant.Type.METHOD_REF
import com.itsaky.androidide.classfile.constants.IConstant.Type.METHOD_TYPE
import com.itsaky.androidide.classfile.constants.IConstant.Type.MODULE
import com.itsaky.androidide.classfile.constants.IConstant.Type.NAME_AND_TYPE
import com.itsaky.androidide.classfile.constants.IConstant.Type.PACKAGE
import com.itsaky.androidide.classfile.constants.IConstant.Type.STRING
import com.itsaky.androidide.classfile.constants.IConstant.Type.UNKNOWN
import com.itsaky.androidide.classfile.constants.IConstant.Type.UTF8
import java.io.DataInputStream
/**
* A constant in a constant pool from a class file.
*
* @property type The type of the constant.
* @author Akash Yadav
*/
interface IConstant {
val type: Type
/** Reads the data from the given [DataInputStream]. */
fun read(input: DataInputStream)
/**
* The type of the [IConstant].
*
* @author Akash Yadav
*/
enum class Type(val tag: Int) {
UTF8(1),
INTEGER(3),
FLOAT(4),
LONG(5),
DOUBLE(6),
CLASS(7),
STRING(8),
FIELD_REF(9),
METHOD_REF(10),
INTERFACE_METHOD_REF(11),
NAME_AND_TYPE(12),
METHOD_HANDLE(15),
METHOD_TYPE(16),
DYNAMIC(17),
INVOKE_DYNAMIC(18),
MODULE(19),
PACKAGE(20),
/** FOR INTERNAL USE ONLY! */
UNKNOWN(-1)
}
companion object {
@JvmStatic
fun forTag(tag: Int): Type {
for (value in Type.values()) {
if (value != UNKNOWN && value.tag == tag) {
return value
}
}
throw IllegalArgumentException("Unsupported or unknown constant pool tag: '$tag'")
}
@JvmStatic
fun forType(type: Type): IConstant {
return when (type) {
UTF8 -> Utf8Constant()
INTEGER -> IntegerConstant()
FLOAT -> FloatConstant()
LONG -> LongConstant()
DOUBLE -> DoubleConstant()
CLASS -> ClassConstant()
STRING -> StringConstant()
FIELD_REF,
METHOD_REF,
INTERFACE_METHOD_REF -> ReferenceConstant(type)
NAME_AND_TYPE -> NameAndTypeConstant()
METHOD_HANDLE -> MethodHandleConstant()
METHOD_TYPE -> MethodTypeConstant()
DYNAMIC,
INVOKE_DYNAMIC -> DynamicConstant(type)
MODULE -> ModuleConstant()
PACKAGE -> PackageConstant()
UNKNOWN -> throw IllegalArgumentException("$type is not allowed or not supported.")
}
}
}
}
@@ -1,58 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.INTEGER
import java.io.DataInputStream
/**
* An integer constant in the constant pool of class file.
*
* @property value The value of this constant.
* @author Akash Yadav
*/
class IntegerConstant : IConstant {
override val type: Type = INTEGER
var value: Int = 0
private set
override fun read(input: DataInputStream) {
this.value = input.readInt()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is IntegerConstant) return false
if (type != other.type) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + value
return result
}
override fun toString(): String {
return "IntegerConstant(type=$type, value=$value)"
}
}
@@ -1,58 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.LONG
import java.io.DataInputStream
/**
* A long constant in the constant pool of class file.
*
* @property value The value of this constant.
* @author Akash Yadav
*/
class LongConstant : IConstant {
override val type: Type = LONG
var value: Long = 0L
private set
override fun read(input: DataInputStream) {
this.value = input.readLong()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is LongConstant) return false
if (type != other.type) return false
if (value != other.value) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + value.hashCode()
return result
}
override fun toString(): String {
return "LongConstant(type=$type, value=$value)"
}
}
@@ -1,97 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.METHOD_HANDLE
import com.itsaky.androidide.classfile.constants.MethodHandleConstant.ReferenceKind.UNKNOWN
import java.io.DataInputStream
/**
* A method handle constant in the constant pool of class file.
*
* @property referenceKind The kind of the reference.
* @property referenceIndex The index of the reference constant in the constant pool. The type of
* the entry in the constant pool at this index depends on [referenceKind].
* @author Akash Yadav
*/
class MethodHandleConstant : IConstant {
override val type: Type = METHOD_HANDLE
var referenceKind: ReferenceKind = UNKNOWN
private set
var referenceIndex: Int = -1
private set
@Suppress("EnumEntryName")
enum class ReferenceKind(val kind: Int) {
REF_getField(1),
REF_getStatic(2),
REF_putField(3),
REF_putStatic(4),
REF_invokeVirtual(5),
REF_invokeStatic(6),
REF_invokeSpecial(7),
REF_newInvokeSpecial(8),
REF_invokeInterface(9),
/**
* FOR INTERNAL USE ONLY!
*/
UNKNOWN(-1)
}
override fun read(input: DataInputStream) {
this.referenceKind = kindFor(input.readUnsignedByte())
this.referenceIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is MethodHandleConstant) return false
if (type != other.type) return false
if (referenceKind != other.referenceKind) return false
if (referenceIndex != other.referenceIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + referenceKind.hashCode()
result = 31 * result + referenceIndex
return result
}
override fun toString(): String {
return "MethodHandleConstant(type=$type, referenceKind=$referenceKind, referenceIndex=$referenceIndex)"
}
companion object {
@JvmStatic
fun kindFor(kind: Int): ReferenceKind {
for (value in ReferenceKind.values()) {
if (value != UNKNOWN && value.kind == kind) {
return value
}
}
throw IllegalArgumentException("Invalid reference kind: '$kind'")
}
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.METHOD_TYPE
import java.io.DataInputStream
/**
* A method type constant in the constant pool of class file.
*
* @property descriptorIndex The index of the constant in the constant pool describing this
* constant. The entry at this index is always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class MethodTypeConstant : IConstant {
override val type: Type = METHOD_TYPE
var descriptorIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.descriptorIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is MethodTypeConstant) return false
if (type != other.type) return false
if (descriptorIndex != other.descriptorIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + descriptorIndex
return result
}
override fun toString(): String {
return "MethodTypeConstant(type=$type, descriptorIndex=$descriptorIndex)"
}
}
@@ -1,58 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.MODULE
import java.io.DataInputStream
/**
* A module info constant in the constant pool of class file.
*
* @property nameIndex The index of the name constant the constant pool. The entry at this index is always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class ModuleConstant : IConstant {
override val type: Type = MODULE
var nameIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.nameIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ModuleConstant) return false
if (type != other.type) return false
if (nameIndex != other.nameIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + nameIndex
return result
}
override fun toString(): String {
return "ModuleConstant(type=$type, nameIndex=$nameIndex)"
}
}
@@ -1,67 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.NAME_AND_TYPE
import java.io.DataInputStream
/**
* A constant that describes the name and type of [ReferenceConstant] and [DynamicConstant] in the
* constant pool of class file.
*
* @property nameIndex The index of the constant in the constant pool which corresponds to the name
* of this constant. The entry at this index is always of type [IConstant.Type.UTF8].
* @property descriptorIndex The index of the constant in the constant pool which corresponds to the
* descriptor of this constant. The entry at this index is always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class NameAndTypeConstant : IConstant {
override val type: Type = NAME_AND_TYPE
var nameIndex: Int = -1
private set
var descriptorIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.nameIndex = input.readUnsignedShort()
this.descriptorIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is NameAndTypeConstant) return false
if (type != other.type) return false
if (nameIndex != other.nameIndex) return false
if (descriptorIndex != other.descriptorIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + nameIndex
result = 31 * result + descriptorIndex
return result
}
override fun toString(): String {
return "NameAndTypeConstant(type=$type, nameIndex=$nameIndex, descriptorIndex=$descriptorIndex)"
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.MODULE
import com.itsaky.androidide.classfile.constants.IConstant.Type.PACKAGE
import java.io.DataInputStream
/**
* A package info constant in the constant pool of class file.
*
* @property nameIndex The index of the name constant the constant pool. The entry at this index is always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class PackageConstant : IConstant {
override val type: Type = PACKAGE
var nameIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.nameIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PackageConstant) return false
if (type != other.type) return false
if (nameIndex != other.nameIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + nameIndex
return result
}
override fun toString(): String {
return "PackageConstant(type=$type, nameIndex=$nameIndex)"
}
}
@@ -1,70 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import java.io.DataInputStream
/**
* A reference constant in the constant pool of class file.
*
* Type [type] is always one of the following :
* - [IConstant.Type.FIELD_REF]
* - [IConstant.Type.METHOD_REF]
* - [IConstant.Type.INTERFACE_METHOD_REF]
*
* @property classIndex The index of the class constant in the constant pool. The entry at this
* index is always of type [IConstant.Type.CLASS].
* @property nameTypeIndex The index of the name and type constant in the constant pool. The entry
* at this index is always of type [IConstant.Type.NAME_AND_TYPE].
* @author Akash Yadav
*/
class ReferenceConstant(override val type: Type) : IConstant {
var classIndex: Int = -1
private set
var nameTypeIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.classIndex = input.readUnsignedShort()
this.nameTypeIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ReferenceConstant) return false
if (type != other.type) return false
if (classIndex != other.classIndex) return false
if (nameTypeIndex != other.nameTypeIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + classIndex
result = 31 * result + nameTypeIndex
return result
}
override fun toString(): String {
return "ReferenceConstant(type=$type, classIndex=$classIndex, nameTypeIndex=$nameTypeIndex)"
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.STRING
import java.io.DataInputStream
/**
* A string constant in the constant pool of class file.
*
* @property stringIndex The index of the constant in the constant pool. The entry at this index is
* always of type [IConstant.Type.UTF8].
* @author Akash Yadav
*/
class StringConstant : IConstant {
override val type: Type = STRING
var stringIndex: Int = -1
private set
override fun read(input: DataInputStream) {
this.stringIndex = input.readUnsignedShort()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is StringConstant) return false
if (type != other.type) return false
if (stringIndex != other.stringIndex) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + stringIndex
return result
}
override fun toString(): String {
return "StringConstant(type=$type, stringIndex=$stringIndex)"
}
}
@@ -1,64 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.constants
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.UTF8
import java.io.DataInputStream
/**
* A UTF-8 constant in the constant pool.
*
* @property bytes The bytes of this UTF-8 constant. This always has a length of
* [Utf8Constant.length].
* @author Akash Yadav
*/
class Utf8Constant : IConstant {
override val type: Type = UTF8
var bytes: ByteArray = ByteArray(0)
private set
/** Get the string represented by this constant. */
fun content() = this.bytes.decodeToString()
override fun read(input: DataInputStream) {
val length = input.readUnsignedShort()
this.bytes = ByteArray(length)
input.readFully(bytes)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Utf8Constant) return false
if (type != other.type) return false
if (!bytes.contentEquals(other.bytes)) return false
return true
}
override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + bytes.contentHashCode()
return result
}
override fun toString(): String {
return "Utf8Constant(type=$type, bytes=${bytes.contentToString()}, bytesAsString=${content()})"
}
}
@@ -1,70 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.internal
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_0
import com.itsaky.androidide.classfile.constants.IConstant
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.IFieldInfo
import com.itsaky.androidide.classfile.constants.ClassConstant
import com.itsaky.androidide.classfile.constants.Utf8Constant
/**
* Model class for holding information about class files.
*
* @author Akash Yadav
*/
internal class ClassFile : IClassFile {
override var version: ClassFileVersion = JAVA_1_0
override var constantPool: Array<IConstant> = emptyArray()
override var accessFlags: Int = 0
override var thisClass: Int = -1
override var superClass: Int = -1
override var interfaces: IntArray = IntArray(0)
override var fields: Array<IFieldInfo> = emptyArray()
override fun getName(): String {
val entry = constantPool[thisClass]
if (entry !is ClassConstant) {
throw IllegalStateException("Invalid constant at index: '$thisClass'")
}
val nameEntry = constantPool[entry.nameIndex]
if (nameEntry !is Utf8Constant) {
throw IllegalStateException("Invalid constant at index: '$thisClass'")
}
return nameEntry.bytes.decodeToString()
}
override fun getSuperClassName(): String {
val entry = constantPool[superClass]
if (entry !is ClassConstant) {
throw IllegalStateException("Invalid constant at index: '$superClass'")
}
val nameEntry = constantPool[entry.nameIndex]
if (nameEntry !is Utf8Constant) {
throw IllegalStateException("Invalid constant at index: '$superClass'")
}
return nameEntry.bytes.decodeToString()
}
}
@@ -1,37 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.internal
import com.itsaky.androidide.classfile.IFieldInfo
import com.itsaky.androidide.classfile.attributes.IAttribute
/**
* Default internal implementation of [IFieldInfo].
*
* @author Akash Yadav
*/
internal class FieldInfo : IFieldInfo {
override var accessFlags: Int = 0
internal set
override var nameIndex: Int = -1
internal set
override var descriptorIndex: Int = -1
internal set
override var attributes: Array<IAttribute> = emptyArray()
internal set
}
@@ -1,44 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.internal
import com.itsaky.androidide.classfile.ClassFileVersion
import com.itsaky.androidide.classfile.IClassFile
import com.itsaky.androidide.classfile.attributes.IAttribute
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
import java.io.DataInputStream
/**
* **FOR INTERNAL USE ONLY**
*
* Represents a null attribute. Not present in a class file.
*
* @author Akash Yadav
*/
internal object NullAttribute : IAttribute {
override val version: ClassFileVersion
get() = throw UnsupportedOperationException()
override val nameIndex: Int
get() = throw UnsupportedOperationException()
override val type: Type
get() = throw UnsupportedOperationException()
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
throw UnsupportedOperationException()
}
}
@@ -1,32 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.internal
import com.itsaky.androidide.classfile.constants.IConstant
import com.itsaky.androidide.classfile.constants.IConstant.Type
import com.itsaky.androidide.classfile.constants.IConstant.Type.UNKNOWN
import java.io.DataInputStream
/** @author Akash Yadav */
object NullConstant : IConstant {
override val type: Type = UNKNOWN
override fun read(input: DataInputStream) {
throw UnsupportedOperationException()
}
}
@@ -1,39 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile.internal
import com.itsaky.androidide.classfile.IFieldInfo
import com.itsaky.androidide.classfile.attributes.IAttribute
/**
* **FOR INTERNAL USE ONLY**
*
* Represents a null field. Not available in class file.
*
* @author Akash Yadav
*/
internal object NullField : IFieldInfo {
override val accessFlags: Int
get() = throw UnsupportedOperationException()
override val nameIndex: Int
get() = throw UnsupportedOperationException()
override val descriptorIndex: Int
get() = throw UnsupportedOperationException()
override val attributes: Array<IAttribute>
get() = throw UnsupportedOperationException()
}
@@ -1,107 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.classfile
import com.google.common.truth.Truth.assertThat
import com.itsaky.androidide.classfile.constants.ClassConstant
import com.itsaky.androidide.classfile.constants.Utf8Constant
import java.io.File
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/** @author Akash Yadav */
@RunWith(JUnit4::class)
class ClassFileReaderTest {
// Extension changed to .txt to prevent git from ignoring this file
private val codeEditor = File("./src/test/resources/CodeEditor.class.txt")
@Test
fun `basic test`() {
val input = codeEditor.inputStream()
val reader = ClassFileReader(input)
val file = reader.read()
assertThat(file).isNotNull()
assertThat(file.version).isEqualTo(ClassFileVersion.JAVA_11)
checkBaseNames(file)
checkInterfaces(file)
checkFIelds(file)
checkAccessFlags(file)
}
private fun checkAccessFlags(file: IClassFile) {
assertThat(file.accessFlags and ClassFileConstants.ACC_PUBLIC).isNotEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_SUPER).isNotEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_ABSTRACT).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_FINAL).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_ANNOTATION).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_ENUM).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_INTERFACE).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_MODULE).isEqualTo(0)
assertThat(file.accessFlags and ClassFileConstants.ACC_SYNTHETIC).isEqualTo(0)
}
private fun checkFIelds(file: IClassFile) {
file.fields
.firstOrNull {
(file.constantPool[it.nameIndex] as Utf8Constant).content() == "mTextActionWindow"
}
.apply {
assertThat(this).isNotNull()
val name = (file.constantPool[this!!.nameIndex] as Utf8Constant).content()
assertThat(name).isEqualTo("mTextActionWindow")
val descriptor = (file.constantPool[this.descriptorIndex] as Utf8Constant).content()
assertThat(descriptor)
.isEqualTo("Lio/github/rosemoe/sora/widget/component/EditorTextActionWindow;")
assertThat(this.accessFlags and ClassFileConstants.ACC_PROTECTED).isNotEqualTo(0)
assertThat(this.accessFlags and ClassFileConstants.ACC_PRIVATE).isEqualTo(0)
assertThat(this.accessFlags and ClassFileConstants.ACC_PUBLIC).isEqualTo(0)
}
}
private fun checkInterfaces(file: IClassFile) {
file.interfaces
.map { file.constantPool[it] }
.filterIsInstance<ClassConstant>()
.map { file.constantPool[it.nameIndex] }
.filterIsInstance<Utf8Constant>()
.map { it.bytes.decodeToString() }
.apply {
assertThat(this).isNotEmpty()
assertThat(this.size).isEqualTo(3)
assertThat(this)
.containsExactly(
"io/github/rosemoe/sora/text/ContentListener",
"io/github/rosemoe/sora/text/FormatThread\$FormatResultReceiver",
"io/github/rosemoe/sora/text/LineRemoveListener"
)
}
}
private fun checkBaseNames(file: IClassFile) {
assertThat(file.getName()).isEqualTo("io/github/rosemoe/sora/widget/CodeEditor")
assertThat(file.getSuperClassName()).isEqualTo("android/view/View")
}
}
File diff suppressed because it is too large Load Diff