4d6d7941ffc9ab93a74be886fd426e6b506933c9
[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: | The source element field does not carry any information for its
17  * constant part, thus | the converted parse tree will not include any field
18  * initializations. | Therefore, any binary produced by compiling against
19  * converted source elements will | not take advantage of remote field constant
20  * inlining. | Given the intended purpose of the conversion is to resolve
21  * references, this is not | a problem.
22  * 
23  */
24
25 import java.util.ArrayList;
26
27 import net.sourceforge.phpdt.core.compiler.CharOperation;
28 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
29 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
30 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
31 import net.sourceforge.phpdt.internal.compiler.ast.ArrayQualifiedTypeReference;
32 import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference;
33 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
34 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
35 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
36 import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
37 import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration;
38 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
39 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference;
40 import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference;
41 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
42 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
43 import net.sourceforge.phpdt.internal.compiler.env.ISourceField;
44 import net.sourceforge.phpdt.internal.compiler.env.ISourceMethod;
45 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
46 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
47 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
48
49 public class SourceTypeConverter implements CompilerModifiers {
50
51         private boolean needFieldInitialization;
52
53         private CompilationUnitDeclaration unit;
54
55         private UnitParser parser;
56
57         private ProblemReporter problemReporter;
58
59         private SourceTypeConverter(boolean needFieldInitialization,
60                         ProblemReporter problemReporter) {
61                 this.needFieldInitialization = needFieldInitialization;
62                 this.problemReporter = problemReporter;
63         }
64
65         /*
66          * Convert a set of source element types into a parsed compilation unit
67          * declaration The argument types are then all grouped in the same unit. The
68          * argument types must at least contain one type. Can optionally ignore
69          * fields & methods or member types or field initialization
70          */
71         public static CompilationUnitDeclaration buildCompilationUnit(
72                         ISourceType[] sourceTypes, boolean needFieldsAndMethods,
73                         boolean needMemberTypes, boolean needFieldInitialization,
74                         ProblemReporter problemReporter, CompilationResult compilationResult) {
75
76                 return new SourceTypeConverter(needFieldInitialization, problemReporter)
77                                 .convert(sourceTypes, needFieldsAndMethods, needMemberTypes,
78                                                 compilationResult);
79         }
80
81         /*
82          * Convert a set of source element types into a parsed compilation unit
83          * declaration The argument types are then all grouped in the same unit. The
84          * argument types must at least contain one type.
85          */
86         private CompilationUnitDeclaration convert(ISourceType[] sourceTypes,
87                         boolean needFieldsAndMethods, boolean needMemberTypes,
88                         CompilationResult compilationResult) {
89                 ISourceType sourceType = sourceTypes[0];
90                 if (sourceType.getName() == null)
91                         return null; // do a basic test that the sourceType is valid
92
93                 this.unit = new CompilationUnitDeclaration(problemReporter,
94                                 compilationResult, 0);
95                 // not filled at this point
96
97                 /* only positions available */
98                 int start = sourceType.getNameSourceStart();
99                 int end = sourceType.getNameSourceEnd();
100
101                 /* convert package and imports */
102                 // if (sourceType.getPackageName() != null
103                 // && sourceType.getPackageName().length > 0)
104                 // // if its null then it is defined in the default package
105                 // this.unit.currentPackage =
106                 // createImportReference(sourceType.getPackageName(), start, end);
107                 char[][] importNames = sourceType.getImports();
108                 int importCount = importNames == null ? 0 : importNames.length;
109                 this.unit.imports = new ImportReference[importCount];
110                 // for (int i = 0; i < importCount; i++)
111                 // this.unit.imports[i] = createImportReference(importNames[i], start,
112                 // end);
113                 /* convert type(s) */
114                 int typeCount = sourceTypes.length;
115                 this.unit.types = new ArrayList(typeCount);
116                 for (int i = 0; i < typeCount; i++) {
117                         this.unit.types.set(i, convert(sourceTypes[i],
118                                         needFieldsAndMethods, needMemberTypes, compilationResult));
119                         // this.unit.types[i] =
120                         // convert(sourceTypes[i], needFieldsAndMethods, needMemberTypes,
121                         // compilationResult);
122                 }
123                 return this.unit;
124         }
125
126         /*
127          * Convert a field source element into a parsed field declaration
128          */
129         private FieldDeclaration convert(ISourceField sourceField,
130                         TypeDeclaration type) {
131
132                 FieldDeclaration field = new FieldDeclaration();
133
134                 int start = sourceField.getNameSourceStart();
135                 int end = sourceField.getNameSourceEnd();
136
137                 field.name = sourceField.getName();
138                 field.sourceStart = start;
139                 field.sourceEnd = end;
140                 field.type = createTypeReference(sourceField.getTypeName(), start, end);
141                 field.declarationSourceStart = sourceField.getDeclarationSourceStart();
142                 field.declarationSourceEnd = sourceField.getDeclarationSourceEnd();
143                 field.modifiers = sourceField.getModifiers();
144
145                 if (this.needFieldInitialization) {
146                         /* conversion of field constant */
147                         char[] initializationSource = sourceField.getInitializationSource();
148                         if (initializationSource != null) {
149                                 if (this.parser == null) {
150                                         this.parser = new UnitParser(this.problemReporter);
151                                         // true,
152                                         // this.problemReporter.options.sourceLevel >=
153                                         // CompilerOptions.JDK1_4);
154                                 }
155                                 this.parser.parse(field, type, this.unit, initializationSource);
156                         }
157                 }
158
159                 return field;
160         }
161
162         /*
163          * Convert a method source element into a parsed method/constructor
164          * declaration
165          */
166         private AbstractMethodDeclaration convert(ISourceMethod sourceMethod,
167                         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(
177                                         compilationResult);
178                         decl.isDefaultConstructor = false;
179                         method = decl;
180                 } else {
181                         MethodDeclaration decl = new MethodDeclaration(compilationResult);
182                         /* convert return type */
183                         decl.returnType = createTypeReference(sourceMethod
184                                         .getReturnTypeName(), start, end);
185                         method = decl;
186                 }
187                 method.selector = sourceMethod.getSelector();
188                 method.modifiers = sourceMethod.getModifiers();
189                 method.sourceStart = start;
190                 method.sourceEnd = end;
191                 method.declarationSourceStart = sourceMethod
192                                 .getDeclarationSourceStart();
193                 method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd();
194
195                 /* convert arguments */
196                 char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames();
197                 char[][] argumentNames = sourceMethod.getArgumentNames();
198                 int argumentCount = argumentTypeNames == null ? 0
199                                 : argumentTypeNames.length;
200                 long position = (long) start << 32 + end;
201                 method.arguments = new Argument[argumentCount];
202                 for (int i = 0; i < argumentCount; i++) {
203                         method.arguments[i] = new Argument(argumentNames[i], 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
212                                 : exceptionTypeNames.length;
213                 method.thrownExceptions = new TypeReference[exceptionCount];
214                 for (int i = 0; i < exceptionCount; i++) {
215                         method.thrownExceptions[i] = createTypeReference(
216                                         exceptionTypeNames[i], start, end);
217                 }
218                 return method;
219         }
220
221         /*
222          * Convert a source element type into a parsed type declaration
223          * 
224          * Can optionally ignore fields & methods
225          */
226         private TypeDeclaration convert(ISourceType sourceType,
227                         boolean needFieldsAndMethods, boolean needMemberTypes,
228                         CompilationResult compilationResult) {
229                 /* create type declaration - can be member type */
230                 TypeDeclaration type;
231                 if (sourceType.getEnclosingType() == null) {
232                         type = new TypeDeclaration(compilationResult);
233                 } else {
234                         type = new MemberTypeDeclaration(compilationResult);
235                 }
236                 type.name = sourceType.getName();
237                 int start, end; // only positions available
238                 type.sourceStart = start = sourceType.getNameSourceStart();
239                 type.sourceEnd = end = sourceType.getNameSourceEnd();
240                 type.modifiers = sourceType.getModifiers();
241                 type.declarationSourceStart = sourceType.getDeclarationSourceStart();
242                 type.declarationSourceEnd = sourceType.getDeclarationSourceEnd();
243                 type.bodyEnd = type.declarationSourceEnd;
244
245                 /* set superclass and superinterfaces */
246                 if (sourceType.getSuperclassName() != null)
247                         type.superclass = createTypeReference(sourceType
248                                         .getSuperclassName(), start, end);
249                 char[][] interfaceNames = sourceType.getInterfaceNames();
250                 int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length;
251                 type.superInterfaces = new TypeReference[interfaceCount];
252                 for (int i = 0; i < interfaceCount; i++) {
253                         type.superInterfaces[i] = createTypeReference(interfaceNames[i],
254                                         start, end);
255                 }
256                 /* convert member types */
257                 if (needMemberTypes) {
258                         ISourceType[] sourceMemberTypes = sourceType.getMemberTypes();
259                         int sourceMemberTypeCount = sourceMemberTypes == null ? 0
260                                         : sourceMemberTypes.length;
261                         type.memberTypes = new MemberTypeDeclaration[sourceMemberTypeCount];
262                         for (int i = 0; i < sourceMemberTypeCount; i++) {
263                                 type.memberTypes[i] = (MemberTypeDeclaration) convert(
264                                                 sourceMemberTypes[i], needFieldsAndMethods, true,
265                                                 compilationResult);
266                         }
267                 }
268                 /* convert fields and methods */
269                 if (needFieldsAndMethods) {
270                         /* convert fields */
271                         ISourceField[] sourceFields = sourceType.getFields();
272                         int sourceFieldCount = sourceFields == null ? 0
273                                         : sourceFields.length;
274                         type.fields = new FieldDeclaration[sourceFieldCount];
275                         for (int i = 0; i < sourceFieldCount; i++) {
276                                 type.fields[i] = convert(sourceFields[i], type);
277                         }
278
279                         /* convert methods - need to add default constructor if necessary */
280                         ISourceMethod[] sourceMethods = sourceType.getMethods();
281                         int sourceMethodCount = sourceMethods == null ? 0
282                                         : 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
293                                                 // constructor already exists.
294                                                 break;
295                                         }
296                                 }
297                         }
298                         type.methods = new AbstractMethodDeclaration[sourceMethodCount
299                                         + neededCount];
300                         if (neededCount != 0) { // add default constructor in first position
301                                 type.methods[0] = type.createsInternalConstructor(false, false);
302                         }
303                         boolean isInterface = type.isInterface();
304                         for (int i = 0; i < sourceMethodCount; i++) {
305                                 AbstractMethodDeclaration method = convert(sourceMethods[i],
306                                                 compilationResult);
307                                 if (isInterface || method.isAbstract()) { // fix-up flag
308                                         method.modifiers |= AccSemicolonBody;
309                                 }
310                                 type.methods[neededCount + i] = method;
311                         }
312                 }
313                 return type;
314         }
315
316         /*
317          * Build an import reference from an import name, e.g. java.lang.*
318          */
319         // private ImportReference createImportReference(
320         // char[] importName,
321         // int start,
322         // int end) {
323         //
324         // /* count identifiers */
325         // int max = importName.length;
326         // int identCount = 0;
327         // for (int i = 0; i < max; i++) {
328         // if (importName[i] == '.')
329         // identCount++;
330         // }
331         // /* import on demand? */
332         // boolean onDemand = importName[max - 1] == '*';
333         // if (!onDemand)
334         // identCount++; // one more ident than dots
335         //
336         // long[] positions = new long[identCount];
337         // long position = (long) start << 32 + end;
338         // for (int i = 0; i < identCount; i++) {
339         // positions[i] = position;
340         // }
341         // return new ImportReference(
342         // CharOperation.splitOn('.', importName, 0, max - (onDemand ? 2 : 0)),
343         // positions,
344         // onDemand);
345         // }
346         /*
347          * Build a type reference from a readable name, e.g. java.lang.Object[][]
348          */
349         private TypeReference createTypeReference(char[] typeSignature, 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,
373                                                 (((long) start) << 32) + end);
374                         } else {
375                                 char[] identifier = new char[dimStart];
376                                 System.arraycopy(typeSignature, 0, identifier, 0, dimStart);
377                                 return new ArrayTypeReference(identifier, dim,
378                                                 (((long) start) << 32) + end);
379                         }
380                 } else { // qualified type reference
381                         long[] positions = new long[identCount];
382                         long pos = (((long) start) << 32) + end;
383                         for (int i = 0; i < identCount; i++) {
384                                 positions[i] = pos;
385                         }
386                         char[][] identifiers = CharOperation.splitOn('.', typeSignature, 0,
387                                         dimStart);
388                         if (dim == 0) {
389                                 return new QualifiedTypeReference(identifiers, positions);
390                         } else {
391                                 return new ArrayQualifiedTypeReference(identifiers, dim,
392                                                 positions);
393                         }
394                 }
395         }
396 }