org.aspectj.org.eclipse.jdt.internal.core.BinaryTypeConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - TypeConverters don't set enclosingType - https://bugs.eclipse.org/bugs/show_bug.cgi?id=320841
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core;
import org.aspectj.org.eclipse.jdt.core.Flags;
import org.aspectj.org.eclipse.jdt.core.IField;
import org.aspectj.org.eclipse.jdt.core.IMethod;
import org.aspectj.org.eclipse.jdt.core.IType;
import org.aspectj.org.eclipse.jdt.core.ITypeParameter;
import org.aspectj.org.eclipse.jdt.core.JavaModelException;
import org.aspectj.org.eclipse.jdt.core.Signature;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.TypeConverter;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.aspectj.org.eclipse.jdt.internal.core.util.HashSetOfCharArrayArray;
import org.aspectj.org.eclipse.jdt.internal.core.util.Util;
/**
* Converter from a binary type to an AST type declaration.
*/
public class BinaryTypeConverter extends TypeConverter {
private CompilationResult compilationResult;
private HashSetOfCharArrayArray typeNames;
public BinaryTypeConverter(ProblemReporter problemReporter, CompilationResult compilationResult, HashSetOfCharArrayArray typeNames) {
super(problemReporter, Signature.C_DOLLAR);
this.compilationResult = compilationResult;
this.typeNames = typeNames;
}
public ImportReference[] buildImports(ClassFileReader reader) {
// add remaining references to the list of type names
// (code extracted from BinaryIndexer#extractReferenceFromConstantPool(...))
int[] constantPoolOffsets = reader.getConstantPoolOffsets();
int constantPoolCount = constantPoolOffsets.length;
for (int i = 0; i < constantPoolCount; i++) {
int tag = reader.u1At(constantPoolOffsets[i]);
char[] name = null;
switch (tag) {
case ClassFileConstants.MethodRefTag :
case ClassFileConstants.InterfaceMethodRefTag :
int constantPoolIndex = reader.u2At(constantPoolOffsets[i] + 3);
int utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[constantPoolIndex] + 3)];
name = reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
break;
case ClassFileConstants.ClassTag :
utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[i] + 1)];
name = reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
break;
}
if (name == null || (name.length > 0 && name[0] == '['))
break; // skip over array references
this.typeNames.add(CharOperation.splitOn('/', name));
}
// convert type names into import references
int typeNamesLength = this.typeNames.size();
ImportReference[] imports = new ImportReference[typeNamesLength];
char[][][] set = this.typeNames.set;
int index = 0;
for (int i = 0, length = set.length; i < length; i++) {
char[][] typeName = set[i];
if (typeName != null) {
imports[index++] = new ImportReference(typeName, new long[typeName.length]/*dummy positions*/, false/*not on demand*/, 0);
}
}
return imports;
}
/**
* Convert a binary type into an AST type declaration and put it in the given compilation unit.
*/
public TypeDeclaration buildTypeDeclaration(IType type, CompilationUnitDeclaration compilationUnit) throws JavaModelException {
PackageFragment pkg = (PackageFragment) type.getPackageFragment();
char[][] packageName = Util.toCharArrays(pkg.names);
if (packageName.length > 0) {
compilationUnit.currentPackage = new ImportReference(packageName, new long[]{0}, false, ClassFileConstants.AccDefault);
}
/* convert type */
TypeDeclaration typeDeclaration = convert(type, null, null);
IType alreadyComputedMember = type;
IType parent = type.getDeclaringType();
TypeDeclaration previousDeclaration = typeDeclaration;
while(parent != null) {
TypeDeclaration declaration = convert(parent, alreadyComputedMember, previousDeclaration);
alreadyComputedMember = parent;
previousDeclaration = declaration;
parent = parent.getDeclaringType();
}
compilationUnit.types = new TypeDeclaration[]{previousDeclaration};
return typeDeclaration;
}
private FieldDeclaration convert(IField field, IType type) throws JavaModelException {
TypeReference typeReference = createTypeReference(field.getTypeSignature());
if (typeReference == null) return null;
FieldDeclaration fieldDeclaration = new FieldDeclaration();
fieldDeclaration.name = field.getElementName().toCharArray();
fieldDeclaration.type = typeReference;
fieldDeclaration.modifiers = field.getFlags();
return fieldDeclaration;
}
private AbstractMethodDeclaration convert(IMethod method, IType type) throws JavaModelException {
AbstractMethodDeclaration methodDeclaration;
org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParams = null;
// convert 1.5 specific constructs only if compliance is 1.5 or above
if (this.has1_5Compliance) {
/* convert type parameters */
ITypeParameter[] typeParameters = method.getTypeParameters();
if (typeParameters != null && typeParameters.length > 0) {
int parameterCount = typeParameters.length;
typeParams = new org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
ITypeParameter typeParameter = typeParameters[i];
typeParams[i] =
createTypeParameter(
typeParameter.getElementName().toCharArray(),
stringArrayToCharArray(typeParameter.getBounds()),
0,
0);
}
}
}
if (method.isConstructor()) {
ConstructorDeclaration decl = new ConstructorDeclaration(this.compilationResult);
decl.bits &= ~ASTNode.IsDefaultConstructor;
decl.typeParameters = typeParams;
methodDeclaration = decl;
} else {
MethodDeclaration decl = type.isAnnotation() ? new AnnotationMethodDeclaration(this.compilationResult) : new MethodDeclaration(this.compilationResult);
/* convert return type */
TypeReference typeReference = createTypeReference(method.getReturnType());
if (typeReference == null) return null;
decl.returnType = typeReference;
decl.typeParameters = typeParams;
methodDeclaration = decl;
}
methodDeclaration.selector = method.getElementName().toCharArray();
int flags = method.getFlags();
boolean isVarargs = Flags.isVarargs(flags);
methodDeclaration.modifiers = flags & ~Flags.AccVarargs;
/* convert arguments */
String[] argumentTypeNames = method.getParameterTypes();
String[] argumentNames = method.getParameterNames();
int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
// Ignore synthetic arguments (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=212224)
int startIndex = (method.isConstructor() && type.isMember() && !Flags.isStatic(type.getFlags())) ? 1 : 0;
argumentCount -= startIndex;
methodDeclaration.arguments = new Argument[argumentCount];
for (int i = 0; i < argumentCount; i++) {
String argumentTypeName = argumentTypeNames[startIndex+i];
TypeReference typeReference = createTypeReference(argumentTypeName);
if (typeReference == null) return null;
if (isVarargs && i == argumentCount-1) {
typeReference.bits |= ASTNode.IsVarArgs;
}
methodDeclaration.arguments[i] = new Argument(
argumentNames[i].toCharArray(),
0,
typeReference,
ClassFileConstants.AccDefault);
// do not care whether was final or not
}
/* convert thrown exceptions */
String[] exceptionTypeNames = method.getExceptionTypes();
int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
if(exceptionCount > 0) {
methodDeclaration.thrownExceptions = new TypeReference[exceptionCount];
for (int i = 0; i < exceptionCount; i++) {
TypeReference typeReference = createTypeReference(exceptionTypeNames[i]);
if (typeReference == null) return null;
methodDeclaration.thrownExceptions[i] = typeReference;
}
}
return methodDeclaration;
}
private TypeDeclaration convert(IType type, IType alreadyComputedMember,TypeDeclaration alreadyComputedMemberDeclaration) throws JavaModelException {
/* create type declaration - can be member type */
TypeDeclaration typeDeclaration = new TypeDeclaration(this.compilationResult);
if (type.getDeclaringType() != null) {
typeDeclaration.bits |= ASTNode.IsMemberType;
}
typeDeclaration.name = type.getElementName().toCharArray();
typeDeclaration.modifiers = type.getFlags();
/* set superclass and superinterfaces */
if (type.getSuperclassName() != null) {
TypeReference typeReference = createTypeReference(type.getSuperclassTypeSignature());
if (typeReference != null) {
typeDeclaration.superclass = typeReference;
typeDeclaration.superclass.bits |= ASTNode.IsSuperType;
}
}
String[] interfaceTypes = type.getSuperInterfaceTypeSignatures();
int interfaceCount = interfaceTypes == null ? 0 : interfaceTypes.length;
typeDeclaration.superInterfaces = new TypeReference[interfaceCount];
int count = 0;
for (int i = 0; i < interfaceCount; i++) {
TypeReference typeReference = createTypeReference(interfaceTypes[i]);
if (typeReference != null) {
typeDeclaration.superInterfaces[count] = typeReference;
typeDeclaration.superInterfaces[count++].bits |= ASTNode.IsSuperType;
}
}
if (count != interfaceCount) {
System.arraycopy(typeDeclaration.fields, 0, typeDeclaration.superInterfaces = new TypeReference[interfaceCount], 0, interfaceCount);
}
// convert 1.5 specific constructs only if compliance is 1.5 or above
if (this.has1_5Compliance) {
/* convert type parameters */
ITypeParameter[] typeParameters = type.getTypeParameters();
if (typeParameters != null && typeParameters.length > 0) {
int parameterCount = typeParameters.length;
org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParams = new org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
ITypeParameter typeParameter = typeParameters[i];
typeParams[i] =
createTypeParameter(
typeParameter.getElementName().toCharArray(),
stringArrayToCharArray(typeParameter.getBounds()),
0,
0);
}
typeDeclaration.typeParameters = typeParams;
}
}
/* convert member types */
IType[] memberTypes = type.getTypes();
int memberTypeCount = memberTypes == null ? 0 : memberTypes.length;
typeDeclaration.memberTypes = new TypeDeclaration[memberTypeCount];
for (int i = 0; i < memberTypeCount; i++) {
if(alreadyComputedMember != null && alreadyComputedMember.getFullyQualifiedName().equals(memberTypes[i].getFullyQualifiedName())) {
typeDeclaration.memberTypes[i] = alreadyComputedMemberDeclaration;
} else {
typeDeclaration.memberTypes[i] = convert(memberTypes[i], null, null);
}
typeDeclaration.memberTypes[i].enclosingType = typeDeclaration;
}
/* convert fields */
IField[] fields = type.getFields();
int fieldCount = fields == null ? 0 : fields.length;
typeDeclaration.fields = new FieldDeclaration[fieldCount];
count = 0;
for (int i = 0; i < fieldCount; i++) {
FieldDeclaration fieldDeclaration = convert(fields[i], type);
if (fieldDeclaration != null) {
typeDeclaration.fields[count++] = fieldDeclaration;
}
}
if (count != fieldCount) {
System.arraycopy(typeDeclaration.fields, 0, typeDeclaration.fields = new FieldDeclaration[count], 0, count);
}
/* convert methods - need to add default constructor if necessary */
IMethod[] methods = type.getMethods();
int methodCount = methods == null ? 0 : methods.length;
/* source type has a constructor ? */
/* by default, we assume that one is needed. */
int neededCount = 1;
for (int i = 0; i < methodCount; i++) {
if (methods[i].isConstructor()) {
neededCount = 0;
// Does not need the extra constructor since one constructor already exists.
break;
}
}
boolean isInterface = type.isInterface();
neededCount = isInterface ? 0 : neededCount;
typeDeclaration.methods = new AbstractMethodDeclaration[methodCount + neededCount];
if (neededCount != 0) { // add default constructor in first position
typeDeclaration.methods[0] = typeDeclaration.createDefaultConstructor(false, false);
}
boolean hasAbstractMethods = false;
count = 0;
for (int i = 0; i < methodCount; i++) {
AbstractMethodDeclaration method = convert(methods[i], type);
if (method != null) {
boolean isAbstract;
if ((isAbstract = method.isAbstract()) || isInterface) { // fix-up flag
method.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
}
if (isAbstract) {
hasAbstractMethods = true;
}
typeDeclaration.methods[neededCount + (count++)] = method;
}
}
if (count != methodCount) {
System.arraycopy(typeDeclaration.methods, 0, typeDeclaration.methods = new AbstractMethodDeclaration[count + neededCount], 0, count + neededCount);
}
if (hasAbstractMethods) {
typeDeclaration.bits |= ASTNode.HasAbstractMethods;
}
return typeDeclaration;
}
private static char[][] stringArrayToCharArray(String[] strings) {
if (strings == null) return null;
int length = strings.length;
if (length == 0) return CharOperation.NO_CHAR_CHAR;
char[][] result = new char [length][];
for (int i = 0; i < length; i++) {
result[i] = strings[i].toCharArray();
}
return result;
}
private TypeReference createTypeReference(String typeSignature) {
TypeReference result = createTypeReference(typeSignature, 0, 0);
if (this.typeNames != null && result instanceof QualifiedTypeReference) {
this.typeNames.add(((QualifiedTypeReference)result).tokens);
}
return result;
}
}