public void checkAndSetImports() { // AspectJ Extension - raised to public if (this.referenceContext.imports == null) { this.imports = getDefaultImports(); return; } // allocate the import array, add java.lang.* by default int numberOfStatements = this.referenceContext.imports.length; int numberOfImports = numberOfStatements + 1; for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = this.referenceContext.imports[i]; if (((importReference.bits & ASTNode.OnDemand) != 0) && CharOperation.equals(TypeConstants.JAVA_LANG, importReference.tokens) && !importReference.isStatic()) { numberOfImports--; break; } } ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; resolvedImports[0] = getDefaultImports()[0]; int index = 1; nextImport: for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = this.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) && resolved.isStatic() == importReference.isStatic()) if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) continue nextImport; } if ((importReference.bits & ASTNode.OnDemand) != 0) { if (CharOperation.equals(compoundName, this.currentPackageName)) continue nextImport; Binding importBinding = findImport(compoundName, compoundName.length); if (!importBinding.isValidBinding() || (importReference.isStatic() && importBinding instanceof PackageBinding)) 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); this.imports = resolvedImports; }
/* * Creates the super class handle of the given type. * Returns null if the type has no super class. * Adds the simple name to the hierarchy missing types if the class is not found and returns null. */ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) { ReferenceBinding superBinding = typeBinding.superclass(); if (superBinding != null) { superBinding = (ReferenceBinding) superBinding.erasure(); if (typeBinding.isHierarchyInconsistent()) { if (superBinding.problemId() == ProblemReasons.NotFound) { this.hasMissingSuperClass = true; this.builder.hierarchy.missingTypes.add( new String(superBinding.sourceName)); // note: this could be Map$Entry return null; } else if ((superBinding.id == TypeIds.T_JavaLangObject)) { char[] superclassName; char separator; if (type instanceof IBinaryType) { superclassName = ((IBinaryType) type).getSuperclassName(); separator = '/'; } else if (type instanceof ISourceType) { superclassName = ((ISourceType) type).getSuperclassName(); separator = '.'; } else if (type instanceof HierarchyType) { superclassName = ((HierarchyType) type).superclassName; separator = '.'; } else { return null; } if (superclassName != null) { // check whether subclass of Object due to broken hierarchy (as opposed to // explicitly extending it) int lastSeparator = CharOperation.lastIndexOf(separator, superclassName); char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray( superclassName, lastSeparator + 1, superclassName.length); if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) { this.hasMissingSuperClass = true; this.builder.hierarchy.missingTypes.add(new String(simpleName)); return null; } } } } for (int t = this.typeIndex; t >= 0; t--) { if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) { return this.builder.getHandle(this.typeModels[t], superBinding); } } } return null; }
public int scanIdentifierOrKeyword() { int kind = super.scanIdentifierOrKeyword(); if (kind != TerminalTokens.TokenNameIdentifier) return kind; char[] contents = getCurrentIdentifierSource(); // XXX performance here is less than optimal, but code simplicity is pretty damn good if (CharOperation.equals(aspectV, contents)) return TerminalTokens.TokenNameaspect; else if (CharOperation.equals(pointcutV, contents)) return TerminalTokens.TokenNamepointcut; else if (CharOperation.equals(privilegedV, contents)) return TerminalTokens.TokenNameprivileged; else if (CharOperation.equals(beforeV, contents)) return TerminalTokens.TokenNamebefore; else if (CharOperation.equals(afterV, contents)) return TerminalTokens.TokenNameafter; else if (CharOperation.equals(aroundV, contents)) return TerminalTokens.TokenNamearound; else if (CharOperation.equals(declareV, contents)) return TerminalTokens.TokenNamedeclare; return kind; }
/* * Returns the handles of the super interfaces of the given type. * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array) */ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) { char[][] superInterfaceNames; char separator; if (type instanceof IBinaryType) { superInterfaceNames = ((IBinaryType) type).getInterfaceNames(); separator = '/'; } else if (type instanceof ISourceType) { ISourceType sourceType = (ISourceType) type; if (sourceType.isAnonymous()) { // if anonymous type if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) { superInterfaceNames = new char[][] {sourceType.getSuperclassName()}; } else { superInterfaceNames = sourceType.getInterfaceNames(); } } else { if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL) superInterfaceNames = new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION}; else superInterfaceNames = sourceType.getInterfaceNames(); } separator = '.'; } else if (type instanceof HierarchyType) { HierarchyType hierarchyType = (HierarchyType) type; if (hierarchyType.isAnonymous()) { // if anonymous type if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) { superInterfaceNames = new char[][] {hierarchyType.superclassName}; } else { superInterfaceNames = hierarchyType.superInterfaceNames; } } else { superInterfaceNames = hierarchyType.superInterfaceNames; } separator = '.'; } else { return null; } ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces(); int bindingIndex = 0; int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length; int length = superInterfaceNames == null ? 0 : superInterfaceNames.length; IType[] superinterfaces = new IType[length]; int index = 0; next: for (int i = 0; i < length; i++) { char[] superInterfaceName = superInterfaceNames[i]; int end = superInterfaceName.length; // find the end of simple name int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName); if (genericStart != -1) end = genericStart; // find the start of simple name int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end); int start = lastSeparator + 1; // case of binary inner type -> take the last part int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start); if (lastDollar != -1) start = lastDollar + 1; char[] simpleName = CharOperation.subarray(superInterfaceName, start, end); if (bindingIndex < bindingLength) { ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex].erasure(); // ensure that the binding corresponds to the interface defined by the user if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) { bindingIndex++; for (int t = this.typeIndex; t >= 0; t--) { if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) { IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding); if (handle != null) { superinterfaces[index++] = handle; continue next; } } } } } this.builder.hierarchy.missingTypes.add(new String(simpleName)); } if (index != length) System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index); return superinterfaces; }
/** * Checks for duplicates. If all ok, records the importBinding returns -1 when this import is * flagged as duplicate. * * @param importBinding * @param typesBySimpleNames * @param importReference * @param compoundName * @return -1 when this import is flagged as duplicate, importPtr otherwise. */ private int checkAndRecordImportBinding( Binding importBinding, HashtableOfType typesBySimpleNames, ImportReference importReference, char[][] compoundName) { ReferenceBinding conflictingType = null; if (importBinding instanceof MethodBinding) { conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length); if (!conflictingType.isValidBinding() || (importReference.isStatic() && !conflictingType.isStatic())) conflictingType = null; } // collisions between an imported static field & a type should be checked according to spec... // but currently not by javac final char[] name = compoundName[compoundName.length - 1]; if (importBinding instanceof ReferenceBinding || conflictingType != null) { ReferenceBinding referenceBinding = conflictingType == null ? (ReferenceBinding) importBinding : conflictingType; ReferenceBinding typeToCheck = referenceBinding.problemId() == ProblemReasons.Ambiguous ? ((ProblemReferenceBinding) referenceBinding).closestMatch : referenceBinding; if (importReference.isTypeUseDeprecated(typeToCheck, this)) problemReporter().deprecatedType(typeToCheck, importReference); ReferenceBinding existingType = typesBySimpleNames.get(name); if (existingType != null) { // duplicate test above should have caught this case, but make sure if (TypeBinding.equalsEquals(existingType, referenceBinding)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302865 // Check all resolved imports to see if this import qualifies as a duplicate for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; if (resolved instanceof ImportConflictBinding) { ImportConflictBinding importConflictBinding = (ImportConflictBinding) resolved; if (TypeBinding.equalsEquals( importConflictBinding.conflictingTypeBinding, referenceBinding)) { if (!importReference.isStatic()) { // resolved is implicitly static problemReporter().duplicateImport(importReference); recordImportBinding( new ImportBinding(compoundName, false, importBinding, importReference)); } } } else if (resolved.resolvedImport == referenceBinding) { if (importReference.isStatic() != resolved.isStatic()) { problemReporter().duplicateImport(importReference); recordImportBinding( new ImportBinding(compoundName, false, importBinding, importReference)); } } } return -1; } // either the type collides with a top level type or another imported type for (int j = 0, length = this.topLevelTypes.length; j < length; j++) { if (CharOperation.equals(this.topLevelTypes[j].sourceName, existingType.sourceName)) { problemReporter().conflictingImport(importReference); return -1; } } if (importReference.isStatic() && importBinding instanceof ReferenceBinding && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates them, // though use is flagged. for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; if (resolved.isStatic() && resolved.resolvedImport instanceof ReferenceBinding && importBinding != resolved.resolvedImport) { if (CharOperation.equals( name, resolved.compoundName[resolved.compoundName.length - 1])) { ReferenceBinding type = (ReferenceBinding) resolved.resolvedImport; resolved.resolvedImport = new ProblemReferenceBinding( new char[][] {name}, type, ProblemReasons.Ambiguous); return -1; } } } } problemReporter().duplicateImport(importReference); return -1; } typesBySimpleNames.put(name, referenceBinding); } else if (importBinding instanceof FieldBinding) { for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; // find other static fields with the same name if (resolved.isStatic() && resolved.resolvedImport instanceof FieldBinding && importBinding != resolved.resolvedImport) { if (CharOperation.equals(name, resolved.compoundName[resolved.compoundName.length - 1])) { if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates // them, though use is flagged. FieldBinding field = (FieldBinding) resolved.resolvedImport; resolved.resolvedImport = new ProblemFieldBinding( field, field.declaringClass, name, ProblemReasons.Ambiguous); return -1; } else { problemReporter().duplicateImport(importReference); return -1; } } } } } if (conflictingType == null) { recordImportBinding(new ImportBinding(compoundName, false, importBinding, importReference)); } else { recordImportBinding( new ImportConflictBinding(compoundName, importBinding, conflictingType, importReference)); } return this.importPtr; }
void buildTypeBindings(AccessRestriction accessRestriction) { this.topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved boolean firstIsSynthetic = false; if (this.referenceContext.compilationResult.compilationUnit != null) { char[][] expectedPackageName = this.referenceContext.compilationResult.compilationUnit.getPackageName(); if (expectedPackageName != null && !CharOperation.equals(this.currentPackageName, expectedPackageName)) { // only report if the unit isn't structurally empty if (this.referenceContext.currentPackage != null || this.referenceContext.types != null || this.referenceContext.imports != null) { problemReporter().packageIsNotExpectedPackage(this.referenceContext); } this.currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName; } } if (this.currentPackageName == CharOperation.NO_CHAR_CHAR) { // environment default package is never null this.fPackage = this.environment.defaultPackage; } else { if ((this.fPackage = this.environment.createPackage(this.currentPackageName)) == null) { if (this.referenceContext.currentPackage != null) { problemReporter() .packageCollidesWithType( this.referenceContext); // only report when the unit has a package statement } // ensure fPackage is not null this.fPackage = this.environment.defaultPackage; return; } else if (this.referenceContext.isPackageInfo()) { // resolve package annotations now if this is "package-info.java". if (this.referenceContext.types == null || this.referenceContext.types.length == 0) { this.referenceContext.types = new TypeDeclaration[1]; this.referenceContext.createPackageInfoType(); firstIsSynthetic = true; } // ensure the package annotations are copied over before resolution if (this.referenceContext.currentPackage != null && this.referenceContext.currentPackage.annotations != null) { this.referenceContext.types[0].annotations = this.referenceContext.currentPackage.annotations; } } recordQualifiedReference(this.currentPackageName); // always dependent on your own package } // Skip typeDeclarations which know of previously reported errors TypeDeclaration[] types = this.referenceContext.types; int typeLength = (types == null) ? 0 : types.length; this.topLevelTypes = new SourceTypeBinding[typeLength]; int count = 0; nextType: for (int i = 0; i < typeLength; i++) { TypeDeclaration typeDecl = types[i]; if (this.environment.isProcessingAnnotations && this.environment.isMissingType(typeDecl.name)) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the // type ReferenceBinding typeBinding = this.fPackage.getType0(typeDecl.name); recordSimpleReference(typeDecl.name); // needed to detect collision cases if (typeBinding != null && typeBinding.isValidBinding() && !(typeBinding instanceof UnresolvedReferenceBinding)) { // if its an unresolved binding - its fixed up whenever its needed, see // UnresolvedReferenceBinding.resolve() if (this.environment.isProcessingAnnotations) throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the // type // if a type exists, check that its a valid type // it can be a NotFound problem type if its a secondary type referenced before its primary // type found in additional units // and it can be an unresolved type which is now being defined problemReporter().duplicateTypes(this.referenceContext, typeDecl); continue nextType; } if (this.fPackage != this.environment.defaultPackage && this.fPackage.getPackage(typeDecl.name) != null) { // if a package exists, it must be a valid package - cannot be a NotFound problem package // this is now a warning since a package does not really 'exist' until it contains a type, // see JLS v2, 7.4.3 problemReporter().typeCollidesWithPackage(this.referenceContext, typeDecl); } if ((typeDecl.modifiers & ClassFileConstants.AccPublic) != 0) { char[] mainTypeName; if ((mainTypeName = this.referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided // to return null && !CharOperation.equals(mainTypeName, typeDecl.name)) { problemReporter().publicClassMustMatchFileName(this.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, this.fPackage, accessRestriction); if (firstIsSynthetic && i == 0) type.modifiers |= ClassFileConstants.AccSynthetic; if (type != null) this.topLevelTypes[count++] = type; } // shrink topLevelTypes... only happens if an error was reported if (count != this.topLevelTypes.length) System.arraycopy( this.topLevelTypes, 0, this.topLevelTypes = new SourceTypeBinding[count], 0, count); }
void faultInImports() { boolean unresolvedFound = false; // should report unresolved only if we are not suppressing caching of failed resolutions boolean reportUnresolved = !this.suppressImportErrors; if (this.typeOrPackageCache != null && !this.skipCachingImports) return; // can be called when a field constant is resolved before static imports if (this.referenceContext.imports == null) { this.typeOrPackageCache = new HashtableOfObject(1); return; } // collect the top level type names if a single type import exists int numberOfStatements = this.referenceContext.imports.length; HashtableOfType typesBySimpleNames = null; for (int i = 0; i < numberOfStatements; i++) { if ((this.referenceContext.imports[i].bits & ASTNode.OnDemand) == 0) { typesBySimpleNames = new HashtableOfType(this.topLevelTypes.length + numberOfStatements); for (int j = 0, length = this.topLevelTypes.length; j < length; j++) typesBySimpleNames.put(this.topLevelTypes[j].sourceName, this.topLevelTypes[j]); break; } } // allocate the import array, add java.lang.* by default int numberOfImports = numberOfStatements + 1; for (int i = 0; i < numberOfStatements; i++) { ImportReference importReference = this.referenceContext.imports[i]; if (((importReference.bits & ASTNode.OnDemand) != 0) && CharOperation.equals(TypeConstants.JAVA_LANG, importReference.tokens) && !importReference.isStatic()) { numberOfImports--; break; } } this.tempImports = new ImportBinding[numberOfImports]; this.tempImports[0] = getDefaultImports()[0]; this.importPtr = 1; // 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 = this.referenceContext.imports[i]; char[][] compoundName = importReference.tokens; // skip duplicates or imports of the current package for (int j = 0; j < this.importPtr; j++) { ImportBinding resolved = this.tempImports[j]; if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0) && resolved.isStatic() == importReference.isStatic()) { if (CharOperation.equals(compoundName, resolved.compoundName)) { problemReporter().unusedImport(importReference); // since skipped, must be reported now continue nextImport; } } } if ((importReference.bits & ASTNode.OnDemand) != 0) { if (CharOperation.equals(compoundName, this.currentPackageName)) { problemReporter().unusedImport(importReference); // since skipped, must be reported now continue nextImport; } Binding importBinding = findImport(compoundName, compoundName.length); if (!importBinding.isValidBinding()) { problemReporter().importProblem(importReference, importBinding); continue nextImport; } if (importReference.isStatic() && importBinding instanceof PackageBinding) { problemReporter().cannotImportPackage(importReference); continue nextImport; } recordImportBinding(new ImportBinding(compoundName, true, importBinding, importReference)); } else { Binding importBinding = findSingleImport( compoundName, Binding.TYPE | Binding.FIELD | Binding.METHOD, importReference.isStatic()); if (!importBinding.isValidBinding()) { if (importBinding.problemId() == ProblemReasons.Ambiguous) { // keep it unless a duplicate can be found below } else { unresolvedFound = true; if (reportUnresolved) { problemReporter().importProblem(importReference, importBinding); } continue nextImport; } } if (importBinding instanceof PackageBinding) { problemReporter().cannotImportPackage(importReference); continue nextImport; } // all the code here which checks for valid bindings have been moved to the method // checkAndRecordImportBinding() since bug 361327 if (checkAndRecordImportBinding( importBinding, typesBySimpleNames, importReference, compoundName) == -1) continue nextImport; if (importReference.isStatic()) { // look for more static bindings being imported by single static import(bug 361327). // findSingleImport() finds fields first, followed by method and then type // So if a type is found, no fields and methods are available anyway // similarly when method is found, type may be available but no field available for sure if (importBinding.kind() == Binding.FIELD) { checkMoreStaticBindings( compoundName, typesBySimpleNames, Binding.TYPE | Binding.METHOD, importReference); } else if (importBinding.kind() == Binding.METHOD) { checkMoreStaticBindings( compoundName, typesBySimpleNames, Binding.TYPE, importReference); } } } } // shrink resolvedImports... only happens if an error was reported if (this.tempImports.length > this.importPtr) System.arraycopy( this.tempImports, 0, this.tempImports = new ImportBinding[this.importPtr], 0, this.importPtr); this.imports = this.tempImports; int length = this.imports.length; this.typeOrPackageCache = new HashtableOfObject(length); for (int i = 0; i < length; i++) { ImportBinding binding = this.imports[i]; if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding || binding instanceof ImportConflictBinding) this.typeOrPackageCache.put(binding.compoundName[binding.compoundName.length - 1], binding); } this.skipCachingImports = this.suppressImportErrors && unresolvedFound; }