| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.parser; |
| |
| /** |
| * Converter from source element type to parsed compilation unit. |
| * |
| * Limitation: |
| * | The source element field does not carry any information for its constant part, thus |
| * | the converted parse tree will not include any field initializations. |
| * | Therefore, any binary produced by compiling against converted source elements will |
| * | not take advantage of remote field constant inlining. |
| * | Given the intended purpose of the conversion is to resolve references, this is not |
| * | a problem. |
| * |
| */ |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.CompilationResult; |
| import org.eclipse.jdt.internal.compiler.ast.*; |
| import org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.Argument; |
| import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.ImportReference; |
| import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeParameter; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.Wildcard; |
| import org.eclipse.jdt.internal.compiler.env.*; |
| import org.eclipse.jdt.internal.compiler.env.ISourceImport; |
| import org.eclipse.jdt.internal.compiler.env.ISourceType; |
| |
| import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; |
| import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; |
| import org.eclipse.jdt.internal.core.*; |
| import org.eclipse.jdt.internal.core.JavaElement; |
| import org.eclipse.jdt.internal.core.SourceFieldElementInfo; |
| import org.eclipse.jdt.internal.core.SourceTypeElementInfo; |
| |
| public class SourceTypeConverter implements CompilerModifiers { |
| |
| public static final int FIELD = 0x01; |
| public static final int CONSTRUCTOR = 0x02; |
| public static final int METHOD = 0x04; |
| public static final int MEMBER_TYPE = 0x08; |
| public static final int FIELD_INITIALIZATION = 0x10; |
| public static final int FIELD_AND_METHOD = FIELD | CONSTRUCTOR | METHOD; |
| public static final int LOCAL_TYPE = 0x20; |
| public static final int NONE = 0; |
| |
| private int flags; |
| private CompilationUnitDeclaration unit; |
| private Parser parser; |
| private ProblemReporter problemReporter; |
| private ICompilationUnit cu; |
| private char[] source; |
| private HashMap annotationPositions; |
| |
| int namePos; |
| |
| private SourceTypeConverter(int flags, ProblemReporter problemReporter) { |
| this.flags = flags; |
| this.problemReporter = problemReporter; |
| } |
| |
| /* |
| * Convert a set of source element types into a parsed compilation unit declaration |
| * The argument types are then all grouped in the same unit. The argument types must |
| * at least contain one type. |
| * Can optionally ignore fields & methods or member types or field initialization |
| */ |
| public static CompilationUnitDeclaration buildCompilationUnit( |
| ISourceType[] sourceTypes, |
| int flags, |
| ProblemReporter problemReporter, |
| CompilationResult compilationResult) { |
| |
| // long start = System.currentTimeMillis(); |
| SourceTypeConverter converter = new SourceTypeConverter(flags, problemReporter); |
| try { |
| return converter.convert(sourceTypes, compilationResult); |
| } catch (JavaModelException e) { |
| return null; |
| /* } finally { |
| System.out.println("Spent " + (System.currentTimeMillis() - start) + "ms to convert " + ((JavaElement) converter.cu).toStringWithAncestors()); |
| */ } |
| } |
| |
| /* |
| * Convert a set of source element types into a parsed compilation unit declaration |
| * The argument types are then all grouped in the same unit. The argument types must |
| * at least contain one type. |
| */ |
| private CompilationUnitDeclaration convert(ISourceType[] sourceTypes, CompilationResult compilationResult) throws JavaModelException { |
| this.unit = new CompilationUnitDeclaration(this.problemReporter, compilationResult, 0); |
| // not filled at this point |
| |
| if (sourceTypes.length == 0) return this.unit; |
| SourceTypeElementInfo topLevelTypeInfo = (SourceTypeElementInfo) sourceTypes[0]; |
| this.cu = (ICompilationUnit) topLevelTypeInfo.getHandle().getCompilationUnit(); |
| this.annotationPositions = ((CompilationUnitElementInfo) ((JavaElement) this.cu).getElementInfo()).annotationPositions; |
| |
| if (this.annotationPositions != null && this.annotationPositions.size() > 10) { // experimental value |
| // if more than 10 annotations, diet parse as this is faster |
| return new Parser(this.problemReporter, true).dietParse(this.cu, compilationResult); |
| } |
| |
| /* only positions available */ |
| int start = topLevelTypeInfo.getNameSourceStart(); |
| int end = topLevelTypeInfo.getNameSourceEnd(); |
| |
| /* convert package and imports */ |
| if (topLevelTypeInfo.getPackageName() != null |
| && topLevelTypeInfo.getPackageName().length > 0) |
| // if its null then it is defined in the default package |
| this.unit.currentPackage = |
| createImportReference(topLevelTypeInfo.getPackageName(), start, end, false, AccDefault); |
| ISourceImport[] sourceImports = topLevelTypeInfo.getImports(); |
| int importCount = sourceImports.length; |
| this.unit.imports = new ImportReference[importCount]; |
| for (int i = 0; i < importCount; i++) { |
| ISourceImport sourceImport = sourceImports[i]; |
| this.unit.imports[i] = createImportReference( |
| sourceImport.getName(), |
| sourceImport.getDeclarationSourceStart(), |
| sourceImport.getDeclarationSourceEnd(), |
| sourceImport.onDemand(), |
| sourceImport.getModifiers()); |
| } |
| /* convert type(s) */ |
| int typeCount = sourceTypes.length; |
| this.unit.types = new TypeDeclaration[typeCount]; |
| for (int i = 0; i < typeCount; i++) { |
| SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i]; |
| this.unit.types[i] = |
| convert((SourceType) typeInfo.getHandle(), compilationResult); |
| } |
| return this.unit; |
| } |
| |
| /* |
| * Convert an initializerinfo into a parsed initializer declaration |
| */ |
| private Initializer convert(InitializerElementInfo initializerInfo, CompilationResult compilationResult) throws JavaModelException { |
| |
| Block block = new Block(0); |
| Initializer initializer = new Initializer(block, IConstants.AccDefault); |
| |
| int start = initializerInfo.getDeclarationSourceStart(); |
| int end = initializerInfo.getDeclarationSourceEnd(); |
| |
| initializer.sourceStart = initializer.declarationSourceStart = start; |
| initializer.sourceEnd = initializer.declarationSourceEnd = end; |
| initializer.modifiers = initializerInfo.getModifiers(); |
| |
| /* convert local and anonymous types */ |
| IJavaElement[] children = initializerInfo.getChildren(); |
| int typesLength = children.length; |
| if (typesLength > 0) { |
| Statement[] statements = new Statement[typesLength]; |
| for (int i = 0; i < typesLength; i++) { |
| SourceType type = (SourceType) children[i]; |
| TypeDeclaration localType = convert(type, compilationResult); |
| if ((localType.bits & ASTNode.IsAnonymousTypeMASK) != 0) { |
| QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType); |
| expression.type = localType.superclass; |
| localType.superclass = null; |
| localType.superInterfaces = null; |
| localType.allocation = expression; |
| statements[i] = expression; |
| } else { |
| statements[i] = localType; |
| } |
| } |
| block.statements = statements; |
| } |
| |
| return initializer; |
| } |
| |
| /* |
| * Convert a field source element into a parsed field declaration |
| */ |
| private FieldDeclaration convert(SourceField fieldHandle, TypeDeclaration type, CompilationResult compilationResult) throws JavaModelException { |
| |
| SourceFieldElementInfo fieldInfo = (SourceFieldElementInfo) fieldHandle.getElementInfo(); |
| FieldDeclaration field = new FieldDeclaration(); |
| |
| int start = fieldInfo.getNameSourceStart(); |
| int end = fieldInfo.getNameSourceEnd(); |
| |
| field.name = fieldInfo.getName(); |
| field.sourceStart = start; |
| field.sourceEnd = end; |
| field.declarationSourceStart = fieldInfo.getDeclarationSourceStart(); |
| field.declarationSourceEnd = fieldInfo.getDeclarationSourceEnd(); |
| int modifiers = fieldInfo.getModifiers(); |
| boolean isEnumConstant = (modifiers & AccEnum) != 0; |
| if (isEnumConstant) { |
| field.modifiers = modifiers & ~Flags.AccEnum; // clear AccEnum bit onto AST (binding will add it) |
| } else { |
| field.modifiers = modifiers; |
| field.type = createTypeReference(fieldInfo.getTypeName(), start, end); |
| } |
| |
| /* convert annotations */ |
| field.annotations = convertAnnotations(fieldHandle); |
| |
| /* conversion of field constant */ |
| if ((this.flags & FIELD_INITIALIZATION) != 0) { |
| char[] initializationSource = fieldInfo.getInitializationSource(); |
| if (initializationSource != null) { |
| if (this.parser == null) { |
| this.parser = new Parser(this.problemReporter, true); |
| } |
| this.parser.parse(field, type, this.unit, initializationSource); |
| } |
| } |
| |
| /* conversion of local and anonymous types */ |
| if ((this.flags & LOCAL_TYPE) != 0) { |
| IJavaElement[] children = fieldInfo.getChildren(); |
| int childrenLength = children.length; |
| if (childrenLength > 0) { |
| ArrayInitializer initializer = new ArrayInitializer(); |
| field.initialization = initializer; |
| Expression[] expressions = new Expression[childrenLength]; |
| initializer.expressions = expressions; |
| for (int i = 0; i < childrenLength; i++) { |
| IJavaElement localType = children[i]; |
| TypeDeclaration anonymousLocalTypeDeclaration = convert((SourceType) localType, compilationResult); |
| QualifiedAllocationExpression expression = new QualifiedAllocationExpression(anonymousLocalTypeDeclaration); |
| expression.type = anonymousLocalTypeDeclaration.superclass; |
| anonymousLocalTypeDeclaration.superclass = null; |
| anonymousLocalTypeDeclaration.superInterfaces = null; |
| anonymousLocalTypeDeclaration.allocation = expression; |
| anonymousLocalTypeDeclaration.modifiers &= ~AccEnum; // remove tag in case this is the init of an enum constant |
| expressions[i] = expression; |
| } |
| } |
| } |
| return field; |
| } |
| |
| /* |
| * Convert a method source element into a parsed method/constructor declaration |
| */ |
| private AbstractMethodDeclaration convert(SourceMethod methodHandle, CompilationResult compilationResult) throws JavaModelException { |
| |
| SourceMethodElementInfo methodInfo = (SourceMethodElementInfo) methodHandle.getElementInfo(); |
| AbstractMethodDeclaration method; |
| |
| /* only source positions available */ |
| int start = methodInfo.getNameSourceStart(); |
| int end = methodInfo.getNameSourceEnd(); |
| |
| /* convert type parameters */ |
| char[][] typeParameterNames = methodInfo.getTypeParameterNames(); |
| TypeParameter[] typeParams = null; |
| if (typeParameterNames != null) { |
| int parameterCount = typeParameterNames.length; |
| if (parameterCount > 0) { // method's type parameters must be null if no type parameter |
| char[][][] typeParameterBounds = methodInfo.getTypeParameterBounds(); |
| typeParams = new TypeParameter[parameterCount]; |
| for (int i = 0; i < parameterCount; i++) { |
| typeParams[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end); |
| } |
| } |
| } |
| |
| int modifiers = methodInfo.getModifiers(); |
| if (methodInfo.isConstructor()) { |
| ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult); |
| decl.isDefaultConstructor = false; |
| method = decl; |
| decl.typeParameters = typeParams; |
| } else { |
| MethodDeclaration decl; |
| if (methodInfo.isAnnotationMethod()) { |
| AnnotationMethodDeclaration annotationMethodDeclaration = new AnnotationMethodDeclaration(compilationResult); |
| |
| /* conversion of default value */ |
| if ((this.flags & FIELD_INITIALIZATION) != 0) { |
| char[] defaultValueSource = ((SourceAnnotationMethodInfo) methodInfo).getDefaultValueSource(getSource()); |
| if (defaultValueSource != null) { |
| Expression expression = parseMemberValue(defaultValueSource); |
| if (expression != null) { |
| annotationMethodDeclaration.defaultValue = expression; |
| modifiers |= AccAnnotationDefault; |
| } |
| } |
| } |
| decl = annotationMethodDeclaration; |
| } else { |
| decl = new MethodDeclaration(compilationResult); |
| } |
| |
| // convert return type |
| decl.returnType = createTypeReference(methodInfo.getReturnTypeName(), start, end); |
| |
| // type parameters |
| decl.typeParameters = typeParams; |
| |
| method = decl; |
| } |
| method.selector = methodInfo.getSelector(); |
| boolean isVarargs = (modifiers & AccVarargs) != 0; |
| method.modifiers = modifiers & ~AccVarargs; |
| method.sourceStart = start; |
| method.sourceEnd = end; |
| method.declarationSourceStart = methodInfo.getDeclarationSourceStart(); |
| method.declarationSourceEnd = methodInfo.getDeclarationSourceEnd(); |
| |
| /* convert annotations */ |
| method.annotations = convertAnnotations(methodHandle); |
| |
| /* convert arguments */ |
| char[][] argumentTypeNames = methodInfo.getArgumentTypeNames(); |
| char[][] argumentNames = methodInfo.getArgumentNames(); |
| int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length; |
| long position = ((long) start << 32) + end; |
| method.arguments = new Argument[argumentCount]; |
| for (int i = 0; i < argumentCount; i++) { |
| TypeReference typeReference = createTypeReference(argumentTypeNames[i], start, end); |
| if (isVarargs && i == argumentCount-1) { |
| typeReference.bits |= ASTNode.IsVarArgs; |
| } |
| method.arguments[i] = |
| new Argument( |
| argumentNames[i], |
| position, |
| typeReference, |
| AccDefault); |
| // do not care whether was final or not |
| } |
| |
| /* convert thrown exceptions */ |
| char[][] exceptionTypeNames = methodInfo.getExceptionTypeNames(); |
| int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length; |
| method.thrownExceptions = new TypeReference[exceptionCount]; |
| for (int i = 0; i < exceptionCount; i++) { |
| method.thrownExceptions[i] = |
| createTypeReference(exceptionTypeNames[i], start, end); |
| } |
| |
| /* convert local and anonymous types */ |
| if ((this.flags & LOCAL_TYPE) != 0) { |
| IJavaElement[] children = methodInfo.getChildren(); |
| int typesLength = children.length; |
| if (typesLength != 0) { |
| Statement[] statements = new Statement[typesLength]; |
| for (int i = 0; i < typesLength; i++) { |
| SourceType type = (SourceType) children[i]; |
| TypeDeclaration localType = convert(type, compilationResult); |
| if ((localType.bits & ASTNode.IsAnonymousTypeMASK) != 0) { |
| QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType); |
| expression.type = localType.superclass; |
| localType.superclass = null; |
| localType.superInterfaces = null; |
| localType.allocation = expression; |
| statements[i] = expression; |
| } else { |
| statements[i] = localType; |
| } |
| } |
| method.statements = statements; |
| } |
| } |
| |
| return method; |
| } |
| |
| /* |
| * Convert a source element type into a parsed type declaration |
| */ |
| private TypeDeclaration convert(SourceType typeHandle, CompilationResult compilationResult) throws JavaModelException { |
| SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) typeHandle.getElementInfo(); |
| /* create type declaration - can be member type */ |
| TypeDeclaration type = new TypeDeclaration(compilationResult); |
| if (typeInfo.getEnclosingType() == null) { |
| if (typeHandle.isAnonymous()) { |
| type.name = TypeDeclaration.ANONYMOUS_EMPTY_NAME; |
| type.bits |= ASTNode.AnonymousAndLocalMask; |
| } else { |
| if (typeHandle.isLocal()) { |
| type.bits |= ASTNode.IsLocalTypeMASK; |
| } |
| } |
| } else { |
| type.bits |= ASTNode.IsMemberTypeMASK; |
| } |
| if ((type.bits & ASTNode.IsAnonymousTypeMASK) == 0) { |
| type.name = typeInfo.getName(); |
| } |
| type.name = typeInfo.getName(); |
| int start, end; // only positions available |
| type.sourceStart = start = typeInfo.getNameSourceStart(); |
| type.sourceEnd = end = typeInfo.getNameSourceEnd(); |
| type.modifiers = typeInfo.getModifiers(); |
| type.declarationSourceStart = typeInfo.getDeclarationSourceStart(); |
| type.declarationSourceEnd = typeInfo.getDeclarationSourceEnd(); |
| type.bodyEnd = type.declarationSourceEnd; |
| |
| /* convert annotations */ |
| type.annotations = convertAnnotations(typeHandle); |
| |
| /* convert type parameters */ |
| char[][] typeParameterNames = typeInfo.getTypeParameterNames(); |
| if (typeParameterNames.length > 0) { |
| int parameterCount = typeParameterNames.length; |
| char[][][] typeParameterBounds = typeInfo.getTypeParameterBounds(); |
| type.typeParameters = new TypeParameter[parameterCount]; |
| for (int i = 0; i < parameterCount; i++) { |
| type.typeParameters[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end); |
| } |
| } |
| /* set superclass and superinterfaces */ |
| if (typeInfo.getSuperclassName() != null) { |
| type.superclass = createTypeReference(typeInfo.getSuperclassName(), start, end); |
| type.superclass.bits |= ASTNode.IsSuperType; |
| } |
| char[][] interfaceNames = typeInfo.getInterfaceNames(); |
| int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length; |
| if (interfaceCount > 0) { |
| type.superInterfaces = new TypeReference[interfaceCount]; |
| for (int i = 0; i < interfaceCount; i++) { |
| type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end); |
| type.superInterfaces[i].bits |= ASTNode.IsSuperType; |
| } |
| } |
| /* convert member types */ |
| if ((this.flags & MEMBER_TYPE) != 0) { |
| SourceType[] sourceMemberTypes = typeInfo.getMemberTypeHandles(); |
| int sourceMemberTypeCount = sourceMemberTypes.length; |
| type.memberTypes = new TypeDeclaration[sourceMemberTypeCount]; |
| for (int i = 0; i < sourceMemberTypeCount; i++) { |
| type.memberTypes[i] = convert(sourceMemberTypes[i], compilationResult); |
| } |
| } |
| |
| /* convert intializers and fields*/ |
| InitializerElementInfo[] initializers = null; |
| int initializerCount = 0; |
| if ((this.flags & LOCAL_TYPE) != 0) { |
| initializers = typeInfo.getInitializers(); |
| initializerCount = initializers.length; |
| } |
| SourceField[] sourceFields = null; |
| int sourceFieldCount = 0; |
| if ((this.flags & FIELD) != 0) { |
| sourceFields = typeInfo.getFieldHandles(); |
| sourceFieldCount = sourceFields.length; |
| } |
| int length = initializerCount + sourceFieldCount; |
| if (length > 0) { |
| type.fields = new FieldDeclaration[length]; |
| for (int i = 0; i < initializerCount; i++) { |
| type.fields[i] = convert(initializers[i], compilationResult); |
| } |
| int index = 0; |
| for (int i = initializerCount; i < length; i++) { |
| type.fields[i] = convert(sourceFields[index++], type, compilationResult); |
| } |
| } |
| |
| /* convert methods - need to add default constructor if necessary */ |
| boolean needConstructor = (this.flags & CONSTRUCTOR) != 0; |
| boolean needMethod = (this.flags & METHOD) != 0; |
| if (needConstructor || needMethod) { |
| |
| SourceMethod[] sourceMethods = typeInfo.getMethodHandles(); |
| int sourceMethodCount = sourceMethods.length; |
| |
| /* source type has a constructor ? */ |
| /* by default, we assume that one is needed. */ |
| int extraConstructor = 0; |
| int methodCount = 0; |
| int kind = type.kind(); |
| boolean isAbstract = kind == IGenericType.INTERFACE_DECL || kind == IGenericType.ANNOTATION_TYPE_DECL; |
| if (!isAbstract) { |
| extraConstructor = needConstructor ? 1 : 0; |
| for (int i = 0; i < sourceMethodCount; i++) { |
| if (sourceMethods[i].isConstructor()) { |
| if (needConstructor) { |
| extraConstructor = 0; // Does not need the extra constructor since one constructor already exists. |
| methodCount++; |
| } |
| } else if (needMethod) { |
| methodCount++; |
| } |
| } |
| } else { |
| methodCount = needMethod ? sourceMethodCount : 0; |
| } |
| type.methods = new AbstractMethodDeclaration[methodCount + extraConstructor]; |
| if (extraConstructor != 0) { // add default constructor in first position |
| type.methods[0] = type.createDefaultConstructor(false, false); |
| } |
| int index = 0; |
| boolean hasAbstractMethods = false; |
| for (int i = 0; i < sourceMethodCount; i++) { |
| SourceMethod sourceMethod = sourceMethods[i]; |
| boolean isConstructor = sourceMethod.isConstructor(); |
| if ((sourceMethod.getFlags() & Flags.AccAbstract) != 0) { |
| hasAbstractMethods = true; |
| } |
| if ((isConstructor && needConstructor) || (!isConstructor && needMethod)) { |
| AbstractMethodDeclaration method = convert(sourceMethod, compilationResult); |
| if (isAbstract || method.isAbstract()) { // fix-up flag |
| method.modifiers |= AccSemicolonBody; |
| } |
| type.methods[extraConstructor + index++] = method; |
| } |
| } |
| if (hasAbstractMethods) type.bits |= ASTNode.HasAbstractMethods; |
| } |
| |
| return type; |
| } |
| |
| private Annotation[] convertAnnotations(JavaElement element) { |
| if (this.annotationPositions == null) return null; |
| char[] cuSource = getSource(); |
| long[] positions = (long[]) this.annotationPositions.get(element); |
| if (positions == null) return null; |
| int length = positions.length; |
| Annotation[] annotations = new Annotation[length]; |
| for (int i = 0; i < length; i++) { |
| long position = positions[i]; |
| int start = (int) (position >>> 32); |
| int end = (int) position; |
| char[] annotationSource = CharOperation.subarray(cuSource, start, end+1); |
| Expression expression = parseMemberValue(annotationSource); |
| annotations[i] = (Annotation) expression; |
| } |
| return annotations; |
| } |
| |
| /* |
| * Build an import reference from an import name, e.g. java.lang.* |
| */ |
| private ImportReference createImportReference( |
| char[] importName, |
| int start, |
| int end, |
| boolean onDemand, |
| int modifiers) { |
| |
| char[][] qImportName = CharOperation.splitOn('.', importName); |
| long[] positions = new long[qImportName.length]; |
| long position = ((long) start << 32) + end; |
| for (int i = 0; i < qImportName.length; i++) { |
| positions[i] = position; // dummy positions |
| } |
| return new ImportReference( |
| qImportName, |
| positions, |
| onDemand, |
| modifiers); |
| } |
| |
| private TypeParameter createTypeParameter(char[] typeParameterName, char[][] typeParameterBounds, int start, int end) { |
| |
| TypeParameter parameter = new TypeParameter(); |
| parameter.name = typeParameterName; |
| parameter.sourceStart = start; |
| parameter.sourceEnd = end; |
| if (typeParameterBounds != null) { |
| int length = typeParameterBounds.length; |
| if (length > 0) { |
| parameter.type = createTypeReference(typeParameterBounds[0], start, end); |
| if (length > 1) { |
| parameter.bounds = new TypeReference[length-1]; |
| for (int i = 1; i < length; i++) { |
| TypeReference bound = createTypeReference(typeParameterBounds[i], start, end); |
| bound.bits |= ASTNode.IsSuperType; |
| parameter.bounds[i-1] = bound; |
| } |
| } |
| } |
| } |
| return parameter; |
| } |
| |
| /* |
| * Build a type reference from a readable name, e.g. java.lang.Object[][] |
| */ |
| private TypeReference createTypeReference( |
| char[] typeName, |
| int start, |
| int end) { |
| |
| int length = typeName.length; |
| this.namePos = 0; |
| TypeReference type = decodeType(typeName, length, start, end); |
| return type; |
| } |
| private TypeReference decodeType(char[] typeName, int length, int start, int end) { |
| int identCount = 1; |
| int dim = 0; |
| int nameFragmentStart = this.namePos, nameFragmentEnd = -1; |
| ArrayList fragments = null; |
| typeLoop: while (this.namePos < length) { |
| char currentChar = typeName[this.namePos]; |
| switch (currentChar) { |
| case '?' : |
| this.namePos++; // skip '?' |
| while (typeName[this.namePos] == ' ') this.namePos++; |
| switch(typeName[this.namePos]) { |
| case 's' : |
| checkSuper: { |
| int max = TypeConstants.WILDCARD_SUPER.length-1; |
| for (int ahead = 1; ahead < max; ahead++) { |
| if (typeName[this.namePos+ahead] != TypeConstants.WILDCARD_SUPER[ahead+1]) { |
| break checkSuper; |
| } |
| } |
| this.namePos += max; |
| Wildcard result = new Wildcard(Wildcard.SUPER); |
| result.bound = decodeType(typeName, length, start, end); |
| result.sourceStart = start; |
| result.sourceEnd = end; |
| return result; |
| } |
| break; |
| case 'e' : |
| checkExtends: { |
| int max = TypeConstants.WILDCARD_EXTENDS.length-1; |
| for (int ahead = 1; ahead < max; ahead++) { |
| if (typeName[this.namePos+ahead] != TypeConstants.WILDCARD_EXTENDS[ahead+1]) { |
| break checkExtends; |
| } |
| } |
| this.namePos += max; |
| Wildcard result = new Wildcard(Wildcard.EXTENDS); |
| result.bound = decodeType(typeName, length, start, end); |
| result.sourceStart = start; |
| result.sourceEnd = end; |
| return result; |
| } |
| break; |
| } |
| Wildcard result = new Wildcard(Wildcard.UNBOUND); |
| result.sourceStart = start; |
| result.sourceEnd = end; |
| return result; |
| case '[' : |
| if (dim == 0) nameFragmentEnd = this.namePos-1; |
| dim++; |
| break; |
| case ']' : |
| break; |
| case '>' : |
| case ',' : |
| break typeLoop; |
| case '.' : |
| if (nameFragmentStart < 0) nameFragmentStart = this.namePos+1; // member type name |
| identCount ++; |
| break; |
| case '<' : |
| if (fragments == null) fragments = new ArrayList(2); |
| nameFragmentEnd = this.namePos-1; |
| char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, this.namePos); |
| fragments.add(identifiers); |
| this.namePos++; // skip '<' |
| TypeReference[] arguments = decodeTypeArguments(typeName, length, start, end); // positionned on '>' at end |
| fragments.add(arguments); |
| identCount = 0; |
| nameFragmentStart = -1; |
| nameFragmentEnd = -1; |
| // next increment will skip '>' |
| } |
| this.namePos++; |
| } |
| if (nameFragmentEnd < 0) nameFragmentEnd = this.namePos-1; |
| if (fragments == null) { // non parameterized |
| /* rebuild identifiers and dimensions */ |
| if (identCount == 1) { // simple type reference |
| if (dim == 0) { |
| char[] nameFragment; |
| if (nameFragmentStart != 0 || nameFragmentEnd >= 0) { |
| int nameFragmentLength = nameFragmentEnd - nameFragmentStart + 1; |
| System.arraycopy(typeName, nameFragmentStart, nameFragment = new char[nameFragmentLength], 0, nameFragmentLength); |
| } else { |
| nameFragment = typeName; |
| } |
| return new SingleTypeReference(nameFragment, ((long) start << 32) + end); |
| } else { |
| int nameFragmentLength = nameFragmentEnd - nameFragmentStart + 1; |
| char[] nameFragment = new char[nameFragmentLength]; |
| System.arraycopy(typeName, nameFragmentStart, nameFragment, 0, nameFragmentLength); |
| return new ArrayTypeReference(nameFragment, dim, ((long) start << 32) + end); |
| } |
| } else { // qualified type reference |
| long[] positions = new long[identCount]; |
| long pos = ((long) start << 32) + end; |
| for (int i = 0; i < identCount; i++) { |
| positions[i] = pos; |
| } |
| char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, nameFragmentEnd+1); |
| if (dim == 0) { |
| return new QualifiedTypeReference(identifiers, positions); |
| } else { |
| return new ArrayQualifiedTypeReference(identifiers, dim, positions); |
| } |
| } |
| } else { // parameterized |
| // rebuild type reference from available fragments: char[][], arguments, char[][], arguments... |
| // check trailing qualified name |
| if (nameFragmentStart > 0 && nameFragmentStart < length) { |
| char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, nameFragmentEnd+1); |
| fragments.add(identifiers); |
| } |
| int fragmentLength = fragments.size(); |
| if (fragmentLength == 2) { |
| char[][] firstFragment = (char[][]) fragments.get(0); |
| if (firstFragment.length == 1) { |
| // parameterized single type |
| return new ParameterizedSingleTypeReference(firstFragment[0], (TypeReference[]) fragments.get(1), dim, ((long) start << 32) + end); |
| } |
| } |
| // parameterized qualified type |
| identCount = 0; |
| for (int i = 0; i < fragmentLength; i ++) { |
| Object element = fragments.get(i); |
| if (element instanceof char[][]) { |
| identCount += ((char[][])element).length; |
| } |
| } |
| char[][] tokens = new char[identCount][]; |
| TypeReference[][] arguments = new TypeReference[identCount][]; |
| int index = 0; |
| for (int i = 0; i < fragmentLength; i ++) { |
| Object element = fragments.get(i); |
| if (element instanceof char[][]) { |
| char[][] fragmentTokens = (char[][]) element; |
| int fragmentTokenLength = fragmentTokens.length; |
| System.arraycopy(fragmentTokens, 0, tokens, index, fragmentTokenLength); |
| index += fragmentTokenLength; |
| } else { |
| arguments[index-1] = (TypeReference[]) element; |
| } |
| } |
| long[] positions = new long[identCount]; |
| long pos = ((long) start << 32) + end; |
| for (int i = 0; i < identCount; i++) { |
| positions[i] = pos; |
| } |
| return new ParameterizedQualifiedTypeReference(tokens, arguments, dim, positions); |
| } |
| } |
| |
| private TypeReference[] decodeTypeArguments(char[] typeName, int length, int start, int end) { |
| ArrayList argumentList = new ArrayList(1); |
| int count = 0; |
| argumentsLoop: while (this.namePos < length) { |
| TypeReference argument = decodeType(typeName, length, start, end); |
| count++; |
| argumentList.add(argument); |
| if (this.namePos >= length) break argumentsLoop; |
| if (typeName[this.namePos] == '>') { |
| break argumentsLoop; |
| } |
| this.namePos++; // skip ',' |
| } |
| TypeReference[] typeArguments = new TypeReference[count]; |
| argumentList.toArray(typeArguments); |
| return typeArguments; |
| } |
| |
| private char[] getSource() { |
| if (this.source == null) |
| this.source = this.cu.getContents(); |
| return this.source; |
| } |
| |
| private Expression parseMemberValue(char[] memberValue) { |
| if (this.parser == null) { |
| this.parser = new Parser(this.problemReporter, true); |
| } |
| return this.parser.parseMemberValue(memberValue, 0, memberValue.length, this.unit); |
| } |
| } |