1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.parser;
 
  14  * Converter from source element type to parsed compilation unit.
 
  17  * | The source element field does not carry any information for its constant part, thus
 
  18  * | the converted parse tree will not include any field initializations.
 
  19  * | Therefore, any binary produced by compiling against converted source elements will
 
  20  * | not take advantage of remote field constant inlining.
 
  21  * | Given the intended purpose of the conversion is to resolve references, this is not
 
  26 import java.util.ArrayList;
 
  28 import net.sourceforge.phpdt.core.compiler.CharOperation;
 
  29 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
 
  30 import net.sourceforge.phpdt.internal.compiler.env.ISourceField;
 
  31 import net.sourceforge.phpdt.internal.compiler.env.ISourceMethod;
 
  32 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
 
  33 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
 
  34 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
 
  35 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
 
  36 import net.sourceforge.phpeclipse.internal.compiler.ast.Argument;
 
  37 import net.sourceforge.phpeclipse.internal.compiler.ast.ArrayQualifiedTypeReference;
 
  38 import net.sourceforge.phpeclipse.internal.compiler.ast.ArrayTypeReference;
 
  39 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
 
  40 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
 
  41 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
 
  42 import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference;
 
  43 import net.sourceforge.phpeclipse.internal.compiler.ast.MemberTypeDeclaration;
 
  44 import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
 
  45 import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedTypeReference;
 
  46 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference;
 
  47 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
 
  48 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference;
 
  50 public class SourceTypeConverter implements CompilerModifiers {
 
  52         private boolean needFieldInitialization;
 
  53         private CompilationUnitDeclaration unit;
 
  54         private UnitParser parser;
 
  55         private ProblemReporter problemReporter;
 
  57         private SourceTypeConverter(boolean needFieldInitialization, ProblemReporter problemReporter) {
 
  58                 this.needFieldInitialization = needFieldInitialization;
 
  59                 this.problemReporter = problemReporter;
 
  63          * Convert a set of source element types into a parsed compilation unit declaration
 
  64          * The argument types are then all grouped in the same unit. The argument types must 
 
  65          * at least contain one type.
 
  66          * Can optionally ignore fields & methods or member types or field initialization
 
  68         public static CompilationUnitDeclaration buildCompilationUnit(
 
  69                 ISourceType[] sourceTypes,
 
  70                 boolean needFieldsAndMethods,
 
  71                 boolean needMemberTypes,
 
  72                 boolean needFieldInitialization,
 
  73                 ProblemReporter problemReporter,
 
  74                 CompilationResult compilationResult) {
 
  77                         new SourceTypeConverter(needFieldInitialization, problemReporter).convert(
 
  85          * Convert a set of source element types into a parsed compilation unit declaration
 
  86          * The argument types are then all grouped in the same unit. The argument types must 
 
  87          * at least contain one type.
 
  89         private CompilationUnitDeclaration convert(
 
  90                 ISourceType[] sourceTypes,
 
  91                 boolean needFieldsAndMethods,
 
  92                 boolean needMemberTypes,
 
  93                 CompilationResult compilationResult) {
 
  94                 ISourceType sourceType = sourceTypes[0];
 
  95                 if (sourceType.getName() == null)
 
  96                         return null; // do a basic test that the sourceType is valid
 
  98                 this.unit = new CompilationUnitDeclaration(problemReporter, compilationResult, 0);
 
  99                 // not filled at this point
 
 101                 /* only positions available */
 
 102                 int start = sourceType.getNameSourceStart();
 
 103                 int end = sourceType.getNameSourceEnd();
 
 105                 /* convert package and imports */
 
 106                 if (sourceType.getPackageName() != null
 
 107                         && sourceType.getPackageName().length > 0)
 
 108                         // if its null then it is defined in the default package
 
 109                         this.unit.currentPackage =
 
 110                                 createImportReference(sourceType.getPackageName(), start, end);
 
 111                 char[][] importNames = sourceType.getImports();
 
 112                 int importCount = importNames == null ? 0 : importNames.length;
 
 113                 this.unit.imports = new ImportReference[importCount];
 
 114                 for (int i = 0; i < importCount; i++)
 
 115                         this.unit.imports[i] = createImportReference(importNames[i], start, end);
 
 116                 /* convert type(s) */
 
 117                 int typeCount = sourceTypes.length;
 
 118                 this.unit.types = new ArrayList(typeCount);
 
 119                 for (int i = 0; i < typeCount; i++) {
 
 120                         this.unit.types.set(i,
 
 121                                                         convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes, compilationResult));
 
 122 //                      this.unit.types[i] =
 
 123 //                              convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes, compilationResult);
 
 129          * Convert a field source element into a parsed field declaration
 
 131         private FieldDeclaration convert(ISourceField sourceField, TypeDeclaration type) {
 
 133                 FieldDeclaration field = new FieldDeclaration();
 
 135                 int start = sourceField.getNameSourceStart();
 
 136                 int end = sourceField.getNameSourceEnd();
 
 138                 field.name = sourceField.getName();
 
 139                 field.sourceStart = start;
 
 140                 field.sourceEnd = end;
 
 141                 field.type = createTypeReference(sourceField.getTypeName(), start, end);
 
 142                 field.declarationSourceStart = sourceField.getDeclarationSourceStart();
 
 143                 field.declarationSourceEnd = sourceField.getDeclarationSourceEnd();
 
 144                 field.modifiers = sourceField.getModifiers();
 
 146                 if (this.needFieldInitialization) {
 
 147                         /* conversion of field constant */
 
 148                         char[] initializationSource = sourceField.getInitializationSource();
 
 149                         if (initializationSource != null) {
 
 150                                 if (this.parser == null) {
 
 153                                                         this.problemReporter); 
 
 155 //                                                      this.problemReporter.options.sourceLevel >= CompilerOptions.JDK1_4);
 
 157                                 this.parser.parse(field, type, this.unit, initializationSource);
 
 165          * Convert a method source element into a parsed method/constructor declaration 
 
 167         private AbstractMethodDeclaration convert(ISourceMethod sourceMethod, CompilationResult compilationResult) {
 
 169                 AbstractMethodDeclaration method;
 
 171                 /* only source positions available */
 
 172                 int start = sourceMethod.getNameSourceStart();
 
 173                 int end = sourceMethod.getNameSourceEnd();
 
 175                 if (sourceMethod.isConstructor()) {
 
 176                         ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
 
 177                         decl.isDefaultConstructor = false;
 
 180                         MethodDeclaration decl = new MethodDeclaration(compilationResult);
 
 181                         /* convert return type */
 
 183                                 createTypeReference(sourceMethod.getReturnTypeName(), start, end);
 
 186                 method.selector = sourceMethod.getSelector();
 
 187                 method.modifiers = sourceMethod.getModifiers();
 
 188                 method.sourceStart = start;
 
 189                 method.sourceEnd = end;
 
 190                 method.declarationSourceStart = sourceMethod.getDeclarationSourceStart();
 
 191                 method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd();
 
 193                 /* convert arguments */
 
 194                 char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames();
 
 195                 char[][] argumentNames = sourceMethod.getArgumentNames();
 
 196                 int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
 
 197                 long position = (long) start << 32 + end;
 
 198                 method.arguments = new Argument[argumentCount];
 
 199                 for (int i = 0; i < argumentCount; i++) {
 
 200                         method.arguments[i] =
 
 204                                         createTypeReference(argumentTypeNames[i], start, end),
 
 206                         // do not care whether was final or not
 
 209                 /* convert thrown exceptions */
 
 210                 char[][] exceptionTypeNames = sourceMethod.getExceptionTypeNames();
 
 211                 int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
 
 212                 method.thrownExceptions = new TypeReference[exceptionCount];
 
 213                 for (int i = 0; i < exceptionCount; i++) {
 
 214                         method.thrownExceptions[i] =
 
 215                                 createTypeReference(exceptionTypeNames[i], start, end);
 
 221          * Convert a source element type into a parsed type declaration
 
 223          * Can optionally ignore fields & methods
 
 225         private TypeDeclaration convert(
 
 226                 ISourceType sourceType,
 
 227                 boolean needFieldsAndMethods,
 
 228                 boolean needMemberTypes,
 
 229                 CompilationResult compilationResult) {
 
 230                 /* create type declaration - can be member type */
 
 231                 TypeDeclaration type;
 
 232                 if (sourceType.getEnclosingType() == null) {
 
 233                         type = new TypeDeclaration(compilationResult);
 
 235                         type = new MemberTypeDeclaration(compilationResult);
 
 237                 type.name = sourceType.getName();
 
 238                 int start, end; // only positions available
 
 239                 type.sourceStart = start = sourceType.getNameSourceStart();
 
 240                 type.sourceEnd = end = sourceType.getNameSourceEnd();
 
 241                 type.modifiers = sourceType.getModifiers();
 
 242                 type.declarationSourceStart = sourceType.getDeclarationSourceStart();
 
 243                 type.declarationSourceEnd = sourceType.getDeclarationSourceEnd();
 
 244                 type.bodyEnd = type.declarationSourceEnd;
 
 246                 /* set superclass and superinterfaces */
 
 247                 if (sourceType.getSuperclassName() != null)
 
 249                                 createTypeReference(sourceType.getSuperclassName(), start, end);
 
 250                 char[][] interfaceNames = sourceType.getInterfaceNames();
 
 251                 int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length;
 
 252                 type.superInterfaces = new TypeReference[interfaceCount];
 
 253                 for (int i = 0; i < interfaceCount; i++) {
 
 254                         type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end);
 
 256                 /* convert member types */
 
 257                 if (needMemberTypes) {
 
 258                         ISourceType[] sourceMemberTypes = sourceType.getMemberTypes();
 
 259                         int sourceMemberTypeCount =
 
 260                                 sourceMemberTypes == null ? 0 : sourceMemberTypes.length;
 
 261                         type.memberTypes = new MemberTypeDeclaration[sourceMemberTypeCount];
 
 262                         for (int i = 0; i < sourceMemberTypeCount; i++) {
 
 263                                 type.memberTypes[i] =
 
 264                                         (MemberTypeDeclaration) convert(sourceMemberTypes[i],
 
 265                                                 needFieldsAndMethods,
 
 270                 /* convert fields and methods */
 
 271                 if (needFieldsAndMethods) {
 
 273                         ISourceField[] sourceFields = sourceType.getFields();
 
 274                         int sourceFieldCount = sourceFields == null ? 0 : sourceFields.length;
 
 275                         type.fields = new FieldDeclaration[sourceFieldCount];
 
 276                         for (int i = 0; i < sourceFieldCount; i++) {
 
 277                                 type.fields[i] = convert(sourceFields[i], type);
 
 280                         /* convert methods - need to add default constructor if necessary */
 
 281                         ISourceMethod[] sourceMethods = sourceType.getMethods();
 
 282                         int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length;
 
 284                         /* source type has a constructor ?           */
 
 285                         /* by default, we assume that one is needed. */
 
 287                         if (!type.isInterface()) {
 
 289                                 for (int i = 0; i < sourceMethodCount; i++) {
 
 290                                         if (sourceMethods[i].isConstructor()) {
 
 292                                                 // Does not need the extra constructor since one constructor already exists.
 
 297                         type.methods = new AbstractMethodDeclaration[sourceMethodCount + neededCount];
 
 298                         if (neededCount != 0) { // add default constructor in first position
 
 299                                 type.methods[0] = type.createsInternalConstructor(false, false);
 
 301                         boolean isInterface = type.isInterface();
 
 302                         for (int i = 0; i < sourceMethodCount; i++) {
 
 303                                 AbstractMethodDeclaration method =convert(sourceMethods[i], compilationResult);
 
 304                                 if (isInterface || method.isAbstract()) { // fix-up flag 
 
 305                                         method.modifiers |= AccSemicolonBody;
 
 307                                 type.methods[neededCount + i] = method;
 
 314          * Build an import reference from an import name, e.g. java.lang.*
 
 316         private ImportReference createImportReference(
 
 321                 /* count identifiers */
 
 322                 int max = importName.length;
 
 324                 for (int i = 0; i < max; i++) {
 
 325                         if (importName[i] == '.')
 
 328                 /* import on demand? */
 
 329                 boolean onDemand = importName[max - 1] == '*';
 
 331                         identCount++; // one more ident than dots
 
 333                 long[] positions = new long[identCount];
 
 334                 long position = (long) start << 32 + end;
 
 335                 for (int i = 0; i < identCount; i++) {
 
 336                         positions[i] = position;
 
 338                 return new ImportReference(
 
 339                         CharOperation.splitOn('.', importName, 0, max - (onDemand ? 2 : 0)),
 
 345          * Build a type reference from a readable name, e.g. java.lang.Object[][]
 
 347         private TypeReference createTypeReference(
 
 348                 char[] typeSignature,
 
 352                 /* count identifiers and dimensions */
 
 353                 int max = typeSignature.length;
 
 357                 for (int i = 0; i < max; i++) {
 
 358                         switch (typeSignature[i]) {
 
 369                 /* rebuild identifiers and dimensions */
 
 370                 if (identCount == 1) { // simple type reference
 
 372                                 return new SingleTypeReference(typeSignature, (((long) start )<< 32) + end);
 
 374                                 char[] identifier = new char[dimStart];
 
 375                                 System.arraycopy(typeSignature, 0, identifier, 0, dimStart);
 
 376                                 return new ArrayTypeReference(identifier, dim, (((long) start) << 32) + end);
 
 378                 } else { // qualified type reference
 
 379                         long[] positions = new long[identCount];
 
 380                         long pos = (((long) start) << 32) + end;
 
 381                         for (int i = 0; i < identCount; i++) {
 
 384                         char[][] identifiers =
 
 385                                 CharOperation.splitOn('.', typeSignature, 0, dimStart);
 
 387                                 return new QualifiedTypeReference(identifiers, positions);
 
 389                                 return new ArrayQualifiedTypeReference(identifiers, dim, positions);