732407a07a517f460196927132f73daedd585a82
[phpeclipse.git] /
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12
13 /**
14  * Converter from source element type to parsed compilation unit.
15  *
16  * Limitation:
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
22  * | a problem.
23  *
24  */
25
26 import java.util.ArrayList;
27
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;
49
50 public class SourceTypeConverter implements CompilerModifiers {
51         
52         private boolean needFieldInitialization;
53         private CompilationUnitDeclaration unit;
54         private UnitParser parser;
55         private ProblemReporter problemReporter;
56         
57         private SourceTypeConverter(boolean needFieldInitialization, ProblemReporter problemReporter) {
58                 this.needFieldInitialization = needFieldInitialization;
59                 this.problemReporter = problemReporter;
60         }
61
62         /*
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
67          */
68         public static CompilationUnitDeclaration buildCompilationUnit(
69                 ISourceType[] sourceTypes,
70                 boolean needFieldsAndMethods,
71                 boolean needMemberTypes,
72                 boolean needFieldInitialization,
73                 ProblemReporter problemReporter,
74                 CompilationResult compilationResult) {
75                         
76                 return 
77                         new SourceTypeConverter(needFieldInitialization, problemReporter).convert(
78                                 sourceTypes, 
79                                 needFieldsAndMethods,
80                                 needMemberTypes,
81                                 compilationResult);
82         }
83
84         /*
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.
88          */
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
97
98                 this.unit = new CompilationUnitDeclaration(problemReporter, compilationResult, 0);
99                 // not filled at this point
100
101                 /* only positions available */
102                 int start = sourceType.getNameSourceStart();
103                 int end = sourceType.getNameSourceEnd();
104
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);
124                 }
125                 return this.unit;
126         }
127         
128         /*
129          * Convert a field source element into a parsed field declaration
130          */
131         private FieldDeclaration convert(ISourceField sourceField, TypeDeclaration type) {
132
133                 FieldDeclaration field = new FieldDeclaration();
134
135                 int start = sourceField.getNameSourceStart();
136                 int end = sourceField.getNameSourceEnd();
137
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();
145
146                 if (this.needFieldInitialization) {
147                         /* conversion of field constant */
148                         char[] initializationSource = sourceField.getInitializationSource();
149                         if (initializationSource != null) {
150                                 if (this.parser == null) {
151                                         this.parser = 
152                                                 new UnitParser(
153                                                         this.problemReporter); 
154 //                                                      true, 
155 //                                                      this.problemReporter.options.sourceLevel >= CompilerOptions.JDK1_4);
156                                 }
157                                 this.parser.parse(field, type, this.unit, initializationSource);
158                         }
159                 }
160                 
161                 return field;
162         }
163
164         /*
165          * Convert a method source element into a parsed method/constructor declaration 
166          */
167         private AbstractMethodDeclaration convert(ISourceMethod sourceMethod, CompilationResult compilationResult) {
168
169                 AbstractMethodDeclaration method;
170
171                 /* only source positions available */
172                 int start = sourceMethod.getNameSourceStart();
173                 int end = sourceMethod.getNameSourceEnd();
174
175                 if (sourceMethod.isConstructor()) {
176                         ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
177                         decl.isDefaultConstructor = false;
178                         method = decl;
179                 } else {
180                         MethodDeclaration decl = new MethodDeclaration(compilationResult);
181                         /* convert return type */
182                         decl.returnType =
183                                 createTypeReference(sourceMethod.getReturnTypeName(), start, end);
184                         method = decl;
185                 }
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();
192
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] =
201                                 new Argument(
202                                         argumentNames[i],
203                                         position,
204                                         createTypeReference(argumentTypeNames[i], start, end),
205                                         AccDefault);
206                         // do not care whether was final or not
207                 }
208
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);
216                 }
217                 return method;
218         }
219
220         /*
221          * Convert a source element type into a parsed type declaration
222          *
223          * Can optionally ignore fields & methods
224          */
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);
234                 } else {
235                         type = new MemberTypeDeclaration(compilationResult);
236                 }
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;
245
246                 /* set superclass and superinterfaces */
247                 if (sourceType.getSuperclassName() != null)
248                         type.superclass =
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);
255                 }
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,
266                                                 true,
267                                                 compilationResult);
268                         }
269                 }
270                 /* convert fields and methods */
271                 if (needFieldsAndMethods) {
272                         /* convert fields */
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);
278                         }
279
280                         /* convert methods - need to add default constructor if necessary */
281                         ISourceMethod[] sourceMethods = sourceType.getMethods();
282                         int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length;
283
284                         /* source type has a constructor ?           */
285                         /* by default, we assume that one is needed. */
286                         int neededCount = 0;
287                         if (!type.isInterface()) {
288                                 neededCount = 1;
289                                 for (int i = 0; i < sourceMethodCount; i++) {
290                                         if (sourceMethods[i].isConstructor()) {
291                                                 neededCount = 0;
292                                                 // Does not need the extra constructor since one constructor already exists.
293                                                 break;
294                                         }
295                                 }
296                         }
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);
300                         }
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;
306                                 }
307                                 type.methods[neededCount + i] = method;
308                         }
309                 }
310                 return type;
311         }
312
313         /*
314          * Build an import reference from an import name, e.g. java.lang.*
315          */
316         private ImportReference createImportReference(
317                 char[] importName,
318                 int start,
319                 int end) {
320
321                 /* count identifiers */
322                 int max = importName.length;
323                 int identCount = 0;
324                 for (int i = 0; i < max; i++) {
325                         if (importName[i] == '.')
326                                 identCount++;
327                 }
328                 /* import on demand? */
329                 boolean onDemand = importName[max - 1] == '*';
330                 if (!onDemand)
331                         identCount++; // one more ident than dots
332
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;
337                 }
338                 return new ImportReference(
339                         CharOperation.splitOn('.', importName, 0, max - (onDemand ? 2 : 0)),
340                         positions,
341                         onDemand);
342         }
343
344         /*
345          * Build a type reference from a readable name, e.g. java.lang.Object[][]
346          */
347         private TypeReference createTypeReference(
348                 char[] typeSignature,
349                 int start,
350                 int end) {
351
352                 /* count identifiers and dimensions */
353                 int max = typeSignature.length;
354                 int dimStart = max;
355                 int dim = 0;
356                 int identCount = 1;
357                 for (int i = 0; i < max; i++) {
358                         switch (typeSignature[i]) {
359                                 case '[' :
360                                         if (dim == 0)
361                                                 dimStart = i;
362                                         dim++;
363                                         break;
364                                 case '.' :
365                                         identCount++;
366                                         break;
367                         }
368                 }
369                 /* rebuild identifiers and dimensions */
370                 if (identCount == 1) { // simple type reference
371                         if (dim == 0) {
372                                 return new SingleTypeReference(typeSignature, (((long) start )<< 32) + end);
373                         } else {
374                                 char[] identifier = new char[dimStart];
375                                 System.arraycopy(typeSignature, 0, identifier, 0, dimStart);
376                                 return new ArrayTypeReference(identifier, dim, (((long) start) << 32) + end);
377                         }
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++) {
382                                 positions[i] = pos;
383                         }
384                         char[][] identifiers =
385                                 CharOperation.splitOn('.', typeSignature, 0, dimStart);
386                         if (dim == 0) {
387                                 return new QualifiedTypeReference(identifiers, positions);
388                         } else {
389                                 return new ArrayQualifiedTypeReference(identifiers, dim, positions);
390                         }
391                 }
392         }
393 }