/******************************************************************************* * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.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 net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.CompilationResult; import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.Argument; import net.sourceforge.phpdt.internal.compiler.ast.ArrayQualifiedTypeReference; import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference; import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference; import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference; import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; import net.sourceforge.phpdt.internal.compiler.env.ISourceField; import net.sourceforge.phpdt.internal.compiler.env.ISourceMethod; import net.sourceforge.phpdt.internal.compiler.env.ISourceType; import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; public class SourceTypeConverter implements CompilerModifiers { private boolean needFieldInitialization; private CompilationUnitDeclaration unit; private UnitParser parser; private ProblemReporter problemReporter; private SourceTypeConverter(boolean needFieldInitialization, ProblemReporter problemReporter) { this.needFieldInitialization = needFieldInitialization; 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, boolean needFieldsAndMethods, boolean needMemberTypes, boolean needFieldInitialization, ProblemReporter problemReporter, CompilationResult compilationResult) { return new SourceTypeConverter(needFieldInitialization, problemReporter) .convert(sourceTypes, needFieldsAndMethods, needMemberTypes, 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, boolean needFieldsAndMethods, boolean needMemberTypes, 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(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); char[][] importNames = sourceType.getImports(); int importCount = importNames == null ? 0 : importNames.length; this.unit.imports = new ImportReference[importCount]; // for (int i = 0; i < importCount; i++) // this.unit.imports[i] = createImportReference(importNames[i], start, // end); /* convert type(s) */ int typeCount = sourceTypes.length; this.unit.types = new ArrayList(typeCount); for (int i = 0; i < typeCount; i++) { this.unit.types.set(i, convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes, compilationResult)); // this.unit.types[i] = // convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes, // 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.needFieldInitialization) { /* conversion of field constant */ char[] initializationSource = sourceField.getInitializationSource(); if (initializationSource != null) { if (this.parser == null) { this.parser = new UnitParser(this.problemReporter); // true, // this.problemReporter.options.sourceLevel >= // CompilerOptions.JDK1_4); } 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); // 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 * * Can optionally ignore fields & methods */ private TypeDeclaration convert(ISourceType sourceType, boolean needFieldsAndMethods, boolean needMemberTypes, CompilationResult compilationResult) { /* create type declaration - can be member type */ TypeDeclaration type; if (sourceType.getEnclosingType() == null) { type = new TypeDeclaration(compilationResult); } else { type = new MemberTypeDeclaration(compilationResult); } 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 (needMemberTypes) { ISourceType[] sourceMemberTypes = sourceType.getMemberTypes(); int sourceMemberTypeCount = sourceMemberTypes == null ? 0 : sourceMemberTypes.length; type.memberTypes = new MemberTypeDeclaration[sourceMemberTypeCount]; for (int i = 0; i < sourceMemberTypeCount; i++) { type.memberTypes[i] = (MemberTypeDeclaration) convert( sourceMemberTypes[i], needFieldsAndMethods, true, compilationResult); } } /* convert fields and methods */ if (needFieldsAndMethods) { /* convert fields */ 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 */ 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 neededCount = 0; if (!type.isInterface()) { neededCount = 1; for (int i = 0; i < sourceMethodCount; i++) { if (sourceMethods[i].isConstructor()) { neededCount = 0; // Does not need the extra constructor since one // constructor already exists. break; } } } type.methods = new AbstractMethodDeclaration[sourceMethodCount + neededCount]; if (neededCount != 0) { // add default constructor in first position type.methods[0] = type.createsInternalConstructor(false, false); } boolean isInterface = type.isInterface(); for (int i = 0; i < sourceMethodCount; i++) { AbstractMethodDeclaration method = convert(sourceMethods[i], compilationResult); if (isInterface || method.isAbstract()) { // fix-up flag method.modifiers |= AccSemicolonBody; } type.methods[neededCount + i] = method; } } return type; } /* * Build an import reference from an import name, e.g. java.lang.* */ // private ImportReference createImportReference( // char[] importName, // int start, // int end) { // // /* count identifiers */ // int max = importName.length; // int identCount = 0; // for (int i = 0; i < max; i++) { // if (importName[i] == '.') // identCount++; // } // /* import on demand? */ // boolean onDemand = importName[max - 1] == '*'; // if (!onDemand) // identCount++; // one more ident than dots // // long[] positions = new long[identCount]; // long position = (long) start << 32 + end; // for (int i = 0; i < identCount; i++) { // positions[i] = position; // } // return new ImportReference( // CharOperation.splitOn('.', importName, 0, max - (onDemand ? 2 : 0)), // positions, // onDemand); // } /* * 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); } } } }