org.eclipse.jdt.internal.compiler.classfmt.ModuleInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* Copyright (c) 2016, 2017 IBM Corporation.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.classfmt;
import java.net.URI;
import java.util.Arrays;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.eclipse.jdt.internal.compiler.env.IBinaryModule;
import org.eclipse.jdt.internal.compiler.env.IModule;
public class ModuleInfo extends ClassFileStruct implements IBinaryModule {
protected int flags;
protected int requiresCount;
protected int exportsCount;
protected int usesCount;
protected int providesCount;
protected int opensCount;
protected char[] name;
protected char[] version;
protected ModuleReferenceInfo[] requires;
protected PackageExportInfo[] exports;
protected PackageExportInfo[] opens;
char[][] uses;
IModule.IService[] provides;
protected AnnotationInfo[] annotations;
private long tagBits;
public URI path;
@Override
public boolean isOpen() {
return (this.flags & ClassFileConstants.ACC_OPEN) != 0;
}
public int requiresCount() {
return this.requiresCount;
}
public int exportsCount() {
return this.exportsCount;
}
public int usesCount() {
return this.usesCount;
}
public int providesCount() {
return this.providesCount;
}
@Override
public char[] name() {
return this.name;
}
public void setName(char[] name) {
this.name = name;
}
@Override
public IModule.IModuleReference[] requires() {
return this.requires;
}
@Override
public IModule.IPackageExport[] exports() {
return this.exports;
}
@Override
public char[][] uses() {
return this.uses;
}
@Override
public IService[] provides() {
return this.provides;
}
@Override
public IModule.IPackageExport[] opens() {
return this.opens;
}
@Override
public IBinaryAnnotation[] getAnnotations() {
return this.annotations;
}
@Override
public long getTagBits() {
return this.tagBits;
}
/**
* @param classFileBytes byte[]
* @param offsets int[]
* @param offset int
*/
protected ModuleInfo (byte classFileBytes[], int offsets[], int offset) {
super(classFileBytes, offsets, offset);
}
/**
* @param classFileBytes bytes of the enclosing class file
* @param offsets constant pool offsets
* @param offset offset to the "Module" attribute
* @return a module info initialized from the "Module" attribute, which was already detected by the caller
*/
public static ModuleInfo createModule(byte classFileBytes[], int offsets[], int offset) {
ModuleInfo module = new ModuleInfo(classFileBytes, offsets, 0);
module.readModuleAttribute(offset+6);
return module;
}
private void readModuleAttribute(int moduleOffset) {
int utf8Offset;
int name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
this.name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(this.name, '/', '.');
moduleOffset += 2;
this.flags = u2At(moduleOffset);
moduleOffset += 2;
int version_index = u2At(moduleOffset);
if (version_index > 0) {
utf8Offset = this.constantPoolOffsets[version_index];
this.version = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
}
moduleOffset += 2;
int count = u2At(moduleOffset);
this.requiresCount = count;
this.requires = new ModuleReferenceInfo[count];
moduleOffset += 2;
for (int i = 0; i < count; i++) {
name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
char[] requiresNames = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.requires[i] = this.new ModuleReferenceInfo();
CharOperation.replace(requiresNames, '/', '.');
this.requires[i].refName = requiresNames;
moduleOffset += 2;
int modifiers = u2At(moduleOffset);
this.requires[i].modifiers = modifiers;
this.requires[i].isTransitive = (ClassFileConstants.ACC_TRANSITIVE & modifiers) != 0; // Access modifier
moduleOffset += 2;
version_index = u2At(moduleOffset);
if (version_index > 0) {
utf8Offset = this.constantPoolOffsets[version_index];
this.requires[i].required_version = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
}
moduleOffset += 2;
}
count = u2At(moduleOffset);
moduleOffset += 2;
this.exportsCount = count;
this.exports = new PackageExportInfo[count];
for (int i = 0; i < count; i++) {
name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
char[] exported = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(exported, '/', '.');
PackageExportInfo pack = this.new PackageExportInfo();
this.exports[i] = pack;
pack.packageName = exported;
moduleOffset += 2;
pack.modifiers = u2At(moduleOffset);
moduleOffset += 2;
int exportedtoCount = u2At(moduleOffset);
moduleOffset += 2;
if (exportedtoCount > 0) {
pack.exportedTo = new char[exportedtoCount][];
pack.exportedToCount = exportedtoCount;
for(int k = 0; k < exportedtoCount; k++) {
name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
char[] exportedToName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(exportedToName, '/', '.');
pack.exportedTo[k] = exportedToName;
moduleOffset += 2;
}
}
}
count = u2At(moduleOffset);
moduleOffset += 2;
this.opensCount = count;
this.opens = new PackageExportInfo[count];
for (int i = 0; i < count; i++) {
name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
char[] exported = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(exported, '/', '.');
PackageExportInfo pack = this.new PackageExportInfo();
this.opens[i] = pack;
pack.packageName = exported;
moduleOffset += 2;
pack.modifiers = u2At(moduleOffset);
moduleOffset += 2;
int exportedtoCount = u2At(moduleOffset);
moduleOffset += 2;
if (exportedtoCount > 0) {
pack.exportedTo = new char[exportedtoCount][];
pack.exportedToCount = exportedtoCount;
for(int k = 0; k < exportedtoCount; k++) {
name_index = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(name_index + 1)];
char[] exportedToName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(exportedToName, '/', '.');
pack.exportedTo[k] = exportedToName;
moduleOffset += 2;
}
}
}
count = u2At(moduleOffset);
moduleOffset += 2;
this.usesCount = count;
this.uses = new char[count][];
for (int i = 0; i < count; i++) {
int classIndex = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(classIndex + 1)];
char[] inf = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(inf, '/', '.');
this.uses[i] = inf;
moduleOffset += 2;
}
count = u2At(moduleOffset);
moduleOffset += 2;
this.providesCount = count;
this.provides = new ServiceInfo[count];
for (int i = 0; i < count; i++) {
int classIndex = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(classIndex + 1)];
char[] inf = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(inf, '/', '.');
ServiceInfo service = this.new ServiceInfo();
this.provides[i] = service;
service.serviceName = inf;
moduleOffset += 2;
int implCount = u2At(moduleOffset);
moduleOffset += 2;
service.with = new char[implCount][];
if (implCount > 0) {
service.with = new char[implCount][];
for(int k = 0; k < implCount; k++) {
classIndex = this.constantPoolOffsets[u2At(moduleOffset)];
utf8Offset = this.constantPoolOffsets[u2At(classIndex + 1)];
char[] implName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
CharOperation.replace(implName, '/', '.');
service.with[k] = implName;
moduleOffset += 2;
}
}
}
}
void setAnnotations(AnnotationInfo[] annotationInfos, long tagBits, boolean fullyInitialize) {
this.annotations = annotationInfos;
this.tagBits = tagBits;
if (fullyInitialize) {
for (int i = 0, max = annotationInfos.length; i < max; i++) {
annotationInfos[i].initialize();
}
}
}
class ModuleReferenceInfo implements IModule.IModuleReference {
char[] refName;
boolean isTransitive = false;
int modifiers;
char[] required_version;
@Override
public char[] name() {
return this.refName;
}
@Override
public boolean isTransitive() {
return this.isTransitive;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof IModule.IModuleReference))
return false;
IModule.IModuleReference mod = (IModule.IModuleReference) o;
if (this.modifiers != mod.getModifiers())
return false;
return CharOperation.equals(this.refName, mod.name(), false);
}
@Override
public int hashCode() {
return CharOperation.hashCode(this.refName);
}
@Override
public int getModifiers() {
return this.modifiers;
}
}
class PackageExportInfo implements IModule.IPackageExport {
char[] packageName;
char[][] exportedTo;
int exportedToCount;
int modifiers;
@Override
public char[] name() {
return this.packageName;
}
@Override
public char[][] targets() {
return this.exportedTo;
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
toStringContent(buffer);
return buffer.toString();
}
protected void toStringContent(StringBuffer buffer) {
buffer.append(this.packageName);
if (this.exportedToCount > 0) {
buffer.append(" to "); //$NON-NLS-1$
for(int i = 0; i < this.exportedToCount; i++) {
buffer.append(this.exportedTo[i]);
buffer.append(',').append(' ');
}
}
buffer.append(';').append('\n');
}
}
class ServiceInfo implements IModule.IService {
char[] serviceName;
char[][] with;
@Override
public char[] name() {
return this.serviceName;
}
@Override
public char[][] with() {
return this.with;
}
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof IModule))
return false;
IModule mod = (IModule) o;
if (!CharOperation.equals(this.name, mod.name()))
return false;
return Arrays.equals(this.requires, mod.requires());
}
@Override
public int hashCode() {
int result = 17;
int c = CharOperation.hashCode(this.name);
result = 31 * result + c;
c = Arrays.hashCode(this.requires);
result = 31 * result + c;
return result;
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer(getClass().getName());
toStringContent(buffer);
return buffer.toString();
}
protected void toStringContent(StringBuffer buffer) {
buffer.append("\nmodule "); //$NON-NLS-1$
buffer.append(this.name).append(' ');
buffer.append('{').append('\n');
if (this.requiresCount > 0) {
for(int i = 0; i < this.requiresCount; i++) {
buffer.append("\trequires "); //$NON-NLS-1$
if (this.requires[i].isTransitive) {
buffer.append(" public "); //$NON-NLS-1$
}
buffer.append(this.requires[i].refName);
buffer.append(';').append('\n');
}
}
if (this.exportsCount > 0) {
buffer.append('\n');
for(int i = 0; i < this.exportsCount; i++) {
buffer.append("\texports "); //$NON-NLS-1$
buffer.append(this.exports[i].toString());
}
}
buffer.append('\n').append('}').toString();
}
@Override
public URI getURI() {
return this.path;
}
}