/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Erling Ellingsen - patch for bug 125570 * NS Solutions Corporation - patch lineno455-459,680-684 *******************************************************************************/ package org.eclipse.wst.jsdt.internal.compiler.lookup; import java.util.ArrayList; import java.util.HashSet; import org.eclipse.wst.jsdt.core.LibrarySuperType; import org.eclipse.wst.jsdt.core.compiler.CharOperation; import org.eclipse.wst.jsdt.core.compiler.libraries.SystemLibraryLocation; import org.eclipse.wst.jsdt.core.infer.InferredType; import org.eclipse.wst.jsdt.core.infer.InferrenceManager; import org.eclipse.wst.jsdt.core.infer.InferrenceProvider; import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor; import org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode; import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.FunctionExpression; import org.eclipse.wst.jsdt.internal.compiler.ast.ImportReference; import org.eclipse.wst.jsdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction; import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter; import org.eclipse.wst.jsdt.internal.compiler.util.CompoundNameVector; import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject; import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfType; import org.eclipse.wst.jsdt.internal.compiler.util.ObjectVector; import org.eclipse.wst.jsdt.internal.compiler.util.SimpleNameVector; import org.eclipse.wst.jsdt.internal.compiler.util.SimpleSetOfCharArray; import org.eclipse.wst.jsdt.internal.core.util.Util; public class CompilationUnitScope extends BlockScope { public LookupEnvironment environment; public CompilationUnitDeclaration referenceContext; public char[][] currentPackageName; public PackageBinding fPackage; public ImportBinding[] imports; public HashtableOfObject typeOrPackageCache; // used in // Scope.getTypeOrPackage() public SourceTypeBinding[] topLevelTypes; private CompoundNameVector qualifiedReferences; private SimpleNameVector simpleNameReferences; private ObjectVector referencedTypes; private ObjectVector referencedSuperTypes; HashtableOfType constantPoolNameUsage; public int analysisIndex; private int captureID = 1; /* Allows a compilation unit to inherit fields from a superType */ public ReferenceBinding superBinding; private MethodScope methodScope; private ClassScope classScope; public int temporaryAnalysisIndex; public HashSet externalCompilationUnits = new HashSet(); public static final char FILENAME_DOT_SUBSTITUTION = '#'; class DeclarationVisitor extends ASTVisitor { ArrayList methods = new ArrayList(); public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { if (localDeclaration.initialization instanceof FunctionExpression) { this.visit(((FunctionExpression) localDeclaration.initialization).getMethodDeclaration(), scope); } else { TypeBinding type = localDeclaration.resolveVarType(scope); LocalVariableBinding binding = new LocalVariableBinding(localDeclaration, type, 0, false); localDeclaration.binding = binding; addLocalVariable(binding); } return false; } public boolean visit(MethodDeclaration methodDeclaration, Scope parentScope) { char[] selector = null; if (methodDeclaration.selector != null) { selector = methodDeclaration.selector; } else if (methodDeclaration.inferredMethod != null && methodDeclaration.inferredMethod.isConstructor) { // this is that inferred constructors get added to the methods // list selector = methodDeclaration.inferredMethod.name; } if (selector != null) { MethodScope scope = new MethodScope(parentScope, methodDeclaration, false); MethodBinding methodBinding = scope.createMethod(methodDeclaration, selector, referenceContext.compilationUnitBinding, false, false); if (methodBinding != null && methodBinding.selector != null) // is // null // if // binding // could // not // be // created methods.add(methodBinding); if (methodBinding.selector != null) { environment.defaultPackage.addBinding(methodBinding, methodBinding.selector, Binding.METHOD); fPackage.addBinding(methodBinding, methodBinding.selector, Binding.METHOD); } methodDeclaration.binding = methodBinding; methodDeclaration.bindArguments(); } return false; } } public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) { super(COMPILATION_UNIT_SCOPE, null); this.environment = environment; this.referenceContext = unit; unit.scope = this; /* bc - start bug 218398 - NPE when doing source->cleanup */ char[][] pkgName = unit.currentPackage == null ? (unit.compilationResult != null ? unit.compilationResult .getPackageName() : null) : unit.currentPackage.tokens; this.currentPackageName = pkgName == null ? CharOperation.NO_CHAR_CHAR : pkgName; // this.currentPackageName = CharOperation.NO_CHAR_CHAR; /* bc - end bug 218398 - NPE when doing source->cleanup */ this.referencedTypes = new ObjectVector(); if (compilerOptions().produceReferenceInfo) { this.qualifiedReferences = new CompoundNameVector(); this.simpleNameReferences = new SimpleNameVector(); this.referencedSuperTypes = new ObjectVector(); } else { this.qualifiedReferences = null; // used to test if dependencies // should be recorded this.simpleNameReferences = null; // this.referencedTypes = null; this.referencedSuperTypes = null; } } protected CompilationUnitScope(LookupEnvironment environment) { super(COMPILATION_UNIT_SCOPE, null); this.environment = environment; this.referencedTypes = new ObjectVector(); if (compilerOptions().produceReferenceInfo) { this.qualifiedReferences = new CompoundNameVector(); this.simpleNameReferences = new SimpleNameVector(); this.referencedSuperTypes = new ObjectVector(); } else { this.qualifiedReferences = null; // used to test if dependencies // should be recorded this.simpleNameReferences = null; // this.referencedTypes = null; this.referencedSuperTypes = null; } } // public MethodScope methodScope() { // if(superBinding!=null && methodScope==null) { // methodScope = new MethodScope(classScope,referenceContext(),false); // } // // return methodScope; // } public ClassScope classScope() { if (this.classScope != null) return this.classScope; return super.classScope(); } void buildFieldsAndMethods() { for (int i = 0, length = topLevelTypes.length; i < length; i++) topLevelTypes[i].buildFieldsAndMethods(); } void buildTypeBindings(AccessRestriction accessRestriction) { buildTypeBindings(new char[0][0], accessRestriction); } void buildTypeBindings(char[][] restrictToNames, AccessRestriction accessRestriction) { topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the // package cannot be // resolved if (referenceContext.compilationResult.compilationUnit != null) { char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName(); if (expectedPackageName != null && !CharOperation.equals(currentPackageName, expectedPackageName)) { currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName; } } if (currentPackageName == CharOperation.NO_CHAR_CHAR) { fPackage = environment.defaultPackage; } else { if ((fPackage = environment.createPackage(currentPackageName)) == null) { // problemReporter().packageCollidesWithType(referenceContext); // return; // } else if (referenceContext.isPackageInfo()) { // // resolve package annotations now if this is // "package-info.js". // if (referenceContext.types == null || // referenceContext.types.length == 0) { // referenceContext.types = new TypeDeclaration[1]; // TypeDeclaration declaration = new // TypeDeclaration(referenceContext.compilationResult); // referenceContext.types[0] = declaration; // declaration.name = TypeConstants.PACKAGE_INFO_NAME; // declaration.modifiers = ClassFileConstants.AccDefault | // ClassFileConstants.AccInterface; // firstIsSynthetic = true; // } } // recordQualifiedReference(currentPackageName); // always dependent // on your own package } // // Skip typeDeclarations which know of previously reported errors // TypeDeclaration[] types = referenceContext.types; // int typeLength = (types == null) ? 0 : types.length; // topLevelTypes = new SourceTypeBinding[typeLength]; // int count = 0; // nextType: for (int i = 0; i < typeLength; i++) { // TypeDeclaration typeDecl = types[i]; // ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name); // recordSimpleReference(typeDecl.name); // needed to detect collision // cases // if (typeBinding != null && !(typeBinding instanceof // UnresolvedReferenceBinding)) { // // if a type exists, it must be a valid type - cannot be a NotFound // problem type // // unless its an unresolved type which is now being defined // problemReporter().duplicateTypes(referenceContext, typeDecl); // continue nextType; // } // if (fPackage != environment.defaultPackage && // fPackage.getPackage(typeDecl.name) != null) { // // if a package exists, it must be a valid package - cannot be a // NotFound problem package // problemReporter().typeCollidesWithPackage(referenceContext, // typeDecl); // continue nextType; // } // // if ((typeDecl.modifiers & ClassFileConstants.AccPublic) != 0) { // char[] mainTypeName; // if ((mainTypeName = referenceContext.getMainTypeName()) != null // // mainTypeName == null means that implementor of IJavaScriptUnit // decided to return null // && !CharOperation.equals(mainTypeName, typeDecl.name)) { // problemReporter().publicClassMustMatchFileName(referenceContext, // typeDecl); // // tolerate faulty main type name (91091), allow to proceed into type // construction // } // } // // ClassScope child = new ClassScope(this, typeDecl); // SourceTypeBinding type = child.buildType(null, fPackage, // accessRestriction); // if (firstIsSynthetic && i == 0) // type.modifiers |= ClassFileConstants.AccSynthetic; // if (type != null) // topLevelTypes[count++] = type; // } // // // shrink topLevelTypes... only happens if an error was reported // if (count != topLevelTypes.length) // System.arraycopy(topLevelTypes, 0, topLevelTypes = new // SourceTypeBinding[count], 0, count); // this.faultInImports(); // Skip typeDeclarations which know of previously reported errors int typeLength = referenceContext.numberInferredTypes; /* Include super type whild building */ // if(superTypeName!=null) { // superType = environment.askForType(new char[][] {superTypeName}); // } // //((SourceTypeBinding)superType).classScope.buildInferredType(null, // environment.defaultPackage,accessRestriction); // //((SourceTypeBinding)superType).classScope.connectTypeHierarchy(); // //FieldBinding[] fields = superType.fields(); // //addSubscope(((SourceTypeBinding)superType).classScope); // // // // this.parent = ((SourceTypeBinding)superType).classScope; // // // } // // // } /* may need to get the actual binding here */ // if(libSuperType!=null) { // //JsGlobalScopeContainerInitializer cinit = // libSuperType.getContainerInitializer(); // //IIncludePathEntry[] entries = libSuperType.getClasspathEntries(); // IPackageFragment[] fragments = libSuperType.getPackageFragments(); // for(int i = 0;i<fragments.length;i++) { // String packageName = fragments[i].getElementName(); // PackageBinding binding = // environment.getPackage0(packageName.toCharArray()); // superBinding = // binding.getType(libSuperType.getSuperTypeName().toCharArray()); // if(superBinding!=null) break; // // } // // }else topLevelTypes = new SourceTypeBinding[typeLength]; int count = 0; SimpleSetOfCharArray addTypes = new SimpleSetOfCharArray(10); // nextType: String fileName = new String(this.referenceContext.getFileName()); nextType: for (int i = 0; i < typeLength; i++) { InferredType typeDecl = referenceContext.inferredTypes[i]; if (typeDecl.isDefinition && !typeDecl.isEmptyGlobal()) { if (restrictToNames.length > 0) { boolean continueBuilding = false; for (int j = 0; !continueBuilding && j < restrictToNames.length; j++) { if (CharOperation.equals(typeDecl.getName(), restrictToNames[j])) continueBuilding = true; } if (!continueBuilding) continue nextType; } ReferenceBinding typeBinding = environment.defaultPackage.getType0(typeDecl.getName()); recordSimpleReference(typeDecl.getName()); // needed to detect // collision cases SourceTypeBinding existingBinding = null; if (typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) { // if a type exists, it must be a valid type - cannot be a // NotFound problem type // unless its an unresolved type which is now being defined // problemReporter().duplicateTypes(referenceContext, // typeDecl); // continue nextType; if (typeBinding instanceof SourceTypeBinding) existingBinding = (SourceTypeBinding) typeBinding; } ClassScope child = new ClassScope(this, typeDecl); SourceTypeBinding type = child.buildInferredType(null, environment.defaultPackage, accessRestriction); // SourceTypeBinding type = buildType(typeDecl,null, fPackage, // accessRestriction); if (type != null) { if (existingBinding != null && typeDecl.isNamed()) { if (existingBinding.nextType != null) { existingBinding.addNextType(type); } else { if (!CharOperation.equals(type.fileName, existingBinding.fileName)) existingBinding.addNextType(type); } environment.defaultPackage.addType(existingBinding); fPackage.addType(existingBinding); } else if (typeDecl.isNamed()) addTypes.add(typeDecl.getName()); // environment.addUnitsContainingBinding(null, // typeDecl.getName(), Binding.TYPE,fileName); topLevelTypes[count++] = type; } } } char[][] typeNames = new char[addTypes.elementSize][]; addTypes.asArray(typeNames); environment.addUnitsContainingBindings(typeNames, Binding.TYPE, fileName); // shrink topLevelTypes... only happens if an error was reported if (count != topLevelTypes.length) System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count); buildSuperType(); char[] path = CharOperation.concatWith(this.currentPackageName, '/'); referenceContext.compilationUnitBinding = new CompilationUnitBinding(this, environment.defaultPackage, path, superBinding); if (fPackage != environment.defaultPackage) fPackage.addBinding(referenceContext.compilationUnitBinding, referenceContext.getMainTypeName(), Binding.COMPILATION_UNIT); DeclarationVisitor visitor = new DeclarationVisitor(); this.referenceContext.traverse(visitor, this); MethodBinding[] methods = (MethodBinding[]) visitor.methods.toArray(new MethodBinding[visitor.methods.size()]); referenceContext.compilationUnitBinding.setMethods(methods); } public void buildSuperType() { char[] superTypeName = null; LibrarySuperType libSuperType = null; if (this.referenceContext.compilationResult != null && this.referenceContext.compilationResult.compilationUnit != null) { libSuperType = this.referenceContext.compilationResult.compilationUnit.getCommonSuperType(); if (libSuperType == null) { superTypeName = null; return; } else superTypeName = libSuperType.getSuperTypeName().toCharArray(); } if (superTypeName == null) return; // superBinding = environment.askForType(new char[][] {superTypeName}); superBinding = findType(superTypeName, environment.defaultPackage, environment.defaultPackage); if (superBinding == null || !superBinding.isValidBinding()) { superTypeName = null; return; } /* * If super type is combined source type, search through SourceTypes for * the specific instance */ if ((superBinding instanceof SourceTypeBinding) && ((SourceTypeBinding) superBinding).nextType != null) { classScope = ((SourceTypeBinding) superBinding).classScope; SourceTypeBinding sourceType = null; if (superBinding instanceof SourceTypeBinding) { sourceType = (SourceTypeBinding) superBinding; } // start 2012/04/09 if (classScope != null) { classScope.buildInferredType(sourceType, environment.defaultPackage, null); } // end 2012/04/09 recordTypeReference(superBinding); recordSuperTypeReference(superBinding); environment().setAccessRestriction(superBinding, null); } else if (superBinding != null) { InferredType te = superBinding.getInferredType(); classScope = new ClassScope(this, te); SourceTypeBinding sourceType = null; if (superBinding instanceof SourceTypeBinding) { sourceType = (SourceTypeBinding) superBinding; } classScope.buildInferredType(sourceType, environment.defaultPackage, null); recordTypeReference(superBinding); recordSuperTypeReference(superBinding); environment().setAccessRestriction(superBinding, null); } if (superTypeName != null && superTypeName.length == 0) { superTypeName = null; } } SourceTypeBinding buildType(InferredType inferredType, SourceTypeBinding enclosingType, PackageBinding packageBinding, AccessRestriction accessRestriction) { // provide the typeDeclaration with needed scopes if (enclosingType == null) { char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, inferredType.getName()); inferredType.binding = new SourceTypeBinding(className, packageBinding, this); // @GINO: Anonymous set bits if (inferredType.isAnonymous) inferredType.binding.tagBits |= TagBits.AnonymousTypeMask; } else { // char[][] className = // CharOperation.deepCopy(enclosingType.compoundName); // className[className.length - 1] = // CharOperation.concat(className[className.length - 1], // inferredType.getName(), '$'); // inferredType.binding = new MemberTypeBinding(className, this, // enclosingType); } SourceTypeBinding sourceType = inferredType.binding; environment().setAccessRestriction(sourceType, accessRestriction); environment().defaultPackage.addType(sourceType); sourceType.fPackage.addType(sourceType); return sourceType; } public PackageBinding getDefaultPackage() { return environment.defaultPackage; } public void addLocalVariable(LocalVariableBinding binding) { super.addLocalVariable(binding); environment.defaultPackage.addBinding(binding, binding.name, Binding.VARIABLE); fPackage.addBinding(binding, binding.name, Binding.VARIABLE); } void checkAndSetImports() { if (referenceContext.imports == null) { imports = getDefaultImports(); return; } // allocate the import array, add java.lang.* by default int numberOfStatements = referenceContext.imports.length; int numberOfImports = numberOfStatements + 1; for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = referenceContext.imports[i]; if (((importReference.bits & ASTNode.OnDemand) != 0) && CharOperation.equals(JAVA_LANG, importReference.tokens)) { numberOfImports--; break; } } ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; resolvedImports[0] = getDefaultImports()[0]; int index = 1; nextImport: for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = referenceContext.imports[i]; char[][] compoundName = importReference.tokens; // skip duplicates or imports of the current package for (int j = 0; j < index; j++) { ImportBinding resolved = resolvedImports[j]; if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)) if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) continue nextImport; } if ((importReference.bits & ASTNode.OnDemand) != 0) { if (CharOperation.equals(compoundName, currentPackageName)) continue nextImport; Binding importBinding = findImport(compoundName, compoundName.length); if (!importBinding.isValidBinding()) continue nextImport; // we report all problems in // faultInImports() resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); } else { // resolve single imports only when the last name matches resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference); } } // shrink resolvedImports... only happens if an error was reported if (resolvedImports.length > index) System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); imports = resolvedImports; } /* * INTERNAL USE-ONLY Innerclasses get their name computed as they are * generated, since some may not be actually outputed if sitting inside * unreachable code. */ public char[] computeConstantPoolName(LocalTypeBinding localType) { if (localType.constantPoolName() != null) { return localType.constantPoolName(); } // delegates to the outermost enclosing classfile, since it is the only // one with a global vision of its innertypes. if (constantPoolNameUsage == null) constantPoolNameUsage = new HashtableOfType(); ReferenceBinding outerMostEnclosingType = localType.scope.outerMostClassScope().enclosingSourceType(); // ensure there is not already such a local type name defined by the // user int index = 0; char[] candidateName; boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5; while (true) { if (localType.isMemberType()) { if (index == 0) { candidateName = CharOperation.concat(localType.enclosingType().constantPoolName(), localType.sourceName, '$'); } else { // in case of collision, then member name gets extra $1 // inserted // e.g. class X { { class L{} new X(){ class L{} } } } candidateName = CharOperation.concat(localType.enclosingType().constantPoolName(), '$', String .valueOf(index).toCharArray(), '$', localType.sourceName); } } else if (localType.isAnonymousType()) { if (isCompliant15) { // from 1.5 on, use immediately enclosing type name candidateName = CharOperation.concat(localType.enclosingType.constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'); } else { candidateName = CharOperation.concat(outerMostEnclosingType.constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'); } } else { // local type if (isCompliant15) { candidateName = CharOperation.concat(CharOperation.concat(localType.enclosingType() .constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'), localType.sourceName); } else { candidateName = CharOperation.concat(outerMostEnclosingType.constantPoolName(), '$', String .valueOf(index + 1).toCharArray(), '$', localType.sourceName); } } if (constantPoolNameUsage.get(candidateName) != null) { index++; } else { constantPoolNameUsage.put(candidateName, localType); break; } } return candidateName; } void connectTypeHierarchy(char[][] typeNames) { // if(superType!=null) { // if(superType instanceof SourceTypeBinding) { // ((SourceTypeBinding)superType).classScope.buildFieldsAndMethods(); // ((SourceTypeBinding)superType).classScope.connectTypeHierarchy(); // // } // ReferenceBinding[] memberTypes = superType.memberTypes(); // ReferenceBinding[] memberFields = superType.typeVariables(); // FunctionBinding[] memberMethods = superType.availableMethods(); // for(int i=0;i<memberTypes.length;i++) { // recordReference(memberTypes[i], memberTypes[i].sourceName); // } // } // if(superTypeName!=null) { // ReferenceBinding binding = environment.askForType(new char[][] // {superTypeName}); // this.recordSuperTypeReference(binding); // } if (classScope != null) classScope.connectTypeHierarchy(); nextType: for (int i = 0; i < referenceContext.numberInferredTypes; i++) { InferredType inferredType = referenceContext.inferredTypes[i]; if (typeNames.length > 0) { boolean continueBuilding = false; for (int j = 0; !continueBuilding && j < typeNames.length; j++) { if (CharOperation.equals(inferredType.getName(), typeNames[j])) continueBuilding = true; } if (!continueBuilding) continue nextType; } // start 2012/04/09 if (inferredType.binding != null && inferredType.binding.classScope != null) inferredType.binding.classScope.connectTypeHierarchy(); // end 2012/04/09 } } void connectTypeHierarchy() { connectTypeHierarchy(new char[0][0]); } void faultInImports() { if (this.typeOrPackageCache != null) return; // can be called when a field constant is resolved before // static imports if (referenceContext.imports == null) { this.typeOrPackageCache = new HashtableOfObject(1); return; } // collect the top level type names if a single type import exists int numberOfStatements = referenceContext.imports.length; HashtableOfType typesBySimpleNames = null; for (int i = 0; i < numberOfStatements; i++) { if ((referenceContext.imports[i].bits & ASTNode.OnDemand) == 0) { typesBySimpleNames = new HashtableOfType(topLevelTypes.length + numberOfStatements); for (int j = 0, length = topLevelTypes.length; j < length; j++) typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]); break; } } // allocate the import array, add java.lang.* by default ImportBinding[] defaultImports = getDefaultImports(); int numberOfImports = numberOfStatements + defaultImports.length; for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = referenceContext.imports[i]; if (((importReference.bits & ASTNode.OnDemand) != 0) && CharOperation.equals(JAVA_LANG, importReference.tokens)) { numberOfImports--; break; } } ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; System.arraycopy(defaultImports, 0, resolvedImports, 0, defaultImports.length); int index = defaultImports.length; // keep static imports with normal imports until there is a reason to // split them up // on demand imports continue to be packages & types. need to check on // demand type imports for fields/methods // single imports change from being just types to types or fields nextImport: for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = referenceContext.imports[i]; char[][] compoundName = importReference.tokens; // skip duplicates or imports of the current package for (int j = 0; j < index; j++) { ImportBinding resolved = resolvedImports[j]; if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)) { if (CharOperation.equals(compoundName, resolved.compoundName)) { continue nextImport; } } } if ((importReference.bits & ASTNode.OnDemand) != 0) { if (CharOperation.equals(compoundName, currentPackageName)) { continue nextImport; } Binding importBinding = findImport(compoundName, compoundName.length); if (!importBinding.isValidBinding()) { continue nextImport; } resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference); } else { Binding importBinding = findSingleImport(compoundName); if (!importBinding.isValidBinding()) { continue nextImport; } ReferenceBinding conflictingType = null; if (importBinding instanceof MethodBinding) { conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length); if (!conflictingType.isValidBinding()) conflictingType = null; } // collisions between an imported static field & a type should // be checked according to spec... but currently not by javac if (importBinding instanceof ReferenceBinding || conflictingType != null) { ReferenceBinding referenceBinding = conflictingType == null ? (ReferenceBinding) importBinding : conflictingType; if (importReference.isTypeUseDeprecated(referenceBinding, this)) problemReporter().deprecatedType(referenceBinding, importReference); ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]); if (existingType != null) { continue nextImport; } typesBySimpleNames.put(compoundName[compoundName.length - 1], referenceBinding); } resolvedImports[index++] = conflictingType == null ? new ImportBinding(compoundName, false, importBinding, importReference) : new ImportConflictBinding(compoundName, importBinding, conflictingType, importReference); } } // shrink resolvedImports... only happens if an error was reported if (resolvedImports.length > index) System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index); imports = resolvedImports; int length = imports.length; this.typeOrPackageCache = new HashtableOfObject(length); for (int i = 0; i < length; i++) { ImportBinding binding = imports[i]; if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding || binding instanceof ImportConflictBinding) this.typeOrPackageCache.put(binding.compoundName[binding.compoundName.length - 1], binding); } } public void faultInTypes() { faultInImports(); this.referenceContext.compilationUnitBinding.faultInTypesForFieldsAndMethods(); for (int i = 0, length = topLevelTypes.length; i < length; i++) topLevelTypes[i].faultInTypesForFieldsAndMethods(); } // this API is for code assist purpose public Binding findImport(char[][] compoundName, boolean onDemand) { if (onDemand) { return findImport(compoundName, compoundName.length); } else { return findSingleImport(compoundName); } } private Binding findImport(char[][] compoundName, int length) { recordQualifiedReference(compoundName); Binding binding = environment.getTopLevelPackage(compoundName[0]); int i = 1; foundNothingOrType: if (binding != null) { PackageBinding packageBinding = (PackageBinding) binding; while (i < length) { int type = (i + 1 == length) ? Binding.COMPILATION_UNIT : Binding.PACKAGE; binding = packageBinding.getTypeOrPackage(compoundName[i++], type); if (binding == null || !binding.isValidBinding()) { binding = null; break foundNothingOrType; } if (i == length && (binding instanceof CompilationUnitBinding)) return binding; if (!(binding instanceof PackageBinding)) break foundNothingOrType; packageBinding = (PackageBinding) binding; } return packageBinding; } ReferenceBinding type; if (binding == null) { if (environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); if (type == null || !type.isValidBinding()) return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); i = 1; // reset to look for member types inside the default package // type } else { type = (ReferenceBinding) binding; } while (i < length) { if (!type.canBeSeenBy(environment.defaultPackage)) return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type, ProblemReasons.NotVisible); char[] name = compoundName[i++]; // does not look for inherited member types on purpose, only // immediate members type = type.getMemberType(name); if (type == null) return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound); } if (!type.canBeSeenBy(environment.defaultPackage)) return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible); return type; } private Binding findSingleImport(char[][] compoundName) { if (compoundName.length == 1) { // findType records the reference // the name cannot be a package if (environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) return new ProblemReferenceBinding(compoundName, null, ProblemReasons.NotFound); ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); if (typeBinding == null) return new ProblemReferenceBinding(compoundName, null, ProblemReasons.NotFound); return typeBinding; } return findImport(compoundName, compoundName.length); } MethodBinding findStaticMethod(ReferenceBinding currentType, char[] selector) { if (!currentType.canBeSeenBy(this)) return null; do { MethodBinding[] methods = currentType.getMethods(selector); if (methods != Binding.NO_METHODS) { for (int i = methods.length; --i >= 0;) { MethodBinding method = methods[i]; if (method.isStatic() && method.canBeSeenBy(environment.defaultPackage)) return method; } } ((SourceTypeBinding) currentType).classScope.connectTypeHierarchy(); } while ((currentType = currentType.superclass()) != null); return null; } ImportBinding[] getDefaultImports() { // initialize the default imports if necessary... share the default // java.lang.* import Binding importBinding = environment.defaultPackage; // if (importBinding != null) // importBinding = ((PackageBinding) // importBinding).getTypeOrPackage(JAVA_LANG[1]); // abort if java.lang cannot be found... if (importBinding == null || !importBinding.isValidBinding()) { // create a proxy for the missing BinaryType MissingBinaryTypeBinding missingObject = environment.cacheMissingBinaryType(JAVA_LANG_OBJECT, this.referenceContext); importBinding = missingObject.fPackage; } ImportBinding systemJSBinding = null; if (environment.defaultImports != null) { systemJSBinding = environment.defaultImports[0]; } else { systemJSBinding = new ImportBinding(new char[][] { SystemLibraryLocation.SYSTEM_LIBARAY_NAME }, true, importBinding, (ImportReference) null); environment.defaultImports = new ImportBinding[] { systemJSBinding }; } ImportBinding[] defaultImports = null; String[] contextIncludes = null; InferrenceProvider[] inferenceProviders = InferrenceManager.getInstance().getInferenceProviders( this.referenceContext); if (inferenceProviders != null && inferenceProviders.length > 0) { for (int i = 0; i < inferenceProviders.length; i++) { if (contextIncludes == null) { contextIncludes = inferenceProviders[i].getResolutionConfiguration().getContextIncludes(); } else { String[] contextIncludesTemp = inferenceProviders[0].getResolutionConfiguration() .getContextIncludes(); if (contextIncludesTemp != null) { String[] contextIncludesOld = contextIncludes; contextIncludes = new String[contextIncludesTemp.length + contextIncludesOld.length]; System.arraycopy(contextIncludesOld, 0, contextIncludes, 0, contextIncludesOld.length); System.arraycopy(contextIncludesTemp, 0, contextIncludes, contextIncludesOld.length - 1, contextIncludesTemp.length); } } } } if (contextIncludes != null && contextIncludes.length > 0) { ArrayList list = new ArrayList(); list.add(systemJSBinding); for (int i = 0; i < contextIncludes.length; i++) { String include = contextIncludes[i]; if (include != null) { int index = Util.indexOfJavaLikeExtension(include); if (index >= 0) include = include.substring(0, index); include = include.replace('.', FILENAME_DOT_SUBSTITUTION); char[][] qualifiedName = CharOperation.splitOn('/', include.toCharArray()); Binding binding = findImport(qualifiedName, qualifiedName.length); if (binding.isValidBinding()) { list.add(new ImportBinding(qualifiedName, true, binding, null)); } } } defaultImports = (ImportBinding[]) list.toArray(new ImportBinding[list.size()]); } else defaultImports = new ImportBinding[] { systemJSBinding }; return defaultImports; } // NOT Public API public final Binding getImport(char[][] compoundName, boolean onDemand) { if (onDemand) return findImport(compoundName, compoundName.length); return findSingleImport(compoundName); } public int nextCaptureID() { return this.captureID++; } /* * Answer the problem reporter to use for raising new problems. * * Note that as a side-effect, this updates the current reference context * (unit, type or method) in case the problem handler decides it is * necessary to abort. */ public ProblemReporter problemReporter() { ProblemReporter problemReporter = referenceContext.problemReporter; problemReporter.referenceContext = referenceContext; return problemReporter; } /* * What do we hold onto: * * 1. when we resolve 'a.b.c', say we keep only 'a.b.c' & when we fail to * resolve 'c' in 'a.b', lets keep 'a.b.c' THEN when we come across a * new/changed/removed item named 'a.b.c', we would find all references to * 'a.b.c' -> This approach fails because every type is resolved in every * onDemand import to detect collision cases... so the references could be * 10 times bigger than necessary. * * 2. when we resolve 'a.b.c', lets keep 'a.b' & 'c' & when we fail to * resolve 'c' in 'a.b', lets keep 'a.b' & 'c' THEN when we come across a * new/changed/removed item named 'a.b.c', we would find all references to * 'a.b' & 'c' -> This approach does not have a space problem but fails to * handle collision cases. What happens if a type is added named 'a.b'? We * would search for 'a' & 'b' but would not find a match. * * 3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c' & when * we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c' * THEN when we come across a new/changed/removed item named 'a.b.c', we * would find all references to 'a.b' & 'c' OR 'a.b' -> 'a' & 'b' OR 'a' -> * '' & 'a' -> As long as each single char[] is interned, we should not have * a space problem and can handle collision cases. * * 4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c' & when we * fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c' THEN when * we come across a new/changed/removed item named 'a.b.c', we would find * all references to 'a.b' & 'c' OR 'a.b' -> 'a' & 'b' in the simple name * collection OR 'a' -> 'a' in the simple name collection -> As long as each * single char[] is interned, we should not have a space problem and can * handle collision cases. */ void recordQualifiedReference(char[][] qualifiedName) { if (qualifiedReferences == null) return; // not recording dependencies int length = qualifiedName.length; if (length > 1) { while (!qualifiedReferences.contains(qualifiedName)) { qualifiedReferences.add(qualifiedName); if (length == 2) { recordSimpleReference(qualifiedName[0]); recordSimpleReference(qualifiedName[1]); return; } length--; recordSimpleReference(qualifiedName[length]); System.arraycopy(qualifiedName, 0, qualifiedName = new char[length][], 0, length); } } else if (length == 1) { recordSimpleReference(qualifiedName[0]); } } void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) { recordQualifiedReference(qualifiedEnclosingName); recordSimpleReference(simpleName); } void recordReference(ReferenceBinding type, char[] simpleName) { ReferenceBinding actualType = typeToRecord(type); if (actualType != null) recordReference(actualType.compoundName, simpleName); } void recordSimpleReference(char[] simpleName) { if (simpleNameReferences == null) return; // not recording dependencies if (!simpleNameReferences.contains(simpleName)) simpleNameReferences.add(simpleName); } void recordSuperTypeReference(TypeBinding type) { if (referencedSuperTypes == null) return; // not recording dependencies ReferenceBinding actualType = typeToRecord(type); if (actualType != null && !referencedSuperTypes.containsIdentical(actualType)) referencedSuperTypes.add(actualType); } public void recordTypeConversion(TypeBinding superType, TypeBinding subType) { recordSuperTypeReference(subType); // must record the hierarchy of the // subType that is converted to the // superType } void recordTypeReference(TypeBinding type) { if (referencedTypes == null) return; // not recording dependencies ReferenceBinding actualType = typeToRecord(type); if (actualType != null && !referencedTypes.containsIdentical(actualType)) referencedTypes.add(actualType); } void recordTypeReferences(TypeBinding[] types) { if (referencedTypes == null) return; // not recording dependencies if (types == null || types.length == 0) return; for (int i = 0, max = types.length; i < max; i++) { // No need to record supertypes of method arguments & thrown // exceptions, just the compoundName // If a field/method is retrieved from such a type then a separate // call does the job ReferenceBinding actualType = typeToRecord(types[i]); if (actualType != null && !referencedTypes.containsIdentical(actualType)) referencedTypes.add(actualType); } } Binding resolveSingleImport(ImportBinding importBinding) { if (importBinding.resolvedImport == null) { importBinding.resolvedImport = findSingleImport(importBinding.compoundName); if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) { if (this.imports != null) { ImportBinding[] newImports = new ImportBinding[imports.length - 1]; for (int i = 0, n = 0, max = this.imports.length; i < max; i++) if (this.imports[i] != importBinding) newImports[n++] = this.imports[i]; this.imports = newImports; } return null; } } return importBinding.resolvedImport; } public void storeDependencyInfo() { // add the type hierarchy of each referenced supertype // cannot do early since the hierarchy may not be fully resolved for (int i = 0; i < referencedSuperTypes.size; i++) { // grows as more // types are // added ReferenceBinding type = (ReferenceBinding) referencedSuperTypes.elementAt(i); if (!referencedTypes.containsIdentical(type)) referencedTypes.add(type); if (!type.isLocalType()) { ReferenceBinding enclosing = type.enclosingType(); if (enclosing != null) recordSuperTypeReference(enclosing); } ReferenceBinding superclass = type.superclass(); if (superclass != null) recordSuperTypeReference(superclass); } for (int i = 0, l = referencedTypes.size; i < l; i++) { ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i); if (type instanceof MultipleTypeBinding) { ReferenceBinding[] types = ((MultipleTypeBinding) type).types; for (int j = 0; j < types.length; j++) { if (!types[j].isLocalType()) recordQualifiedReference(types[j].isMemberType() ? CharOperation.splitOn('.', types[j].readableName()) : types[j].compoundName); } } else if (!type.isLocalType()) recordQualifiedReference(type.isMemberType() ? CharOperation.splitOn('.', type.readableName()) : type.compoundName); } int size = qualifiedReferences.size; char[][][] qualifiedRefs = new char[size][][]; for (int i = 0; i < size; i++) qualifiedRefs[i] = qualifiedReferences.elementAt(i); referenceContext.compilationResult.qualifiedReferences = qualifiedRefs; size = simpleNameReferences.size; char[][] simpleRefs = new char[size][]; for (int i = 0; i < size; i++) simpleRefs[i] = simpleNameReferences.elementAt(i); referenceContext.compilationResult.simpleNameReferences = simpleRefs; } public String toString() { return "--- JavaScriptUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$ } private ReferenceBinding typeToRecord(TypeBinding type) { while (type.isArrayType()) type = ((ArrayBinding) type).leafComponentType; switch (type.kind()) { case Binding.BASE_TYPE: return null; } if (type instanceof CompilationUnitBinding) return null; ReferenceBinding refType = (ReferenceBinding) type; if (refType.isLocalType()) return null; return refType; } public void verifyMethods(MethodVerifier verifier) { for (int i = 0, length = topLevelTypes.length; i < length; i++) topLevelTypes[i].verifyMethods(verifier); } public void cleanup() { if (this.referencedTypes != null) for (int i = 0, l = referencedTypes.size; i < l; i++) { Object obj = referencedTypes.elementAt(i); if (obj instanceof SourceTypeBinding) { SourceTypeBinding type = (SourceTypeBinding) obj; type.cleanup(); } } } public void addExternalVar(LocalVariableBinding binding) { externalCompilationUnits.add(binding.declaringScope.compilationUnitScope()); } }