001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Erling Ellingsen - patch for bug 125570
011: *******************************************************************************/package org.eclipse.jdt.internal.compiler.lookup;
012:
013: import org.eclipse.jdt.core.compiler.CharOperation;
014: import org.eclipse.jdt.internal.compiler.ast.*;
015: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
016: import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
017: import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
018: import org.eclipse.jdt.internal.compiler.util.*;
019:
020: public class CompilationUnitScope extends Scope {
021:
022: public LookupEnvironment environment;
023: public CompilationUnitDeclaration referenceContext;
024: public char[][] currentPackageName;
025: public PackageBinding fPackage;
026: public ImportBinding[] imports;
027: public HashtableOfObject typeOrPackageCache; // used in Scope.getTypeOrPackage()
028:
029: public SourceTypeBinding[] topLevelTypes;
030:
031: private CompoundNameVector qualifiedReferences;
032: private SimpleNameVector simpleNameReferences;
033: private ObjectVector referencedTypes;
034: private ObjectVector referencedSuperTypes;
035:
036: HashtableOfType constantPoolNameUsage;
037: private int captureID = 1;
038:
039: public CompilationUnitScope(CompilationUnitDeclaration unit,
040: LookupEnvironment environment) {
041: super (COMPILATION_UNIT_SCOPE, null);
042: this .environment = environment;
043: this .referenceContext = unit;
044: unit.scope = this ;
045: this .currentPackageName = unit.currentPackage == null ? CharOperation.NO_CHAR_CHAR
046: : unit.currentPackage.tokens;
047:
048: if (compilerOptions().produceReferenceInfo) {
049: this .qualifiedReferences = new CompoundNameVector();
050: this .simpleNameReferences = new SimpleNameVector();
051: this .referencedTypes = new ObjectVector();
052: this .referencedSuperTypes = new ObjectVector();
053: } else {
054: this .qualifiedReferences = null; // used to test if dependencies should be recorded
055: this .simpleNameReferences = null;
056: this .referencedTypes = null;
057: this .referencedSuperTypes = null;
058: }
059: }
060:
061: void buildFieldsAndMethods() {
062: for (int i = 0, length = topLevelTypes.length; i < length; i++)
063: topLevelTypes[i].scope.buildFieldsAndMethods();
064: }
065:
066: void buildTypeBindings(AccessRestriction accessRestriction) {
067: topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved
068: boolean firstIsSynthetic = false;
069: if (referenceContext.compilationResult.compilationUnit != null) {
070: char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit
071: .getPackageName();
072: if (expectedPackageName != null
073: && !CharOperation.equals(currentPackageName,
074: expectedPackageName)) {
075:
076: // only report if the unit isn't structurally empty
077: if (referenceContext.currentPackage != null
078: || referenceContext.types != null
079: || referenceContext.imports != null) {
080: problemReporter().packageIsNotExpectedPackage(
081: referenceContext);
082: }
083: currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR
084: : expectedPackageName;
085: }
086: }
087: if (currentPackageName == CharOperation.NO_CHAR_CHAR) {
088: if ((fPackage = environment.defaultPackage) == null) {
089: problemReporter().mustSpecifyPackage(referenceContext);
090: return;
091: }
092: } else {
093: if ((fPackage = environment
094: .createPackage(currentPackageName)) == null) {
095: problemReporter().packageCollidesWithType(
096: referenceContext);
097: return;
098: } else if (referenceContext.isPackageInfo()) {
099: // resolve package annotations now if this is "package-info.java".
100: if (referenceContext.types == null
101: || referenceContext.types.length == 0) {
102: referenceContext.types = new TypeDeclaration[1];
103: TypeDeclaration declaration = new TypeDeclaration(
104: referenceContext.compilationResult);
105: referenceContext.types[0] = declaration;
106: declaration.name = TypeConstants.PACKAGE_INFO_NAME;
107: declaration.modifiers = ClassFileConstants.AccDefault
108: | ClassFileConstants.AccInterface;
109: firstIsSynthetic = true;
110: }
111: }
112: recordQualifiedReference(currentPackageName); // always dependent on your own package
113: }
114:
115: // Skip typeDeclarations which know of previously reported errors
116: TypeDeclaration[] types = referenceContext.types;
117: int typeLength = (types == null) ? 0 : types.length;
118: topLevelTypes = new SourceTypeBinding[typeLength];
119: int count = 0;
120: nextType: for (int i = 0; i < typeLength; i++) {
121: TypeDeclaration typeDecl = types[i];
122: ReferenceBinding typeBinding = fPackage
123: .getType0(typeDecl.name);
124: recordSimpleReference(typeDecl.name); // needed to detect collision cases
125: if (typeBinding != null
126: && typeBinding.isValidBinding()
127: && !(typeBinding instanceof UnresolvedReferenceBinding)) {
128: // if a type exists, check that its a valid type
129: // it can be a NotFound problem type if its a secondary type referenced before its primary type found in additional units
130: // and it can be an unresolved type which is now being defined
131: problemReporter().duplicateTypes(referenceContext,
132: typeDecl);
133: continue nextType;
134: }
135: if (fPackage != environment.defaultPackage
136: && fPackage.getPackage(typeDecl.name) != null) {
137: // if a package exists, it must be a valid package - cannot be a NotFound problem package
138: // this is now a warning since a package does not really 'exist' until it contains a type, see JLS v2, 7.4.3
139: problemReporter().typeCollidesWithPackage(
140: referenceContext, typeDecl);
141: }
142:
143: if ((typeDecl.modifiers & ClassFileConstants.AccPublic) != 0) {
144: char[] mainTypeName;
145: if ((mainTypeName = referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided to return null
146: && !CharOperation.equals(mainTypeName,
147: typeDecl.name)) {
148: problemReporter().publicClassMustMatchFileName(
149: referenceContext, typeDecl);
150: // tolerate faulty main type name (91091), allow to proceed into type construction
151: }
152: }
153:
154: ClassScope child = new ClassScope(this , typeDecl);
155: SourceTypeBinding type = child.buildType(null, fPackage,
156: accessRestriction);
157: if (firstIsSynthetic && i == 0)
158: type.modifiers |= ClassFileConstants.AccSynthetic;
159: if (type != null)
160: topLevelTypes[count++] = type;
161: }
162:
163: // shrink topLevelTypes... only happens if an error was reported
164: if (count != topLevelTypes.length)
165: System.arraycopy(topLevelTypes, 0,
166: topLevelTypes = new SourceTypeBinding[count], 0,
167: count);
168: }
169:
170: void checkAndSetImports() {
171: if (referenceContext.imports == null) {
172: imports = getDefaultImports();
173: return;
174: }
175:
176: // allocate the import array, add java.lang.* by default
177: int numberOfStatements = referenceContext.imports.length;
178: int numberOfImports = numberOfStatements + 1;
179: for (int i = 0; i < numberOfStatements; i++) {
180: ImportReference importReference = referenceContext.imports[i];
181: if (((importReference.bits & ASTNode.OnDemand) != 0)
182: && CharOperation.equals(JAVA_LANG,
183: importReference.tokens)
184: && !importReference.isStatic()) {
185: numberOfImports--;
186: break;
187: }
188: }
189: ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
190: resolvedImports[0] = getDefaultImports()[0];
191: int index = 1;
192:
193: nextImport: for (int i = 0; i < numberOfStatements; i++) {
194: ImportReference importReference = referenceContext.imports[i];
195: char[][] compoundName = importReference.tokens;
196:
197: // skip duplicates or imports of the current package
198: for (int j = 0; j < index; j++) {
199: ImportBinding resolved = resolvedImports[j];
200: if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)
201: && resolved.isStatic() == importReference
202: .isStatic())
203: if (CharOperation.equals(compoundName,
204: resolvedImports[j].compoundName))
205: continue nextImport;
206: }
207:
208: if ((importReference.bits & ASTNode.OnDemand) != 0) {
209: if (CharOperation.equals(compoundName,
210: currentPackageName))
211: continue nextImport;
212:
213: Binding importBinding = findImport(compoundName,
214: compoundName.length);
215: if (!importBinding.isValidBinding()
216: || (importReference.isStatic() && importBinding instanceof PackageBinding))
217: continue nextImport; // we report all problems in faultInImports()
218: resolvedImports[index++] = new ImportBinding(
219: compoundName, true, importBinding,
220: importReference);
221: } else {
222: // resolve single imports only when the last name matches
223: resolvedImports[index++] = new ImportBinding(
224: compoundName, false, null, importReference);
225: }
226: }
227:
228: // shrink resolvedImports... only happens if an error was reported
229: if (resolvedImports.length > index)
230: System.arraycopy(resolvedImports, 0,
231: resolvedImports = new ImportBinding[index], 0,
232: index);
233: imports = resolvedImports;
234: }
235:
236: /**
237: * Perform deferred check specific to parameterized types: bound checks, supertype collisions
238: */
239: void checkParameterizedTypes() {
240: if (compilerOptions().sourceLevel < ClassFileConstants.JDK1_5)
241: return;
242:
243: for (int i = 0, length = topLevelTypes.length; i < length; i++) {
244: ClassScope scope = topLevelTypes[i].scope;
245: scope.checkParameterizedTypeBounds();
246: scope.checkParameterizedSuperTypeCollisions();
247: }
248: }
249:
250: /*
251: * INTERNAL USE-ONLY
252: * Innerclasses get their name computed as they are generated, since some may not
253: * be actually outputed if sitting inside unreachable code.
254: */
255: public char[] computeConstantPoolName(LocalTypeBinding localType) {
256: if (localType.constantPoolName() != null) {
257: return localType.constantPoolName();
258: }
259: // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
260:
261: if (constantPoolNameUsage == null)
262: constantPoolNameUsage = new HashtableOfType();
263:
264: ReferenceBinding outerMostEnclosingType = localType.scope
265: .outerMostClassScope().enclosingSourceType();
266:
267: // ensure there is not already such a local type name defined by the user
268: int index = 0;
269: char[] candidateName;
270: boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5;
271: while (true) {
272: if (localType.isMemberType()) {
273: if (index == 0) {
274: candidateName = CharOperation.concat(localType
275: .enclosingType().constantPoolName(),
276: localType.sourceName, '$');
277: } else {
278: // in case of collision, then member name gets extra $1 inserted
279: // e.g. class X { { class L{} new X(){ class L{} } } }
280: candidateName = CharOperation.concat(localType
281: .enclosingType().constantPoolName(), '$',
282: String.valueOf(index).toCharArray(), '$',
283: localType.sourceName);
284: }
285: } else if (localType.isAnonymousType()) {
286: if (isCompliant15) {
287: // from 1.5 on, use immediately enclosing type name
288: candidateName = CharOperation.concat(
289: localType.enclosingType.constantPoolName(),
290: String.valueOf(index + 1).toCharArray(),
291: '$');
292: } else {
293: candidateName = CharOperation.concat(
294: outerMostEnclosingType.constantPoolName(),
295: String.valueOf(index + 1).toCharArray(),
296: '$');
297: }
298: } else {
299: // local type
300: if (isCompliant15) {
301: candidateName = CharOperation.concat(CharOperation
302: .concat(localType.enclosingType()
303: .constantPoolName(), String
304: .valueOf(index + 1).toCharArray(),
305: '$'), localType.sourceName);
306: } else {
307: candidateName = CharOperation.concat(
308: outerMostEnclosingType.constantPoolName(),
309: '$', String.valueOf(index + 1)
310: .toCharArray(), '$',
311: localType.sourceName);
312: }
313: }
314: if (constantPoolNameUsage.get(candidateName) != null) {
315: index++;
316: } else {
317: constantPoolNameUsage.put(candidateName, localType);
318: break;
319: }
320: }
321: return candidateName;
322: }
323:
324: void connectTypeHierarchy() {
325: for (int i = 0, length = topLevelTypes.length; i < length; i++)
326: topLevelTypes[i].scope.connectTypeHierarchy();
327: }
328:
329: void faultInImports() {
330: if (this .typeOrPackageCache != null)
331: return; // can be called when a field constant is resolved before static imports
332: if (referenceContext.imports == null) {
333: this .typeOrPackageCache = new HashtableOfObject(1);
334: return;
335: }
336:
337: // collect the top level type names if a single type import exists
338: int numberOfStatements = referenceContext.imports.length;
339: HashtableOfType typesBySimpleNames = null;
340: for (int i = 0; i < numberOfStatements; i++) {
341: if ((referenceContext.imports[i].bits & ASTNode.OnDemand) == 0) {
342: typesBySimpleNames = new HashtableOfType(
343: topLevelTypes.length + numberOfStatements);
344: for (int j = 0, length = topLevelTypes.length; j < length; j++)
345: typesBySimpleNames.put(topLevelTypes[j].sourceName,
346: topLevelTypes[j]);
347: break;
348: }
349: }
350:
351: // allocate the import array, add java.lang.* by default
352: int numberOfImports = numberOfStatements + 1;
353: for (int i = 0; i < numberOfStatements; i++) {
354: ImportReference importReference = referenceContext.imports[i];
355: if (((importReference.bits & ASTNode.OnDemand) != 0)
356: && CharOperation.equals(JAVA_LANG,
357: importReference.tokens)
358: && !importReference.isStatic()) {
359: numberOfImports--;
360: break;
361: }
362: }
363: ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
364: resolvedImports[0] = getDefaultImports()[0];
365: int index = 1;
366:
367: // keep static imports with normal imports until there is a reason to split them up
368: // on demand imports continue to be packages & types. need to check on demand type imports for fields/methods
369: // single imports change from being just types to types or fields
370: nextImport: for (int i = 0; i < numberOfStatements; i++) {
371: ImportReference importReference = referenceContext.imports[i];
372: char[][] compoundName = importReference.tokens;
373:
374: // skip duplicates or imports of the current package
375: for (int j = 0; j < index; j++) {
376: ImportBinding resolved = resolvedImports[j];
377: if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)
378: && resolved.isStatic() == importReference
379: .isStatic()) {
380: if (CharOperation.equals(compoundName,
381: resolved.compoundName)) {
382: problemReporter().unusedImport(importReference); // since skipped, must be reported now
383: continue nextImport;
384: }
385: }
386: }
387: if ((importReference.bits & ASTNode.OnDemand) != 0) {
388: if (CharOperation.equals(compoundName,
389: currentPackageName)) {
390: problemReporter().unusedImport(importReference); // since skipped, must be reported now
391: continue nextImport;
392: }
393:
394: Binding importBinding = findImport(compoundName,
395: compoundName.length);
396: if (!importBinding.isValidBinding()) {
397: problemReporter().importProblem(importReference,
398: importBinding);
399: continue nextImport;
400: }
401: if (importReference.isStatic()
402: && importBinding instanceof PackageBinding) {
403: problemReporter().cannotImportPackage(
404: importReference);
405: continue nextImport;
406: }
407: resolvedImports[index++] = new ImportBinding(
408: compoundName, true, importBinding,
409: importReference);
410: } else {
411: Binding importBinding = findSingleImport(compoundName,
412: importReference.isStatic());
413: if (!importBinding.isValidBinding()) {
414: problemReporter().importProblem(importReference,
415: importBinding);
416: continue nextImport;
417: }
418: if (importBinding instanceof PackageBinding) {
419: problemReporter().cannotImportPackage(
420: importReference);
421: continue nextImport;
422: }
423: ReferenceBinding conflictingType = null;
424: if (importBinding instanceof MethodBinding) {
425: conflictingType = (ReferenceBinding) getType(
426: compoundName, compoundName.length);
427: if (!conflictingType.isValidBinding())
428: conflictingType = null;
429: }
430: // collisions between an imported static field & a type should be checked according to spec... but currently not by javac
431: if (importBinding instanceof ReferenceBinding
432: || conflictingType != null) {
433: ReferenceBinding referenceBinding = conflictingType == null ? (ReferenceBinding) importBinding
434: : conflictingType;
435: if (importReference.isTypeUseDeprecated(
436: referenceBinding, this ))
437: problemReporter().deprecatedType(
438: referenceBinding, importReference);
439:
440: ReferenceBinding existingType = typesBySimpleNames
441: .get(compoundName[compoundName.length - 1]);
442: if (existingType != null) {
443: // duplicate test above should have caught this case, but make sure
444: if (existingType == referenceBinding)
445: continue nextImport;
446: // either the type collides with a top level type or another imported type
447: for (int j = 0, length = topLevelTypes.length; j < length; j++) {
448: if (CharOperation.equals(
449: topLevelTypes[j].sourceName,
450: existingType.sourceName)) {
451: problemReporter().conflictingImport(
452: importReference);
453: continue nextImport;
454: }
455: }
456: problemReporter().duplicateImport(
457: importReference);
458: continue nextImport;
459: }
460: typesBySimpleNames.put(
461: compoundName[compoundName.length - 1],
462: referenceBinding);
463: } else if (importBinding instanceof FieldBinding) {
464: for (int j = 0; j < index; j++) {
465: ImportBinding resolved = resolvedImports[j];
466: // find other static fields with the same name
467: if (resolved.isStatic()
468: && resolved.resolvedImport instanceof FieldBinding
469: && importBinding != resolved.resolvedImport) {
470: if (CharOperation
471: .equals(
472: compoundName[compoundName.length - 1],
473: resolved.compoundName[resolved.compoundName.length - 1])) {
474: problemReporter().duplicateImport(
475: importReference);
476: continue nextImport;
477: }
478: }
479: }
480: }
481: resolvedImports[index++] = conflictingType == null ? new ImportBinding(
482: compoundName, false, importBinding,
483: importReference)
484: : new ImportConflictBinding(compoundName,
485: importBinding, conflictingType,
486: importReference);
487: }
488: }
489:
490: // shrink resolvedImports... only happens if an error was reported
491: if (resolvedImports.length > index)
492: System.arraycopy(resolvedImports, 0,
493: resolvedImports = new ImportBinding[index], 0,
494: index);
495: imports = resolvedImports;
496:
497: int length = imports.length;
498: this .typeOrPackageCache = new HashtableOfObject(length);
499: for (int i = 0; i < length; i++) {
500: ImportBinding binding = imports[i];
501: if (!binding.onDemand
502: && binding.resolvedImport instanceof ReferenceBinding
503: || binding instanceof ImportConflictBinding)
504: this .typeOrPackageCache
505: .put(
506: binding.compoundName[binding.compoundName.length - 1],
507: binding);
508: }
509: }
510:
511: public void faultInTypes() {
512: faultInImports();
513:
514: for (int i = 0, length = topLevelTypes.length; i < length; i++)
515: topLevelTypes[i].faultInTypesForFieldsAndMethods();
516: }
517:
518: // this API is for code assist purpose
519: public Binding findImport(char[][] compoundName,
520: boolean findStaticImports, boolean onDemand) {
521: if (onDemand) {
522: return findImport(compoundName, compoundName.length);
523: } else {
524: return findSingleImport(compoundName, findStaticImports);
525: }
526: }
527:
528: private Binding findImport(char[][] compoundName, int length) {
529: recordQualifiedReference(compoundName);
530:
531: Binding binding = environment
532: .getTopLevelPackage(compoundName[0]);
533: int i = 1;
534: foundNothingOrType: if (binding != null) {
535: PackageBinding packageBinding = (PackageBinding) binding;
536: while (i < length) {
537: binding = packageBinding
538: .getTypeOrPackage(compoundName[i++]);
539: if (binding == null || !binding.isValidBinding()) {
540: binding = null;
541: break foundNothingOrType;
542: }
543: if (!(binding instanceof PackageBinding))
544: break foundNothingOrType;
545:
546: packageBinding = (PackageBinding) binding;
547: }
548: return packageBinding;
549: }
550:
551: ReferenceBinding type;
552: if (binding == null) {
553: if (environment.defaultPackage == null
554: || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
555: return new ProblemReferenceBinding(CharOperation
556: .subarray(compoundName, 0, i), null,
557: ProblemReasons.NotFound);
558: type = findType(compoundName[0],
559: environment.defaultPackage,
560: environment.defaultPackage);
561: if (type == null || !type.isValidBinding())
562: return new ProblemReferenceBinding(CharOperation
563: .subarray(compoundName, 0, i), null,
564: ProblemReasons.NotFound);
565: i = 1; // reset to look for member types inside the default package type
566: } else {
567: type = (ReferenceBinding) binding;
568: }
569:
570: while (i < length) {
571: type = (ReferenceBinding) environment
572: .convertToRawType(type); // type imports are necessarily raw for all except last
573: if (!type.canBeSeenBy(fPackage))
574: return new ProblemReferenceBinding(CharOperation
575: .subarray(compoundName, 0, i), type,
576: ProblemReasons.NotVisible);
577:
578: char[] name = compoundName[i++];
579: // does not look for inherited member types on purpose, only immediate members
580: type = type.getMemberType(name);
581: if (type == null)
582: return new ProblemReferenceBinding(CharOperation
583: .subarray(compoundName, 0, i), null,
584: ProblemReasons.NotFound);
585: }
586: if (!type.canBeSeenBy(fPackage))
587: return new ProblemReferenceBinding(compoundName, type,
588: ProblemReasons.NotVisible);
589: return type;
590: }
591:
592: private Binding findSingleImport(char[][] compoundName,
593: boolean findStaticImports) {
594: if (compoundName.length == 1) {
595: // findType records the reference
596: // the name cannot be a package
597: if (environment.defaultPackage == null
598: || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
599: return new ProblemReferenceBinding(compoundName, null,
600: ProblemReasons.NotFound);
601: ReferenceBinding typeBinding = findType(compoundName[0],
602: environment.defaultPackage, fPackage);
603: if (typeBinding == null)
604: return new ProblemReferenceBinding(compoundName, null,
605: ProblemReasons.NotFound);
606: return typeBinding;
607: }
608:
609: if (findStaticImports)
610: return findSingleStaticImport(compoundName);
611: return findImport(compoundName, compoundName.length);
612: }
613:
614: private Binding findSingleStaticImport(char[][] compoundName) {
615: Binding binding = findImport(compoundName,
616: compoundName.length - 1);
617: if (!binding.isValidBinding())
618: return binding;
619:
620: char[] name = compoundName[compoundName.length - 1];
621: if (binding instanceof PackageBinding) {
622: Binding temp = ((PackageBinding) binding)
623: .getTypeOrPackage(name);
624: if (temp != null && temp instanceof ReferenceBinding) // must resolve to a member type or field, not a top level type
625: return new ProblemReferenceBinding(compoundName,
626: (ReferenceBinding) temp,
627: ProblemReasons.InvalidTypeForStaticImport);
628: return binding; // cannot be a package, error is caught in sender
629: }
630:
631: // look to see if its a static field first
632: ReferenceBinding type = (ReferenceBinding) binding;
633: FieldBinding field = findField(type, name, null, true);
634: if (field != null && field.isValidBinding() && field.isStatic()
635: && field.canBeSeenBy(type, null, this ))
636: return field;
637:
638: // look to see if there is a static method with the same selector
639: MethodBinding method = findStaticMethod(type, name);
640: if (method != null)
641: return method;
642:
643: type = findMemberType(name, type);
644: if (type == null || !type.isStatic()) {
645: if (field != null && !field.isValidBinding()
646: && field.problemId() != ProblemReasons.NotFound)
647: return field;
648: return new ProblemReferenceBinding(compoundName, type,
649: ProblemReasons.NotFound);
650: }
651: if (!type.canBeSeenBy(fPackage))
652: return new ProblemReferenceBinding(compoundName, type,
653: ProblemReasons.NotVisible);
654: return type;
655: }
656:
657: MethodBinding findStaticMethod(ReferenceBinding currentType,
658: char[] selector) {
659: if (!currentType.canBeSeenBy(this ))
660: return null;
661:
662: do {
663: MethodBinding[] methods = currentType.getMethods(selector);
664: if (methods != Binding.NO_METHODS) {
665: for (int i = methods.length; --i >= 0;) {
666: MethodBinding method = methods[i];
667: if (method.isStatic()
668: && method.canBeSeenBy(fPackage))
669: return method;
670: }
671: }
672: if (currentType.super Interfaces() == null) // needed for statically imported types which don't know their hierarchy yet
673: ((SourceTypeBinding) currentType).scope
674: .connectTypeHierarchy();
675: } while ((currentType = currentType.super class()) != null);
676: return null;
677: }
678:
679: ImportBinding[] getDefaultImports() {
680: // initialize the default imports if necessary... share the default java.lang.* import
681: if (environment.defaultImports != null)
682: return environment.defaultImports;
683:
684: Binding importBinding = environment.getTopLevelPackage(JAVA);
685: if (importBinding != null)
686: importBinding = ((PackageBinding) importBinding)
687: .getTypeOrPackage(JAVA_LANG[1]);
688:
689: if (importBinding == null || !importBinding.isValidBinding()) {
690: // create a proxy for the missing BinaryType
691: BinaryTypeBinding missingObject = environment
692: .cacheMissingBinaryType(JAVA_LANG_OBJECT,
693: this .referenceContext);
694: importBinding = missingObject.fPackage;
695: }
696:
697: return environment.defaultImports = new ImportBinding[] { new ImportBinding(
698: JAVA_LANG, true, importBinding, null) };
699: }
700:
701: // NOT Public API
702: public final Binding getImport(char[][] compoundName,
703: boolean onDemand, boolean isStaticImport) {
704: if (onDemand)
705: return findImport(compoundName, compoundName.length);
706: return findSingleImport(compoundName, isStaticImport);
707: }
708:
709: public int nextCaptureID() {
710: return this .captureID++;
711: }
712:
713: /* Answer the problem reporter to use for raising new problems.
714: *
715: * Note that as a side-effect, this updates the current reference context
716: * (unit, type or method) in case the problem handler decides it is necessary
717: * to abort.
718: */
719: public ProblemReporter problemReporter() {
720: ProblemReporter problemReporter = referenceContext.problemReporter;
721: problemReporter.referenceContext = referenceContext;
722: return problemReporter;
723: }
724:
725: /*
726: What do we hold onto:
727:
728: 1. when we resolve 'a.b.c', say we keep only 'a.b.c'
729: & when we fail to resolve 'c' in 'a.b', lets keep 'a.b.c'
730: THEN when we come across a new/changed/removed item named 'a.b.c',
731: we would find all references to 'a.b.c'
732: -> This approach fails because every type is resolved in every onDemand import to
733: detect collision cases... so the references could be 10 times bigger than necessary.
734:
735: 2. when we resolve 'a.b.c', lets keep 'a.b' & 'c'
736: & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'c'
737: THEN when we come across a new/changed/removed item named 'a.b.c',
738: we would find all references to 'a.b' & 'c'
739: -> This approach does not have a space problem but fails to handle collision cases.
740: What happens if a type is added named 'a.b'? We would search for 'a' & 'b' but
741: would not find a match.
742:
743: 3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c'
744: & when we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c'
745: THEN when we come across a new/changed/removed item named 'a.b.c',
746: we would find all references to 'a.b' & 'c'
747: OR 'a.b' -> 'a' & 'b'
748: OR 'a' -> '' & 'a'
749: -> As long as each single char[] is interned, we should not have a space problem
750: and can handle collision cases.
751:
752: 4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c'
753: & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c'
754: THEN when we come across a new/changed/removed item named 'a.b.c',
755: we would find all references to 'a.b' & 'c'
756: OR 'a.b' -> 'a' & 'b' in the simple name collection
757: OR 'a' -> 'a' in the simple name collection
758: -> As long as each single char[] is interned, we should not have a space problem
759: and can handle collision cases.
760: */
761: void recordQualifiedReference(char[][] qualifiedName) {
762: if (qualifiedReferences == null)
763: return; // not recording dependencies
764:
765: int length = qualifiedName.length;
766: if (length > 1) {
767: while (!qualifiedReferences.contains(qualifiedName)) {
768: qualifiedReferences.add(qualifiedName);
769: if (length == 2) {
770: recordSimpleReference(qualifiedName[0]);
771: recordSimpleReference(qualifiedName[1]);
772: return;
773: }
774: length--;
775: recordSimpleReference(qualifiedName[length]);
776: System.arraycopy(qualifiedName, 0,
777: qualifiedName = new char[length][], 0, length);
778: }
779: } else if (length == 1) {
780: recordSimpleReference(qualifiedName[0]);
781: }
782: }
783:
784: void recordReference(char[][] qualifiedEnclosingName,
785: char[] simpleName) {
786: recordQualifiedReference(qualifiedEnclosingName);
787: recordSimpleReference(simpleName);
788: }
789:
790: void recordReference(ReferenceBinding type, char[] simpleName) {
791: ReferenceBinding actualType = typeToRecord(type);
792: if (actualType != null)
793: recordReference(actualType.compoundName, simpleName);
794: }
795:
796: void recordSimpleReference(char[] simpleName) {
797: if (simpleNameReferences == null)
798: return; // not recording dependencies
799:
800: if (!simpleNameReferences.contains(simpleName))
801: simpleNameReferences.add(simpleName);
802: }
803:
804: void recordSuperTypeReference(TypeBinding type) {
805: if (referencedSuperTypes == null)
806: return; // not recording dependencies
807:
808: ReferenceBinding actualType = typeToRecord(type);
809: if (actualType != null
810: && !referencedSuperTypes.containsIdentical(actualType))
811: referencedSuperTypes.add(actualType);
812: }
813:
814: public void recordTypeConversion(TypeBinding super Type,
815: TypeBinding subType) {
816: recordSuperTypeReference(subType); // must record the hierarchy of the subType that is converted to the superType
817: }
818:
819: void recordTypeReference(TypeBinding type) {
820: if (referencedTypes == null)
821: return; // not recording dependencies
822:
823: ReferenceBinding actualType = typeToRecord(type);
824: if (actualType != null
825: && !referencedTypes.containsIdentical(actualType))
826: referencedTypes.add(actualType);
827: }
828:
829: void recordTypeReferences(TypeBinding[] types) {
830: if (referencedTypes == null)
831: return; // not recording dependencies
832: if (types == null || types.length == 0)
833: return;
834:
835: for (int i = 0, max = types.length; i < max; i++) {
836: // No need to record supertypes of method arguments & thrown exceptions, just the compoundName
837: // If a field/method is retrieved from such a type then a separate call does the job
838: ReferenceBinding actualType = typeToRecord(types[i]);
839: if (actualType != null
840: && !referencedTypes.containsIdentical(actualType))
841: referencedTypes.add(actualType);
842: }
843: }
844:
845: Binding resolveSingleImport(ImportBinding importBinding) {
846: if (importBinding.resolvedImport == null) {
847: importBinding.resolvedImport = findSingleImport(
848: importBinding.compoundName, importBinding
849: .isStatic());
850: if (!importBinding.resolvedImport.isValidBinding()
851: || importBinding.resolvedImport instanceof PackageBinding) {
852: if (this .imports != null) {
853: ImportBinding[] newImports = new ImportBinding[imports.length - 1];
854: for (int i = 0, n = 0, max = this .imports.length; i < max; i++)
855: if (this .imports[i] != importBinding)
856: newImports[n++] = this .imports[i];
857: this .imports = newImports;
858: }
859: return null;
860: }
861: }
862: return importBinding.resolvedImport;
863: }
864:
865: public void storeDependencyInfo() {
866: // add the type hierarchy of each referenced supertype
867: // cannot do early since the hierarchy may not be fully resolved
868: for (int i = 0; i < referencedSuperTypes.size; i++) { // grows as more types are added
869: ReferenceBinding type = (ReferenceBinding) referencedSuperTypes
870: .elementAt(i);
871: if (!referencedTypes.containsIdentical(type))
872: referencedTypes.add(type);
873:
874: if (!type.isLocalType()) {
875: ReferenceBinding enclosing = type.enclosingType();
876: if (enclosing != null)
877: recordSuperTypeReference(enclosing);
878: }
879: ReferenceBinding super class = type.super class();
880: if (super class != null)
881: recordSuperTypeReference(super class);
882: ReferenceBinding[] interfaces = type.super Interfaces();
883: if (interfaces != null)
884: for (int j = 0, length = interfaces.length; j < length; j++)
885: recordSuperTypeReference(interfaces[j]);
886: }
887:
888: for (int i = 0, l = referencedTypes.size; i < l; i++) {
889: ReferenceBinding type = (ReferenceBinding) referencedTypes
890: .elementAt(i);
891: if (!type.isLocalType())
892: recordQualifiedReference(type.isMemberType() ? CharOperation
893: .splitOn('.', type.readableName())
894: : type.compoundName);
895: }
896:
897: int size = qualifiedReferences.size;
898: char[][][] qualifiedRefs = new char[size][][];
899: for (int i = 0; i < size; i++)
900: qualifiedRefs[i] = qualifiedReferences.elementAt(i);
901: referenceContext.compilationResult.qualifiedReferences = qualifiedRefs;
902:
903: size = simpleNameReferences.size;
904: char[][] simpleRefs = new char[size][];
905: for (int i = 0; i < size; i++)
906: simpleRefs[i] = simpleNameReferences.elementAt(i);
907: referenceContext.compilationResult.simpleNameReferences = simpleRefs;
908: }
909:
910: public String toString() {
911: return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$
912: }
913:
914: private ReferenceBinding typeToRecord(TypeBinding type) {
915: if (type.isArrayType())
916: type = ((ArrayBinding) type).leafComponentType;
917:
918: switch (type.kind()) {
919: case Binding.BASE_TYPE:
920: case Binding.TYPE_PARAMETER:
921: case Binding.WILDCARD_TYPE:
922: return null;
923: case Binding.PARAMETERIZED_TYPE:
924: case Binding.RAW_TYPE:
925: type = type.erasure();
926: }
927: ReferenceBinding refType = (ReferenceBinding) type;
928: if (refType.isLocalType())
929: return null;
930: return refType;
931: }
932:
933: public void verifyMethods(MethodVerifier verifier) {
934: for (int i = 0, length = topLevelTypes.length; i < length; i++)
935: topLevelTypes[i].verifyMethods(verifier);
936: }
937: }
|