| /******************************************************************************* |
| * 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 org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.CompilationResult; |
| 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.QualifiedTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.eclipse.jdt.internal.compiler.env.ISourceField; |
| import org.eclipse.jdt.internal.compiler.env.ISourceImport; |
| import org.eclipse.jdt.internal.compiler.env.ISourceMethod; |
| import org.eclipse.jdt.internal.compiler.env.ISourceType; |
| |
| import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; |
| import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; |
| |
| 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 NONE = 0; |
| |
| private int flags; |
| private CompilationUnitDeclaration unit; |
| private Parser parser; |
| private ProblemReporter problemReporter; |
| |
| 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) { |
| |
| return |
| new SourceTypeConverter(flags, problemReporter).convert(sourceTypes, compilationResult); |
| } |
| |
| /* |
| * 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) { |
| ISourceType sourceType = sourceTypes[0]; |
| if (sourceType.getName() == null) |
| return null; // do a basic test that the sourceType is valid |
| |
| this.unit = new CompilationUnitDeclaration(this.problemReporter, compilationResult, 0); |
| // not filled at this point |
| |
| /* only positions available */ |
| int start = sourceType.getNameSourceStart(); |
| int end = sourceType.getNameSourceEnd(); |
| |
| /* convert package and imports */ |
| if (sourceType.getPackageName() != null |
| && sourceType.getPackageName().length > 0) |
| // if its null then it is defined in the default package |
| this.unit.currentPackage = |
| createImportReference(sourceType.getPackageName(), start, end, false, AccDefault); |
| ISourceImport[] sourceImports = sourceType.getImports(); |
| int importCount = sourceImports == null ? 0 : 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++) { |
| this.unit.types[i] = |
| convert(sourceTypes[i], compilationResult); |
| } |
| return this.unit; |
| } |
| |
| /* |
| * Convert a field source element into a parsed field declaration |
| */ |
| private FieldDeclaration convert(ISourceField sourceField, TypeDeclaration type) { |
| |
| FieldDeclaration field = new FieldDeclaration(); |
| |
| int start = sourceField.getNameSourceStart(); |
| int end = sourceField.getNameSourceEnd(); |
| |
| field.name = sourceField.getName(); |
| field.sourceStart = start; |
| field.sourceEnd = end; |
| field.type = createTypeReference(sourceField.getTypeName(), start, end); |
| field.declarationSourceStart = sourceField.getDeclarationSourceStart(); |
| field.declarationSourceEnd = sourceField.getDeclarationSourceEnd(); |
| field.modifiers = sourceField.getModifiers(); |
| |
| if ((this.flags & FIELD_INITIALIZATION) != 0) { |
| /* conversion of field constant */ |
| char[] initializationSource = sourceField.getInitializationSource(); |
| if (initializationSource != null) { |
| if (this.parser == null) { |
| this.parser = new Parser(this.problemReporter, true); |
| } |
| this.parser.parse(field, type, this.unit, initializationSource); |
| } |
| } |
| |
| return field; |
| } |
| |
| /* |
| * Convert a method source element into a parsed method/constructor declaration |
| */ |
| private AbstractMethodDeclaration convert(ISourceMethod sourceMethod, CompilationResult compilationResult) { |
| |
| AbstractMethodDeclaration method; |
| |
| /* only source positions available */ |
| int start = sourceMethod.getNameSourceStart(); |
| int end = sourceMethod.getNameSourceEnd(); |
| |
| if (sourceMethod.isConstructor()) { |
| ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult); |
| decl.isDefaultConstructor = false; |
| method = decl; |
| } else { |
| MethodDeclaration decl = new MethodDeclaration(compilationResult); |
| /* convert return type */ |
| decl.returnType = |
| createTypeReference(sourceMethod.getReturnTypeName(), start, end); |
| method = decl; |
| } |
| method.selector = sourceMethod.getSelector(); |
| method.modifiers = sourceMethod.getModifiers(); |
| method.sourceStart = start; |
| method.sourceEnd = end; |
| method.declarationSourceStart = sourceMethod.getDeclarationSourceStart(); |
| method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd(); |
| |
| /* convert arguments */ |
| char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames(); |
| char[][] argumentNames = sourceMethod.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++) { |
| method.arguments[i] = |
| new Argument( |
| argumentNames[i], |
| position, |
| createTypeReference(argumentTypeNames[i], start, end), |
| AccDefault, |
| false); |
| // do not care whether was final or not |
| } |
| |
| /* convert thrown exceptions */ |
| char[][] exceptionTypeNames = sourceMethod.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); |
| } |
| return method; |
| } |
| |
| /* |
| * Convert a source element type into a parsed type declaration |
| */ |
| private TypeDeclaration convert(ISourceType sourceType, CompilationResult compilationResult) { |
| /* create type declaration - can be member type */ |
| TypeDeclaration type = type = new TypeDeclaration(compilationResult); |
| if (sourceType.getEnclosingType() != null) { |
| type.bits |= ASTNode.IsMemberTypeMASK; |
| } |
| type.name = sourceType.getName(); |
| int start, end; // only positions available |
| type.sourceStart = start = sourceType.getNameSourceStart(); |
| type.sourceEnd = end = sourceType.getNameSourceEnd(); |
| type.modifiers = sourceType.getModifiers(); |
| type.declarationSourceStart = sourceType.getDeclarationSourceStart(); |
| type.declarationSourceEnd = sourceType.getDeclarationSourceEnd(); |
| type.bodyEnd = type.declarationSourceEnd; |
| |
| /* set superclass and superinterfaces */ |
| if (sourceType.getSuperclassName() != null) |
| type.superclass = |
| createTypeReference(sourceType.getSuperclassName(), start, end); |
| char[][] interfaceNames = sourceType.getInterfaceNames(); |
| int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length; |
| type.superInterfaces = new TypeReference[interfaceCount]; |
| for (int i = 0; i < interfaceCount; i++) { |
| type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end); |
| } |
| /* convert member types */ |
| if ((this.flags & MEMBER_TYPE) != 0) { |
| ISourceType[] sourceMemberTypes = sourceType.getMemberTypes(); |
| int sourceMemberTypeCount = |
| sourceMemberTypes == null ? 0 : sourceMemberTypes.length; |
| type.memberTypes = new TypeDeclaration[sourceMemberTypeCount]; |
| for (int i = 0; i < sourceMemberTypeCount; i++) { |
| type.memberTypes[i] = convert(sourceMemberTypes[i], compilationResult); |
| } |
| } |
| |
| /* convert fields */ |
| if ((this.flags & FIELD) != 0) { |
| ISourceField[] sourceFields = sourceType.getFields(); |
| int sourceFieldCount = sourceFields == null ? 0 : sourceFields.length; |
| type.fields = new FieldDeclaration[sourceFieldCount]; |
| for (int i = 0; i < sourceFieldCount; i++) { |
| type.fields[i] = convert(sourceFields[i], type); |
| } |
| } |
| |
| /* convert methods - need to add default constructor if necessary */ |
| boolean needConstructor = (this.flags & CONSTRUCTOR) != 0; |
| boolean needMethod = (this.flags & METHOD) != 0; |
| if (needConstructor || needMethod) { |
| |
| ISourceMethod[] sourceMethods = sourceType.getMethods(); |
| int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length; |
| |
| /* source type has a constructor ? */ |
| /* by default, we assume that one is needed. */ |
| int extraConstructor = 0; |
| int methodCount = 0; |
| boolean isInterface = type.isInterface(); |
| if (!isInterface) { |
| 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.createsInternalConstructor(false, false); |
| } |
| int index = 0; |
| for (int i = 0; i < sourceMethodCount; i++) { |
| ISourceMethod sourceMethod = sourceMethods[i]; |
| boolean isConstructor = sourceMethod.isConstructor(); |
| if ((isConstructor && needConstructor) || (!isConstructor && needMethod)) { |
| AbstractMethodDeclaration method =convert(sourceMethod, compilationResult); |
| if (isInterface || method.isAbstract()) { // fix-up flag |
| method.modifiers |= AccSemicolonBody; |
| } |
| type.methods[extraConstructor + index++] = method; |
| } |
| } |
| } |
| |
| return type; |
| } |
| |
| /* |
| * 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); |
| } |
| |
| /* |
| * Build a type reference from a readable name, e.g. java.lang.Object[][] |
| */ |
| private TypeReference createTypeReference( |
| char[] typeSignature, |
| int start, |
| int end) { |
| |
| /* count identifiers and dimensions */ |
| int max = typeSignature.length; |
| int dimStart = max; |
| int dim = 0; |
| int identCount = 1; |
| for (int i = 0; i < max; i++) { |
| switch (typeSignature[i]) { |
| case '[' : |
| if (dim == 0) |
| dimStart = i; |
| dim++; |
| break; |
| case '.' : |
| identCount++; |
| break; |
| } |
| } |
| /* rebuild identifiers and dimensions */ |
| if (identCount == 1) { // simple type reference |
| if (dim == 0) { |
| return new SingleTypeReference(typeSignature, (((long) start )<< 32) + end); |
| } else { |
| char[] identifier = new char[dimStart]; |
| System.arraycopy(typeSignature, 0, identifier, 0, dimStart); |
| return new ArrayTypeReference(identifier, 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('.', typeSignature, 0, dimStart); |
| if (dim == 0) { |
| return new QualifiedTypeReference(identifiers, positions); |
| } else { |
| return new ArrayQualifiedTypeReference(identifiers, dim, positions); |
| } |
| } |
| } |
| } |