diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org')
87 files changed, 2404 insertions, 1548 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 8922355aa..4fa4be4e0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -181,14 +181,6 @@ * DuplicateInheritedDefaultMethods * SuperAccessCannotBypassDirectSuper * SuperCallCannotBypassOverride - * IllegalModifierForInterfaceDefaultMethod - * InheritedDefaultMethodConflictsWithOtherInherited - * ConflictingNullAnnotations - * ConflictingInheritedNullAnnotations - * UnsafeElementTypeConversion - * ArrayReferencePotentialNullReference - * DereferencingNullableExpression - * NullityMismatchingTypeAnnotation * ConflictingNullAnnotations * ConflictingInheritedNullAnnotations * UnsafeElementTypeConversion @@ -206,7 +198,18 @@ * TargetTypeNotAFunctionalInterface * OuterLocalMustBeEffectivelyFinal * IllegalModifiersForPackage - *******************************************************************************/ + * DuplicateAnnotationNotMarkedRepeatable + * DisallowedTargetForContainerAnnotation + * RepeatedAnnotationWithContainerAnnotation + * ContainingAnnotationMustHaveValue + * ContainingAnnotationHasNonDefaultMembers + * ContainingAnnotationHasWrongValueType + * ContainingAnnotationHasShorterRetention + * RepeatableAnnotationHasTargets + * RepeatableAnnotationTargetMismatch + * RepeatableAnnotationIsDocumented + * RepeatableAnnotationIsInherited +*******************************************************************************/ package org.eclipse.jdt.core.compiler; import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; @@ -1621,6 +1624,41 @@ void setSourceStart(int sourceStart); int MultipleFunctionalInterfaces = TypeRelated + 895; /** @since 3.9 BETA_JAVA8 */ int StaticInterfaceMethodNotBelow18 = Internal + Syntax + 896; + /** @since 3.9 BETA_JAVA8 */ + int DuplicateAnnotationNotMarkedRepeatable = TypeRelated + 897; + /** @since 3.9 BETA_JAVA8 */ + int DisallowedTargetForContainerAnnotation = TypeRelated + 898; + /** @since 3.9 BETA_JAVA8 */ + int RepeatedAnnotationWithContainerAnnotation = TypeRelated + 899; + + /** + * External problems -- These are problems defined by other plugins + */ + + /** @since 3.2 */ + int ExternalProblemNotFixable = 900; + + // indicates an externally defined problem that has a quick-assist processor + // associated with it + /** @since 3.2 */ + int ExternalProblemFixable = 901; + + /** @since 3.9 BETA_JAVA8 */ + int ContainingAnnotationHasWrongValueType = TypeRelated + 902; + /** @since 3.9 BETA_JAVA8 */ + int ContainingAnnotationMustHaveValue = TypeRelated + 903; + /** @since 3.9 BETA_JAVA8 */ + int ContainingAnnotationHasNonDefaultMembers = TypeRelated + 904; + /** @since 3.9 BETA_JAVA8 */ + int ContainingAnnotationHasShorterRetention = TypeRelated + 905; + /** @since 3.9 BETA_JAVA8 */ + int RepeatableAnnotationHasTargets = TypeRelated + 906; + /** @since 3.9 BETA_JAVA8 */ + int RepeatableAnnotationTargetMismatch = TypeRelated + 907; + /** @since 3.9 BETA_JAVA8 */ + int RepeatableAnnotationIsDocumented = TypeRelated + 908; + /** @since 3.9 BETA_JAVA8 */ + int RepeatableAnnotationIsInherited = TypeRelated + 909; /** * Errors/warnings from annotation based null analysis @@ -1752,18 +1790,8 @@ void setSourceStart(int sourceStart); int IllegalModifierCombinationForInterfaceMethod = MethodRelated + 1056; /** @since 3.9 BETA_JAVA8 */ int IllegalStrictfpForAbstractInterfaceMethod = MethodRelated + 1057; - - /** - * External problems -- These are problems defined by other plugins - */ - - /** @since 3.2 */ - int ExternalProblemNotFixable = 900; - - // indicates an externally defined problem that has a quick-assist processor - // associated with it - /** @since 3.2 */ - int ExternalProblemFixable = 901; + /** @since 3.9 BETA_JAVA8 */ + int IllegalDefaultModifierSpecification = MethodRelated + 1058; //{ObjectTeams: int OTJ_RELATED = 1000000; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java index c39682280..3e3919048 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -1507,7 +1507,7 @@ public class ClassFile implements TypeConstants, TypeIds { for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = exceptionLabels[i]; if (exceptionLabel.exceptionTypeReference != null && (exceptionLabel.exceptionTypeReference.bits & ASTNode.HasTypeAnnotations) != 0) { - exceptionLabel.exceptionTypeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.EXCEPTION_PARAMETER, i, allTypeAnnotationContexts); + exceptionLabel.exceptionTypeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.EXCEPTION_PARAMETER, i, allTypeAnnotationContexts, exceptionLabel.se7Annotations); } } @@ -4610,10 +4610,7 @@ public class ClassFile implements TypeConstants, TypeIds { int[] locations = Annotation.getLocations( annotationContext.typeReference, - annotationContext.primaryAnnotations, - annotationContext.annotation, - annotationContext.annotationsOnDimensions, - annotationContext.dimensions); + annotationContext.annotation); if (this.contentsOffset + 5 >= this.contents.length) { resizeContents(5); @@ -4631,10 +4628,7 @@ public class ClassFile implements TypeConstants, TypeIds { int[] locations = Annotation.getLocations( annotationContext.typeReference, - null, - annotationContext.annotation, - null, - 0); + annotationContext.annotation); // reserve enough space if (this.contentsOffset + 5 >= this.contents.length) { resizeContents(5); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java index 0b6622a36..875043ae5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -22,17 +22,23 @@ * bug 374605 - Unreasonable warning for enum-based switch statements * bug 384870 - [compiler] @Deprecated annotation not detected if preceded by other annotation * bug 393719 - [compiler] inconsistent warnings on iteration variables - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper S Moller - Contributions for * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment + * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable + * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding; /** @@ -780,8 +786,16 @@ public abstract class ASTNode implements TypeConstants, TypeIds { Annotation annotation = sourceAnnotations[i]; final Binding annotationRecipient = annotation.recipient; if (annotationRecipient != null && recipient != null) { - // only local and field can share annnotations + // only local and field can share annnotations and their types. switch (recipient.kind()) { + case Binding.TYPE_USE: + if (annotations != null) { + // need to fill the instances array + for (int j = 0; j < length; j++) { + annotations[j] = sourceAnnotations[j].getCompilerAnnotation(); + } + } + break; case Binding.FIELD : FieldBinding field = (FieldBinding) recipient; field.tagBits = ((FieldBinding) annotationRecipient).tagBits; @@ -828,6 +842,11 @@ public abstract class ASTNode implements TypeConstants, TypeIds { } } break; + default: + if (annotations != null) { + annotations[i] = annotation.getCompilerAnnotation(); + } + break; } return annotations; } else { @@ -841,30 +860,66 @@ public abstract class ASTNode implements TypeConstants, TypeIds { } if (copySE8AnnotationsToType) - copySE8AnnotationsToType(scope, recipient, annotations); + copySE8AnnotationsToType(scope, recipient, sourceAnnotations); + + if (annotations != null && length > 0 && recipient != null && recipient.isAnnotationType()) { + // See if this is meta-annotated as repeatable and if so validate constraints. + for (int i = 0; i < length; i++) { + Annotation annotation = sourceAnnotations[i]; + MemberValuePair[] valuePairs = annotation.memberValuePairs(); + ReferenceBinding annotationType = annotations[i] != null ? annotations[i].getAnnotationType() : null; + if (annotationType != null && annotationType.id == TypeIds.T_JavaLangAnnotationRepeatable && valuePairs != null && valuePairs.length > 0) { + annotation.checkRepeatableAnnotation(valuePairs[0], scope, valuePairs[0].compilerElementPair.value); + } + } + } // check duplicate annotations if (annotations != null && length > 1) { AnnotationBinding[] distinctAnnotations = annotations; // only copy after 1st duplicate is detected + Map implicitContainerAnnotations = null; for (int i = 0; i < length; i++) { AnnotationBinding annotation = distinctAnnotations[i]; if (annotation == null) continue; - TypeBinding annotationType = annotation.getAnnotationType(); + ReferenceBinding annotationType = annotation.getAnnotationType(); boolean foundDuplicate = false; for (int j = i+1; j < length; j++) { AnnotationBinding otherAnnotation = distinctAnnotations[j]; if (otherAnnotation == null) continue; if (otherAnnotation.getAnnotationType() == annotationType) { - foundDuplicate = true; - if (distinctAnnotations == annotations) { - System.arraycopy(distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length); + if (annotationType.isRepeatableAnnotation()) { + ReferenceBinding resolvedContainer = annotationType.resolveContainerAnnotation(); + if (resolvedContainer != null) { + // Since this is a repeated annotation, we need to check if the container is also used - so store it + // in a map of (container's ReferenceBinding -> the repeated source Annotation) + if (implicitContainerAnnotations == null) implicitContainerAnnotations = new HashMap(3); + implicitContainerAnnotations.put(resolvedContainer, sourceAnnotations[i]); + // Validate the repeated *use* of a repeatable annotation. + Annotation.checkContainingAnnotation(sourceAnnotations[i], scope, resolvedContainer, annotationType); + } + } else { + foundDuplicate = true; + if (distinctAnnotations == annotations) { + System.arraycopy(distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length); + } + distinctAnnotations[j] = null; // report it only once + scope.problemReporter().duplicateAnnotation(sourceAnnotations[j], scope.compilerOptions().sourceLevel); } - distinctAnnotations[j] = null; // report it only once - scope.problemReporter().duplicateAnnotation(sourceAnnotations[j]); } } if (foundDuplicate) { - scope.problemReporter().duplicateAnnotation(sourceAnnotations[i]); + scope.problemReporter().duplicateAnnotation(sourceAnnotations[i], scope.compilerOptions().sourceLevel); + } + } + // Check for presence of repeating annotation together with the containing annotation + if (implicitContainerAnnotations != null) { + for (int i = 0; i < length; i++) { + if (distinctAnnotations[i] == null) continue; + Annotation annotation = sourceAnnotations[i]; + ReferenceBinding annotationType = distinctAnnotations[i].getAnnotationType(); + if (implicitContainerAnnotations.containsKey(annotationType)) { + scope.problemReporter().repeatedAnnotationWithContainer((Annotation) implicitContainerAnnotations.get(annotationType), annotation); + } } } } @@ -895,20 +950,31 @@ public abstract class ASTNode implements TypeConstants, TypeIds { /** When SE8 annotations feature in SE7 locations, they get attributed to the declared entity. Copy these to the type of the declared entity (field, local, argument etc.) We leave in the annotation in the declared entity's binding as of now, i.e we do a copy not a transfer. */ - public static void copySE8AnnotationsToType(BlockScope scope, Binding recipient, AnnotationBinding[] annotations) { + public static void copySE8AnnotationsToType(BlockScope scope, Binding recipient, Annotation[] annotations) { if (annotations != null && recipient.kind() != Binding.TYPE_USE) { AnnotationBinding [] se8Annotations = null; int se8count = 0; + long se8nullBits = 0; + Annotation se8NullAnnotation = null; for (int i = 0, length = annotations.length; i < length; i++) { - final ReferenceBinding annotationType = annotations[i].getAnnotationType(); + AnnotationBinding annotation = annotations[i].getCompilerAnnotation(); + if (annotation == null) continue; + final ReferenceBinding annotationType = annotation.getAnnotationType(); long metaTagBits = annotationType.getAnnotationTagBits(); if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { if (se8Annotations == null) { - se8Annotations = new AnnotationBinding[] { annotations[i] }; + se8Annotations = new AnnotationBinding[] { annotation }; se8count = 1; } else { System.arraycopy(se8Annotations, 0, se8Annotations = new AnnotationBinding[se8count + 1], 0, se8count); - se8Annotations[se8count++] = annotations[i]; + se8Annotations[se8count++] = annotation; + } + if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull) { + se8nullBits = TagBits.AnnotationNonNull; + se8NullAnnotation = annotations[i]; + } else if (annotationType.id == TypeIds.T_ConfiguredAnnotationNullable) { + se8nullBits = TagBits.AnnotationNullable; + se8NullAnnotation = annotations[i]; } } } @@ -916,14 +982,11 @@ public abstract class ASTNode implements TypeConstants, TypeIds { switch (recipient.kind()) { case Binding.LOCAL: LocalVariableBinding local = (LocalVariableBinding) recipient; - if (Annotation.isTypeUseCompatible(local.declaration.type, scope)) { // discard hybrid annotations on package qualified types. + TypeReference typeRef = local.declaration.type; + if (Annotation.isTypeUseCompatible(typeRef, scope)) { // discard hybrid annotations on package qualified types. local.declaration.bits |= HasTypeAnnotations; - final TypeBinding localType = local.type; - TypeBinding oldLeafType = localType.leafComponentType(); - AnnotationBinding [][] goodies = new AnnotationBinding[local.declaration.type.getAnnotatableLevels()][]; - goodies[0] = se8Annotations; // @T X.Y.Z local; ==> @T should annotate X - TypeBinding newLeafType = scope.environment().createAnnotatedType(oldLeafType, goodies); - local.type = localType.isArrayType() ? scope.environment().createArrayType(newLeafType, localType.dimensions(), localType.getTypeAnnotations()) : newLeafType; + typeRef.bits |= HasTypeAnnotations; + local.type = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, typeRef, local.type); } break; case Binding.FIELD: @@ -931,12 +994,9 @@ public abstract class ASTNode implements TypeConstants, TypeIds { SourceTypeBinding sourceType = (SourceTypeBinding) field.declaringClass; FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(field); if (Annotation.isTypeUseCompatible(fieldDeclaration.type, scope)) { // discard hybrid annotations on package qualified types. - TypeBinding fieldType = field.type; - TypeBinding oldLeafType = fieldType.leafComponentType(); - AnnotationBinding [][] goodies = new AnnotationBinding[fieldDeclaration.type.getAnnotatableLevels()][]; - goodies[0] = se8Annotations; // @T X.Y.Z field; ==> @T should annotate X - TypeBinding newLeafType = scope.environment().createAnnotatedType(oldLeafType, goodies); - field.type = fieldType.isArrayType() ? scope.environment().createArrayType(newLeafType, fieldType.dimensions(), fieldType.getTypeAnnotations()) : newLeafType; + fieldDeclaration.bits |= HasTypeAnnotations; + fieldDeclaration.type.bits |= HasTypeAnnotations; + field.type = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, fieldDeclaration.type, field.type); } break; case Binding.METHOD: @@ -945,12 +1005,9 @@ public abstract class ASTNode implements TypeConstants, TypeIds { sourceType = (SourceTypeBinding) method.declaringClass; MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(method); if (Annotation.isTypeUseCompatible(methodDecl.returnType, scope)) { - final TypeBinding returnType = method.returnType; - TypeBinding oldLeafType = returnType.leafComponentType(); - AnnotationBinding [][] goodies = new AnnotationBinding[methodDecl.returnType.getAnnotatableLevels()][]; - goodies[0] = se8Annotations; - TypeBinding newLeafType = scope.environment().createAnnotatedType(oldLeafType, goodies); - method.returnType = returnType.isArrayType() ? scope.environment().createArrayType(newLeafType, returnType.dimensions(), returnType.getTypeAnnotations()) : newLeafType; + methodDecl.bits |= HasTypeAnnotations; + methodDecl.returnType.bits |= HasTypeAnnotations; + method.returnType = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, methodDecl.returnType, method.returnType); } } break; @@ -959,6 +1016,30 @@ public abstract class ASTNode implements TypeConstants, TypeIds { } } + private static TypeBinding mergeAnnotationsIntoType(BlockScope scope, AnnotationBinding[] se8Annotations, long se8nullBits, Annotation se8NullAnnotation, + TypeReference typeRef, TypeBinding existingType) + { + if (existingType == null || !existingType.isValidBinding()) return existingType; + TypeReference unionRef = typeRef.isUnionType() ? ((UnionTypeReference) typeRef).typeReferences[0] : null; + + long prevNullBits = existingType.tagBits & TagBits.AnnotationNullMASK; + if (se8nullBits != 0 && prevNullBits != se8nullBits && ((prevNullBits | se8nullBits) == TagBits.AnnotationNullMASK)) { + scope.problemReporter().contradictoryNullAnnotations(se8NullAnnotation); + } + TypeBinding oldLeafType = (unionRef == null) ? existingType.leafComponentType() : unionRef.resolvedType; + AnnotationBinding [][] goodies = new AnnotationBinding[typeRef.getAnnotatableLevels()][]; + goodies[0] = se8Annotations; // @T X.Y.Z local; ==> @T should annotate X + TypeBinding newLeafType = scope.environment().createAnnotatedType(oldLeafType, goodies); + + if (unionRef == null) { + typeRef.resolvedType = existingType.isArrayType() ? scope.environment().createArrayType(newLeafType, existingType.dimensions(), existingType.getTypeAnnotations()) : newLeafType; + } else { + unionRef.resolvedType = newLeafType; + unionRef.bits |= HasTypeAnnotations; + } + return typeRef.resolvedType; + } + /** * Figures if @Deprecated annotation is specified, do not resolve entire annotations. */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java index e64483fd3..c0907ae76 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -25,6 +25,7 @@ * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 403216 - [1.8][null] TypeReference#captureTypeAnnotations treats type annotations as type argument annotations + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -987,8 +988,9 @@ public abstract class AbstractMethodDeclaration } else { int length = this.binding.parameters.length; for (int i=0; i<length; i++) { - if (!this.scope.validateNullAnnotation(this.binding.parameters[i].tagBits, this.arguments[i].type, this.arguments[i].annotations)) - this.binding.parameters[i] = this.binding.parameters[i].unannotated(); + this.scope.validateNullAnnotation(this.binding.parameters[i].tagBits, this.arguments[i].type, this.arguments[i].annotations); +// TODO(stephan) remove once we're sure: +// this.binding.parameters[i] = this.binding.parameters[i].unannotated(); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 187ef9bb6..0c012ebe0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -27,9 +27,10 @@ * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 378674 - "The method can be declared as static" is wrong - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for + * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method *******************************************************************************/ @@ -366,7 +367,7 @@ public TypeBinding resolveType(BlockScope scope) { this.type.bits |= IsAllocationType; // SH} this.resolvedType = this.type.resolveType(scope, true /* check bounds*/); - this.resolvedType = checkIllegalNullAnnotation(scope, this.resolvedType); + checkIllegalNullAnnotation(scope, this.resolvedType); checkParameterizedAllocation: { if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>() ReferenceBinding currentType = (ReferenceBinding)this.resolvedType; @@ -591,19 +592,16 @@ public TypeBinding resolveType(BlockScope scope) { /** * Check if 'allocationType' illegally has a top-level null annotation. - * If so: report an error and return the unannotated variant. */ -TypeBinding checkIllegalNullAnnotation(BlockScope scope, TypeBinding allocationType) { +void checkIllegalNullAnnotation(BlockScope scope, TypeBinding allocationType) { if (allocationType != null) { // only check top-level null annotation (annots on details are OK): long nullTagBits = allocationType.tagBits & TagBits.AnnotationNullMASK; if (nullTagBits != 0) { Annotation annotation = this.type.findAnnotation(nullTagBits); scope.problemReporter().nullAnnotationUnsupportedLocation(annotation); - return allocationType.unannotated(); } } - return allocationType; } public TypeBinding[] inferElidedTypes(ReferenceBinding allocationType, ReferenceBinding enclosingType, TypeBinding[] argumentTypes, final BlockScope scope) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java index c295955d2..e9713750b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java @@ -21,11 +21,15 @@ * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409517 - [1.8][compiler] Type annotation problems on more elaborate array references * Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped * Bug 414384 - [1.8] type annotation on abbreviated inner class is not marked as inner type + * Jesper S Moller <jesper@selskabet.org> - Contributions for + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable +# Bug 412151 - [1.8][compiler] Check repeating annotation's collection type *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -53,453 +57,145 @@ public abstract class Annotation extends Expression { * Return the location for the corresponding annotation inside the type reference, <code>null</code> if none. */ public static int[] getLocations( - final TypeReference reference, - final Annotation[] primaryAnnotation, - final Annotation annotation, - final Annotation[][] annotationsOnDimensionsOnExpression, - final int dimensions) { + final Expression reference, + final Annotation annotation) { class LocationCollector extends ASTVisitor { Stack typePathEntries; - Annotation currentAnnotation; - boolean search = true; + Annotation searchedAnnotation; + boolean continueSearch = true; public LocationCollector(Annotation currentAnnotation) { this.typePathEntries = new Stack(); - this.currentAnnotation = currentAnnotation; + this.searchedAnnotation = currentAnnotation; } - public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - - Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations = annotationsOnDimensions[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - // found it, push any relevant type path entries - for (int k = 0; k < i; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - this.search = false; - return false; - } - } - } - - } - } - - // Example cases handled here: @B(1) List<String>[] - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - this.search = false; - // Found it, insert any necessary type path elements - for (int k = 0; k < typeReference.dimensions; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - return false; - } + private int[] computeNestingDepth(TypeReference typeReference) { + TypeBinding type = typeReference.resolvedType == null ? null : typeReference.resolvedType.leafComponentType(); + int[] nestingDepths = new int[typeReference.getAnnotatableLevels()]; + if (type != null && type.isNestedType()) { + int depth = 0; + TypeBinding currentType = type; + while (currentType != null) { + depth += (currentType.isStatic()) ? 0 : 1; + currentType = currentType.enclosingType(); } - } - - // If a type argument is annotated it is necessary jump past the array elements - if (typeReference.dimensions != 0) { - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - } - TypeReference[] typeReferences = typeReference.typeArguments; - for (int i = 0, max = typeReferences.length; i < max; i++) { - this.typePathEntries.add(new int[]{3,i}); - typeReferences[i].traverse(this, scope); - if (!this.search) { - return false; - } else { - this.typePathEntries.pop(); + // Work backwards computing whether a INNER_TYPE entry is required for each level + int counter = nestingDepths.length - 1; + while (type != null && counter >= 0) { + nestingDepths[counter--] = depth; + depth -= type.isStatic() ? 0 : 1; + type = type.enclosingType(); } } - if (typeReference.dimensions != 0) { - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.pop(); - } - } - return true; + return nestingDepths; } + - public boolean visit(SingleTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - - // Example case handled by this block: X[][] x = new @A X @B [] @C[]{ { null }, { null } }; - if (dimensions != 0 && annotationsOnDimensionsOnExpression != null) { - for (int i = 0, max = annotationsOnDimensionsOnExpression.length; i < max; i++) { - Annotation[] annotations = annotationsOnDimensionsOnExpression[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - // Found it, insert relevant type path elements - for (int k = 0, maxk = i; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - return false; - } - } - } - } - } - - if (dimensions != 0) { - for (int k = 0; k < dimensions; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - } - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; + private void inspectAnnotations(Annotation [] annotations) { + for (int i = 0, length = annotations == null ? 0 : annotations.length; this.continueSearch && i < length; i++) { + if (annotations[i] == this.searchedAnnotation) + this.continueSearch = false; } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - // Found - this.search = false; - int depth = getInnerDepth(typeReference.resolvedType); - if (depth != 0) { - for (int k = 0; k<depth; k++) { - this.typePathEntries.add(TYPE_PATH_INNER_TYPE); - } - } - return false; - } - } - } - if (dimensions != 0) { - for (int k = 0; k < dimensions; k++) { - this.typePathEntries.pop(); - } - } - return false; } - public boolean visit(ArrayTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - - Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations = annotationsOnDimensions[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - for (int k = 0; k < i; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - this.search = false; - return false; - } - } - } - - } + private void inspectArrayDimensions(Annotation [][] annotationsOnDimensions, int dimensions) { + for (int i = 0; this.continueSearch && i < dimensions; i++) { + Annotation[] annotations = annotationsOnDimensions == null ? null : annotationsOnDimensions[i]; + inspectAnnotations(annotations); + if (!this.continueSearch) return; + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); } - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - for (int k = 0, maxk=typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - this.search = false; - return false; - } - } - } - return true; } - public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations = annotationsOnDimensions[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - // Found it, insert relevant type path elements - for (int k = 0, maxk = i; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - return false; - } - } - } - } - } - - if (primaryAnnotation != null) { - for (int i = 0, max = primaryAnnotation.length; i < max; i++) { - if (primaryAnnotation[i] == this.currentAnnotation) { - this.search = false; - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - return false; - } - } - } - - Annotation[][] annotations = typeReference.annotations; - if (annotations != null) { - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - this.search = false; - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - // depth allows for references like: one.two.three.@B Foo[] - // the inner_type elements to the type path depend on the types not the package qualifiers - int depth = getInnerDepth(typeReference.resolvedType); - if (depth != 0) { - for (int k = 0; k < depth; k++) { - this.typePathEntries.push(TYPE_PATH_INNER_TYPE); - } - } - return false; - } - } - } + private void inspectTypeArguments(TypeReference[] typeReferences) { + for (int i = 0, length = typeReferences == null ? 0 : typeReferences.length; this.continueSearch && i < length; i++) { + int size = this.typePathEntries.size(); + this.typePathEntries.add(new int[]{3,i}); + typeReferences[i].traverse(this, (BlockScope) null); + if (!this.continueSearch) return; + this.typePathEntries.setSize(size); } - return true; } - public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - - // Example case handled by this block: java.util.List<String>[]@A[] - Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations = annotationsOnDimensions[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - // Found it, insert relevant type path elements - for (int k = 0, maxk = i; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - return false; - } - } - } - } - } - - boolean[] needsInnerEntryInfo = computeInnerEntryInfo(typeReference); - - // Example cases handled by this block: - // java.util.@A List<String>[][], com.demo.@A Outer.@B Inner<String>, java.util.Map.@A Entry<String,String> - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - this.search = false; - // Found, insert any relevant type path elements - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + public boolean visit(TypeReference typeReference, BlockScope scope) { + if (this.continueSearch) { + inspectArrayDimensions(typeReference.getAnnotationsOnDimensions(), typeReference.dimensions()); + if (this.continueSearch) { + int[] nestingDepths = computeNestingDepth(typeReference); + Annotation[][] annotations = typeReference.annotations; + TypeReference [][] typeArguments = typeReference.getTypeArguments(); + int levels = typeReference.getAnnotatableLevels(); + int size = this.typePathEntries.size(); + for (int i = levels - 1; this.continueSearch && i >= 0; i--) { // traverse outwards, see comment below about type annotations from SE7 locations. + this.typePathEntries.setSize(size); + for (int j = 0, depth = nestingDepths[i]; j < depth; j++) + this.typePathEntries.add(TYPE_PATH_INNER_TYPE); + if (annotations != null) + inspectAnnotations(annotations[i]); + if (this.continueSearch && typeArguments != null) { + inspectTypeArguments(typeArguments[i]); } - // Found, insert any relevant type path elements - if (needsInnerEntryInfo != null) { - for (int k = 0; k <= i; k++) { - if (needsInnerEntryInfo[k]) { - this.typePathEntries.push(TYPE_PATH_INNER_TYPE); - } - } - } - return false; - } - } - } - - // Example cases handled by this block: - // java.util.List<@A String> - if (typeReference.dimensions != 0) { - for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - } - int toPop = 0; - for (int i = 0, max = typeReference.typeArguments.length; i < max; i++) { - TypeReference[] typeArgumentsForComponent = typeReference.typeArguments[i]; - if (needsInnerEntryInfo != null && needsInnerEntryInfo[i]) { - this.typePathEntries.push(TYPE_PATH_INNER_TYPE); - toPop++; - } - if (typeArgumentsForComponent != null) { - for (int j = 0, max2 = typeArgumentsForComponent.length; j < max2; j++) { - this.typePathEntries.push(new int[]{3,j}); - typeArgumentsForComponent[j].traverse(this,scope); - if (!this.search) return false; - this.typePathEntries.pop(); } } } - toPop += typeReference.dimensions; - for (int k = 0, maxk = toPop; k < maxk; k++) { - this.typePathEntries.pop(); - } - return true; + return false; // if annotation is not found in the type reference, it must be one from SE7 location, typePathEntries captures the proper path entries for them. + } + public boolean visit(SingleTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); } - public boolean visit(Wildcard typeReference, BlockScope scope) { - if (!this.search) return false; - - // This block handles List<@Foo ? extends Serializable> - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - this.search = false; - return false; - } - } - } + public boolean visit(ArrayTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); + } + + public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); + } - TypeReference bound = typeReference.bound; - this.typePathEntries.push(TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND); - bound.traverse(this, scope); - if (!this.search) { - return false; - } - this.typePathEntries.pop(); - return true; + public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); } - private boolean[] computeInnerEntryInfo(QualifiedTypeReference typeReference) { - ReferenceBinding resolvedType = (ReferenceBinding) - (typeReference.resolvedType instanceof ArrayBinding ? typeReference.resolvedType.leafComponentType() : typeReference.resolvedType); - boolean[] needsInnerEntryInfo = null; - if (resolvedType != null && resolvedType.isNestedType()) { - // Work backwards computing whether a INNER_TYPE entry is required for each level - needsInnerEntryInfo = new boolean[typeReference.tokens.length]; - int counter = needsInnerEntryInfo.length - 1; - ReferenceBinding type = resolvedType;//resolvedType.enclosingType(); - while (type != null && counter > 0) { - needsInnerEntryInfo[counter--] = !type.isStatic(); - type = type.enclosingType(); - } - } - return needsInnerEntryInfo; + public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); } - private int getInnerDepth(TypeBinding resolvedType) { - ReferenceBinding type = null; - if (resolvedType instanceof ReferenceBinding) { - type = (ReferenceBinding)resolvedType; - } else if (resolvedType instanceof ArrayBinding) { - TypeBinding leafComponentType = ((ArrayBinding)resolvedType).leafComponentType; - if (leafComponentType instanceof ReferenceBinding) { - type = (ReferenceBinding)leafComponentType; - } - } - int depth = 0; - while (type != null) { - depth += (type.isStatic())?0:1; - type = type.enclosingType(); - } - return depth; + public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) { + return visit((TypeReference) typeReference, scope); } - public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) { - if (!this.search) return false; - boolean[] needsInnerEntryInfo = computeInnerEntryInfo(typeReference); - - if (dimensions != 0) { - for (int k = 0; k < dimensions; k++) { - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - } - - // Example cases handled by this block: - // java.util.@A List, com.demo.@A Outer.@B Inner, java.util.Map.@A Entry - Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - Annotation [] current = annotations[i]; - int annotationsLength = current == null ? 0 : current.length; - for (int j = 0; j < annotationsLength; j++) { - if (current[j] == this.currentAnnotation) { - this.search = false; - // Found, insert any relevant type path elements - if (needsInnerEntryInfo != null) { - for (int k = 0; k <= i; k++) { - if (needsInnerEntryInfo[k]) { - this.typePathEntries.push(TYPE_PATH_INNER_TYPE); - } - } - } - return false; - } + public boolean visit(Wildcard typeReference, BlockScope scope) { + visit((TypeReference) typeReference, scope); + if (this.continueSearch) { + TypeReference bound = typeReference.bound; + if (bound != null) { + int size = this.typePathEntries.size(); + this.typePathEntries.push(TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND); + bound.traverse(this, scope); + if (this.continueSearch) + this.typePathEntries.setSize(size); } } - if (dimensions != 0) { - for (int k = 0; k < dimensions; k++) { - this.typePathEntries.pop(); + return false; + } + + public boolean visit(ArrayAllocationExpression allocationExpression, BlockScope scope) { + if (this.continueSearch) { + inspectArrayDimensions(allocationExpression.getAnnotationsOnDimensions(), allocationExpression.dimensions.length); + if (this.continueSearch) { + allocationExpression.type.traverse(this, scope); } + if (this.continueSearch) throw new IllegalStateException(); } - return true; + return false; } - + public String toString() { StringBuffer buffer = new StringBuffer(); buffer .append("search location for ") //$NON-NLS-1$ - .append(this.currentAnnotation) + .append(this.searchedAnnotation) .append("\ncurrent type_path entries : "); //$NON-NLS-1$ for (int i = 0, maxi = this.typePathEntries.size(); i < maxi; i++) { int[] typePathEntry = (int[]) this.typePathEntries.get(i); @@ -711,6 +407,155 @@ public abstract class Annotation extends Expression { return tagBits; } + static String getRetentionName(long tagBits) { + if ((tagBits & TagBits.AnnotationRuntimeRetention) == TagBits.AnnotationRuntimeRetention) { + // TagBits.AnnotationRuntimeRetention combines both TagBits.AnnotationClassRetention & TagBits.AnnotationSourceRetention + return new String(UPPER_RUNTIME); + } else if ((tagBits & TagBits.AnnotationSourceRetention) != 0) { + return new String(UPPER_SOURCE); + } else { + return new String(TypeConstants.UPPER_CLASS); + } + } + + private static long getAnnotationRetention(ReferenceBinding binding) { + long retention = binding.getAnnotationTagBits() & TagBits.AnnotationRetentionMASK; + // Retention defaults to CLASS + return retention != 0 ? retention : TagBits.AnnotationClassRetention; + } + + public void checkRepeatableAnnotation(ASTNode valueAttribute, Scope scope, Object containingBinding) { + if (! (this.recipient instanceof ReferenceBinding && containingBinding instanceof ReferenceBinding)) return; // Has deeper problems... + ReferenceBinding containing = (ReferenceBinding)containingBinding; + ReferenceBinding repeatableAnnotation = (ReferenceBinding) this.recipient; + repeatableAnnotation.setContainingAnnotation(containing); + + checkContainingAnnotation(valueAttribute, scope, containing, repeatableAnnotation); + } + + public static void checkContainingAnnotation(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) { + MethodBinding[] annotationMethods = container.methods(); + boolean sawValue = false; + for (int i = 0, length = annotationMethods.length; i < length; ++i) { + MethodBinding method = annotationMethods[i]; + if (CharOperation.equals(method.selector, TypeConstants.VALUE)) { + sawValue = true; + if (method.returnType.isArrayType() && method.returnType.dimensions() == 1) { + ArrayBinding array = (ArrayBinding) method.returnType; + if (TypeBinding.equalsEquals(array.elementsType(), repeatableAnnotation)) continue; + } + scope.problemReporter().containingAnnotationHasWrongValueType(markerNode, container, repeatableAnnotation, method.returnType); + } else { + // Not the value() - must have default (or else isn't suitable as container + if ((method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) { + scope.problemReporter().containingAnnotationHasNonDefaultMembers(markerNode, container, method.selector); + } + } + } + if (!sawValue) { + scope.problemReporter().containingAnnotationMustHaveValue(markerNode, container); + } + + checkContainingAnnotationRetention(markerNode, scope, container, repeatableAnnotation); + if (markerNode instanceof Annotation) + checkContainingAnnotationTarget((Annotation) markerNode, (BlockScope) scope, (TypeBinding) container, repeatableAnnotation); + else + checkContainingAnnotationTarget(markerNode, scope, container, repeatableAnnotation); + checkContaintAnnotationDocumented(markerNode, scope, container, repeatableAnnotation); + checkContaintAnnotationInherited(markerNode, scope, container, repeatableAnnotation); + } + + // This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message. + public static void checkContainingAnnotationTarget(Annotation annotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding annotationType) { + // check (meta)target compatibility + if (!annotationType.isValidBinding()) { + // no need to check annotation usage if missing + return; + } + if (! isAnnotationTargetAllowed(annotation, scope, containerAnnotationType, annotation.recipient.kind())) { + scope.problemReporter().disallowedTargetForContainerAnnotation(annotation, containerAnnotationType); + } + } + + // This is for error reporting for bad targets at annotation type declaration site (as opposed to the repeat site) + private static void checkContainingAnnotationTarget(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) { + long tagBits = repeatableAnnotation.getAnnotationTagBits(); + if ((tagBits & TagBits.AnnotationTargetMASK) != 0) { + long containingTagBits = container.getAnnotationTagBits(); + if ((containingTagBits & TagBits.AnnotationTargetMASK) == 0) { + scope.problemReporter().repeatableAnnotationHasTargets(markerNode, repeatableAnnotation, container); + } else { + final long targets = tagBits & TagBits.AnnotationTargetMASK; + final long containingTargets = containingTagBits & TagBits.AnnotationTargetMASK; + + if ((containingTargets & ~targets) != 0) { + class MissingTargetBuilder { + StringBuffer targetBuffer = new StringBuffer(); + void check(long targetMask, char[] targetName) { + if ((containingTargets & targetMask & ~targets) != 0) { + add(targetName); + } + } + void checkAnnotationType(char[] targetName) { + if ((containingTargets & TagBits.AnnotationForAnnotationType) != 0 && + ((targets & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType))) == 0) { + add(targetName); + } + } + private void add(char[] targetName) { + if (this.targetBuffer.length() != 0) { + this.targetBuffer.append(", "); //$NON-NLS-1$ + } + this.targetBuffer.append(targetName); + } + public String toString() { + return this.targetBuffer.toString(); + } + public boolean hasError() { + return this.targetBuffer.length() != 0; + } + } + MissingTargetBuilder builder = new MissingTargetBuilder(); + + builder.check(TagBits.AnnotationForType, TypeConstants.TYPE); + builder.check(TagBits.AnnotationForField, TypeConstants.UPPER_FIELD); + builder.check(TagBits.AnnotationForMethod, TypeConstants.UPPER_METHOD); + builder.check(TagBits.AnnotationForParameter, TypeConstants.UPPER_PARAMETER); + builder.check(TagBits.AnnotationForConstructor, TypeConstants.UPPER_CONSTRUCTOR); + builder.check(TagBits.AnnotationForLocalVariable, TypeConstants.UPPER_LOCAL_VARIABLE); + builder.checkAnnotationType(TypeConstants.UPPER_ANNOTATION_TYPE); + builder.check(TagBits.AnnotationForPackage, TypeConstants.UPPER_PACKAGE); + builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET); + builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET); + if (builder.hasError()) { + scope.problemReporter().repeatableAnnotationTargetMismatch(markerNode, repeatableAnnotation, container, builder.toString()); + } + } + } + } + } + + private static void checkContaintAnnotationDocumented(ASTNode markerNode, Scope scope, ReferenceBinding containing, ReferenceBinding repeatableAnnotation) { + if ((repeatableAnnotation.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containing.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) { + scope.problemReporter().repeatableAnnotationIsDocumented(markerNode, repeatableAnnotation, containing); + } + } + + private static void checkContaintAnnotationInherited(ASTNode markerNode, Scope scope, ReferenceBinding containing, ReferenceBinding repeatableAnnotation) { + if ((repeatableAnnotation.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containing.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) { + scope.problemReporter().repeatableAnnotationIsInherited(markerNode, repeatableAnnotation, containing); + } + } + + private static void checkContainingAnnotationRetention(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) { + long annotationBits = getAnnotationRetention(repeatableAnnotation); + long containerBits = getAnnotationRetention(container); + // Due to clever layout of the bits, we can compare the absolute value directly + if (containerBits < annotationBits) { + scope.problemReporter().containingAnnotationHasShorterRetention(markerNode, repeatableAnnotation, getRetentionName(annotationBits), container, getRetentionName(containerBits)); + } + } + public AnnotationBinding getCompilerAnnotation() { return this.compilerAnnotation; } @@ -1012,159 +857,149 @@ public abstract class Annotation extends Expression { break; case Binding.LOCAL : LocalVariableBinding variable = (LocalVariableBinding) this.recipient; - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { - variable.tagBits |= tagBits; - if ((variable.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this); - variable.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems - } - } else if (variable.type != null) { - // bits not relating to null analysis go into the variable: - variable.tagBits |= tagBits & ~TagBits.AnnotationNullMASK; - // null bits go into the type: - long nullTagBits = tagBits & TagBits.AnnotationNullMASK; - if (nullTagBits != 0) { - if (variable.type.isBaseType()) { - scope.problemReporter().illegalAnnotationForBaseType(this, variable.type); - } else if (variable.declaration.type instanceof QualifiedTypeReference) { - scope.problemReporter().nullAnnotationUnsupportedLocation(this); - } else if (nullTagBits != (variable.type.tagBits & TagBits.AnnotationNullMASK)) { - if (((variable.type.tagBits & TagBits.AnnotationNullMASK) | nullTagBits ) == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this); - variable.type = variable.type.unannotated(); - } - } - } + variable.tagBits |= tagBits; + if ((variable.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { + scope.problemReporter().contradictoryNullAnnotations(this); + variable.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems } if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - LocalDeclaration localDeclaration = variable.declaration; + LocalDeclaration localDeclaration = variable.declaration; recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings); } break; } } - // check (meta)target compatibility - checkTargetCompatibility: { - if (!annotationType.isValidBinding()) { - // no need to check annotation usage if missing - break checkTargetCompatibility; - } + checkAnnotationTarget(this, scope, annotationType, kind); + } + return this.resolvedType; + } - long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { - // does not specify any target restriction - all locations supported in Java 7 and before are possible - if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) { - scope.problemReporter().explitAnnotationTargetRequired(this); - } - break checkTargetCompatibility; - } + static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { + long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference + if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { + // does not specify any target restriction - all locations supported in Java 7 and before are possible + if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) { + scope.problemReporter().explitAnnotationTargetRequired(annotation); + } + return true; + } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 - if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0 - && (metaTagBits & (TagBits.AnnotationForTypeUse | TagBits.AnnotationForTypeParameter)) != 0) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { - switch (kind) { - case Binding.PACKAGE : - case Binding.TYPE : - case Binding.GENERIC_TYPE : - case Binding.METHOD : - case Binding.FIELD : - case Binding.LOCAL : - scope.problemReporter().invalidUsageOfTypeAnnotations(this); - } - } - } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 + if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0 + && (metaTagBits & (TagBits.AnnotationForTypeUse | TagBits.AnnotationForTypeParameter)) != 0) { + if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { switch (kind) { case Binding.PACKAGE : - if ((metaTagBits & TagBits.AnnotationForPackage) != 0) - break checkTargetCompatibility; - break; - case Binding.TYPE_USE : - if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - // jsr 308 - break checkTargetCompatibility; - } - break; case Binding.TYPE : case Binding.GENERIC_TYPE : - if (((ReferenceBinding)this.recipient).isAnnotationType()) { - if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) != 0) - break checkTargetCompatibility; - } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) { - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) { - if (CharOperation.equals(((ReferenceBinding)this.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) - break checkTargetCompatibility; - } -//{ObjectTeams: allow @Override for roles: - if ( (((ReferenceBinding)this.recipient).isRole()) - && (tagBits & TagBits.AnnotationOverride) != 0) - break checkTargetCompatibility; -// SH} - break; case Binding.METHOD : - MethodBinding methodBinding = (MethodBinding) this.recipient; - if (methodBinding.isConstructor()) { - if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0) - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) { - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass; - MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding); - if (isTypeUseCompatible(methodDecl.returnType, scope)) { - break checkTargetCompatibility; - } - } - break; -//{ObjectTeams: method mappings - // TODO(SH): should annotations for method mappings be controlled separately? - case Binding.BINDING : - if ((metaTagBits & TagBits.AnnotationForMethod) != 0) - break checkTargetCompatibility; - break; -// SH} case Binding.FIELD : - if ((metaTagBits & TagBits.AnnotationForField) != 0) { - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - FieldBinding sourceField = (FieldBinding) this.recipient; - SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass; - FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); - if (isTypeUseCompatible(fieldDeclaration.type, scope)) { - break checkTargetCompatibility; - } - } - break; case Binding.LOCAL : - LocalVariableBinding localVariableBinding = (LocalVariableBinding)this.recipient; - if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) { - if ((metaTagBits & TagBits.AnnotationForParameter) != 0) { - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - break checkTargetCompatibility; - } - } - } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) { - break checkTargetCompatibility; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - break checkTargetCompatibility; - } - } - break; - case Binding.TYPE_PARAMETER : // jsr308 - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196 - if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) { - break checkTargetCompatibility; + scope.problemReporter().invalidUsageOfTypeAnnotations(annotation); + } + } + } + switch (kind) { + case Binding.PACKAGE : + if ((metaTagBits & TagBits.AnnotationForPackage) != 0) + return true; + break; + case Binding.TYPE_USE : + if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { + // jsr 308 + return true; + } + break; + case Binding.TYPE : + case Binding.GENERIC_TYPE : + if (((ReferenceBinding)annotation.recipient).isAnnotationType()) { + if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) != 0) + return true; + } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) { + return true; + } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) { + if (CharOperation.equals(((ReferenceBinding) annotation.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) + return true; + } +//{ObjectTeams: allow @Override for roles: + if ( (((ReferenceBinding)annotation.recipient).isRole()) + && (annotation.resolvedType.id == TypeIds.T_JavaLangObject)) + return true; +//SH} + break; +//{ObjectTeams: method mappings + // TODO(SH): should annotations for method mappings be controlled separately? + case Binding.BINDING : + if ((metaTagBits & TagBits.AnnotationForMethod) != 0) + return true; + break; +//SH} + case Binding.METHOD : + MethodBinding methodBinding = (MethodBinding) annotation.recipient; + if (methodBinding.isConstructor()) { + if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0) + return true; + } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) { + return true; + } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { + SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass; + MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding); + if (isTypeUseCompatible(methodDecl.returnType, scope)) { + return true; + } + } + break; + case Binding.FIELD : + if ((metaTagBits & TagBits.AnnotationForField) != 0) { + return true; + } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { + FieldBinding sourceField = (FieldBinding) annotation.recipient; + SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass; + FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); + if (isTypeUseCompatible(fieldDeclaration.type, scope)) { + return true; + } + } + break; + case Binding.LOCAL : + LocalVariableBinding localVariableBinding = (LocalVariableBinding) annotation.recipient; + if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) { + if ((metaTagBits & TagBits.AnnotationForParameter) != 0) { + return true; + } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { + if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { + return true; } } - scope.problemReporter().disallowedTargetForAnnotation(this); - } + } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) { + return true; + } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { + if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { + return true; + } + } + break; + case Binding.TYPE_PARAMETER : // jsr308 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196 + if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) { + return true; + } + } + return false; + } + + static void checkAnnotationTarget(Annotation annotation, BlockScope scope, ReferenceBinding annotationType, int kind) { + // check (meta)target compatibility + if (!annotationType.isValidBinding()) { + // no need to check annotation usage if missing + return; + } + if (! isAnnotationTargetAllowed(annotation, scope, annotationType, kind)) { + scope.problemReporter().disallowedTargetForAnnotation(annotation); } - return this.resolvedType; } + + // Check and answer if an attempt to annotate a package is being made. Error should be reported by caller. public static boolean isTypeUseCompatible(TypeReference reference, Scope scope) { if (reference != null && !(reference instanceof SingleTypeReference)) { Binding binding = scope.getPackage(reference.getTypeName()); @@ -1175,6 +1010,34 @@ public abstract class Annotation extends Expression { } return true; } + + // Complain if an attempt to annotate the enclosing type of a static member type is being made. + public static void isTypeUseCompatible(TypeReference reference, Scope scope, Annotation[] annotations) { + if (annotations == null || reference == null || reference.getAnnotatableLevels() == 1) + return; + if (scope.environment().globalOptions.sourceLevel < ClassFileConstants.JDK1_8) + return; + + TypeBinding resolvedType = reference.resolvedType == null ? null : reference.resolvedType.leafComponentType(); + if (resolvedType == null || !resolvedType.isNestedType()) + return; + + nextAnnotation: + for (int i = 0, annotationsLength = annotations.length; i < annotationsLength; i++) { + Annotation annotation = annotations[i]; + long metaTagBits = annotation.resolvedType.getAnnotationTagBits(); + if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0 && (metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) { + ReferenceBinding currentType = (ReferenceBinding) resolvedType; + while (currentType.isNestedType()) { + if (currentType.isStatic()) { + QualifiedTypeReference.rejectAnnotationsOnStaticMemberQualififer(scope, currentType, new Annotation [] { annotation }); + continue nextAnnotation; + } + currentType = currentType.enclosingType(); + } + } + } + } public abstract void traverse(ASTVisitor visitor, BlockScope scope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java index f71cf7c2f..88c513ca9 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java @@ -16,6 +16,7 @@ * Stephan Herrmann - Contributions for * bug 186342 - [compiler][null] Using annotations for null checking * bug 365519 - editorial cleanup after bug 186342 and bug 365387 + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly *******************************************************************************/ @@ -93,7 +94,12 @@ public class Argument extends LocalDeclaration { } } } - resolveAnnotations(scope, this.annotations, this.binding, true); + if ((this.binding.tagBits & TagBits.AnnotationResolved) == 0) { + resolveAnnotations(scope, this.annotations, this.binding, true); + Annotation.isTypeUseCompatible(this.type, scope, this.annotations); + if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) + scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations); + } this.binding.declaration = this; return this.binding.type; // might have been updated during resolveAnnotations (for typeAnnotations) } @@ -235,49 +241,7 @@ public class Argument extends LocalDeclaration { this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers, false); // argument decl, but local var (where isArgument = false) } resolveAnnotations(scope, this.annotations, this.binding, true); - - // Type annotations may need attaching to the type references - // Example of code this block handles: } catch(@A Exception e) { - if (this.annotations != null) { - for (int i = 0, max = this.annotations.length; i < max; i++) { - Annotation annotation = this.annotations[i]; - if ((annotation.resolvedType.tagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) { - // Copy it to the type reference. - if (this.type instanceof UnionTypeReference) { - // Only need to consider the first element of the union type reference - TypeReference firstTypeReference = ((UnionTypeReference) this.type).typeReferences[0]; - Annotation[][] annotationsOnFirstReference = firstTypeReference.annotations; - if (annotationsOnFirstReference == null) { - firstTypeReference.annotations = annotationsOnFirstReference = new Annotation[firstTypeReference.getAnnotatableLevels()][]; - } - if (annotationsOnFirstReference[0] == null) { - firstTypeReference.annotations[0] = new Annotation[] { annotation }; - } else { - int len = annotationsOnFirstReference.length; - Annotation[] newAnnotations = new Annotation[len + 1]; - System.arraycopy(annotationsOnFirstReference[0], 0, newAnnotations, 0, len); - newAnnotations[len] = annotation; - firstTypeReference.annotations[0] = newAnnotations; - } - firstTypeReference.bits |= ASTNode.HasTypeAnnotations; - } else { - if (this.type.annotations == null) { - this.type.annotations = new Annotation[this.type.getAnnotatableLevels()][]; - } - if (this.type.annotations[0] == null) { - this.type.annotations[0] = new Annotation[] { annotation }; - } else { - int len = this.type.annotations[0].length; - Annotation[] newAnnotations = new Annotation[len + 1]; - System.arraycopy(this.type.annotations[0], 0, newAnnotations, 0, len); - newAnnotations[len] = annotation; - this.type.annotations[0] = newAnnotations; - } - this.type.bits |= ASTNode.HasTypeAnnotations; - } - } - } - } + Annotation.isTypeUseCompatible(this.type, scope, this.annotations); scope.addLocalVariable(this.binding); this.binding.setConstant(Constant.NotAConstant); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java index 172f5a3e3..55b07c3e8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java @@ -17,14 +17,18 @@ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking + * Bug 417758 - [1.8][null] Null safety compromise during array creation. * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409247 - [1.8][compiler] Verify error with code allocating multidimensional array *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; +import java.util.List; + import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; import org.eclipse.jdt.internal.compiler.codegen.*; import org.eclipse.jdt.internal.compiler.flow.*; import org.eclipse.jdt.internal.compiler.lookup.*; @@ -71,7 +75,7 @@ public class ArrayAllocationExpression extends Expression { int pc = codeStream.position; if (this.initializer != null) { - this.initializer.generateCode(this.type, this.annotationsOnDimensions, currentScope, codeStream, valueRequired); + this.initializer.generateCode(this.type, this, currentScope, codeStream, valueRequired); return; } @@ -86,10 +90,10 @@ public class ArrayAllocationExpression extends Expression { // array allocation if (explicitDimCount == 1) { // Mono-dimensional array - codeStream.newArray(this.type, this.annotationsOnDimensions, (ArrayBinding)this.resolvedType); + codeStream.newArray(this.type, this, (ArrayBinding)this.resolvedType); } else { // Multi-dimensional array - codeStream.multianewarray(this.type, this.resolvedType, explicitDimCount, this.dimensions.length, this.annotationsOnDimensions); + codeStream.multianewarray(this.type, this.resolvedType, explicitDimCount, this); } if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); @@ -183,6 +187,10 @@ public class ArrayAllocationExpression extends Expression { // SH} this.resolvedType = scope.createArrayType(referenceType, this.dimensions.length); + if (this.annotationsOnDimensions != null) { + this.resolvedType = resolveAnnotations(scope, this.annotationsOnDimensions, this.resolvedType); + } + // check the initializer if (this.initializer != null) { if ((this.initializer.resolveTypeExpecting(scope, this.resolvedType)) != null) @@ -192,9 +200,6 @@ public class ArrayAllocationExpression extends Expression { return null; } } - if (this.annotationsOnDimensions != null) { - this.resolvedType = resolveAnnotations(scope, this.annotationsOnDimensions, this.resolvedType); - } return this.resolvedType; } @@ -204,6 +209,11 @@ public class ArrayAllocationExpression extends Expression { int dimensionsLength = this.dimensions.length; this.type.traverse(visitor, scope); for (int i = 0; i < dimensionsLength; i++) { + Annotation [] annotations = this.annotationsOnDimensions == null ? null : this.annotationsOnDimensions[i]; + int annotationsLength = annotations == null ? 0 : annotations.length; + for (int j = 0; j < annotationsLength; j++) { + annotations[j].traverse(visitor, scope); + } if (this.dimensions[i] != null) this.dimensions[i].traverse(visitor, scope); } @@ -212,4 +222,23 @@ public class ArrayAllocationExpression extends Expression { } visitor.endVisit(this, scope); } + + public void getAllAnnotationContexts(int targetType, int info, List allTypeAnnotationContexts) { + AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allTypeAnnotationContexts); + this.type.traverse(collector, (BlockScope) null); + if (this.annotationsOnDimensions != null) { + int dimensionsLength = this.dimensions.length; + for (int i = 0; i < dimensionsLength; i++) { + Annotation [] annotations = this.annotationsOnDimensions[i]; + int annotationsLength = annotations == null ? 0 : annotations.length; + for (int j = 0; j < annotationsLength; j++) { + annotations[j].traverse(collector, (BlockScope) null); + } + } + } + } + + public Annotation[][] getAnnotationsOnDimensions() { + return this.annotationsOnDimensions; + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java index d39eeef47..caa6e5bac 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java @@ -15,14 +15,17 @@ * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK * bug 370639 - [compiler][resource] restore the default for resource leak warnings * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' + * Bug 417758 - [1.8][null] Null safety compromise during array creation. * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.*; import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.*; @@ -42,13 +45,19 @@ public class ArrayInitializer extends Expression { public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { if (this.expressions != null) { - boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; + CompilerOptions compilerOptions = currentScope.compilerOptions(); + boolean analyseResources = compilerOptions.analyseResourceLeaks; + boolean evalNullTypeAnnotations = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 + && compilerOptions.isAnnotationBasedNullAnalysisEnabled; for (int i = 0, max = this.expressions.length; i < max; i++) { flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); if (analyseResources && FakedTrackingVariable.isAnyCloseable(this.expressions[i].resolvedType)) { flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expressions[i], flowInfo, flowContext, false); } + if (evalNullTypeAnnotations) { + checkAgainstNullTypeAnnotation(currentScope, this.binding.elementsType(), this.expressions[i], flowContext, flowInfo); + } } } return flowInfo; @@ -61,13 +70,13 @@ public class ArrayInitializer extends Expression { /** * Code generation for a array initializer */ - public void generateCode(TypeReference typeReference, Annotation[][] annotationsOnDimensions, BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + public void generateCode(TypeReference typeReference, ArrayAllocationExpression allocationExpression, BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers int pc = codeStream.position; int expressionLength = (this.expressions == null) ? 0: this.expressions.length; codeStream.generateInlinedValue(expressionLength); - codeStream.newArray(typeReference, annotationsOnDimensions, this.binding); + codeStream.newArray(typeReference, allocationExpression, this.binding); if (this.expressions != null) { // binding is an ArrayType, so I can just deal with the dimension int elementsTypeID = this.binding.dimensions > 1 ? -1 : this.binding.leafComponentType.id; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java index ade9f79c1..63eb10e90 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java @@ -22,7 +22,8 @@ import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; public class ArrayQualifiedTypeReference extends QualifiedTypeReference { int dimensions; - Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions + private Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions + public int extendedDimensions; //{ObjectTeams: mark generated reference: public ArrayQualifiedTypeReference(char[][] sources , int dim, long[] poss, boolean isGenerated) { @@ -49,8 +50,17 @@ public class ArrayQualifiedTypeReference extends QualifiedTypeReference { return this.dimensions; } - public Annotation[][] getAnnotationsOnDimensions() { - return this.annotationsOnDimensions; + /** + @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getAnnotationsOnDimensions(boolean) + */ + public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { + if (useSourceOrder || this.annotationsOnDimensions == null || this.annotationsOnDimensions.length == 0 || this.extendedDimensions == 0 || this.extendedDimensions == this.dimensions) + return this.annotationsOnDimensions; + Annotation [][] externalAnnotations = new Annotation[this.dimensions][]; + final int baseDimensions = this.dimensions - this.extendedDimensions; + System.arraycopy(this.annotationsOnDimensions, baseDimensions, externalAnnotations, 0, this.extendedDimensions); + System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions); + return externalAnnotations; } public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java index e6cd3e0ea..011600f7a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java @@ -23,8 +23,9 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; public class ArrayTypeReference extends SingleTypeReference { public int dimensions; - public Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions. + private Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions. public int originalSourceEnd; + public int extendedDimensions; /** * ArrayTypeReference constructor comment. @@ -53,9 +54,19 @@ public class ArrayTypeReference extends SingleTypeReference { return this.dimensions; } - public Annotation[][] getAnnotationsOnDimensions() { - return this.annotationsOnDimensions; + /** + @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getAnnotationsOnDimensions(boolean) + */ + public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { + if (useSourceOrder || this.annotationsOnDimensions == null || this.annotationsOnDimensions.length == 0 || this.extendedDimensions == 0 || this.extendedDimensions == this.dimensions) + return this.annotationsOnDimensions; + Annotation [][] externalAnnotations = new Annotation[this.dimensions][]; + final int baseDimensions = this.dimensions - this.extendedDimensions; + System.arraycopy(this.annotationsOnDimensions, baseDimensions, externalAnnotations, 0, this.extendedDimensions); + System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions); + return externalAnnotations; } + public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) { this.annotationsOnDimensions = annotationsOnDimensions; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java index 05dc8f1f3..1d09d0706 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -22,6 +22,7 @@ * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -516,7 +517,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, // from valueIFTrue or valueIfFalse to the receiver constant this.constant = condConstant.booleanValue() ? trueConstant : falseConstant; } - if (valueIfTrueType == valueIfFalseType) { // harmed the implicit conversion + if (TypeBinding.equalsEquals(valueIfTrueType, valueIfFalseType)) { // harmed the implicit conversion this.valueIfTrue.computeConversion(scope, valueIfTrueType, this.originalValueIfTrueType); this.valueIfFalse.computeConversion(scope, valueIfFalseType, this.originalValueIfFalseType); if (valueIfTrueType == TypeBinding.BOOLEAN) { @@ -533,7 +534,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, : this.optimizedIfFalseConstant; } } - return this.resolvedType = valueIfTrueType; + return this.resolvedType = NullAnnotationMatching.moreDangerousType(valueIfTrueType, valueIfFalseType); } // Determine the return type depending on argument types // Numeric types diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java index 84c6eae1a..cfe58d258 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java @@ -691,7 +691,7 @@ public void maybeRecordByteCode(ClassFile classFile, int methodAttributeOffset) // SH} public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); + AnnotationCollector collector = new AnnotationCollector(null, targetType, allAnnotationContexts); for (int i = 0, max = this.annotations.length; i < max; i++) { Annotation annotation = this.annotations[i]; annotation.traverse(collector, (BlockScope) null); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java index 990746174..2227eac83 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -23,7 +23,8 @@ * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -398,7 +399,7 @@ public final boolean checkCastTypesCompatibility( boolean use17specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7; if (castType.isBaseType()) { if (expressionType.isBaseType()) { - if (expressionType == castType) { + if (TypeBinding.equalsEquals(expressionType, castType)) { if (expression != null) { this.constant = expression.constant; //use the same constant } @@ -453,7 +454,7 @@ public final boolean checkCastTypesCompatibility( return false; case Binding.ARRAY_TYPE : - if (castType == expressionType) { + if (TypeBinding.equalsEquals(castType, expressionType)) { tagAsUnnecessaryCast(scope, castType); return true; // identity conversion } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java index 4d1682a13..617379f50 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java @@ -170,7 +170,7 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { codeStream.recordPositionsFrom(pc, this.sourceStart); } public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); + AnnotationCollector collector = new AnnotationCollector(this.type, targetType, allAnnotationContexts); for (int i = 0, max = this.annotations.length; i < max; i++) { Annotation annotation = this.annotations[i]; annotation.traverse(collector, (BlockScope) null); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java index 5acf63f53..94c2f6b18 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java @@ -891,7 +891,7 @@ public void traverse(ASTVisitor visitor, BlockScope scope) { public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) { if (this.binding != null) { if (supportTypeAnnotations - || ((this.binding.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) != 0)) { + || ((this.binding.tagBits & TagBits.AnnotationNullMASK) != 0)) { return this.binding; } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java index 4e6475292..b2e589d56 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java @@ -38,7 +38,8 @@ public abstract class FunctionalExpression extends Expression { TypeBinding expectedType; public MethodBinding descriptor; - public MethodBinding binding; + public MethodBinding binding; // Code generation binding. May include synthetics. See getMethodBinding() + protected MethodBinding actualMethodBinding; // void of synthetics. boolean ignoreFurtherInvestigation; protected ExpressionContext expressionContext = VANILLA_CONTEXT; protected SimpleLookupTable resultExpressions; @@ -51,7 +52,10 @@ public abstract class FunctionalExpression extends Expression { public FunctionalExpression(CompilationResult compilationResult) { this.compilationResult = compilationResult; } - + // Return the actual (non-code generation) method binding that is void of synthetics. + public MethodBinding getMethodBinding() { + return null; + } public void setExpectedType(TypeBinding expectedType) { this.expectedType = this.ellipsisArgument ? ((ArrayBinding) expectedType).elementsType() : expectedType; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java index 55c205c50..d8a595c65 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java @@ -18,6 +18,7 @@ * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Andy Clement - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) *******************************************************************************/ @@ -156,7 +157,6 @@ public TypeBinding resolveType(BlockScope scope) { TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/); if (expressionType != null && checkedType != null && NullAnnotationMatching.analyse(checkedType, expressionType, -1).isAnyMismatch()) { scope.problemReporter().nullAnnotationUnsupportedLocation(this.type); - checkedType = checkedType.unannotated(); } if (expressionType == null || checkedType == null) return null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java index 27da4692c..fc51a505a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java @@ -40,11 +40,7 @@ public class IntersectionCastTypeReference extends TypeReference { } } - public TypeReference copyDims(int dim) { - throw new UnsupportedOperationException(); // no syntax for this. - } - - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { throw new UnsupportedOperationException(); // no syntax for this. } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java index 7f985aa6e..cfb139c3c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java @@ -28,14 +28,8 @@ public class JavadocImplicitTypeReference extends TypeReference { this.sourceStart = pos; this.sourceEnd = pos; } - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int) - */ - public TypeReference copyDims(int dim) { - return null; - } - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { return null; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java index 8c2609425..ea454757a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java @@ -49,6 +49,7 @@ import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; +import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; @@ -789,6 +790,17 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC return this.outerLocalVariables[i]; return null; } + + // Return the actual method binding devoid of synthetics. + public MethodBinding getMethodBinding() { + if (this.actualMethodBinding == null) { + this.actualMethodBinding = new MethodBinding(this.binding.modifiers, this.binding.selector, this.binding.returnType, + this.binding instanceof SyntheticMethodBinding ? this.descriptor.parameters : this.binding.parameters, // retain any faults in parameter list. + this.binding.thrownExceptions, this.binding.declaringClass); + this.actualMethodBinding.tagBits = this.binding.tagBits; + } + return this.actualMethodBinding; + } } class IncongruentLambdaException extends RuntimeException { private static final long serialVersionUID = 4145723509219836114L; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java index d80efc2aa..b233bdbce 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -370,6 +370,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } // only resolve annotation at the end, for constant to be positioned before (96991) resolveAnnotations(scope, this.annotations, this.binding, true); + Annotation.isTypeUseCompatible(this.type, scope, this.annotations); if (!scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations)) this.binding.tagBits &= ~TagBits.AnnotationNullMASK; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 8a20f1c0d..bf1905cf6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -39,7 +39,7 @@ * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 405569 - Resource leak check false positive when using DbUtils.closeQuietly * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement - * Bug 405569 - Resource leak check false positive when using DbUtils.closeQuietly + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper S Moller - Contributions for * Bug 378674 - "The method can be declared as static" is wrong * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for @@ -214,7 +214,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); - } + } if (this.arguments != null) { int length = this.arguments.length; @@ -235,7 +235,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo = analyseNullAssertion(currentScope, argument, flowContext, flowInfo, true); break; default: - flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); } if (analyseResources) { // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) @@ -244,13 +244,6 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); } - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { - if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { - TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); - for (int i = 0; i < this.typeArguments.length; i++) - this.typeArguments[i].checkNullConstraints(currentScope, typeVariables, i); - } - } ReferenceBinding[] thrownExceptions; if ((thrownExceptions = this.binding.thrownExceptions) != Binding.NO_EXCEPTIONS) { if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { @@ -1114,12 +1107,21 @@ public TypeBinding resolveType(BlockScope scope) { return null; } - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { - // not interested in reporting problems against this.binding: + if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { + if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { + // not interested in reporting problems against this.binding: //{ObjectTeams: added 2nd arg: - new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, scope.environment()) + new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, scope.environment()) // SH} - .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + } + if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { + TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); + for (int i = 0; i < this.typeArguments.length; i++) + this.typeArguments[i].checkNullConstraints(scope, typeVariables, i); + } + } } if (((this.bits & ASTNode.InsideExpressionStatement) != 0) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java index 73077e746..d287ba521 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java @@ -239,7 +239,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { // SH} public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); + AnnotationCollector collector = new AnnotationCollector(this.returnType, targetType, allAnnotationContexts); for (int i = 0, max = this.annotations.length; i < max; i++) { Annotation annotation = this.annotations[i]; annotation.traverse(collector, (BlockScope) null); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java index 24a94937c..009cb5f89 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java @@ -106,8 +106,8 @@ public class NullAnnotationMatching { severity = 1; // required is annotated, provided not, need unchecked conversion } else { for (int i=0; i<=dims; i++) { - long requiredBits = requiredDimsTagBits[i] & TagBits.AnnotationNullMASK; - long providedBits = providedDimsTagBits[i] & TagBits.AnnotationNullMASK; + long requiredBits = validNullTagBits(requiredDimsTagBits[i]); + long providedBits = validNullTagBits(providedDimsTagBits[i]); if (i > 0) nullStatus = -1; // don't use beyond the outermost dimension severity = Math.max(severity, computeNullProblemSeverity(requiredBits, providedBits, nullStatus)); @@ -121,11 +121,11 @@ public class NullAnnotationMatching { } } } else if (requiredType.hasNullTypeAnnotations() || providedType.hasNullTypeAnnotations()) { - long requiredBits = requiredType.tagBits & TagBits.AnnotationNullMASK; + long requiredBits = validNullTagBits(requiredType.tagBits); if (requiredBits != TagBits.AnnotationNullable // nullable lhs accepts everything, ... || nullStatus == -1) // only at detail/recursion even nullable must be matched exactly { - long providedBits = providedType.tagBits & TagBits.AnnotationNullMASK; + long providedBits = validNullTagBits(providedType.tagBits); severity = computeNullProblemSeverity(requiredBits, providedBits, nullStatus); } if (severity < 2) { @@ -144,8 +144,12 @@ public class NullAnnotationMatching { } } } else if (requiredType instanceof WildcardBinding) { - NullAnnotationMatching status = analyse(((WildcardBinding) requiredType).bound, providedType, nullStatus); - severity = Math.max(severity, status.severity); + WildcardBinding wildcardBinding = (WildcardBinding) requiredType; + if (wildcardBinding.bound != null) { + NullAnnotationMatching status = analyse(wildcardBinding.bound, providedType, nullStatus); + severity = Math.max(severity, status.severity); + } + // TODO(stephan): what about otherBounds? Do we accept "? extends @NonNull I1 & @Nullable I2" in the first place?? } TypeBinding requiredEnclosing = requiredType.enclosingType(); TypeBinding providedEnclosing = providedType.enclosingType(); @@ -160,14 +164,40 @@ public class NullAnnotationMatching { return new NullAnnotationMatching(severity, superTypeHint); } + public static long validNullTagBits(long bits) { + bits &= TagBits.AnnotationNullMASK; + return bits == TagBits.AnnotationNullMASK ? 0 : bits; + } + + /** Provided that both types are {@link TypeBinding#equalsEquals}, return the one that is more likely to show null at runtime. */ + public static TypeBinding moreDangerousType(TypeBinding one, TypeBinding two) { + if (one == null) return null; + long oneNullBits = validNullTagBits(one.tagBits); + long twoNullBits = validNullTagBits(two.tagBits); + if (oneNullBits != twoNullBits) { + if (oneNullBits == TagBits.AnnotationNullable) + return one; // nullable is dangerous + if (twoNullBits == TagBits.AnnotationNullable) + return two; // nullable is dangerous + // below this point we have unknown vs. nonnull, which is which? + if (oneNullBits == 0) + return one; // unknown is more dangerous than nonnull + return two; // unknown is more dangerous than nonnull + } else if (one != two) { + if (analyse(one, two, -1).isAnyMismatch()) + return two; // two doesn't snugly fit into one, so it must be more dangerous + } + return one; + } + private static int computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus) { if (requiredBits != 0 && requiredBits != providedBits) { + if (requiredBits == TagBits.AnnotationNonNull && nullStatus == FlowInfo.NON_NULL) { + return 0; // OK by flow analysis + } if (providedBits != 0) { return 2; // mismatching annotations } else { - if (requiredBits == TagBits.AnnotationNonNull && nullStatus == FlowInfo.NON_NULL) { - return 0; // OK by flow analysis - } return 1; // need unchecked conversion regarding type detail } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java index 17cd958f9..d280a3669 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java @@ -76,7 +76,7 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer } public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long[] positions) { this(tokens, typeArguments, dim, positions); - this.annotationsOnDimensions = annotationsOnDimensions; + setAnnotationsOnDimensions(annotationsOnDimensions); if (annotationsOnDimensions != null) { this.bits |= ASTNode.HasTypeAnnotations; } @@ -103,16 +103,15 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer } } } - public TypeReference copyDims(int dim){ - return new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, dim, this.sourcePositions); - } - public TypeReference copyDims(int dim, Annotation[][] dimensionAnnotations){ - ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference = new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, dim, dimensionAnnotations, this.sourcePositions); - parameterizedQualifiedTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (dimensionAnnotations != null) { - parameterizedQualifiedTypeReference.bits |= ASTNode.HasTypeAnnotations; - } - return parameterizedQualifiedTypeReference; + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { + int totalDimensions = this.dimensions() + additionalDimensions; + Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); + ParameterizedQualifiedTypeReference pqtr = new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, totalDimensions, allAnnotations, this.sourcePositions); + pqtr.annotations = this.annotations; + pqtr.bits |= (this.bits & ASTNode.HasTypeAnnotations); + if (!isVarargs) + pqtr.extendedDimensions = additionalDimensions; + return pqtr; } public boolean isParameterizedTypeReference() { return true; @@ -155,6 +154,10 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer return qParamName; } + public TypeReference[][] getTypeArguments() { + return this.typeArguments; + } + /* (non-Javadoc) * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) */ @@ -253,7 +256,8 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer : scope.environment().convertToParameterizedType(qualifyingType); } } else { - rejectAnnotationsOnStaticMemberQualififer(scope, currentType, i); + if (this.annotations != null) + rejectAnnotationsOnStaticMemberQualififer(scope, currentType, this.annotations[i-1]); if (typeIsConsistent && currentType.isStatic() && (qualifyingType.isParameterizedTypeWithActualArguments() || qualifyingType.isGenericType())) { scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifyingType), i); @@ -408,26 +412,27 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer } output.append('>'); } + Annotation [][] annotationsOnDimensions = this.getAnnotationsOnDimensions(); if ((this.bits & IsVarArgs) != 0) { for (int i= 0 ; i < this.dimensions - 1; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); + printAnnotations(annotationsOnDimensions[i], output); output.append(" "); //$NON-NLS-1$ } output.append("[]"); //$NON-NLS-1$ } - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[this.dimensions - 1] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[this.dimensions - 1], output); + printAnnotations(annotationsOnDimensions[this.dimensions - 1], output); output.append(" "); //$NON-NLS-1$ } output.append("..."); //$NON-NLS-1$ } else { for (int i= 0 ; i < this.dimensions; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); + printAnnotations(annotationsOnDimensions[i], output); output.append(" "); //$NON-NLS-1$ } output.append("[]"); //$NON-NLS-1$ @@ -452,9 +457,10 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer this.annotations[i][j].traverse(visitor, scope); } } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; + Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); + if (annotationsOnDimensions != null) { + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations2 = annotationsOnDimensions[i]; for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { Annotation annotation = annotations2[j]; annotation.traverse(visitor, scope); @@ -482,9 +488,10 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer this.annotations[i][j].traverse(visitor, scope); } } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; + Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); + if (annotationsOnDimensions != null) { + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations2 = annotationsOnDimensions[i]; for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { Annotation annotation = annotations2[j]; annotation.traverse(visitor, scope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java index e33a10a1c..eff0e7ccf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java @@ -78,7 +78,7 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { } public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long pos) { this(name, typeArguments, dim, pos); - this.annotationsOnDimensions = annotationsOnDimensions; + setAnnotationsOnDimensions(annotationsOnDimensions); if (annotationsOnDimensions != null) { this.bits |= ASTNode.HasTypeAnnotations; } @@ -96,18 +96,15 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { } } } - /** - * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int) - */ - public TypeReference copyDims(int dim) { - return new ParameterizedSingleTypeReference(this.token, this.typeArguments, dim, (((long)this.sourceStart)<<32)+this.sourceEnd); - } - public TypeReference copyDims(int dim, Annotation [][] annotationsOnDims) { - ParameterizedSingleTypeReference parameterizedSingleTypeReference = new ParameterizedSingleTypeReference(this.token, this.typeArguments, dim, annotationsOnDims, (((long)this.sourceStart)<<32)+this.sourceEnd); + + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) { + int totalDimensions = this.dimensions() + additionalDimensions; + Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); + ParameterizedSingleTypeReference parameterizedSingleTypeReference = new ParameterizedSingleTypeReference(this.token, this.typeArguments, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd); + parameterizedSingleTypeReference.annotations = this.annotations; parameterizedSingleTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (annotationsOnDims != null) { - parameterizedSingleTypeReference.bits |= ASTNode.HasTypeAnnotations; - } + if (!isVarargs) + parameterizedSingleTypeReference.extendedDimensions = additionalDimensions; return parameterizedSingleTypeReference; } @@ -152,6 +149,11 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { } return new char[][]{ name }; } + + public TypeReference[][] getTypeArguments() { + return new TypeReference[][] { this.typeArguments }; + } + /** * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) */ @@ -494,26 +496,27 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { this.typeArguments[max].print(0, output); } output.append(">"); //$NON-NLS-1$ + Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(); if ((this.bits & IsVarArgs) != 0) { for (int i= 0 ; i < this.dimensions - 1; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); + printAnnotations(annotationsOnDimensions[i], output); output.append(" "); //$NON-NLS-1$ } output.append("[]"); //$NON-NLS-1$ } - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[this.dimensions - 1] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[this.dimensions - 1], output); + printAnnotations(annotationsOnDimensions[this.dimensions - 1], output); output.append(" "); //$NON-NLS-1$ } output.append("..."); //$NON-NLS-1$ } else { for (int i= 0 ; i < this.dimensions; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { + if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); + printAnnotations(annotationsOnDimensions[i], output); output.append(" "); //$NON-NLS-1$ } output.append("[]"); //$NON-NLS-1$ @@ -603,9 +606,10 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { typeAnnotations[i].traverse(visitor, scope); } } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; + Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); + if (annotationsOnDimensions != null) { + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations2 = annotationsOnDimensions[i]; if (annotations2 != null) { for (int j = 0, max2 = annotations2.length; j < max2; j++) { Annotation annotation = annotations2[j]; @@ -629,9 +633,10 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference { typeAnnotations[i].traverse(visitor, scope); } } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; + Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); + if (annotationsOnDimensions != null) { + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations2 = annotationsOnDimensions[i]; for (int j = 0, max2 = annotations2.length; j < max2; j++) { Annotation annotation = annotations2[j]; annotation.traverse(visitor, scope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index 048aaeeb0..bc51c76e3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -27,6 +27,7 @@ * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 378674 - "The method can be declared as static" is wrong * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for @@ -411,7 +412,7 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc hasError = true; } else { receiverType = ((SingleTypeReference) this.type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType); - receiverType = checkIllegalNullAnnotation(scope, receiverType); + checkIllegalNullAnnotation(scope, receiverType); if (receiverType != null && enclosingInstanceContainsCast) { CastExpression.checkNeedForEnclosingInstanceCast(scope, this.enclosingInstance, enclosingInstanceType, receiverType); } @@ -422,7 +423,7 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc receiverType = scope.enclosingSourceType(); } else { receiverType = this.type.resolveType(scope, true /* check bounds*/); - receiverType = checkIllegalNullAnnotation(scope, receiverType); + checkIllegalNullAnnotation(scope, receiverType); checkParameterizedAllocation: { if (receiverType == null || !receiverType.isValidBinding()) break checkParameterizedAllocation; if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>() diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java index 95c56db9c..3c896c591 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 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 @@ -58,20 +58,14 @@ public class QualifiedTypeReference extends TypeReference { this.sourceEnd = (int)(this.sourcePositions[this.sourcePositions.length-1] & 0x00000000FFFFFFFFL ) ; } - public TypeReference copyDims(int dim){ - //return a type reference copy of me with some dimensions - //warning : the new type ref has a null binding - return new ArrayQualifiedTypeReference(this.tokens, dim, this.sourcePositions); - } - - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { - //return a type reference copy of me with some dimensions - //warning : the new type ref has a null binding - ArrayQualifiedTypeReference arrayQualifiedTypeReference = new ArrayQualifiedTypeReference(this.tokens, dim, annotationsOnDimensions, this.sourcePositions); + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { + int totalDimensions = this.dimensions() + additionalDimensions; + Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); + ArrayQualifiedTypeReference arrayQualifiedTypeReference = new ArrayQualifiedTypeReference(this.tokens, totalDimensions, allAnnotations, this.sourcePositions); + arrayQualifiedTypeReference.annotations = this.annotations; arrayQualifiedTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (annotationsOnDimensions != null) { - arrayQualifiedTypeReference.bits |= ASTNode.HasTypeAnnotations; - } + if (!isVarargs) + arrayQualifiedTypeReference.extendedDimensions = additionalDimensions; return arrayQualifiedTypeReference; } @@ -153,14 +147,11 @@ public class QualifiedTypeReference extends TypeReference { } } - protected void rejectAnnotationsOnStaticMemberQualififer(Scope scope, ReferenceBinding currentType, int tokenIndex) { + protected static void rejectAnnotationsOnStaticMemberQualififer(Scope scope, ReferenceBinding currentType, Annotation[] qualifierAnnot) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385137 - if (this.annotations != null && currentType.isMemberType() && currentType.isStatic()) { - Annotation[] qualifierAnnot = this.annotations[tokenIndex - 1]; - if (qualifierAnnot != null) { - scope.problemReporter().illegalTypeAnnotationsInStaticMemberAccess(qualifierAnnot[0], - qualifierAnnot[qualifierAnnot.length - 1]); - } + if (currentType.isMemberType() && currentType.isStatic() && qualifierAnnot != null && qualifierAnnot.length > 0) { + scope.problemReporter().illegalTypeAnnotationsInStaticMemberAccess(qualifierAnnot[0], + qualifierAnnot[qualifierAnnot.length - 1]); } } @@ -230,7 +221,9 @@ public class QualifiedTypeReference extends TypeReference { return null; ReferenceBinding currentType = (ReferenceBinding) this.resolvedType; if (qualifiedType != null) { - rejectAnnotationsOnStaticMemberQualififer(scope, currentType, i); + if (this.annotations != null) { + rejectAnnotationsOnStaticMemberQualififer(scope, currentType, this.annotations[i-1]); + } ReferenceBinding enclosingType = currentType.enclosingType(); if (enclosingType != null && enclosingType.erasure() != qualifiedType.erasure()) { qualifiedType = enclosingType; // inherited member type, leave it associated with its enclosing rather than subtype diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java index 6dc9e6be5..b80d1b8bc 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java @@ -81,6 +81,7 @@ public class ReferenceExpression extends FunctionalExpression implements Invocat } public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { + this.actualMethodBinding = this.binding; // grab before synthetics come into play. SourceTypeBinding sourceType = currentScope.enclosingSourceType(); if (this.receiverType.isArrayType()) { if (isConstructorReference()) { @@ -637,4 +638,10 @@ public class ReferenceExpression extends FunctionalExpression implements Invocat tSam = t.getSingleAbstractMethod(this.enclosingScope); return resultExpression.tIsMoreSpecific(tSam.returnType, sSam.returnType); } + + public org.eclipse.jdt.internal.compiler.lookup.MethodBinding getMethodBinding() { + if (this.actualMethodBinding == null) // array new/clone, no real binding. + this.actualMethodBinding = this.binding; + return this.actualMethodBinding; + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java index c2ab7bf48..9d0f40df1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -32,8 +32,9 @@ * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking + * Bug 417758 - [1.8][null] Null safety compromise during array creation. * Jesper S Moller - Contributions for - * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression + * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -78,7 +79,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); if (flowInfo.reachMode() == FlowInfo.REACHABLE) - checkAgainstNullAnnotation(currentScope, flowContext, this.expression.nullStatus(flowInfo, flowContext)); + checkAgainstNullAnnotation(currentScope, flowContext, flowInfo); if (currentScope.compilerOptions().analyseResourceLeaks) { FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.expression, flowInfo, flowContext); if (trackingVariable != null) { @@ -165,7 +166,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowContext.recordAbruptExit(); return FlowInfo.DEAD_END; } -void checkAgainstNullAnnotation(BlockScope scope, FlowContext flowContext, int nullStatus) { +void checkAgainstNullAnnotation(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { + int nullStatus = this.expression.nullStatus(flowInfo, flowContext); long tagBits; MethodBinding methodBinding = null; boolean useTypeAnnotations = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8; @@ -178,12 +180,7 @@ void checkAgainstNullAnnotation(BlockScope scope, FlowContext flowContext, int n return; } if (useTypeAnnotations) { - NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(methodBinding.returnType, this.expression.resolvedType, nullStatus); - if (annotationStatus.isDefiniteMismatch()) { - scope.problemReporter().nullityMismatchingTypeAnnotation(this.expression, this.expression.resolvedType, methodBinding.returnType, annotationStatus); - } else if (annotationStatus.isUnchecked()) { - flowContext.recordNullityMismatch(scope, this.expression, this.expression.resolvedType, methodBinding.returnType, nullStatus); - } + checkAgainstNullTypeAnnotation(scope, methodBinding.returnType, this.expression, flowContext, flowInfo); } else if (nullStatus != FlowInfo.NON_NULL) { // if we can't prove non-null check against declared null-ness of the enclosing method: if ((tagBits & TagBits.AnnotationNonNull) != 0) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java index 87d909d45..88b387d40 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java @@ -887,7 +887,7 @@ public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotatio case Binding.FIELD : // reading a field case Binding.LOCAL : // reading a local variable if (supportTypeAnnotations - || (((VariableBinding)this.binding).tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) != 0) + || (((VariableBinding)this.binding).tagBits & TagBits.AnnotationNullMASK) != 0) return (VariableBinding) this.binding; } return null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java index acc228117..8d0517ed1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java @@ -43,21 +43,14 @@ public class SingleTypeReference extends TypeReference { } - public TypeReference copyDims(int dim){ - //return a type reference copy of me with some dimensions - //warning : the new type ref has a null binding - - return new ArrayTypeReference(this.token, dim,(((long)this.sourceStart)<<32)+this.sourceEnd); - } - - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions){ - //return a type reference copy of me with some dimensions - //warning : the new type ref has a null binding - ArrayTypeReference arrayTypeReference = new ArrayTypeReference(this.token, dim, annotationsOnDimensions, (((long)this.sourceStart)<<32)+this.sourceEnd); + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { + int totalDimensions = this.dimensions() + additionalDimensions; + Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); + ArrayTypeReference arrayTypeReference = new ArrayTypeReference(this.token, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd); + arrayTypeReference.annotations = this.annotations; arrayTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (annotationsOnDimensions != null) { - arrayTypeReference.bits |= ASTNode.HasTypeAnnotations; - } + if (!isVarargs) + arrayTypeReference.extendedDimensions = additionalDimensions; return arrayTypeReference; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java index 431d79194..19b2704fa 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -29,6 +29,7 @@ * Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking + * Bug 417758 - [1.8][null] Null safety compromise during array creation. * Andy Clement - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation @@ -156,6 +157,16 @@ void analyseOneArgument18(BlockScope currentScope, FlowContext flowContext, Flow } } +protected void checkAgainstNullTypeAnnotation(BlockScope scope, TypeBinding requiredType, Expression expression, FlowContext flowContext, FlowInfo flowInfo) { + int nullStatus = expression.nullStatus(flowInfo, flowContext); + NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(requiredType, expression.resolvedType, nullStatus); + if (annotationStatus.isDefiniteMismatch()) { + scope.problemReporter().nullityMismatchingTypeAnnotation(expression, expression.resolvedType, requiredType, annotationStatus); + } else if (annotationStatus.isUnchecked()) { + flowContext.recordNullityMismatch(scope, expression, expression.resolvedType, requiredType, nullStatus); + } +} + /** * INTERNAL USE ONLY. * This is used to redirect inter-statements jumps. diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java index a9d41fc9d..ad875f947 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java @@ -524,10 +524,10 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { ExceptionLabel exceptionLabel = null; if ((argument.binding.tagBits & TagBits.MultiCatchParameter) != 0) { MultiCatchExceptionLabel multiCatchExceptionLabel = new MultiCatchExceptionLabel(codeStream, argument.binding.type); - multiCatchExceptionLabel.initialize((UnionTypeReference) argument.type); + multiCatchExceptionLabel.initialize((UnionTypeReference) argument.type, argument.annotations); exceptionLabel = multiCatchExceptionLabel; } else { - exceptionLabel = new ExceptionLabel(codeStream, argument.binding.type, argument.type); + exceptionLabel = new ExceptionLabel(codeStream, argument.binding.type, argument.type, argument.annotations); } exceptionLabel.placeStart(); exceptionLabels[i] = exceptionLabel; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java index 2eb350bde..4214bf69d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java @@ -19,6 +19,7 @@ * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator @@ -65,9 +66,8 @@ public abstract class TypeReference extends Expression { public static final TypeReference[] NO_TYPE_ARGUMENTS = new TypeReference[0]; static class AnnotationCollector extends ASTVisitor { List annotationContexts; - TypeReference typeReference; + Expression typeReference; int targetType; - Annotation[] primaryAnnotations; int info = 0; int info2 = 0; LocalVariableBinding localVariable; @@ -83,7 +83,6 @@ static class AnnotationCollector extends ASTVisitor { this.annotationContexts = annotationContexts; this.typeReference = typeParameter.type; this.targetType = targetType; - this.primaryAnnotations = typeParameter.annotations; this.info = typeParameterIndex; } @@ -95,7 +94,6 @@ static class AnnotationCollector extends ASTVisitor { this.annotationContexts = annotationContexts; this.typeReference = localDeclaration.type; this.targetType = targetType; - this.primaryAnnotations = localDeclaration.annotations; this.localVariable = localVariable; } @@ -107,39 +105,10 @@ static class AnnotationCollector extends ASTVisitor { this.annotationContexts = annotationContexts; this.typeReference = localDeclaration.type; this.targetType = targetType; - this.primaryAnnotations = localDeclaration.annotations; this.info = parameterIndex; } public AnnotationCollector( - MethodDeclaration methodDeclaration, - int targetType, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = methodDeclaration.returnType; - this.targetType = targetType; - this.primaryAnnotations = methodDeclaration.annotations; - } - - public AnnotationCollector( - ConstructorDeclaration constructorDeclaration, - int targetType, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.targetType = targetType; - this.primaryAnnotations = constructorDeclaration.annotations; - } - - public AnnotationCollector( - FieldDeclaration fieldDeclaration, - int targetType, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = fieldDeclaration.type; - this.targetType = targetType; - this.primaryAnnotations = fieldDeclaration.annotations; - } - public AnnotationCollector( TypeReference typeReference, int targetType, List annotationContexts) { @@ -148,7 +117,7 @@ static class AnnotationCollector extends ASTVisitor { this.targetType = targetType; } public AnnotationCollector( - TypeReference typeReference, + Expression typeReference, int targetType, int info, List annotationContexts) { @@ -192,9 +161,9 @@ static class AnnotationCollector extends ASTVisitor { private boolean internalVisit(Annotation annotation) { AnnotationContext annotationContext = null; if (annotation.isRuntimeTypeInvisible()) { - annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, this.primaryAnnotations, AnnotationContext.INVISIBLE, this.annotationsOnDimensions, this.dimensions); + annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, AnnotationContext.INVISIBLE); } else if (annotation.isRuntimeTypeVisible()) { - annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, this.primaryAnnotations, AnnotationContext.VISIBLE, this.annotationsOnDimensions, this.dimensions); + annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, AnnotationContext.VISIBLE); } if (annotationContext != null) { annotationContext.wildcard = this.currentWildcard; @@ -375,17 +344,46 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl public void checkBounds(Scope scope) { // only parameterized type references have bounds } -public abstract TypeReference copyDims(int dim); -public abstract TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions); +public abstract TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs); + +protected Annotation[][] getMergedAnnotationsOnDimensions(int additionalDimensions, Annotation[][] additionalAnnotations) { + /* Note, we actually concatenate the additional annotations after base annotations, in bindings, they should appear before base annotations. + Given @English int @Nullable [] x @NonNull []; the type x is a @NonNull arrays of of @Nullable arrays of @English Strings, not the other + way about. Changing this in the compiler AST representation will cause too many ripples, so we leave it as is. On the bindings, the type + will reflect rotated (i.e will reflect correctly). See AnnotatableTypeSystem.flattenedAnnotations + */ + Annotation[][] annotationsOnDimensions = this.getAnnotationsOnDimensions(true); + int dimensions = this.dimensions(); + + if (annotationsOnDimensions == null && additionalAnnotations == null) + return null; + + final int totalDimensions = dimensions + additionalDimensions; + Annotation [][] mergedAnnotations = new Annotation[totalDimensions][]; + if (annotationsOnDimensions != null) { + for (int i = 0; i < dimensions; i++) { + mergedAnnotations[i] = annotationsOnDimensions[i]; + } + } + if (additionalAnnotations != null) { + for (int i = dimensions, j = 0; i < totalDimensions; i++, j++) { + mergedAnnotations[i] = additionalAnnotations[j]; + } + } + return mergedAnnotations; +} + public int dimensions() { return 0; } + //{ObjectTeams: synthetic AST can use TypeReference as receiver for static method: @Override public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { // nop } // SH} + public AnnotationContext[] getAllAnnotationContexts(int targetType) { List allAnnotationContexts = new ArrayList(); AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); @@ -402,6 +400,14 @@ public void getAllAnnotationContexts(int targetType, int info, List allAnnotatio AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allAnnotationContexts); this.traverse(collector, (BlockScope) null); } +public void getAllAnnotationContexts(int targetType, int info, List allAnnotationContexts, Annotation [] se7Annotations) { + AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allAnnotationContexts); + for (int i = 0, length = se7Annotations == null ? 0 : se7Annotations.length; i < length; i++) { + Annotation annotation = se7Annotations[i]; + annotation.traverse(collector, (BlockScope) null); + } + this.traverse(collector, (BlockScope) null); +} /** * info can be either a type index (superclass/superinterfaces) or a pc into the bytecode */ @@ -428,6 +434,22 @@ public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) this.traverse(collector, (BlockScope) null); } public Annotation[][] getAnnotationsOnDimensions() { + return getAnnotationsOnDimensions(false); +} + +public TypeReference [][] getTypeArguments() { + return null; +} +/** + * @param useSourceOrder if true annotations on dimensions are returned in source order, otherwise they are returned per + * how they ought to be interpreted by a type system, or external persistence view. For example, given the following: + * int @Nullable [] f @NonNull [] ==> f is really a @NonNull array of @Nullable arrays of ints. This is the type system + * view since extended dimensions bind more readily than type components that precede the identifier. This is how it ought + * to be encoded in bindings and how it ought to be persisted in class files. However for DOM/AST construction, we need the + * dimensions in source order, so we provide a way for the clients to ask what they want. + * + */ +public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { return null; } @@ -628,6 +650,12 @@ public boolean isDeclaredLifting() { public boolean isWildcard() { return false; } +public boolean isUnionType() { + return false; +} +public boolean isVarargs() { + return (this.bits & ASTNode.IsVarArgs) != 0; +} public boolean isParameterizedTypeReference() { return false; } @@ -759,7 +787,7 @@ protected void checkNullConstraints(Scope scope, TypeReference[] typeArguments) protected void checkNullConstraints(Scope scope, TypeBinding[] variables, int rank) { if (variables != null && variables.length > rank) { if (variables[rank].hasNullTypeAnnotations()) { - if ((this.resolvedType.tagBits & TagBits.AnnotationNullMASK) != (variables[rank].tagBits & TagBits.AnnotationNullMASK)) { + if (NullAnnotationMatching.validNullTagBits(this.resolvedType.tagBits) != NullAnnotationMatching.validNullTagBits(variables[rank].tagBits)) { scope.problemReporter().nullityMismatchTypeArgument(variables[rank], this.resolvedType, this); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java index 9a4e07c4b..945d55322 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java @@ -34,13 +34,6 @@ public class UnionTypeReference extends TypeReference { } /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int) - */ - public TypeReference copyDims(int dim) { - return this; // arrays are not legal as union types. - } - - /* (non-Javadoc) * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getLastToken() */ public char[] getLastToken() { @@ -159,8 +152,10 @@ public class UnionTypeReference extends TypeReference { } return output; } - - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { + public boolean isUnionType() { + return true; + } + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { return this; // arrays are not legal as union types. } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java index 5235cde38..4bf06d185 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java @@ -15,6 +15,7 @@ * Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped * Stephan Herrmann - Contribution for * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -78,8 +79,6 @@ public class Wildcard extends SingleTypeReference { if (((boundType.tagBits | this.resolvedType.tagBits) & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { // are both set? Annotation annotation = this.bound.findAnnotation(boundType.tagBits & TagBits.AnnotationNullMASK); scope.problemReporter().contradictoryNullAnnotationsOnBounds(annotation, this.resolvedType.tagBits); - this.resolvedType = this.resolvedType.unannotated(); - this.bound.resolvedType = ((WildcardBinding)this.resolvedType).bound = boundType.unannotated(); } } return this.resolvedType; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java index 1b7b52e65..e77920b2d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java @@ -16,7 +16,6 @@ package org.eclipse.jdt.internal.compiler.classfmt; import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; -import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation; /** @@ -36,12 +35,13 @@ public class TypeAnnotationWalker { * At the end of any walk an empty array of annotations is returned. */ public static final TypeAnnotationWalker EMPTY_ANNOTATION_WALKER = new TypeAnnotationWalker(new IBinaryTypeAnnotation[0], 0L) { + public TypeAnnotationWalker toField() { return this; } public TypeAnnotationWalker toTarget(int targetType) { return this; } public TypeAnnotationWalker toThrows(int rank) { return this; } public TypeAnnotationWalker toTypeArgument(int rank) { return this; } public TypeAnnotationWalker toMethodParameter(short index) { return this; } public TypeAnnotationWalker toSupertype(short index) { return this; } - public TypeAnnotationWalker toTypeBarameterBounds(boolean isClassTypeParameter, int parameterRank) { return this; } + public TypeAnnotationWalker toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank) { return this; } public TypeAnnotationWalker toTypeBound(short boundIndex) { return this; } public TypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) { return this; } public TypeAnnotationWalker toNextDetail(int detailKind) { return this; } @@ -53,7 +53,7 @@ public class TypeAnnotationWalker { final private int pathPtr; // pointer into the typePath // precondition: not-empty typeAnnotations - private TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations) { + public TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations) { this(typeAnnotations, -1L >>> (64-typeAnnotations.length)); // initialize so lowest length bits are 1 } TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations, long matchBits) { @@ -72,19 +72,6 @@ public class TypeAnnotationWalker { return new TypeAnnotationWalker(this.typeAnnotations, newMatches, newPathPtr); } - /** Answer a walker for the given type annotations initialized to the root of the tree. */ - public static TypeAnnotationWalker create(IBinaryTypeAnnotation[] typeAnnotations) { - if (typeAnnotations == null || typeAnnotations.length == 0) - return EMPTY_ANNOTATION_WALKER; - return new TypeAnnotationWalker(typeAnnotations); - } - /** Answer a walker for the type annotations of the given method initialized to the root of the tree. */ - public static TypeAnnotationWalker create(IBinaryMethod method) { - if (method instanceof MethodInfoWithAnnotations) - return create(((MethodInfoWithAnnotations) method).getTypeAnnotations()); - return EMPTY_ANNOTATION_WALKER; - } - // ==== filter by top-level targetType: ==== /** Walk to a field. */ @@ -146,7 +133,7 @@ public class TypeAnnotationWalker { * @param isClassTypeParameter whether we are looking at a class type parameter (else: method type type parameter) * @param parameterRank rank of the type parameter. */ - public TypeAnnotationWalker toTypeBarameterBounds(boolean isClassTypeParameter, int parameterRank) { + public TypeAnnotationWalker toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank) { long newMatches = this.matches; if (newMatches == 0) return EMPTY_ANNOTATION_WALKER; @@ -162,7 +149,7 @@ public class TypeAnnotationWalker { return restrict(newMatches, 0); } /** - * Detail of {@link #toTypeBarameterBounds(boolean, int)}: walk to the bounds + * Detail of {@link #toTypeParameterBounds(boolean, int)}: walk to the bounds * of the previously selected type parameter. * @param boundIndex */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AnnotationContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AnnotationContext.java index c743d436f..865db3999 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AnnotationContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AnnotationContext.java @@ -17,7 +17,7 @@ package org.eclipse.jdt.internal.compiler.codegen; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; @@ -25,34 +25,23 @@ public class AnnotationContext { public static final int VISIBLE = 0x1; public static final int INVISIBLE = 0x2; public Annotation annotation; - public TypeReference typeReference; + public Expression typeReference; public int targetType; public int info; public int info2; public int visibility; - public Annotation[] primaryAnnotations; public LocalVariableBinding variableBinding; - public Annotation[][] annotationsOnDimensions; public Wildcard wildcard; - // annotationsOnDimensions might be null but the dimensions may still be important. In some - // cases they are not on the reference. - public int dimensions; public AnnotationContext( Annotation annotation, - TypeReference typeReference, + Expression typeReference, int targetType, - Annotation[] primaryAnnotations, - int visibility, - Annotation[][] annotationsOnDimensions, - int dimensions) { + int visibility) { this.annotation = annotation; this.typeReference = typeReference; this.targetType = targetType; - this.primaryAnnotations = primaryAnnotations; this.visibility = visibility; - this.annotationsOnDimensions = annotationsOnDimensions; - this.dimensions = dimensions; } public String toString() { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java index 06905c154..6b1ebdb82 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java @@ -37,7 +37,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; -import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; @@ -5930,8 +5930,7 @@ public void multianewarray( TypeReference typeReference, TypeBinding typeBinding, int dimensions, - int declaredDimensions, - Annotation [][] annotationsOnDimensions) { + ArrayAllocationExpression allocationExpression) { this.countLabels = 0; this.stackDepth += (1 - dimensions); if (this.classFileOffset + 3 >= this.bCodeStream.length) { @@ -5986,7 +5985,7 @@ public void newArray(ArrayBinding arrayBinding) { this.newArray(null, null, arrayBinding); } -public void newArray(TypeReference typeReference, Annotation[][] annotationsOnDimensions, ArrayBinding arrayBinding) { +public void newArray(TypeReference typeReference, ArrayAllocationExpression allocationExpression, ArrayBinding arrayBinding) { TypeBinding component = arrayBinding.elementsType(); switch (component.id) { case TypeIds.T_int : diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java index 85246d2ea..ad91159f7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java @@ -15,6 +15,7 @@ * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 * Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile * Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.codegen; @@ -263,6 +264,8 @@ public class ConstantPool implements ClassFileConstants, TypeIds { // Java 8 lambda support public static final char[] METAFACTORY = "metafactory".toCharArray(); //$NON-NLS-1$ public static final char[] JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_METAFACTORY_SIGNATURE = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;".toCharArray(); //$NON-NLS-1$ + // Java 8 repeatable annotation support + public static final char[] JAVA_LANG_ANNOTATION_REPEATABLE = "Ljava/lang/annotation/Repeatable;".toCharArray(); //$NON-NLS-1$ public static final char[] HashCode = "hashCode".toCharArray(); //$NON-NLS-1$ public static final char[] HashCodeSignature = "()I".toCharArray(); //$NON-NLS-1$; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java index e6e619d1f..ccc80639a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java @@ -17,6 +17,7 @@ package org.eclipse.jdt.internal.compiler.codegen; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; @@ -26,11 +27,13 @@ public class ExceptionLabel extends Label { private int count = 0; // incremented each time placeStart or placeEnd is called public TypeBinding exceptionType; public TypeReference exceptionTypeReference; + public Annotation [] se7Annotations; -public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType, TypeReference exceptionTypeReference) { +public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType, TypeReference exceptionTypeReference, Annotation [] se7Annotations) { super(codeStream); this.exceptionType = exceptionType; this.exceptionTypeReference = exceptionTypeReference; + this.se7Annotations = se7Annotations; } public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java index 21fc79f2b..61587e190 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java @@ -18,6 +18,7 @@ package org.eclipse.jdt.internal.compiler.codegen; import java.util.List; +import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; @@ -30,12 +31,12 @@ public class MultiCatchExceptionLabel extends ExceptionLabel { super(codeStream, exceptionType); } - public void initialize(UnionTypeReference typeReference) { + public void initialize(UnionTypeReference typeReference, Annotation [] annotations) { TypeReference[] typeReferences = typeReference.typeReferences; int length = typeReferences.length; this.exceptionLabels = new ExceptionLabel[length]; for (int i = 0; i < length; i++) { - this.exceptionLabels[i] = new ExceptionLabel(this.codeStream, typeReferences[i].resolvedType, typeReferences[i]); + this.exceptionLabels[i] = new ExceptionLabel(this.codeStream, typeReferences[i].resolvedType, typeReferences[i], i == 0 ? annotations : null); } } public void place() { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java index bc66e5b48..e5342e9a2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java @@ -24,7 +24,7 @@ import java.util.List; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; @@ -40,8 +40,8 @@ public class TypeAnnotationCodeStream extends StackMapFrameCodeStream { this.allTypeAnnotationContexts = new ArrayList(); } - private void addAnnotationContext(TypeReference typeReference, int info, int targetType, Annotation[][] annotationsOnDimensions, int dimensions) { - typeReference.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts, annotationsOnDimensions, dimensions); + private void addAnnotationContext(TypeReference typeReference, int info, int targetType, ArrayAllocationExpression allocationExpression) { + allocationExpression.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts); } private void addAnnotationContext(TypeReference typeReference, int info, int targetType) { @@ -63,12 +63,11 @@ public class TypeAnnotationCodeStream extends StackMapFrameCodeStream { TypeReference typeReference, TypeBinding typeBinding, int dimensions, - int declaredDimensions, - Annotation [][] annotationsOnDimensions) { + ArrayAllocationExpression allocationExpression) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { - addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, annotationsOnDimensions, declaredDimensions); + addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, allocationExpression); } - super.multianewarray(typeReference, typeBinding, dimensions, declaredDimensions, annotationsOnDimensions); + super.multianewarray(typeReference, typeBinding, dimensions, allocationExpression); } public void new_(TypeReference typeReference, TypeBinding typeBinding) { @@ -78,11 +77,11 @@ public class TypeAnnotationCodeStream extends StackMapFrameCodeStream { super.new_(typeReference, typeBinding); } - public void newArray(TypeReference typeReference, Annotation[][] annotationsOnDimensions, ArrayBinding arrayBinding) { + public void newArray(TypeReference typeReference, ArrayAllocationExpression allocationExpression, ArrayBinding arrayBinding) { if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { - addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, annotationsOnDimensions, arrayBinding.dimensions); + addAnnotationContext(typeReference, this.position, AnnotationTargetTypeConstants.NEW, allocationExpression); } - super.newArray(typeReference, annotationsOnDimensions, arrayBinding); + super.newArray(typeReference, allocationExpression, arrayBinding); } public void checkcast(TypeReference typeReference, TypeBinding typeBinding) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index 4e04c1234..9ac3acabf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -155,6 +155,8 @@ public class CompilerOptions { public static final String OPTION_ReportOverridingMethodWithoutSuperInvocation = "org.eclipse.jdt.core.compiler.problem.overridingMethodWithoutSuperInvocation"; //$NON-NLS-1$ public static final String OPTION_GenerateClassFiles = "org.eclipse.jdt.core.compiler.generateClassFiles"; //$NON-NLS-1$ public static final String OPTION_Process_Annotations = "org.eclipse.jdt.core.compiler.processAnnotations"; //$NON-NLS-1$ + // OPTION_Store_Annotations: undocumented option for testing purposes + public static final String OPTION_Store_Annotations = "org.eclipse.jdt.core.compiler.storeAnnotations"; //$NON-NLS-1$ public static final String OPTION_ReportRedundantSuperinterface = "org.eclipse.jdt.core.compiler.problem.redundantSuperinterface"; //$NON-NLS-1$ public static final String OPTION_ReportComparingIdentical = "org.eclipse.jdt.core.compiler.problem.comparingIdentical"; //$NON-NLS-1$ public static final String OPTION_ReportMissingSynchronizedOnInheritedMethod = "org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod"; //$NON-NLS-1$ @@ -1430,6 +1432,7 @@ public class CompilerOptions { optionsMap.put(OPTION_ReportOverridingMethodWithoutSuperInvocation, getSeverityString(OverridingMethodWithoutSuperInvocation)); optionsMap.put(OPTION_GenerateClassFiles, this.generateClassFiles ? ENABLED : DISABLED); optionsMap.put(OPTION_Process_Annotations, this.processAnnotations ? ENABLED : DISABLED); + optionsMap.put(OPTION_Store_Annotations, this.storeAnnotations ? ENABLED : DISABLED); optionsMap.put(OPTION_ReportRedundantSuperinterface, getSeverityString(RedundantSuperinterface)); optionsMap.put(OPTION_ReportComparingIdentical, getSeverityString(ComparingIdentical)); optionsMap.put(OPTION_ReportMissingSynchronizedOnInheritedMethod, getSeverityString(MissingSynchronizedModifierInInheritedMethod)); @@ -2021,6 +2024,7 @@ public class CompilerOptions { this.isAnnotationBasedNullAnalysisEnabled = ENABLED.equals(optionValue); } if (this.isAnnotationBasedNullAnalysisEnabled) { + this.storeAnnotations = true; if ((optionValue = optionsMap.get(OPTION_ReportNullSpecViolation)) != null) { if (ERROR.equals(optionValue)) { this.errorThreshold.set(NullSpecViolation); @@ -2161,7 +2165,16 @@ public class CompilerOptions { this.storeAnnotations = true; // annotation processing requires annotation to be stored } else if (DISABLED.equals(optionValue)) { this.processAnnotations = false; - this.storeAnnotations = false; + if (!this.isAnnotationBasedNullAnalysisEnabled) + this.storeAnnotations = false; + } + } + if ((optionValue = optionsMap.get(OPTION_Store_Annotations)) != null) { + if (ENABLED.equals(optionValue)) { + this.storeAnnotations = true; + } else if (DISABLED.equals(optionValue)) { + if (!this.isAnnotationBasedNullAnalysisEnabled && !this.processAnnotations) + this.storeAnnotations = false; } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java index 60765bf72..73bb07c50 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java @@ -14,6 +14,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.util.Util; import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding; @@ -31,7 +32,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBindin We do not keep track of unannotated types here, that is done by UTS whose handle we maintain. */ -public class AnnotatableTypeSystem { +public class AnnotatableTypeSystem extends TypeSystem { LookupEnvironment environment; UnannotatedTypeSystem unannotatedTypeSystem; @@ -48,44 +49,96 @@ public class AnnotatableTypeSystem { return this.unannotatedTypeSystem.getUnannotatedType(type); } + // Given a type, return all its variously annotated versions. + public TypeBinding[] getAnnotatedTypes(TypeBinding type) { + + TypeBinding keyType = getUnannotatedType(type); + TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType); + if (cachedInfo == null) + return Binding.NO_TYPES; + + final int length = cachedInfo.length; + TypeBinding [] annotatedVersions = new TypeBinding[length]; + int versions = 0; + for (int i = 0; i < length; i++) { + final TypeBinding cachedType = cachedInfo[i]; + if (cachedType == null) + break; + if (cachedType.id == type.id) + annotatedVersions[versions++] = cachedType; + } + + if (versions == 0) + return Binding.NO_TYPES; + + if (versions != length) + System.arraycopy(annotatedVersions, 0, annotatedVersions = new TypeBinding[versions], 0, versions); + + return annotatedVersions; + } + + public ArrayBinding getArrayType(TypeBinding leaftType, int dimensions) { + return getArrayType(leaftType, dimensions, Binding.NO_ANNOTATIONS); + } + /* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations, where each dimension's annotations end with a sentinel null. */ - public ArrayBinding getArrayType(TypeBinding leafType, int dimensions, AnnotationBinding [] annotations) { + public ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions, AnnotationBinding [] annotations) { - if (!haveTypeAnnotations(leafType, annotations)) - return this.unannotatedTypeSystem.getArrayType(leafType, dimensions); + if (!haveTypeAnnotations(leafComponentType, annotations)) + return this.unannotatedTypeSystem.getArrayType(leafComponentType, dimensions); - TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(leafType); + // Leaf component type can be an annotated type. + TypeBinding keyType = getUnannotatedType(leafComponentType); + TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType); // unannotated key promotes better instance sharing. int index = 0; if (cachedInfo != null) { for (int max = cachedInfo.length; index < max; index++) { TypeBinding cachedType = cachedInfo[index]; if (cachedType == null) break; + if (cachedType.leafComponentType() != leafComponentType) continue; if (cachedType.isArrayType() && cachedType.dimensions() == dimensions && Util.effectivelyEqual(cachedType.getTypeAnnotations(), annotations)) return (ArrayBinding) cachedType; } } else { - this.annotatedTypes.put(leafType, cachedInfo = new TypeBinding[4]); + this.annotatedTypes.put(keyType, cachedInfo = new TypeBinding[4]); } int length = cachedInfo.length; if (index == length) { System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length); - this.annotatedTypes.put(leafType, cachedInfo); + this.annotatedTypes.put(keyType, cachedInfo); } // Add the newcomer, ensuring its identity is the same as the naked version of it. - ArrayBinding unannotatedArrayType = this.unannotatedTypeSystem.getArrayType(leafType, dimensions); - TypeBinding arrayBinding = new ArrayBinding(leafType, dimensions, this.environment); + ArrayBinding unannotatedArrayType = this.unannotatedTypeSystem.getArrayType(leafComponentType, dimensions); + TypeBinding arrayBinding = new ArrayBinding(leafComponentType, dimensions, this.environment); arrayBinding.id = unannotatedArrayType.id; arrayBinding.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); return (ArrayBinding) (cachedInfo[index] = arrayBinding); } + + public ReferenceBinding getMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) { + if (!haveTypeAnnotations(memberType, enclosingType)) + return this.unannotatedTypeSystem.getMemberType(memberType, enclosingType); + return (ReferenceBinding) getAnnotatedType(memberType, enclosingType, memberType.typeArguments(), memberType.getTypeAnnotations()); + } + +//{ObjectTeams: 2 args added for role types: +/* orig: + public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) { + return getParameterizedType(genericType, typeArguments, enclosingType, Binding.NO_ANNOTATIONS); + :giro */ + public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, + ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType) { + return getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType, Binding.NO_ANNOTATIONS); +// SH} + } - public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { //{ObjectTeams: more arguments for role types: - return getParameterizedType(genericType, typeArguments, null, -1, enclosingType, annotations); - } +/* orig: + public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { + :giro */ public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { if (teamAnchor == null && genericType instanceof DependentTypeBinding) @@ -98,20 +151,9 @@ public class AnnotatableTypeSystem { return this.unannotatedTypeSystem.getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType); // SH} - /* When restoring annotations from class files, we encounter a situation where the generic type comes in attributed with the annotations that should - really belong to the parameterized type that is being created just now. e.g @T List<String> => comes in as (@T List)<String>. The question really - is List being parameterized by String and then the resultant type is annotated or is "@T List" being parameterized with String ? We don't care one - way or other except that we would want a uniform treatment. As a stop gap, we "repair" the situation here, so it is consistent with treatment of - type references in source code. Probably need similar treatment for raw types and wildcards ? - */ - AnnotationBinding [] misplacedAnnotations = genericType.getTypeAnnotations(); - if (misplacedAnnotations != null && misplacedAnnotations != Binding.NO_ANNOTATIONS) { - if (annotations != null && annotations != Binding.NO_ANNOTATIONS) - throw new IllegalStateException(); // cannot cut both ways. - annotations = misplacedAnnotations; - genericType = (ReferenceBinding) this.unannotatedTypeSystem.getUnannotatedType(genericType); - } - + if (genericType.hasTypeAnnotations()) + throw new IllegalStateException(); + int index = 0; TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType); if (cachedInfo != null) { @@ -165,11 +207,18 @@ public class AnnotatableTypeSystem { return (ParameterizedTypeBinding) (cachedInfo[index] = parameterizedType); } + public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) { + return getRawType(genericType, enclosingType, Binding.NO_ANNOTATIONS); + } + public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { if (!haveTypeAnnotations(genericType, enclosingType, null, annotations)) return this.unannotatedTypeSystem.getRawType(genericType, enclosingType); + if (genericType.hasTypeAnnotations()) + throw new IllegalStateException(); + TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType); int index = 0; if (cachedInfo != null) { @@ -197,6 +246,10 @@ public class AnnotatableTypeSystem { return (RawTypeBinding) (cachedInfo[index] = rawType); } + public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) { + return getWildcard(genericType, rank, bound, otherBounds, boundKind, Binding.NO_ANNOTATIONS); + } + public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding [] annotations) { if (!haveTypeAnnotations(genericType, bound, otherBounds, annotations)) @@ -205,7 +258,10 @@ public class AnnotatableTypeSystem { if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation genericType = ReferenceBinding.LUB_GENERIC; - TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType); + if (genericType.hasTypeAnnotations()) + throw new IllegalStateException(); + + TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType); // promotes better instance sharing. int index = 0; if (cachedInfo != null) { for (int max = cachedInfo.length; index < max; index++) { @@ -236,9 +292,10 @@ public class AnnotatableTypeSystem { return (WildcardBinding) (cachedInfo[index] = wildcard); } - // Private subroutine for getAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) + // Private subroutine for public APIs. private TypeBinding getAnnotatedType(TypeBinding type, TypeBinding enclosingType, TypeBinding [] typeArguments, AnnotationBinding[] annotations) { - TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(type); + TypeBinding keyType = getUnannotatedType(type); + TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType); int i = 0; if (cachedInfo != null) { for (int length = cachedInfo.length; i < length; i++) { @@ -251,20 +308,20 @@ public class AnnotatableTypeSystem { } } } else { - this.annotatedTypes.put(type, cachedInfo = new TypeBinding[4]); + this.annotatedTypes.put(keyType, cachedInfo = new TypeBinding[4]); } int length = cachedInfo.length; if (i == length) { System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length); - this.annotatedTypes.put(type, cachedInfo); + this.annotatedTypes.put(keyType, cachedInfo); } /* Add the new comer, retaining the same type binding id as the naked type. To materialize the new comer we can't use new since this is a general - purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type and type arguments - that may themselves be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. - Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> + purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type that may itself be + possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. Likewise so the bindings + for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> */ TypeBinding unannotatedType = this.unannotatedTypeSystem.getUnannotatedType(type); - TypeBinding annotatedType = type.clone(enclosingType, typeArguments); + TypeBinding annotatedType = type.clone(enclosingType); annotatedType.id = unannotatedType.id; annotatedType.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); return cachedInfo[i] = annotatedType; @@ -298,6 +355,10 @@ public class AnnotatableTypeSystem { java.lang.@T X.@T Y.@T Z in all these cases the incoming type binding is for Z, but annotations are for different levels. Align their layout for proper attribution. */ + + if (type.isUnresolvedType() && CharOperation.indexOf('$', type.sourceName()) > 0) + type = BinaryTypeBinding.resolveType(type, this.environment, true); // must resolve member types before asking for enclosingType + int levels = type.depth() + 1; TypeBinding [] types = new TypeBinding[levels]; types[--levels] = type; @@ -317,16 +378,21 @@ public class AnnotatableTypeSystem { return type; // types[j] is the first component being annotated. Its annotations are annotations[i] for (enclosingType = j == 0 ? null : types[j - 1]; i < levels; i++, j++) { - annotatedType = getAnnotatedType(types[j], enclosingType, types[j].typeArguments(), annotations[i]); + final TypeBinding currentType = types[j]; + // while handling annotations from SE7 locations, take care not to drop existing annotations. + AnnotationBinding [] currentAnnotations = annotations[i] != null && annotations[i].length > 0 ? annotations[i] : currentType.getTypeAnnotations(); + annotatedType = getAnnotatedType(currentType, enclosingType, currentType.typeArguments(), currentAnnotations); enclosingType = annotatedType; } break; + default: + throw new IllegalStateException(); } return annotatedType; } - public AnnotationBinding getAnnotationType(ReferenceBinding annotationType) { - return this.unannotatedTypeSystem.getAnnotationType(annotationType); // deflect, annotation type uses cannot be type annotated. + public AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requireResolved) { + return this.unannotatedTypeSystem.getAnnotationType(annotationType, requireResolved); // deflect, annotation type uses cannot be type annotated. } private boolean haveTypeAnnotations(TypeBinding baseType, TypeBinding someType, TypeBinding[] someTypes, AnnotationBinding[] annotations) { @@ -346,6 +412,10 @@ public class AnnotatableTypeSystem { private boolean haveTypeAnnotations(TypeBinding leafType, AnnotationBinding[] annotations) { return haveTypeAnnotations(leafType, null, null, annotations); } + + private boolean haveTypeAnnotations(TypeBinding memberType, TypeBinding enclosingType) { + return haveTypeAnnotations(memberType, enclosingType, null, null); + } /* Utility method to "flatten" annotations. For multidimensional arrays, we encode the annotations into a flat array where a null separates the annotations of dimension n from dimension n - 1 as well as dimenion n + 1. There is a @@ -396,4 +466,8 @@ public class AnnotatableTypeSystem { } this.unannotatedTypeSystem.updateCaches(unresolvedType.prototype, unresolvedType.prototype.resolvedType); } + + public boolean isAnnotatedTypeSystem() { + return true; + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java index 038c5ade8..e9f1d8663 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java @@ -1,10 +1,14 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 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 * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ @@ -195,6 +199,10 @@ public ReferenceBinding getAnnotationType() { return this.type; } +public void resolve() { + // Nothing to do, this is already resolved. +} + public ElementValuePair[] getElementValuePairs() { return this.pairs; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java index 6091c972c..e8782d519 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java @@ -20,6 +20,7 @@ * Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -306,8 +307,7 @@ public char[] nullAnnotatedReadableName(CompilerOptions options, boolean shortNa brackets[i] = new char[]{'[', ']'}; } } - char[] leafTypeName = shortNames ? this.leafComponentType.shortReadableName() : this.leafComponentType.readableName(); - return CharOperation.concat(leafTypeName, + return CharOperation.concat(this.leafComponentType.nullAnnotatedReadableName(options, shortNames), CharOperation.concatWith(brackets, ' '), ' '); } @@ -343,9 +343,10 @@ public char[] readableName() /* java.lang.Object[] */ { } public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) { - + this.tagBits |= TagBits.HasTypeAnnotations; + if (annotations == null || annotations.length == 0) + return; this.typeAnnotations = annotations; - this.tagBits |= TagBits.HasTypeAnnotations | TagBits.HasTypeAnnotations; if (evalNullAnnotations) { long nullTagBits = 0; @@ -412,7 +413,7 @@ public TypeBinding maybeWrapRoleType(ASTNode typedNode, TypeArgumentUpdater upda } // SH} public String toString() { - return this.leafComponentType != null ? this.hasTypeAnnotations() ? annotatedDebugName() : debugName() : "NULL TYPE ARRAY"; //$NON-NLS-1$ + return this.leafComponentType != null ? debugName() : "NULL TYPE ARRAY"; //$NON-NLS-1$ } public TypeBinding unannotated() { return this.hasTypeAnnotations() ? this.environment.getUnannotatedType(this) : this; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java index 1bc3bc92d..5238d000c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java @@ -13,6 +13,7 @@ * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -134,12 +135,6 @@ public final class BaseTypeBinding extends TypeBinding { this.simpleName = name; this.constantPoolName = constantPoolName; } - - BaseTypeBinding(BaseTypeBinding prototype) { - super(prototype); - this.simpleName = prototype.simpleName; - this.constantPoolName = prototype.constantPoolName; - } /** * int -> I @@ -155,8 +150,8 @@ public final class BaseTypeBinding extends TypeBinding { return this.constantPoolName; } - public TypeBinding clone(TypeBinding enclosingType, TypeBinding[] typeArguments) { - return new BaseTypeBinding(this); + public TypeBinding clone(TypeBinding enclosingType) { + return new BaseTypeBinding(this.id, this.simpleName, this.constantPoolName); } public PackageBinding getPackage() { @@ -177,7 +172,13 @@ public final class BaseTypeBinding extends TypeBinding { return this == TypeBinding.NULL && !right.isBaseType(); } + public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) { + super.setTypeAnnotations(annotations, false); // never set nullTagBits on base types + } + public TypeBinding unannotated() { + if (!this.hasTypeAnnotations()) + return this; switch (this.id) { case TypeIds.T_boolean: return TypeBinding.BOOLEAN; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index b7ad5af7d..4c92d8b89 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -27,8 +27,10 @@ * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper Steen Moller - Contributions for * Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -42,11 +44,12 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.FieldInfo; import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo; import org.eclipse.jdt.internal.compiler.classfmt.TypeAnnotationWalker; -import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; import org.eclipse.jdt.internal.compiler.env.*; import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; import org.eclipse.jdt.internal.compiler.util.Util; @@ -132,13 +135,15 @@ public class BinaryTypeBinding extends ReferenceBinding { protected MethodBinding[] methods; protected ReferenceBinding[] memberTypes; protected TypeVariableBinding[] typeVariables; - protected BinaryTypeBinding prototype; + private BinaryTypeBinding prototype; // For the link with the principle structure protected LookupEnvironment environment; protected SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder + private ReferenceBinding containingAnnotation; + //{ObjectTeams: support callout-to-field /** Callout to field adds faked access method (set or get): */ @@ -219,15 +224,9 @@ static Object convertMemberValue(Object binaryValue, LookupEnvironment env, char throw new IllegalStateException(); } -public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { +public TypeBinding clone(TypeBinding outerType) { BinaryTypeBinding copy = new BinaryTypeBinding(this); - copy.enclosingType = (ReferenceBinding) outerType; - if (outerType instanceof UnresolvedReferenceBinding) - copy.tagBits |= TagBits.HasUnresolvedEnclosingType; - else - copy.tagBits &= ~TagBits.HasUnresolvedEnclosingType; - return copy; } @@ -367,8 +366,11 @@ public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, */ public FieldBinding[] availableFields() { - if (this != this.prototype) + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreFieldsComplete) != 0) + return this.fields; return this.prototype.availableFields(); + } if ((this.tagBits & TagBits.AreFieldsComplete) != 0) return this.fields; @@ -396,6 +398,7 @@ public FieldBinding[] availableFields() { } private TypeVariableBinding[] addMethodTypeVariables(TypeVariableBinding[] methodTypeVars) { + if (this != this.prototype) throw new IllegalStateException(); if (this.typeVariables == null || this.typeVariables == Binding.NO_TYPE_VARIABLES) { return methodTypeVars; } @@ -425,8 +428,11 @@ private TypeVariableBinding[] addMethodTypeVariables(TypeVariableBinding[] metho */ public MethodBinding[] availableMethods() { - if (this != this.prototype) + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreMethodsComplete) != 0) + return this.methods; return this.prototype.availableMethods(); + } if ((this.tagBits & TagBits.AreMethodsComplete) != 0) return this.methods; @@ -454,6 +460,7 @@ public MethodBinding[] availableMethods() { } void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { + if (this != this.prototype) throw new IllegalStateException(); try { // default initialization for super-interfaces early, in case some aborting compilation error occurs, // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748). @@ -521,7 +528,7 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { and/or super interfaces in order to be able to detect overriding in the presence of generics. */ - TypeAnnotationWalker walker = sourceLevel >= ClassFileConstants.JDK1_8 ? TypeAnnotationWalker.create(binaryType.getTypeAnnotations()) : TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER; + TypeAnnotationWalker walker = getTypeAnnotationWalker(binaryType.getTypeAnnotations()); char[] typeSignature = binaryType.getGenericSignature(); // use generic signature even in 1.4 this.tagBits |= binaryType.getTagBits(); @@ -655,6 +662,8 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { // SH} if (this.environment.globalOptions.storeAnnotations) setAnnotations(createAnnotations(binaryType.getAnnotations(), this.environment, missingTypeNames)); + if (this.isAnnotationType()) + scanTypeForContainerAnnotation(binaryType, missingTypeNames); } finally { // protect against incorrect use of the needFieldsAndMethods flag, see 48459 if (this.fields == null) @@ -664,20 +673,28 @@ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) { } } +private TypeAnnotationWalker getTypeAnnotationWalker(IBinaryTypeAnnotation[] annotations) { + if (this != this.prototype) throw new IllegalStateException(); + if (annotations == null || annotations.length == 0) + return TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER; + + return this.environment.usesAnnotatedTypeSystem() ? new TypeAnnotationWalker(annotations) : TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER; +} + private void createFields(IBinaryField[] iFields, long sourceLevel, char[][][] missingTypeNames) { + if (this != this.prototype) throw new IllegalStateException(); this.fields = Binding.NO_FIELDS; if (iFields != null) { int size = iFields.length; if (size > 0) { this.fields = new FieldBinding[size]; boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5; - boolean use18specifics = sourceLevel >= ClassFileConstants.JDK1_8; boolean hasRestrictedAccess = hasRestrictedAccess(); int firstAnnotatedFieldIndex = -1; for (int i = 0; i < size; i++) { IBinaryField binaryField = iFields[i]; char[] fieldSignature = use15specifics ? binaryField.getGenericSignature() : null; - TypeAnnotationWalker walker = use18specifics ? TypeAnnotationWalker.create(binaryField.getTypeAnnotations()).toField() : TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER; + TypeAnnotationWalker walker = getTypeAnnotationWalker(binaryField.getTypeAnnotations()).toField(); TypeBinding type = fieldSignature == null ? this.environment.getTypeFromSignature(binaryField.getTypeName(), 0, -1, false, this, missingTypeNames, walker) : this.environment.getTypeFromTypeSignature(new SignatureWrapper(fieldSignature), Binding.NO_TYPE_VARIABLES, this, missingTypeNames, walker); @@ -758,6 +775,7 @@ private MethodBinding createMethod(IBinaryMethod method, long sourceLevel, char[ MethodBinding result = null; try { // SH} + if (this != this.prototype) throw new IllegalStateException(); int methodModifiers = method.getModifiers() | ExtraCompilerModifiers.AccUnresolved; if (sourceLevel < ClassFileConstants.JDK1_5) methodModifiers &= ~ClassFileConstants.AccVarargs; // vararg methods are not recognized until 1.5 @@ -782,7 +800,7 @@ private MethodBinding createMethod(IBinaryMethod method, long sourceLevel, char[ variables properly in order to be able to apply substitutions and thus be able to detect overriding in the presence of generics. Seeing the erased form is not good enough. */ - TypeAnnotationWalker walker = sourceLevel >= ClassFileConstants.JDK1_8 ? TypeAnnotationWalker.create(method) : TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER; + TypeAnnotationWalker walker = getTypeAnnotationWalker(method.getTypeAnnotations()); char[] methodSignature = method.getGenericSignature(); // always use generic signature, even in 1.4 if (methodSignature == null) { // no generics char[] methodDescriptor = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V @@ -1013,6 +1031,7 @@ private MethodBinding createMethod(IBinaryMethod method, long sourceLevel, char[ * iMethods for which MethodBindings have been created; indices match those in this.methods. */ private IBinaryMethod[] createMethods(IBinaryMethod[] iMethods, long sourceLevel, char[][][] missingTypeNames) { + if (this != this.prototype) throw new IllegalStateException(); int total = 0, initialTotal = 0, iClinit = -1; int[] toSkip = null; if (iMethods != null) { @@ -1091,6 +1110,7 @@ public void createOTREMethods(RoleModel role) { private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, boolean assignVariables, char[][][] missingTypeNames, TypeAnnotationWalker walker, boolean isClassTypeParameter) { + if (this != this.prototype) throw new IllegalStateException(); // detect all type variables first char[] typeSignature = wrapper.signature; int depth = 0, length = typeSignature.length; @@ -1135,7 +1155,7 @@ private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, bool if (assignVariables) this.typeVariables = result; for (int i = 0; i < rank; i++) { - initializeTypeVariable(result[i], result, wrapper, missingTypeNames, walker.toTypeBarameterBounds(isClassTypeParameter, i)); + initializeTypeVariable(result[i], result, wrapper, missingTypeNames, walker.toTypeParameterBounds(isClassTypeParameter, i)); } return result; } @@ -1144,8 +1164,7 @@ private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, bool * * NOTE: enclosingType of a binary type is resolved when needed */ -public ReferenceBinding enclosingType() { - +public ReferenceBinding enclosingType() { // should not delegate to prototype. if ((this.tagBits & TagBits.HasUnresolvedEnclosingType) == 0) return this.enclosingType; @@ -1157,8 +1176,13 @@ public ReferenceBinding enclosingType() { // NOTE: the type of each field of a binary type is resolved when needed public FieldBinding[] fields() { - if (this != this.prototype) - return this.prototype.fields(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreFieldsComplete) != 0) + return this.fields; + this.fields = this.prototype.fields(); + this.tagBits |= TagBits.AreFieldsComplete; + return this.fields; + } if ((this.tagBits & TagBits.AreFieldsComplete) != 0) return this.fields; @@ -1177,6 +1201,7 @@ public FieldBinding[] fields() { } private MethodBinding findMethod(char[] methodDescriptor, char[][][] missingTypeNames) { + if (this != this.prototype) throw new IllegalStateException(); int index = -1; while (methodDescriptor[++index] != Util.C_PARAM_START) { // empty @@ -1368,12 +1393,14 @@ public FieldBinding getField(char[] fieldName, boolean needResolve) { return needResolve && field != null ? resolveTypeFor(field) : field; } /** - * Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested + * Rewrite of default memberTypes() to avoid resolving eagerly all member types when one is requested */ public ReferenceBinding getMemberType(char[] typeName) { - if (this != this.prototype) - return this.prototype.getMemberType(typeName); + if (this != this.prototype) { + ReferenceBinding memberType = this.prototype.getMemberType(typeName); + return memberType == null ? null : this.environment.createMemberType(memberType, this); + } for (int i = this.memberTypes.length; --i >= 0;) { ReferenceBinding memberType = this.memberTypes[i]; @@ -1507,8 +1534,6 @@ public MethodBinding[] getMethods(char[] selector, int suggestedParameterLength) return Binding.NO_METHODS; } public boolean hasMemberTypes() { - if (this != this.prototype) - return this.prototype.hasMemberTypes(); return this.memberTypes.length > 0; } // NOTE: member types of binary types are resolved when needed @@ -1537,6 +1562,7 @@ public boolean hasTypeBit(int bit) { return (this.typeBits & bit) != 0; } private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBinding[] existingVariables, SignatureWrapper wrapper, char[][][] missingTypeNames, TypeAnnotationWalker walker) { + if (this != this.prototype) throw new IllegalStateException(); // ParameterSignature = Identifier ':' TypeSignature // or Identifier ':' TypeSignature(optional) InterfaceBound(s) // InterfaceBound = ':' TypeSignature @@ -1559,7 +1585,7 @@ private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBi // variable is visible to its bounds variable.modifiers |= ExtraCompilerModifiers.AccUnresolved; - variable.superclass = type; + variable.setSuperClass(type); ReferenceBinding[] bounds = null; if (wrapper.signature[wrapper.start] == Util.C_COLON) { @@ -1572,11 +1598,11 @@ private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBi types.toArray(bounds); } - variable.superInterfaces = bounds == null ? Binding.NO_SUPERINTERFACES : bounds; + variable.setSuperInterfaces(bounds == null ? Binding.NO_SUPERINTERFACES : bounds); if (firstBound == null) { firstBound = variable.superInterfaces.length == 0 ? null : variable.superInterfaces[0]; } - variable.firstBound = firstBound; + variable.setFirstBound(firstBound); } /** * Returns true if a type is identical to another one, @@ -1617,6 +1643,10 @@ public boolean isHierarchyConnected() { return (this.tagBits & (TagBits.HasUnresolvedSuperclass | TagBits.HasUnresolvedSuperinterfaces)) == 0; } +public boolean isRepeatableAnnotation() { + if (this != this.prototype) throw new IllegalStateException(); + return this.containingAnnotation != null; +} public int kind() { if (this != this.prototype) @@ -1628,9 +1658,19 @@ public int kind() { } // NOTE: member types of binary types are resolved when needed public ReferenceBinding[] memberTypes() { - - if (this != this.prototype) - return this.prototype.memberTypes(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.HasUnresolvedMemberTypes) == 0) + return this.memberTypes; + ReferenceBinding [] members = this.prototype.memberTypes(); + int memberTypesLength = members == null ? 0 : members.length; + if (memberTypesLength > 0) { + this.memberTypes = new ReferenceBinding[memberTypesLength]; + for (int i = 0; i < memberTypesLength; i++) + this.memberTypes[i] = this.environment.createMemberType(members[i], this); + } + this.tagBits &= ~TagBits.HasUnresolvedMemberTypes; + return this.memberTypes; + } if ((this.tagBits & TagBits.HasUnresolvedMemberTypes) == 0) return this.memberTypes; @@ -1643,8 +1683,13 @@ public ReferenceBinding[] memberTypes() { // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed public MethodBinding[] methods() { - if (this != this.prototype) - return this.prototype.methods(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreMethodsComplete) != 0) + return this.methods; + this.methods = this.prototype.methods(); + this.tagBits |= TagBits.AreMethodsComplete; + return this.methods; + } if ((this.tagBits & TagBits.AreMethodsComplete) != 0) return this.methods; @@ -1661,6 +1706,19 @@ public MethodBinding[] methods() { this.tagBits |= TagBits.AreMethodsComplete; return this.methods; } + +public TypeBinding prototype() { + return this.prototype; +} + +public ReferenceBinding resolveContainerAnnotation() { + if (this != this.prototype) throw new IllegalStateException(); + if (this.containingAnnotation instanceof UnresolvedReferenceBinding) { + this.containingAnnotation = (ReferenceBinding) BinaryTypeBinding.resolveType(this.containingAnnotation, this.environment, false); + } + return this.containingAnnotation; +} + private FieldBinding resolveTypeFor(FieldBinding field) { if (this != this.prototype) @@ -1753,6 +1811,10 @@ AnnotationBinding[] retrieveAnnotations(Binding binding) { return AnnotationBinding.addStandardAnnotations(super.retrieveAnnotations(binding), binding.getAnnotationTagBits(), this.environment); } +public void setContainingAnnotation(ReferenceBinding value) { + if (this != this.prototype) throw new IllegalStateException(); + this.containingAnnotation = value; +} SimpleLookupTable storedAnnotations(boolean forceInitialize) { if (this != this.prototype) @@ -1770,6 +1832,18 @@ SimpleLookupTable storedAnnotations(boolean forceInitialize) { } private void scanFieldForNullAnnotation(IBinaryField field, FieldBinding fieldBinding) { + if (this != this.prototype) throw new IllegalStateException(); + if (this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + TypeBinding fieldType = fieldBinding.type; + if (fieldType != null + && !fieldType.isBaseType() + && (fieldType.tagBits & TagBits.AnnotationNullMASK) == 0 + && (this.tagBits & TagBits.AnnotationNonNullByDefault) != 0) { + fieldBinding.type = this.environment.createAnnotatedType(fieldType, new AnnotationBinding[]{this.environment.getNonNullAnnotation()}); + } + return; // not using fieldBinding.tagBits when we have type annotations. + } + // global option is checked by caller char[][] nullableAnnotationName = this.environment.getNullableAnnotationName(); char[][] nonNullAnnotationName = this.environment.getNonNullAnnotationName(); @@ -1805,6 +1879,7 @@ private void scanFieldForNullAnnotation(IBinaryField field, FieldBinding fieldBi } private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding methodBinding) { + if (this != this.prototype) throw new IllegalStateException(); if (!this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) return; boolean useTypeAnnotations = this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8; @@ -1827,12 +1902,11 @@ private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding met if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault; } - if (!useTypeAnnotations) { - if (!explicitNullness && CharOperation.equals(typeName, nonNullAnnotationName)) { + if (!useTypeAnnotations && !explicitNullness) { + if (CharOperation.equals(typeName, nonNullAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNonNull; explicitNullness = true; - } - if (!explicitNullness && CharOperation.equals(typeName, nullableAnnotationName)) { + } else if (CharOperation.equals(typeName, nullableAnnotationName)) { methodBinding.tagBits |= TagBits.AnnotationNullable; explicitNullness = true; } @@ -1876,6 +1950,7 @@ private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding met } } private void scanTypeForNullDefaultAnnotation(IBinaryType binaryType, PackageBinding packageBinding, BinaryTypeBinding binaryBinding) { + if (this != this.prototype) throw new IllegalStateException(); char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName(); if (nonNullByDefaultAnnotationName == null) return; // not well-configured to use null annotations @@ -1951,14 +2026,40 @@ private void scanTypeForNullDefaultAnnotation(IBinaryType binaryType, PackageBin } } +private void scanTypeForContainerAnnotation(IBinaryType binaryType, char[][][] missingTypeNames) { + if (this != this.prototype) throw new IllegalStateException(); + IBinaryAnnotation[] annotations = binaryType.getAnnotations(); + if (annotations != null) { + int length = annotations.length; + for (int i = 0; i < length; i++) { + char[] annotationTypeName = annotations[i].getTypeName(); + if (CharOperation.equals(annotationTypeName, ConstantPool.JAVA_LANG_ANNOTATION_REPEATABLE)) { + IBinaryElementValuePair[] elementValuePairs = annotations[i].getElementValuePairs(); + if (elementValuePairs != null && elementValuePairs.length == 1) { + Object value = elementValuePairs[0].getValue(); + if (value instanceof ClassSignature) { + this.containingAnnotation = (ReferenceBinding) this.environment.getTypeFromSignature(((ClassSignature)value).getTypeName(), 0, -1, false, null, missingTypeNames, TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER); + } + } + break; + } + } + } +} + /* Answer the receiver's superclass... null if the receiver is Object or an interface. * * NOTE: superclass of a binary type is resolved when needed */ public ReferenceBinding superclass() { - if (this != this.prototype) - return this.prototype.superclass(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.HasUnresolvedSuperclass) == 0) + return this.superclass; + this.superclass = this.prototype.superclass(); + this.tagBits &= ~TagBits.HasUnresolvedSuperclass; + return this.superclass; + } if ((this.tagBits & TagBits.HasUnresolvedSuperclass) == 0) return this.superclass; @@ -2004,9 +2105,13 @@ public void resetSuperclass(ReferenceBinding superClass) { // NOTE: superInterfaces of binary types are resolved when needed public ReferenceBinding[] superInterfaces() { - if (this != this.prototype) - return this.prototype.superInterfaces(); - + if (this != this.prototype) { + if ((this.tagBits & TagBits.HasUnresolvedSuperinterfaces) == 0) + return this.superInterfaces; + this.superInterfaces = this.prototype.superInterfaces(); + this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces; + return this.superInterfaces; + } if ((this.tagBits & TagBits.HasUnresolvedSuperinterfaces) == 0) return this.superInterfaces; @@ -2032,9 +2137,13 @@ public ReferenceBinding[] superInterfaces() { } public TypeVariableBinding[] typeVariables() { - if (this != this.prototype) - return this.prototype.typeVariables(); - + if (this != this.prototype) { + if ((this.tagBits & TagBits.HasUnresolvedTypeVariables) == 0) + return this.typeVariables; + this.typeVariables = this.prototype.typeVariables(); + this.tagBits &= ~TagBits.HasUnresolvedTypeVariables; + return this.typeVariables; + } if ((this.tagBits & TagBits.HasUnresolvedTypeVariables) == 0) return this.typeVariables; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java index ecb74a11b..56b0e8596 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -109,6 +109,8 @@ public abstract class Binding { /** * Compute the tagbits for standard annotations. For source types, these could require * lazily resolving corresponding annotation nodes, in case of forward references. + * For type use bindings, this method still returns the tagbits corresponding to the type + * declaration binding. * @see org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding#getAnnotationTagBits() */ public long getAnnotationTagBits() { @@ -124,6 +126,10 @@ public abstract class Binding { // empty block } + public boolean isAnnotationType() { + return false; + } + /* API * Answer true if the receiver is not a problem binding */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java index 913ca61b2..b63d85188 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java @@ -34,18 +34,29 @@ public class CaptureBinding extends TypeVariableBinding { public CaptureBinding(WildcardBinding wildcard, ReferenceBinding sourceType, int position, int captureID) { super(TypeConstants.WILDCARD_CAPTURE_NAME_PREFIX, null, 0, wildcard.environment); - // Capture the unannotated wildcard and then capture the annotations. - if (wildcard.hasTypeAnnotations()) { - this.wildcard = (WildcardBinding) wildcard.unannotated(); - setTypeAnnotations(wildcard.getTypeAnnotations(), wildcard.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); - } else { - this.wildcard = wildcard; - } + this.wildcard = wildcard; this.modifiers = ClassFileConstants.AccPublic | ExtraCompilerModifiers.AccGenericSignature; // treat capture as public this.fPackage = wildcard.fPackage; this.sourceType = sourceType; this.position = position; this.captureID = captureID; + if (wildcard.hasTypeAnnotations()) { + setTypeAnnotations(wildcard.getTypeAnnotations(), wildcard.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); + } + } + + public CaptureBinding(CaptureBinding prototype) { + super(prototype); + this.wildcard = prototype.wildcard; + this.sourceType = prototype.sourceType; + this.position = prototype.position; + this.captureID = prototype.captureID; + this.lowerBound = prototype.lowerBound; + } + + // Captures may get cloned and annotated during type inference. + public TypeBinding clone(TypeBinding enclosingType) { + return new CaptureBinding(this); } /* @@ -110,30 +121,30 @@ public class CaptureBinding extends TypeVariableBinding { // still need to capture bound supertype as well so as not to expose wildcards to the outside (111208) TypeBinding capturedWildcardBound = originalWildcardBound.capture(scope, this.position); if (originalWildcardBound.isInterface()) { - this.superclass = scope.getJavaLangObject(); - this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) capturedWildcardBound }; + this.setSuperClass(scope.getJavaLangObject()); + this.setSuperInterfaces(new ReferenceBinding[] { (ReferenceBinding) capturedWildcardBound }); } else { // the wildcard bound should be a subtype of variable superclass // it may occur that the bound is less specific, then consider glb (202404) if (capturedWildcardBound.isArrayType() || capturedWildcardBound == this) { - this.superclass = scope.getJavaLangObject(); + this.setSuperClass(scope.getJavaLangObject()); } else { - this.superclass = (ReferenceBinding) capturedWildcardBound; + this.setSuperClass((ReferenceBinding) capturedWildcardBound); } - this.superInterfaces = Binding.NO_SUPERINTERFACES; + this.setSuperInterfaces(Binding.NO_SUPERINTERFACES); } - this.firstBound = capturedWildcardBound; + this.setFirstBound(capturedWildcardBound); if ((capturedWildcardBound.tagBits & TagBits.HasTypeVariable) == 0) this.tagBits &= ~TagBits.HasTypeVariable; break; case Wildcard.UNBOUND : - this.superclass = scope.getJavaLangObject(); - this.superInterfaces = Binding.NO_SUPERINTERFACES; + this.setSuperClass(scope.getJavaLangObject()); + this.setSuperInterfaces(Binding.NO_SUPERINTERFACES); this.tagBits &= ~TagBits.HasTypeVariable; break; case Wildcard.SUPER : - this.superclass = scope.getJavaLangObject(); - this.superInterfaces = Binding.NO_SUPERINTERFACES; + this.setSuperClass(scope.getJavaLangObject()); + this.setSuperInterfaces(Binding.NO_SUPERINTERFACES); this.lowerBound = this.wildcard.bound; if ((originalWildcardBound.tagBits & TagBits.HasTypeVariable) == 0) this.tagBits &= ~TagBits.HasTypeVariable; @@ -166,44 +177,44 @@ public class CaptureBinding extends TypeVariableBinding { capturedWildcardBound = RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, capturedWildcardBound.enclosingType(), capturedWildcardBound, scope.methodScope().referenceMethod(), scope.problemReporter()); // SH} if (originalWildcardBound.isInterface()) { - this.superclass = substitutedVariableSuperclass; + this.setSuperClass(substitutedVariableSuperclass); // merge wildcard bound into variable superinterfaces using glb if (substitutedVariableInterfaces == Binding.NO_SUPERINTERFACES) { - this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) capturedWildcardBound }; + this.setSuperInterfaces(new ReferenceBinding[] { (ReferenceBinding) capturedWildcardBound }); } else { int length = substitutedVariableInterfaces.length; System.arraycopy(substitutedVariableInterfaces, 0, substitutedVariableInterfaces = new ReferenceBinding[length+1], 1, length); substitutedVariableInterfaces[0] = (ReferenceBinding) capturedWildcardBound; - this.superInterfaces = Scope.greaterLowerBound(substitutedVariableInterfaces); + this.setSuperInterfaces(Scope.greaterLowerBound(substitutedVariableInterfaces)); } } else { // the wildcard bound should be a subtype of variable superclass // it may occur that the bound is less specific, then consider glb (202404) if (capturedWildcardBound.isArrayType() || capturedWildcardBound == this) { - this.superclass = substitutedVariableSuperclass; + this.setSuperClass(substitutedVariableSuperclass); } else { - this.superclass = (ReferenceBinding) capturedWildcardBound; + this.setSuperClass((ReferenceBinding) capturedWildcardBound); if (this.superclass.isSuperclassOf(substitutedVariableSuperclass)) { - this.superclass = substitutedVariableSuperclass; + this.setSuperClass(substitutedVariableSuperclass); } } - this.superInterfaces = substitutedVariableInterfaces; + this.setSuperInterfaces(substitutedVariableInterfaces); } - this.firstBound = capturedWildcardBound; + this.setFirstBound(capturedWildcardBound); if ((capturedWildcardBound.tagBits & TagBits.HasTypeVariable) == 0) this.tagBits &= ~TagBits.HasTypeVariable; break; case Wildcard.UNBOUND : - this.superclass = substitutedVariableSuperclass; - this.superInterfaces = substitutedVariableInterfaces; + this.setSuperClass(substitutedVariableSuperclass); + this.setSuperInterfaces(substitutedVariableInterfaces); this.tagBits &= ~TagBits.HasTypeVariable; break; case Wildcard.SUPER : - this.superclass = substitutedVariableSuperclass; + this.setSuperClass(substitutedVariableSuperclass); if (wildcardVariable.firstBound == substitutedVariableSuperclass || originalWildcardBound == substitutedVariableSuperclass) { - this.firstBound = substitutedVariableSuperclass; + this.setFirstBound(substitutedVariableSuperclass); } - this.superInterfaces = substitutedVariableInterfaces; + this.setSuperInterfaces(substitutedVariableInterfaces); this.lowerBound = originalWildcardBound; if ((originalWildcardBound.tagBits & TagBits.HasTypeVariable) == 0) this.tagBits &= ~TagBits.HasTypeVariable; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index be686c2bf..fe74e5c2a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 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 @@ -22,6 +22,8 @@ * Bug 395977 - [compiler][resource] Resource leak warning behavior possibly incorrect for anonymous inner class * Bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables + * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for + * Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -171,33 +173,35 @@ public class ClassScope extends Scope { } anonymousType.typeBits |= inheritedBits; if (supertype.isInterface()) { - anonymousType.superclass = getJavaLangObject(); - anonymousType.superInterfaces = new ReferenceBinding[] { supertype }; + anonymousType.setSuperClass(getJavaLangObject()); + anonymousType.setSuperInterfaces(new ReferenceBinding[] { supertype }); TypeReference typeReference = this.referenceContext.allocation.type; if (typeReference != null) { + this.referenceContext.superInterfaces = new TypeReference[] { typeReference }; if ((supertype.tagBits & TagBits.HasDirectWildcard) != 0) { problemReporter().superTypeCannotUseWildcard(anonymousType, typeReference, supertype); anonymousType.tagBits |= TagBits.HierarchyHasProblems; - anonymousType.superInterfaces = Binding.NO_SUPERINTERFACES; + anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); } } } else { - anonymousType.superclass = supertype; - anonymousType.superInterfaces = Binding.NO_SUPERINTERFACES; + anonymousType.setSuperClass(supertype); + anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); TypeReference typeReference = this.referenceContext.allocation.type; if (typeReference != null) { // no check for enum constant body + this.referenceContext.superclass = typeReference; if (supertype.erasure().id == TypeIds.T_JavaLangEnum) { problemReporter().cannotExtendEnum(anonymousType, typeReference, supertype); anonymousType.tagBits |= TagBits.HierarchyHasProblems; - anonymousType.superclass = getJavaLangObject(); + anonymousType.setSuperClass(getJavaLangObject()); } else if (supertype.isFinal()) { problemReporter().anonymousClassCannotExtendFinalClass(typeReference, supertype); anonymousType.tagBits |= TagBits.HierarchyHasProblems; - anonymousType.superclass = getJavaLangObject(); + anonymousType.setSuperClass(getJavaLangObject()); } else if ((supertype.tagBits & TagBits.HasDirectWildcard) != 0) { problemReporter().superTypeCannotUseWildcard(anonymousType, typeReference, supertype); anonymousType.tagBits |= TagBits.HierarchyHasProblems; - anonymousType.superclass = getJavaLangObject(); + anonymousType.setSuperClass(getJavaLangObject()); } } } @@ -420,7 +424,7 @@ public class ClassScope extends Scope { if (count != size) System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); } - localType.memberTypes = memberTypeBindings; + localType.setMemberTypes(memberTypeBindings); return localType; } @@ -507,7 +511,7 @@ public class ClassScope extends Scope { if (count != length) System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); } - sourceType.memberTypes = memberTypeBindings; + sourceType.setMemberTypes(memberTypeBindings); } void buildMethods() { @@ -712,10 +716,10 @@ public class ClassScope extends Scope { TypeParameter[] typeParameters = this.referenceContext.typeParameters; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850, If they exist at all, process type parameters irrespective of source level. if (typeParameters == null || typeParameters.length == 0) { - sourceType.typeVariables = Binding.NO_TYPE_VARIABLES; + sourceType.setTypeVariables(Binding.NO_TYPE_VARIABLES); return; } - sourceType.typeVariables = Binding.NO_TYPE_VARIABLES; // safety + sourceType.setTypeVariables(Binding.NO_TYPE_VARIABLES); // safety if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front problemReporter().objectCannotBeGeneric(this.referenceContext); @@ -726,7 +730,7 @@ public class ClassScope extends Scope { if (typeParameters.length == 0) return; // consumed all parameters // SH} - sourceType.typeVariables = createTypeVariables(typeParameters, sourceType); + sourceType.setTypeVariables(createTypeVariables(typeParameters, sourceType)); sourceType.modifiers |= ExtraCompilerModifiers.AccGenericSignature; } @@ -1542,8 +1546,8 @@ public class ClassScope extends Scope { return connectSuperteam(); // SH} if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front - sourceType.superclass = null; - sourceType.superInterfaces = Binding.NO_SUPERINTERFACES; + sourceType.setSuperClass(null); + sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); if (!sourceType.isClass()) problemReporter().objectMustBeClass(sourceType); if (this.referenceContext.superclass != null || (this.referenceContext.superInterfaces != null && this.referenceContext.superInterfaces.length > 0)) @@ -1557,7 +1561,7 @@ public class ClassScope extends Scope { // SH} if (sourceType.isEnum() && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) // do not connect if source < 1.5 as enum already got flagged as syntax error return connectEnumSuperclass(); - sourceType.superclass = getJavaLangObject(); + sourceType.setSuperClass(getJavaLangObject()); return !detectHierarchyCycle(sourceType, sourceType.superclass, null); } TypeReference superclassRef = this.referenceContext.superclass; @@ -1592,7 +1596,7 @@ public class ClassScope extends Scope { problemReporter().cannotExtendEnum(sourceType, superclassRef, superclass); } else if ((superclass.tagBits & TagBits.HierarchyHasProblems) != 0 || !superclassRef.resolvedType.isValidBinding()) { - sourceType.superclass = superclass; + sourceType.setSuperClass(superclass); sourceType.tagBits |= TagBits.HierarchyHasProblems; // propagate if missing supertype return superclassRef.resolvedType.isValidBinding(); // reported some error against the source type ? //{ObjectTeams: team super class only allowed for teams @@ -1603,7 +1607,7 @@ public class ClassScope extends Scope { // SH} } else { // only want to reach here when no errors are reported - sourceType.superclass = superclass; + sourceType.setSuperClass(superclass); sourceType.typeBits |= (superclass.typeBits & TypeIds.InheritableBits); // further analysis against white lists for the unlikely case we are compiling java.io.*: if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) @@ -1612,7 +1616,7 @@ public class ClassScope extends Scope { } } sourceType.tagBits |= TagBits.HierarchyHasProblems; - sourceType.superclass = getJavaLangObject(); + sourceType.setSuperClass(getJavaLangObject()); if ((sourceType.superclass.tagBits & TagBits.BeginHierarchyCheck) == 0) detectHierarchyCycle(sourceType, sourceType.superclass, null); return false; // reported some error against the source type @@ -1626,7 +1630,7 @@ public class ClassScope extends Scope { ReferenceBinding rootEnumType = getJavaLangEnum(); if ((rootEnumType.tagBits & TagBits.HasMissingType) != 0) { sourceType.tagBits |= TagBits.HierarchyHasProblems; // mark missing supertpye - sourceType.superclass = rootEnumType; + sourceType.setSuperClass(rootEnumType); return false; } boolean foundCycle = detectHierarchyCycle(sourceType, rootEnumType, null); @@ -1647,7 +1651,7 @@ public class ClassScope extends Scope { } , null); sourceType.tagBits |= (superType.tagBits & TagBits.HierarchyHasProblems); // propagate if missing supertpye - sourceType.superclass = superType; + sourceType.setSuperClass(superType); // bound check (in case of bogus definition of Enum type) if (refTypeVariables[0].boundCheck(superType, sourceType, this) != TypeConstants.OK) { problemReporter().typeMismatchError(rootEnumType, refTypeVariables[0], sourceType, null); @@ -2021,12 +2025,12 @@ public class ClassScope extends Scope { */ private boolean connectSuperInterfaces() { SourceTypeBinding sourceType = this.referenceContext.binding; - sourceType.superInterfaces = Binding.NO_SUPERINTERFACES; + sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); if (this.referenceContext.superInterfaces == null) { if (sourceType.isAnnotationType() && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // do not connect if source < 1.5 as annotation already got flagged as syntax error) { ReferenceBinding annotationType = getJavaLangAnnotationAnnotation(); boolean foundCycle = detectHierarchyCycle(sourceType, annotationType, null); - sourceType.superInterfaces = new ReferenceBinding[] { annotationType }; + sourceType.setSuperInterfaces(new ReferenceBinding[] { annotationType }); return !foundCycle; } return true; @@ -2097,7 +2101,7 @@ public class ClassScope extends Scope { if (count > 0) { if (count != length) System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count); - sourceType.superInterfaces = interfaceBindings; + sourceType.setSuperInterfaces(interfaceBindings); } return noProblems; } @@ -2370,7 +2374,7 @@ public class ClassScope extends Scope { return superType; } catch (AbortCompilation e) { SourceTypeBinding sourceType = this.referenceContext.binding; - if (sourceType.superInterfaces == null) sourceType.superInterfaces = Binding.NO_SUPERINTERFACES; // be more resilient for hierarchies (144976) + if (sourceType.superInterfaces == null) sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); // be more resilient for hierarchies (144976) e.updateContext(typeReference, referenceCompilationUnit().compilationResult); throw e; } finally { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java index 2afd2b693..bfd619539 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java @@ -4,7 +4,10 @@ * 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 - * $Id: FieldBinding.java 23405 2010-02-03 17:02:18Z stephan $ + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. * * Contributors: * IBM Corporation - initial API and implementation @@ -13,6 +16,7 @@ * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for * bug 185682 - Increment/decrement operators mark local variables as read * bug 331649 - [compiler][null] consider null annotations for fields + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -136,7 +140,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca if (isPublic()) return true; SourceTypeBinding invocationType = scope.enclosingSourceType(); - if (invocationType == this.declaringClass && invocationType == receiverType) return true; + if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverType)) return true; if (invocationType == null) // static import call return !isPrivate() && scope.getCurrentPackage() == this.declaringClass.fPackage; @@ -152,7 +156,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // AND the receiverType is the invocationType or its subclass // OR the method is a static method accessed directly through a type // OR previous assertions are true for one of the enclosing type - if (invocationType == this.declaringClass) return true; + if (TypeBinding.equalsEquals(invocationType, this.declaringClass)) return true; if (invocationType.fPackage == this.declaringClass.fPackage) return true; ReferenceBinding currentType = invocationType; @@ -170,7 +174,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca if (depth > 0) invocationSite.setDepth(depth); return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); } - if (currentType == receiverErasure || receiverErasure.findSuperTypeOriginatingFrom(currentType) != null) { + if (TypeBinding.equalsEquals(currentType, receiverErasure) || receiverErasure.findSuperTypeOriginatingFrom(currentType) != null) { if (depth > 0) invocationSite.setDepth(depth); return true; } @@ -185,7 +189,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // answer true if the receiverType is the declaringClass // AND the invocationType and the declaringClass have a common enclosingType receiverCheck: { - if (receiverType != this.declaringClass) { + if (TypeBinding.notEquals(receiverType, this.declaringClass)) { // special tolerance for type variable direct bounds, but only if compliance <= 1.6, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 if (scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_6 && receiverType.isTypeVariable() && ((TypeVariableBinding) receiverType).isErasureBoundTo(this.declaringClass.erasure())) break receiverCheck; @@ -193,7 +197,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca } } - if (invocationType != this.declaringClass) { + if (TypeBinding.notEquals(invocationType, this.declaringClass)) { ReferenceBinding outerInvocationType = invocationType; ReferenceBinding temp = outerInvocationType.enclosingType(); while (temp != null) { @@ -207,7 +211,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca outerDeclaringClass = temp; temp = temp.enclosingType(); } - if (outerInvocationType != outerDeclaringClass) return false; + if (TypeBinding.notEquals(outerInvocationType, outerDeclaringClass)) return false; } return true; } @@ -223,9 +227,9 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca ReferenceBinding currentType = (ReferenceBinding) receiverType; do { if (currentType.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002 - if (originalDeclaringClass == currentType.erasure().original()) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.erasure().original())) return true; } else { - if (originalDeclaringClass == currentType.original()) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.original())) return true; } PackageBinding currentPackage = currentType.fPackage; // package could be null for wildcards/intersection types, ignore and recurse in superclass @@ -302,11 +306,15 @@ public Constant constant() { } public void fillInDefaultNonNullness(FieldDeclaration sourceField, Scope scope) { + LookupEnvironment environment = scope.environment(); if ( this.type != null && !this.type.isBaseType() - && (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) + && (this.tagBits & TagBits.AnnotationNullMASK) == 0) { - this.tagBits |= TagBits.AnnotationNonNull; + if (environment.globalOptions.sourceLevel < ClassFileConstants.JDK1_8) + this.tagBits |= TagBits.AnnotationNonNull; + else + this.type = environment.createAnnotatedType(this.type, new AnnotationBinding[]{environment.getNonNullAnnotation()}); } else if ((this.tagBits & TagBits.AnnotationNonNull) != 0) { scope.problemReporter().nullAnnotationIsRedundant(sourceField); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java index 8a506c422..feffe9d61 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java @@ -23,6 +23,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; @@ -52,9 +53,10 @@ public class ImplicitNullAnnotationVerifier { // can be 'this', but is never a MethodVerifier (to avoid infinite recursion). ImplicitNullAnnotationVerifier buddyImplicitNullAnnotationsVerifier; private boolean inheritNullAnnotations; + +//{ObjectTeams: added field and 2nd ctor arg: private LookupEnvironment environment; -//{ObjectTeams: added 2nd arg: public ImplicitNullAnnotationVerifier(boolean inheritNullAnnotations, LookupEnvironment environment) { this.environment = environment; // SH} @@ -137,9 +139,8 @@ public class ImplicitNullAnnotationVerifier { currentMethod.tagBits |= tagBits; } else { if (!currentMethod.returnType.isBaseType()) { - // TODO(Stephan: Synthesize AnnotationBinding[] and call LE#createAnnotatedType(TB, AB[]); - // currentMethod.returnType = scope.environment() - // .createAnnotatedType(currentMethod.returnType, tagBits); + LookupEnvironment env = scope.environment(); + currentMethod.returnType = env.createAnnotatedType(currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits)); } } } @@ -401,8 +402,7 @@ public class ImplicitNullAnnotationVerifier { method.tagBits |= nullnessBits; } else { if (!method.returnType.isBaseType()) { - // TODO(Stephan: Synthesize AnnotationBinding[] and call LE#createAnnotatedType(TB, AB[]); - // method.returnType = environment.createAnnotatedType(method.returnType, nullnessBits); + method.returnType = environment.createAnnotatedType(method.returnType, environment.nullAnnotationsFromTagBits(nullnessBits)); } } } @@ -411,7 +411,7 @@ public class ImplicitNullAnnotationVerifier { if (useTypeAnnotations) { TypeBinding parameter = method.parameters[i]; if (parameter != null) { - long nullBits = parameter.tagBits & TagBits.AnnotationNullMASK; + long nullBits = NullAnnotationMatching.validNullTagBits(parameter.tagBits); if (nullBits != 0L) return Boolean.valueOf(nullBits == TagBits.AnnotationNonNull); } @@ -425,7 +425,7 @@ public class ImplicitNullAnnotationVerifier { if (useTypeAnnotations) { if (method.returnType == null) return 0L; - return method.returnType.tagBits & TagBits.AnnotationNullMASK; + return NullAnnotationMatching.validNullTagBits(method.returnType.tagBits); } return method.tagBits & TagBits.AnnotationNullMASK; } @@ -458,9 +458,8 @@ public class ImplicitNullAnnotationVerifier { } } void recordArgNonNullness18(MethodBinding method, int paramIdx, Argument currentArgument, Boolean nonNullNess, LookupEnvironment env) { - // TODO(Stephan: Synthesize AnnotationBinding[] and call LE#createAnnotatedType(TB, AB[]); - // method.parameters[paramIdx] = env.createAnnotatedType(method.parameters[paramIdx], - // nonNullNess.booleanValue() ? TagBits.AnnotationNonNull : TagBits.AnnotationNullable); + AnnotationBinding annotationBinding = nonNullNess.booleanValue() ? env.getNonNullAnnotation() : env.getNullableAnnotation(); + method.parameters[paramIdx] = env.createAnnotatedType(method.parameters[paramIdx], new AnnotationBinding[]{ annotationBinding}); if (currentArgument != null) { currentArgument.binding.type = method.parameters[paramIdx]; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java index 4f3d236bb..dd1a922f6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java @@ -90,6 +90,7 @@ public LocalTypeBinding(LocalTypeBinding prototype) { * all its dependents so as to update them (see updateInnerEmulationDependents()). */ public void addInnerEmulationDependent(BlockScope dependentScope, boolean wasEnclosingInstanceSupplied) { + if (this != this.prototype) throw new IllegalStateException(); int index; if (this.dependents == null) { index = 0; @@ -128,10 +129,9 @@ public ReferenceBinding anonymousOriginalSuperType() { } protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) { - if (this != this.prototype) { - this.prototype.checkRedundantNullnessDefaultRecurse(location, annotations, annotationTagBits); - return; - } + + if (this != this.prototype) throw new IllegalStateException(); + long outerDefault = this.enclosingMethod != null ? this.enclosingMethod.tagBits & ((TagBits.AnnotationNonNullByDefault|TagBits.AnnotationNullUnspecifiedByDefault)) : 0; if (outerDefault != 0) { if (outerDefault == annotationTagBits) { @@ -175,7 +175,7 @@ public char[] constantPoolName() /* java/lang/Object */ { if (this.constantPoolName != null) return this.constantPoolName; if (this != this.prototype) - this.prototype.constantPoolName(); + return this.constantPoolName = this.prototype.constantPoolName(); if (this.constantPoolName == null && this.scope != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=322154, we do have some // cases where the left hand does not know what the right is doing. @@ -184,11 +184,9 @@ public char[] constantPoolName() /* java/lang/Object */ { return this.constantPoolName; } -public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { +public TypeBinding clone(TypeBinding outerType) { LocalTypeBinding copy = new LocalTypeBinding(this); - if (outerType == null) { - outerType = enclosingType(); - } + copy.enclosingType = (SourceTypeBinding) outerType; return copy; } @@ -264,9 +262,10 @@ public char[] shortReadableName() /*Object*/ { return shortReadableName; } -//Record that the type is a local member type +// Record that the type is a local member type public void setAsMemberType() { if (this != this.prototype) { + this.tagBits |= TagBits.MemberTypeMask; ((LocalTypeBinding) this.prototype).setAsMemberType(); return; } @@ -275,6 +274,7 @@ public void setAsMemberType() { public void setConstantPoolName(char[] computedConstantPoolName) /* java/lang/Object */ { if (this != this.prototype) { + this.constantPoolName = computedConstantPoolName; ((LocalTypeBinding) this.prototype).setConstantPoolName(computedConstantPoolName); return; } @@ -332,10 +332,7 @@ public String toString() { * to be propagated to all dependent source types. */ public void updateInnerEmulationDependents() { - if (this != this.prototype) { - ((LocalTypeBinding) this.prototype).updateInnerEmulationDependents(); - return; - } + if (this != this.prototype) throw new IllegalStateException(); if (this.dependents != null) { for (int i = 0; i < this.dependents.length; i++) { InnerEmulationDependency dependency = this.dependents[i]; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index 2165a379c..652722b7a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -27,6 +27,7 @@ * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 * Bug 416183 - [1.8][compiler][null] Overload resolution fails with null annotations * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -114,7 +115,7 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { private int lastCompletedUnitIndex = -1; private int lastUnitIndex = -1; - private AnnotatableTypeSystem typeSystem; + private TypeSystem typeSystem; public INameEnvironment nameEnvironment; public CompilerOptions globalOptions; @@ -151,6 +152,9 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { PackageBinding nonnullAnnotationPackage; // the package supposed to contain the NonNull annotation type PackageBinding nonnullByDefaultAnnotationPackage; // the package supposed to contain the NonNullByDefault annotation type + AnnotationBinding nonNullAnnotation; + AnnotationBinding nullableAnnotation; + final static int BUILD_FIELDS_AND_METHODS = 4; final static int BUILD_TYPE_HIERARCHY = 1; final static int CHECK_AND_SET_IMPORTS = 2; @@ -186,7 +190,12 @@ public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions globalOpt this.accessRestrictions = new HashMap(3); this.classFilePool = ClassFilePool.newInstance(); this.typesBeingConnected = new HashSet(); - this.typeSystem = new AnnotatableTypeSystem(this); + boolean stillTesting = true; + if (this.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8 && (stillTesting || this.globalOptions.storeAnnotations)) { + this.typeSystem = new AnnotatableTypeSystem(this); + } else { + this.typeSystem = new UnannotatedTypeSystem(this); + } } /** @@ -431,7 +440,7 @@ public int internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit) { //{ObjectTeams: one more step: if (todo >= ROLES_LINKED) RoleSplitter.linkRoles(this.unitBeingCompleted = parsedUnit); - +// SH} this.unitBeingCompleted = null; } //{ObjectTeams: report actual step achieved: @@ -848,22 +857,32 @@ public TypeBinding convertUnresolvedBinaryToRawType(TypeBinding type) { } return type; } -/* - * Used to guarantee annotation identity: we do that only for marker annotations. We don't have the machinery for the general case as of now. - */ +/* Used to guarantee annotation identity: we do that only for marker annotations and others with all default values. + We don't have the machinery for the general case as of now. +*/ public AnnotationBinding createAnnotation(ReferenceBinding annotationType, ElementValuePair[] pairs) { if (pairs.length != 0) { AnnotationBinding.setMethodBindings(annotationType, pairs); return new AnnotationBinding(annotationType, pairs); } - return this.typeSystem.getAnnotationType(annotationType); + return this.typeSystem.getAnnotationType(annotationType, true); +} + +/* Used to guarantee annotation identity: we do that only for marker annotations and others with all default values. + We don't have the machinery for the general case as of now. +*/ +public AnnotationBinding createUnresolvedAnnotation(ReferenceBinding annotationType, ElementValuePair[] pairs) { + if (pairs.length != 0) { + return new UnresolvedAnnotationBinding(annotationType, pairs, this); + } + return this.typeSystem.getAnnotationType(annotationType, false); } /* * Used to guarantee array type identity. */ public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount) { - return this.typeSystem.getArrayType(leafComponentType, dimensionCount, Binding.NO_ANNOTATIONS); + return this.typeSystem.getArrayType(leafComponentType, dimensionCount); } public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount, AnnotationBinding [] annotations) { @@ -880,13 +899,13 @@ public TypeBinding createIntersectionCastType(ReferenceBinding[] intersectingTyp if (count < length) { if ((intersectionCastTypeBindings = this.uniqueIntersectionCastTypeBindings[count]) == null) - this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[10]; + this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[4]; } else { System.arraycopy( this.uniqueIntersectionCastTypeBindings, 0, this.uniqueIntersectionCastTypeBindings = new IntersectionCastTypeBinding[count + 1][], 0, length); - this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[10]; + this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[4]; } int index = -1; @@ -898,7 +917,7 @@ public TypeBinding createIntersectionCastType(ReferenceBinding[] intersectingTyp ReferenceBinding [] priorIntersectingTypes = priorBinding.intersectingTypes; for (int i = 0; i < count; i++) { if (intersectingTypes[i] != priorIntersectingTypes[i]) - continue next; + continue next; } return priorBinding; } @@ -920,16 +939,12 @@ public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBin // resolve any array bindings which reference the unresolvedType ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]); - if (cachedType != null) { // update reference to unresolved binding after having read classfile (knows whether generic for raw conversion) - if (cachedType instanceof UnresolvedReferenceBinding) { - ((UnresolvedReferenceBinding) cachedType).setResolvedType(binaryBinding, this); - } else { - if (cachedType.isBinaryBinding()) // sanity check... at this point the cache should ONLY contain unresolved types - return (BinaryTypeBinding) cachedType; - // it is possible with a large number of source files (exceeding AbstractImageBuilder.MAX_AT_ONCE) that a member type can be in the cache as an UnresolvedType, - // but because its enclosingType is resolved while its created (call to BinaryTypeBinding constructor), its replaced with a source type - return null; - } + if (cachedType != null && !cachedType.isUnresolvedType()) { + if (cachedType.isBinaryBinding()) // sanity check... at this point the cache should ONLY contain unresolved types + return (BinaryTypeBinding) cachedType; + // it is possible with a large number of source files (exceeding AbstractImageBuilder.MAX_AT_ONCE) that a member type can be in the cache as an UnresolvedType, + // but because its enclosingType is resolved while its created (call to BinaryTypeBinding constructor), its replaced with a source type + return null; } packageBinding.addType(binaryBinding); setAccessRestriction(binaryBinding, accessRestriction); @@ -1127,6 +1142,11 @@ public PolymorphicMethodBinding createPolymorphicMethod(MethodBinding originalPo cachedInfo[index] = polymorphicMethod; return polymorphicMethod; } + +public boolean usesAnnotatedTypeSystem() { + return this.typeSystem.isAnnotatedTypeSystem(); +} + public MethodBinding updatePolymorphicMethodReturnType(PolymorphicMethodBinding binding, TypeBinding typeBinding) { // update the return type to be the given return type, but reuse existing binding if one can match String key = new String(binding.selector); @@ -1179,9 +1199,15 @@ public ParameterizedMethodBinding createGetClassMethod(TypeBinding receiverType, } return retVal; } - +public ReferenceBinding createMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) { + return this.typeSystem.getMemberType(memberType, enclosingType); +} public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) { - return this.typeSystem.getParameterizedType(genericType, typeArguments, enclosingType, Binding.NO_ANNOTATIONS); + return this.typeSystem.getParameterizedType(genericType, typeArguments, null, -1, enclosingType); +} + +public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { + return this.typeSystem.getParameterizedType(genericType, typeArguments, null, -1, enclosingType, annotations); } //{ObjectTeams: for anchored role types: @@ -1218,11 +1244,19 @@ public TypeBinding createAnnotatedType(TypeBinding type, AnnotationBinding[] new } public RawTypeBinding createRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) { - return this.typeSystem.getRawType(genericType, enclosingType, Binding.NO_ANNOTATIONS); + return this.typeSystem.getRawType(genericType, enclosingType); +} + +public RawTypeBinding createRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding [] annotations) { + return this.typeSystem.getRawType(genericType, enclosingType, annotations); } public WildcardBinding createWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) { - return this.typeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind, Binding.NO_ANNOTATIONS); + return this.typeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind); +} + +public WildcardBinding createWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding [] annotations) { + return this.typeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind, annotations); } /** @@ -1255,8 +1289,10 @@ public ReferenceBinding getCachedType(char[][] compoundName) { } public AnnotationBinding getNullableAnnotation() { + if (this.nullableAnnotation != null) + return this.nullableAnnotation; ReferenceBinding nullable = getResolvedType(this.globalOptions.nullableAnnotationName, null); - return new AnnotationBinding(nullable, Binding.NO_ELEMENT_VALUE_PAIRS); + return this.nullableAnnotation = this.typeSystem.getAnnotationType(nullable, true); } public char[][] getNullableAnnotationName() { @@ -1264,8 +1300,18 @@ public char[][] getNullableAnnotationName() { } public AnnotationBinding getNonNullAnnotation() { + if (this.nonNullAnnotation != null) + return this.nonNullAnnotation; ReferenceBinding nonNull = getResolvedType(this.globalOptions.nonNullAnnotationName, null); - return new AnnotationBinding(nonNull, Binding.NO_ELEMENT_VALUE_PAIRS); + return this.nonNullAnnotation = this.typeSystem.getAnnotationType(nonNull, true); +} + +public AnnotationBinding[] nullAnnotationsFromTagBits(long nullTagBits) { + if (nullTagBits == TagBits.AnnotationNonNull) + return new AnnotationBinding[] { getNonNullAnnotation() }; + else if (nullTagBits == TagBits.AnnotationNullable) + return new AnnotationBinding[] { getNullableAnnotation() }; + return null; } public char[][] getNonNullAnnotationName() { @@ -1521,7 +1567,7 @@ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean i start++; dimension++; } - // null annotations on dimensions? + // annotations on dimensions? AnnotationBinding [][] annotationsOnDimensions = null; if (dimension > 0 && walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { for (int i = 0; i < dimension; i++) { @@ -1577,16 +1623,27 @@ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean i binding = getTypeFromConstantPoolName(signature, start + 1, end, isParameterized, missingTypeNames); // skip leading 'L' or 'T' } - int depth = binding.depth(); - while (depth > 0 && walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { // we are dropping annotations on enclosing types. - walker = walker.toNextNestedType(); - depth--; + if (isParameterized) { + if (dimension != 0) + throw new IllegalStateException(); + return binding; } - AnnotationBinding [][] annotations = new AnnotationBinding[depth + 1][]; - annotations[depth] = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); - if (annotations[depth] != null && annotations[depth] != Binding.NO_ANNOTATIONS) - binding = createAnnotatedType(binding, annotations); + if (walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { + final int depth = binding.depth(); + AnnotationBinding [][] annotations = null; + for (int i = 0; i <= depth; i++) { + AnnotationBinding[] annots = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + if (annots != null && annots.length > 0) { + if (annotations == null) + annotations = new AnnotationBinding[depth + 1][]; + annotations[i] = annots; + } + walker = walker.toNextNestedType(); + } + if (annotations != null) + binding = createAnnotatedType(binding, annotations); + } if (dimension != 0) binding = this.typeSystem.getArrayType(binding, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions)); @@ -1622,12 +1679,25 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab wrapper.start++; dimension++; } + // annotations on dimensions? + AnnotationBinding [][] annotationsOnDimensions = null; + if (dimension > 0 && walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { + for (int i = 0; i < dimension; i++) { + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); + if (annotations != Binding.NO_ANNOTATIONS) { + if (annotationsOnDimensions == null) + annotationsOnDimensions = new AnnotationBinding[dimension][]; + annotationsOnDimensions[i] = annotations; + } + walker = walker.toNextArrayDimension(); + } + } if (wrapper.signature[wrapper.start] == 'T') { int varStart = wrapper.start + 1; int varEnd = wrapper.computeEnd(); for (int i = staticVariables.length; --i >= 0;) if (CharOperation.equals(staticVariables[i].sourceName, wrapper.signature, varStart, varEnd)) - return typeFromTypeVariable(staticVariables[i], dimension, walker, missingTypeNames); + return getTypeFromTypeVariable(staticVariables[i], dimension, annotationsOnDimensions, walker, missingTypeNames); ReferenceBinding initialType = enclosingType; do { TypeVariableBinding[] enclosingTypeVariables; @@ -1638,7 +1708,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab } for (int i = enclosingTypeVariables.length; --i >= 0;) if (CharOperation.equals(enclosingTypeVariables[i].sourceName, wrapper.signature, varStart, varEnd)) - return typeFromTypeVariable(enclosingTypeVariables[i], dimension, walker, missingTypeNames); + return getTypeFromTypeVariable(enclosingTypeVariables[i], dimension, annotationsOnDimensions, walker, missingTypeNames); } while ((enclosingType = enclosingType.enclosingType()) != null); this.problemReporter.undefinedTypeVariableSignature(CharOperation.subarray(wrapper.signature, varStart, varEnd), initialType); return null; // cannot reach this, since previous problem will abort compilation @@ -1647,7 +1717,7 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab TypeBinding type = getTypeFromSignature(wrapper.signature, wrapper.start, wrapper.computeEnd(), isParameterized = (wrapper.end == wrapper.bracket), enclosingType, missingTypeNames, walker); if (!isParameterized) - return dimension == 0 ? type : createArrayType(type, dimension); + return dimension == 0 ? type : createArrayType(type, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions)); // type must be a ReferenceBinding at this point, cannot be a BaseTypeBinding or ArrayTypeBinding ReferenceBinding actualType = (ReferenceBinding) type; @@ -1658,8 +1728,9 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab if (actualEnclosing != null) { // convert needed if read some static member type actualEnclosing = (ReferenceBinding) convertToRawType(actualEnclosing, false /*do not force conversion of enclosing types*/); } + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); TypeBinding[] typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, actualType, missingTypeNames, walker); - ParameterizedTypeBinding parameterizedType = createParameterizedType(actualType, typeArguments, actualEnclosing); + ParameterizedTypeBinding parameterizedType = createParameterizedType(actualType, typeArguments, actualEnclosing, annotations); while (wrapper.signature[wrapper.start] == '.') { wrapper.start++; // skip '.' @@ -1670,37 +1741,25 @@ public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariab // need to protect against the member type being null when the signature is invalid if (memberType == null) this.problemReporter.corruptedSignature(parameterizedType, wrapper.signature, memberStart); // aborts + walker = walker.toNextNestedType(); + annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); if (wrapper.signature[wrapper.start] == '<') { wrapper.start++; // skip '<' typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, memberType, missingTypeNames, walker); } else { typeArguments = null; } - parameterizedType = createParameterizedType(memberType, typeArguments, parameterizedType); + parameterizedType = createParameterizedType(memberType, typeArguments, parameterizedType, annotations); } wrapper.start++; // skip ';' - return dimension == 0 ? (TypeBinding) parameterizedType : createArrayType(parameterizedType, dimension); + return dimension == 0 ? (TypeBinding) parameterizedType : createArrayType(parameterizedType, dimension, AnnotatableTypeSystem.flattenedAnnotations(annotationsOnDimensions)); } -private TypeBinding typeFromTypeVariable(TypeVariableBinding typeVariableBinding, int dimension, TypeAnnotationWalker walker, char [][][] missingTypeNames) { - AnnotationBinding [] annotations; - AnnotationBinding [][] annotationsOnDimensions = null; - if (walker != TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER) { - for (int i = 0; i < dimension; i++) { - annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); - if (annotations != Binding.NO_ANNOTATIONS) { - if (annotationsOnDimensions == null) - annotationsOnDimensions = new AnnotationBinding[dimension][]; - annotationsOnDimensions[i] = annotations; - } - walker = walker.toNextArrayDimension(); - } - } - - annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); +private TypeBinding getTypeFromTypeVariable(TypeVariableBinding typeVariableBinding, int dimension, AnnotationBinding [][] annotationsOnDimensions, TypeAnnotationWalker walker, char [][][] missingTypeNames) { + AnnotationBinding [] annotations = BinaryTypeBinding.createAnnotations(walker.getAnnotationsAtCursor(), this, missingTypeNames); if (annotations != null && annotations != Binding.NO_ANNOTATIONS) typeVariableBinding = (TypeVariableBinding) createAnnotatedType(typeVariableBinding, new AnnotationBinding [][] { annotations }); - + if (dimension == 0) { return typeVariableBinding; } @@ -1857,4 +1916,9 @@ public void addResolutionListener(IQualifiedTypeResolutionListener resolutionLis public TypeBinding getUnannotatedType(TypeBinding typeBinding) { return this.typeSystem.getUnannotatedType(typeBinding); } + +// Given a type, return all its variously annotated versions. +public TypeBinding[] getAnnotatedTypes(TypeBinding type) { + return this.typeSystem.getAnnotatedTypes(type); +} }
\ No newline at end of file diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java index c2dbeef61..a4cefa411 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java @@ -54,6 +54,7 @@ public MemberTypeBinding(MemberTypeBinding prototype) { } void checkSyntheticArgsAndFields() { + if (this != this.prototype) throw new IllegalStateException(); //{ObjectTeams: role ifcs require synth args too /* orig: if (isStatic()) return; @@ -89,10 +90,9 @@ public char[] constantPoolName() /* java/lang/Object */ { return this.constantPoolName = CharOperation.concat(enclosingType().constantPoolName(), this.sourceName, '$'); } -public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { +public TypeBinding clone(TypeBinding outerType) { MemberTypeBinding copy = new MemberTypeBinding(this); - if (outerType != null) - copy.enclosingType = (SourceTypeBinding) outerType; + copy.enclosingType = (SourceTypeBinding) outerType; return copy; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java index 9f3690258..403aaedf3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java @@ -21,6 +21,7 @@ * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults * bug 388281 - [compiler][null] inheritance of null annotations as an option * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper Steen Moller - Contributions for * Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing *******************************************************************************/ @@ -499,9 +500,9 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // Static interface methods can be explicitly invoked only through the type reference of the declaring interface or implicitly in the interface itself. if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) return false; - if (invocationSite.isTypeAccess() && receiverType == this.declaringClass) + if (invocationSite.isTypeAccess() && TypeBinding.equalsEquals(receiverType, this.declaringClass)) return true; - if (invocationSite.receiverIsImplicitThis() && invocationType == this.declaringClass) + if (invocationSite.receiverIsImplicitThis() && TypeBinding.equalsEquals(invocationType, this.declaringClass)) return true; return false; } @@ -536,9 +537,9 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // SH} //{ObjectTeams: use receiverClass: /* orig: - if (invocationType == this.declaringClass && invocationType == receiverType) return true; + if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverType)) return true; :giro */ - if (invocationType == this.declaringClass && invocationType == receiverClass) return true; + if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverClass)) return true; // SH} if (invocationType == null) // static import call @@ -555,7 +556,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // AND the receiverType is the invocationType or its subclass // OR the method is a static method accessed directly through a type // OR previous assertions are true for one of the enclosing type - if (invocationType == this.declaringClass) return true; + if (TypeBinding.equalsEquals(invocationType, this.declaringClass)) return true; if (invocationType.fPackage == this.declaringClass.fPackage) return true; ReferenceBinding currentType = invocationType; @@ -578,7 +579,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca if (depth > 0) invocationSite.setDepth(depth); return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); } - if (currentType == receiverErasure || receiverErasure.findSuperTypeOriginatingFrom(currentType) != null) { + if (TypeBinding.equalsEquals(currentType, receiverErasure) || receiverErasure.findSuperTypeOriginatingFrom(currentType) != null) { if (depth > 0) invocationSite.setDepth(depth); return true; } @@ -600,7 +601,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // answer true if the receiverType is the declaringClass // AND the invocationType and the declaringClass have a common enclosingType receiverCheck: { - if (receiverType != this.declaringClass) { + if (TypeBinding.notEquals(receiverType, this.declaringClass)) { // special tolerance for type variable direct bounds, but only if compliance <= 1.6, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 if (scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_6 && receiverType.isTypeVariable() && ((TypeVariableBinding) receiverType).isErasureBoundTo(this.declaringClass.erasure())) break receiverCheck; @@ -608,7 +609,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca } } - if (invocationType != this.declaringClass) { + if (TypeBinding.notEquals(invocationType, this.declaringClass)) { ReferenceBinding outerInvocationType = invocationType; ReferenceBinding temp = outerInvocationType.enclosingType(); while (temp != null) { @@ -622,7 +623,7 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca outerDeclaringClass = temp; temp = temp.enclosingType(); } - if (outerInvocationType != outerDeclaringClass) return false; + if (TypeBinding.notEquals(outerInvocationType, outerDeclaringClass)) return false; } return true; //{ObjectTeams: reset: @@ -648,9 +649,9 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca // SH} do { if (currentType.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002 - if (originalDeclaringClass == currentType.erasure().original()) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.erasure().original())) return true; } else { - if (originalDeclaringClass == currentType.original()) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.original())) return true; } PackageBinding currentPackage = currentType.fPackage; // package could be null for wildcards/intersection types, ignore and recurse in superclass @@ -907,7 +908,7 @@ protected void fillInDefaultNonNullness(AbstractMethodDeclaration sourceMethod) this.tagBits |= TagBits.HasParameterAnnotations; if ( this.returnType != null && !this.returnType.isBaseType() - && (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) + && (this.tagBits & TagBits.AnnotationNullMASK) == 0) { this.tagBits |= TagBits.AnnotationNonNull; } else if (sourceMethod != null && (this.tagBits & TagBits.AnnotationNonNull) != 0) { @@ -926,8 +927,7 @@ protected void fillInDefaultNonNullness18(AbstractMethodDeclaration sourceMethod if (existing == 0L) { added = true; if (!parameter.isBaseType()) { - // TODO(Stephan): Synthesize AnnotationBinding[] and call LE#createAnnotatedType(TB, AB[]); - // this.parameters[i] = env.createAnnotatedType(parameter, TagBits.AnnotationNonNull); + this.parameters[i] = env.createAnnotatedType(parameter, new AnnotationBinding[]{env.getNonNullAnnotation()}); if (sourceMethod != null) sourceMethod.arguments[i].binding.type = this.parameters[i]; } @@ -939,10 +939,9 @@ protected void fillInDefaultNonNullness18(AbstractMethodDeclaration sourceMethod this.tagBits |= TagBits.HasParameterAnnotations; if ( this.returnType != null && !this.returnType.isBaseType() - && (this.returnType.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) + && (this.returnType.tagBits & TagBits.AnnotationNullMASK) == 0) { - // TODO(Stephan: Synthesize AnnotationBinding[] and call LE#createAnnotatedType(TB, AB[]); - // this.returnType = env.createAnnotatedType(this.returnType, TagBits.AnnotationNonNull); + this.returnType = env.createAnnotatedType(this.returnType, new AnnotationBinding[]{env.getNonNullAnnotation()}); } else if (sourceMethod != null && (this.returnType.tagBits & TagBits.AnnotationNonNull) != 0) { sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, -1/*signifies method return*/); } @@ -1711,7 +1710,7 @@ public final char[] signature(ClassFile classFile) { } //{ObjectTeams: 'weaken' to that erasure that was used in the tsuper version: /* orig: - buffer.append(this.returnType.signature()); + buffer.append(this.returnType.signature()); :giro */ buffer.append(getCodeGenType(-1).signature()); // SH} @@ -1782,6 +1781,7 @@ public String toString(boolean showModifiers) { } //{ObjectTeams: print only conditionally: if (showModifiers) +// SH} ASTNode.printModifiers(this.modifiers, output); output.append(this.returnType != null ? this.returnType.debugName() : "<no type>"); //$NON-NLS-1$ output.append(" "); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java index 46b28059b..3281d4393 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java @@ -43,10 +43,6 @@ public MissingTypeBinding(PackageBinding packageBinding, char[][] compoundName, this.methods = Binding.NO_METHODS; } -public MissingTypeBinding(MissingTypeBinding prototype) { - super(prototype); -} - //{ObjectTeams: missing o.o.Team cannot be further initialized: @Override protected void setupOrgObjectteamsTeamModel() { @@ -55,14 +51,6 @@ protected void setupOrgObjectteamsTeamModel() { } // SH} -public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { - MissingTypeBinding copy = new MissingTypeBinding(this); - copy.enclosingType = (ReferenceBinding) outerType; // for better or worse. - return copy; -} -public TypeBinding unannotated() { - return this.prototype; -} /** * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#collectMissingTypes(java.util.List) */ @@ -90,13 +78,10 @@ public int problemId() { * @see LookupEnvironment#createMissingType(PackageBinding, char[][]) */ void setMissingSuperclass(ReferenceBinding missingSuperclass) { - if (this != this.prototype) { - ((MissingTypeBinding) this.prototype).setMissingSuperclass(missingSuperclass); - } this.superclass = missingSuperclass; } public String toString() { - return this.hasTypeAnnotations() ? annotatedDebugName() + " (missing)" : "[MISSING:" + new String(CharOperation.concatWith(this.compoundName, '.')) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ -} + return "[MISSING:" + new String(CharOperation.concatWith(this.compoundName, '.')) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java index aa1f04403..97d4c3ccc 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java @@ -4,6 +4,10 @@ * 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 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. * * Contributors: * IBM Corporation - initial API and implementation @@ -46,6 +50,9 @@ public NestedTypeBinding(NestedTypeBinding prototype) { * Answer the new argument or the existing argument if one already existed. */ public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + + if (this != this.prototype) throw new IllegalStateException(); + SyntheticArgumentBinding synthLocal = null; if (this.outerLocalVariables == null) { @@ -76,6 +83,7 @@ public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actual * Answer the new argument or the existing argument if one already existed. */ public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding targetEnclosingType) { + if (this != this.prototype) throw new IllegalStateException(); SyntheticArgumentBinding synthLocal = null; if (this.enclosingInstances == null) { synthLocal = new SyntheticArgumentBinding(targetEnclosingType); @@ -100,6 +108,7 @@ public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding targetEncl * Answer the new argument or the existing argument if one already existed. */ public SyntheticArgumentBinding addSyntheticArgumentAndField(LocalVariableBinding actualOuterLocalVariable) { + if (this != this.prototype) throw new IllegalStateException(); SyntheticArgumentBinding synthLocal = addSyntheticArgument(actualOuterLocalVariable); if (synthLocal == null) return null; @@ -112,6 +121,7 @@ public SyntheticArgumentBinding addSyntheticArgumentAndField(LocalVariableBindin * Answer the new argument or the existing argument if one already existed. */ public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding targetEnclosingType) { + if (this != this.prototype) throw new IllegalStateException(); SyntheticArgumentBinding synthLocal = addSyntheticArgument(targetEnclosingType); if (synthLocal == null) return null; @@ -121,6 +131,7 @@ public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding ta } protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) { + if (this != this.prototype) throw new IllegalStateException(); ReferenceBinding currentType = this.enclosingType; do { if (!((SourceTypeBinding)currentType).checkRedundantNullnessDefaultOne(location, annotations, annotationTagBits)) { @@ -141,6 +152,7 @@ public ReferenceBinding enclosingType() { * @return the enclosingInstancesSlotSize */ public int getEnclosingInstancesSlotSize() { + if (this != this.prototype) throw new IllegalStateException(); return this.enclosingInstances == null ? 0 : this.enclosingInstances.length; } @@ -148,6 +160,7 @@ public int getEnclosingInstancesSlotSize() { * @return the outerLocalVariablesSlotSize */ public int getOuterLocalVariablesSlotSize() { + if (this != this.prototype) throw new IllegalStateException(); if (this.outerLocalVariablesSlotSize < 0) { this.outerLocalVariablesSlotSize = 0; int outerLocalsCount = this.outerLocalVariables == null ? 0 : this.outerLocalVariables.length; @@ -170,6 +183,7 @@ public int getOuterLocalVariablesSlotSize() { /* Answer the synthetic argument for <actualOuterLocalVariable> or null if one does not exist. */ public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { + if (this != this.prototype) throw new IllegalStateException(); if (this.outerLocalVariables == null) return null; // is null if no outer local variables are known for (int i = this.outerLocalVariables.length; --i >= 0;) if (this.outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) @@ -180,6 +194,9 @@ public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actual /* Answer the synthetic argument for <targetEnclosingType> or null if one does not exist. */ public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean scopeIsConstructorCall) { + + if (this != this.prototype) throw new IllegalStateException(); + if (this.enclosingInstances == null) return null; // is null if no enclosing instances are known // exact match @@ -218,10 +235,12 @@ public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEncl } public SyntheticArgumentBinding[] syntheticEnclosingInstances() { + if (this != this.prototype) throw new IllegalStateException(); return this.enclosingInstances; // is null if no enclosing instances are required } public ReferenceBinding[] syntheticEnclosingInstanceTypes() { + if (this != this.prototype) throw new IllegalStateException(); if (this.enclosingTypes == UNINITIALIZED_REFERENCE_TYPES) { //{ObjectTeams: enclosing instances of local types are set during analyzeCode: if (this.isLocalType()) @@ -241,6 +260,7 @@ public ReferenceBinding[] syntheticEnclosingInstanceTypes() { } public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { + if (this != this.prototype) throw new IllegalStateException(); return this.outerLocalVariables; // is null if no outer locals are required } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java index 0c6cd255e..cab1ec097 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -1,10 +1,13 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 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 - * $Id: PackageBinding.java 23405 2010-02-03 17:02:18Z stephan $ + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. * * Contributors: * IBM Corporation - initial API and implementation @@ -79,7 +82,11 @@ void addType(ReferenceBinding element) { if ((element.tagBits & TagBits.HasMissingType) == 0) clearMissingTagBit(); if (this.knownTypes == null) this.knownTypes = new HashtableOfType(25); - this.knownTypes.put(element.compoundName[element.compoundName.length - 1], element); + char [] name = element.compoundName[element.compoundName.length - 1]; + ReferenceBinding priorType = this.knownTypes.getput(name, element); + if (priorType != null && priorType.isUnresolvedType() && !element.isUnresolvedType()) { + ((UnresolvedReferenceBinding) priorType).setResolvedType(element, this.environment); + } if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) if (element.isAnnotationType() || element instanceof UnresolvedReferenceBinding) // unresolved types don't yet have the modifiers set checkIfNullAnnotationType(element); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java index cbce3ddc7..621fa2b48 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java @@ -569,7 +569,7 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin return Scope.substitute(new LingeringTypeVariableEliminator(this.variables, null, this.scope), this.substitutes[typeVariable.rank]); } ReferenceBinding genericType = (ReferenceBinding) (typeVariable.declaringElement instanceof ReferenceBinding ? typeVariable.declaringElement : null); - return this.scope.environment().createWildcard(genericType, typeVariable.rank, null, null, Wildcard.UNBOUND); + return this.scope.environment().createWildcard(genericType, typeVariable.rank, null, null, Wildcard.UNBOUND, typeVariable.getTypeAnnotations()); } public LookupEnvironment environment() { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java index 3c235005a..653f0cf68 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java @@ -17,9 +17,11 @@ * bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; +import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel; @@ -106,25 +108,27 @@ public class ParameterizedMethodBinding extends MethodBinding { TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass); ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces); if (originalVariable.firstBound != null) { - substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass + TypeBinding firstBound; + firstBound = originalVariable.firstBound == originalVariable.superclass ? substitutedSuperclass // could be array type or interface : substitutedInterfaces[0]; + substitutedVariable.setFirstBound(firstBound); } switch (substitutedSuperclass.kind()) { case Binding.ARRAY_TYPE : - substitutedVariable.superclass = parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); + substitutedVariable.setSuperInterfaces(substitutedInterfaces); break; default: if (substitutedSuperclass.isInterface()) { - substitutedVariable.superclass = parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); + substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); int interfaceCount = substitutedInterfaces.length; System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount); substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass; - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } else { - substitutedVariable.superclass = (ReferenceBinding) substitutedSuperclass; // typeVar was extending other typeVar which got substituted with interface - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } } } @@ -138,14 +142,14 @@ public class ParameterizedMethodBinding extends MethodBinding { // after substitution transfer nullness information from type annotations: if (parameterizedDeclaringClass.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { - long returnNullBits = this.returnType.tagBits & TagBits.AnnotationNullMASK; + long returnNullBits = NullAnnotationMatching.validNullTagBits(this.returnType.tagBits); if (returnNullBits != 0L) { this.tagBits &= ~TagBits.AnnotationNullMASK; this.tagBits |= returnNullBits; } int parametersLen = this.parameters.length; for (int i=0; i<parametersLen; i++) { - long paramTagBits = this.parameters[i].tagBits & TagBits.AnnotationNullMASK; + long paramTagBits = NullAnnotationMatching.validNullTagBits(this.parameters[i].tagBits); if (paramTagBits != 0) { if (this.parameterNonNullness == null) this.parameterNonNullness = new Boolean[parametersLen]; @@ -246,25 +250,27 @@ public class ParameterizedMethodBinding extends MethodBinding { TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass); ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces); if (originalVariable.firstBound != null) { - substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass + TypeBinding firstBound; + firstBound = originalVariable.firstBound == originalVariable.superclass ? substitutedSuperclass // could be array type or interface : substitutedInterfaces[0]; + substitutedVariable.setFirstBound(firstBound); } switch (substitutedSuperclass.kind()) { case Binding.ARRAY_TYPE : - substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass(environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); + substitutedVariable.setSuperInterfaces(substitutedInterfaces); break; default: if (substitutedSuperclass.isInterface()) { - substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); + substitutedVariable.setSuperClass(environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); int interfaceCount = substitutedInterfaces.length; System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount); substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass; - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } else { - substitutedVariable.superclass = (ReferenceBinding) substitutedSuperclass; // typeVar was extending other typeVar which got substituted with interface - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java index c2887368f..52f873362 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java @@ -71,14 +71,6 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi public ParameterizedTypeBinding(ReferenceBinding type, TypeBinding[] arguments, ReferenceBinding enclosingType, LookupEnvironment environment){ this.environment = environment; this.enclosingType = enclosingType; // never unresolved, never lazy per construction -// if (enclosingType != null && enclosingType.isGenericType()) { -// RuntimeException e = new RuntimeException("PARAM TYPE with GENERIC ENCLOSING"); -// e.printStackTrace(); -// throw e; -// } -// if (!(type instanceof UnresolvedReferenceBinding) && type.typeVariables() == Binding.NO_TYPE_VARIABLES) { -// System.out.println(); -// } initialize(type, arguments); if (type instanceof UnresolvedReferenceBinding) ((UnresolvedReferenceBinding) type).addWrapper(this, environment); @@ -178,7 +170,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi capturedArguments[i] = argument; } } - ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType()); + ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType(), this.typeAnnotations); for (int i = 0; i < length; i++) { TypeBinding argument = capturedArguments[i]; if (argument.isCapture()) { @@ -372,11 +364,8 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi return this.type.constantPoolName(); // erasure } - public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { - ParameterizedTypeBinding copy = new ParameterizedTypeBinding(this.type, typeArguments, (ReferenceBinding) outerType, this.environment); - if (this.hasTypeAnnotations()) - copy.setTypeAnnotations(this.getTypeAnnotations(), this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); - return copy; + public TypeBinding clone(TypeBinding outerType) { + return new ParameterizedTypeBinding(this.type, this.arguments, (ReferenceBinding) outerType, this.environment); } public ParameterizedMethodBinding createParameterizedMethod(MethodBinding originalMethod) { @@ -851,7 +840,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi case Binding.PARAMETERIZED_TYPE : ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType; - if (this.type != otherParamType.type) + if (TypeBinding.notEquals(this.type, otherParamType.type)) return false; if (!isStatic()) { // static member types do not compare their enclosing ReferenceBinding enclosing = enclosingType(); @@ -859,7 +848,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi ReferenceBinding otherEnclosing = otherParamType.enclosingType(); if (otherEnclosing == null) return false; if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) { - if (enclosing != otherEnclosing) return false; + if (TypeBinding.notEquals(enclosing, otherEnclosing)) return false; } else { if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false; } @@ -874,9 +863,6 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi for (int i = 0; i < length; i++) { if (!this.arguments[i].isTypeArgumentContainedBy(otherArguments[i])) return false; - // Stephan : is this intentional ?? -// if ((this.arguments[i].tagBits & TagBits.AnnotationNullMASK) != (otherArguments[i].tagBits & TagBits.AnnotationNullMASK)) -// return false; } return true; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java index caf7fff29..4013dc59d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java @@ -77,11 +77,8 @@ public class RawTypeBinding extends ParameterizedTypeBinding { return uniqueKey; } - public TypeBinding clone(TypeBinding outerType, TypeBinding[] typeArguments) { - RawTypeBinding copy = new RawTypeBinding(this.actualType(), (ReferenceBinding) outerType, this.environment); - if (this.hasTypeAnnotations()) - copy.setTypeAnnotations(this.getTypeAnnotations(), this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); - return copy; + public TypeBinding clone(TypeBinding outerType) { + return new RawTypeBinding(this.actualType(), (ReferenceBinding) outerType, this.environment); } /** diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java index 6b4ee908a..e1c7e1da3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -31,6 +31,7 @@ * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables * Jesper S Moller - Contributions for * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression + * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -408,7 +409,7 @@ public final boolean canBeSeenBy(PackageBinding invocationPackage) { public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding invocationType) { if (isPublic()) return true; - if (invocationType == this && invocationType == receiverType) return true; + if (TypeBinding.equalsEquals(invocationType, this) && TypeBinding.equalsEquals(invocationType, receiverType)) return true; if (isProtected()) { // answer true if the invocationType is the declaringClass or they are in the same package @@ -416,12 +417,12 @@ public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding // AND the invocationType is the invocationType or its subclass // OR the type is a static method accessed directly through a type // OR previous assertions are true for one of the enclosing type - if (invocationType == this) return true; + if (TypeBinding.equalsEquals(invocationType, this)) return true; if (invocationType.fPackage == this.fPackage) return true; TypeBinding currentType = invocationType.erasure(); TypeBinding declaringClass = enclosingType().erasure(); // protected types always have an enclosing one - if (declaringClass == invocationType) return true; + if (TypeBinding.equalsEquals(declaringClass, invocationType)) return true; if (declaringClass == null) return false; // could be null if incorrect top-level protected type //int depth = 0; do { @@ -436,7 +437,7 @@ public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding // answer true if the receiverType is the receiver or its enclosingType // AND the invocationType and the receiver have a common enclosingType receiverCheck: { - if (!(receiverType == this || receiverType == enclosingType())) { + if (!(TypeBinding.equalsEquals(receiverType, this) || TypeBinding.equalsEquals(receiverType, enclosingType()))) { // special tolerance for type variable direct bounds, but only if compliance <= 1.6, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622 if (receiverType.isTypeVariable()) { TypeVariableBinding typeVariable = (TypeVariableBinding) receiverType; @@ -447,7 +448,7 @@ public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding } } - if (invocationType != this) { + if (TypeBinding.notEquals(invocationType, this)) { ReferenceBinding outerInvocationType = invocationType; ReferenceBinding temp = outerInvocationType.enclosingType(); while (temp != null) { @@ -461,7 +462,7 @@ public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding outerDeclaringClass = temp; temp = temp.enclosingType(); } - if (outerInvocationType != outerDeclaringClass) return false; + if (TypeBinding.notEquals(outerInvocationType, outerDeclaringClass)) return false; } return true; } @@ -473,9 +474,9 @@ public final boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding TypeBinding originalDeclaringClass = (enclosingType() == null ? this : enclosingType()).original(); do { if (currentType.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002 - if (originalDeclaringClass == currentType.erasure().original()) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.erasure().original())) return true; } else { - if (equalsEquals(originalDeclaringClass, currentType.original())) return true; + if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.original())) return true; } PackageBinding currentPackage = currentType.fPackage; // package could be null for wildcards/intersection types, ignore and recurse in superclass @@ -882,6 +883,10 @@ public void computeId() { if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_RETENTION[3])) this.id = TypeIds.T_JavaLangAnnotationRetention; return; + case 10 : + if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_REPEATABLE[3])) + this.id = TypeIds.T_JavaLangAnnotationRepeatable; + return; case 15 : if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY[3])) this.id = TypeIds.T_JavaLangAnnotationRetentionPolicy; @@ -1598,7 +1603,7 @@ public void resetIncompatibleTypes() { //{ObjectTeams: new parameter useObjectShortcut private boolean isCompatibleWith0(TypeBinding otherType, boolean useObjectShortcut, /*@Nullable*/ Scope captureScope) { // SH} - if (otherType == this) + if (TypeBinding.equalsEquals(otherType, this)) return true; //{ObjectTeams: respect new param: /*orig: @@ -1635,7 +1640,7 @@ private boolean isCompatibleWith0(TypeBinding otherType, boolean useObjectShortc case Binding.GENERIC_TYPE : case Binding.PARAMETERIZED_TYPE : case Binding.RAW_TYPE : - if (erasure() == otherType.erasure()) + if (TypeBinding.equalsEquals(erasure(), otherType.erasure())) return false; // should have passed equivalence check // above if same erasure } @@ -1765,6 +1770,13 @@ public final boolean isPublic() { } /** + * Answer true if the receiver is an annotation which may be repeatable. Overridden as appropriate. + */ +public boolean isRepeatableAnnotation() { + return false; +} + +/** * Answer true if the receiver is a static member type (or toplevel) */ public final boolean isStatic() { @@ -1928,6 +1940,10 @@ public char[] readableName() /*java.lang.Object, p.X<T> */ { return readableName; } +public ReferenceBinding resolveContainerAnnotation() { + return null; +} + protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) { if (options.isAnnotationBasedNullAnalysisEnabled) { // restore applied null annotation from tagBits: @@ -1957,6 +1973,9 @@ AnnotationBinding[] retrieveAnnotations(Binding binding) { public void setAnnotations(AnnotationBinding[] annotations) { storeAnnotations(this, annotations); } +public void setContainingAnnotation(ReferenceBinding value) { + // Leave this to subclasses +} /** * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#nullAnnotatedReadableName(CompilerOptions,boolean) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java index 64d023834..50b9573e6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -491,13 +491,13 @@ public abstract class Scope { substitutedEnclosing = (ReferenceBinding) substitute(substitution, originalEnclosing); if (isMemberTypeOfRaw(originalType, substitutedEnclosing)) return originalParameterizedType.environment.createRawType( - originalParameterizedType.genericType(), substitutedEnclosing); + originalParameterizedType.genericType(), substitutedEnclosing, originalType.getTypeAnnotations()); } TypeBinding[] originalArguments = originalParameterizedType.arguments; TypeBinding[] substitutedArguments = originalArguments; if (originalArguments != null) { if (substitution.isRawSubstitution()) { - return originalParameterizedType.environment.createRawType(originalParameterizedType.genericType(), substitutedEnclosing); + return originalParameterizedType.environment.createRawType(originalParameterizedType.genericType(), substitutedEnclosing, originalType.getTypeAnnotations()); } substitutedArguments = substitute(substitution, originalArguments); } @@ -510,16 +510,16 @@ public abstract class Scope { } // SH} return originalParameterizedType.environment.createParameterizedType( - originalParameterizedType.genericType(), substitutedArguments, substitutedEnclosing); + originalParameterizedType.genericType(), substitutedArguments, substitutedEnclosing, originalType.getTypeAnnotations()); } break; case Binding.ARRAY_TYPE: ArrayBinding originalArrayType = (ArrayBinding) originalType; TypeBinding originalLeafComponentType = originalArrayType.leafComponentType; - TypeBinding substitute = substitute(substitution, originalLeafComponentType); // substitute could itself be array type + TypeBinding substitute = substitute(substitution, originalLeafComponentType); // substitute could itself be array type, TODO(Srikanth): need a test case. if (substitute != originalLeafComponentType) { - return originalArrayType.environment.createArrayType(substitute.leafComponentType(), substitute.dimensions() + originalType.dimensions()); + return originalArrayType.environment.createArrayType(substitute.leafComponentType(), substitute.dimensions() + originalType.dimensions(), originalType.getTypeAnnotations()); } break; @@ -550,7 +550,7 @@ public abstract class Scope { } } } - return wildcard.environment.createWildcard(wildcard.genericType, wildcard.rank, substitutedBound, substitutedOtherBounds, wildcard.boundKind); + return wildcard.environment.createWildcard(wildcard.genericType, wildcard.rank, substitutedBound, substitutedOtherBounds, wildcard.boundKind, wildcard.getTypeAnnotations()); } } break; @@ -563,14 +563,14 @@ public abstract class Scope { if (originalEnclosing != null) { substitutedEnclosing = (ReferenceBinding) substitute(substitution, originalEnclosing); if (isMemberTypeOfRaw(originalType, substitutedEnclosing)) - return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing); + return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing, originalType.getTypeAnnotations()); } // treat as if parameterized with its type variables (non generic type gets 'null' arguments) if (substitutedEnclosing != originalEnclosing) { return substitution.isRawSubstitution() - ? substitution.environment().createRawType(originalReferenceType, substitutedEnclosing) - : substitution.environment().createParameterizedType(originalReferenceType, null, substitutedEnclosing); + ? substitution.environment().createRawType(originalReferenceType, substitutedEnclosing, originalType.getTypeAnnotations()) + : substitution.environment().createParameterizedType(originalReferenceType, null, substitutedEnclosing, originalType.getTypeAnnotations()); } break; case Binding.GENERIC_TYPE: @@ -580,16 +580,16 @@ public abstract class Scope { if (originalEnclosing != null) { substitutedEnclosing = (ReferenceBinding) substitute(substitution, originalEnclosing); if (isMemberTypeOfRaw(originalType, substitutedEnclosing)) - return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing); + return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing, originalType.getTypeAnnotations()); } if (substitution.isRawSubstitution()) { - return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing); + return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing, originalType.getTypeAnnotations()); } // treat as if parameterized with its type variables (non generic type gets 'null' arguments) originalArguments = originalReferenceType.typeVariables(); substitutedArguments = substitute(substitution, originalArguments); - return substitution.environment().createParameterizedType(originalReferenceType, substitutedArguments, substitutedEnclosing); + return substitution.environment().createParameterizedType(originalReferenceType, substitutedArguments, substitutedEnclosing, originalType.getTypeAnnotations()); } return originalType; } @@ -798,10 +798,10 @@ public abstract class Scope { TypeVariableBinding typeVariable = typeParameter.binding; if (typeVariable == null) return false; - typeVariable.superclass = getJavaLangObject(); - typeVariable.superInterfaces = Binding.NO_SUPERINTERFACES; + typeVariable.setSuperClass(getJavaLangObject()); + typeVariable.setSuperInterfaces(Binding.NO_SUPERINTERFACES); // set firstBound to the binding of the first explicit bound in parameter declaration - typeVariable.firstBound = null; // first bound used to compute erasure + typeVariable.setFirstBound(null); // first bound used to compute erasure } nextVariable: for (int i = 0; i < paramLength; i++) { TypeParameter typeParameter = typeParameters[i]; @@ -883,12 +883,12 @@ public abstract class Scope { } else // SH} if (!superType.isInterface()) { - typeVariable.superclass = superRefType; + typeVariable.setSuperClass(superRefType); } else { - typeVariable.superInterfaces = new ReferenceBinding[] {superRefType}; + typeVariable.setSuperInterfaces(new ReferenceBinding[] {superRefType}); } typeVariable.tagBits |= superType.tagBits & TagBits.ContainsNestedTypeReferences; - typeVariable.firstBound = superRefType; // first bound used to compute erasure + typeVariable.setFirstBound(superRefType); // first bound used to compute erasure } } TypeReference[] boundRefs = typeParameter.bounds; @@ -946,7 +946,7 @@ public abstract class Scope { } } int size = typeVariable.superInterfaces.length; - System.arraycopy(typeVariable.superInterfaces, 0, typeVariable.superInterfaces = new ReferenceBinding[size + 1], 0, size); + System.arraycopy(typeVariable.superInterfaces, 0, typeVariable.setSuperInterfaces(new ReferenceBinding[size + 1]), 0, size); typeVariable.superInterfaces[size] = superRefType; } } @@ -961,8 +961,12 @@ public abstract class Scope { } public ArrayBinding createArrayType(TypeBinding type, int dimension) { + return createArrayType(type, dimension, Binding.NO_ANNOTATIONS); + } + + public ArrayBinding createArrayType(TypeBinding type, int dimension, AnnotationBinding[] annotations) { if (type.isValidBinding()) - return environment().createArrayType(type, dimension); + return environment().createArrayType(type, dimension, annotations); // do not cache obvious invalid types return new ArrayBinding(type, dimension, environment()); } @@ -4921,25 +4925,27 @@ public abstract class Scope { TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass); ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces); if (originalVariable.firstBound != null) { - substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass + TypeBinding firstBound; + firstBound = originalVariable.firstBound == originalVariable.superclass ? substitutedSuperclass // could be array type or interface : substitutedInterfaces[0]; + substitutedVariable.setFirstBound(firstBound); } switch (substitutedSuperclass.kind()) { case Binding.ARRAY_TYPE : - substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass(environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); + substitutedVariable.setSuperInterfaces(substitutedInterfaces); break; default: if (substitutedSuperclass.isInterface()) { - substitutedVariable.superclass = environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); + substitutedVariable.setSuperClass(environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null)); int interfaceCount = substitutedInterfaces.length; System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount); substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass; - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } else { - substitutedVariable.superclass = (ReferenceBinding) substitutedSuperclass; // typeVar was extending other typeVar which got substituted with interface - substitutedVariable.superInterfaces = substitutedInterfaces; + substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface + substitutedVariable.setSuperInterfaces(substitutedInterfaces); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index 8247e9771..3e1149edd 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -33,6 +33,9 @@ * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled * Bug 416172 - [1.8][compiler][null] null type annotation not evaluated on method return type + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. + * Jesper S Moller <jesper@selskabet.org> - Contributions for + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -115,18 +118,19 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer; */ @SuppressWarnings("unchecked") public class SourceTypeBinding extends ReferenceBinding { - public ReferenceBinding superclass; - public ReferenceBinding[] superInterfaces; - private FieldBinding[] fields; - private MethodBinding[] methods; - public ReferenceBinding[] memberTypes; + public ReferenceBinding superclass; // MUST NOT be modified directly, use setter ! + public ReferenceBinding[] superInterfaces; // MUST NOT be modified directly, use setter ! + private FieldBinding[] fields; // MUST NOT be modified directly, use setter ! + private MethodBinding[] methods; // MUST NOT be modified directly, use setter ! + public ReferenceBinding[] memberTypes; // MUST NOT be modified directly, use setter ! //{ObjectTeams: initialization added // readableName() will otherwise not work before Scope.buildTypeVariables()! - public TypeVariableBinding[] typeVariables = Binding.NO_TYPE_VARIABLES; + public TypeVariableBinding[] typeVariables = Binding.NO_TYPE_VARIABLES; // MUST NOT be modified directly, use setter ! // SH} public ClassScope scope; protected SourceTypeBinding prototype; + LookupEnvironment environment; // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and bridge methods // if a new category is added, also increment MAX_SYNTHETICS @@ -154,12 +158,13 @@ public class SourceTypeBinding extends ReferenceBinding { protected SourceTypeBinding() { super(); } // default ctor for Singleton membertypes NoBaseclass, ProblemBaseclass //Markus Witte} - + private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder private int defaultNullness; private int nullnessDefaultInitialized = 0; // 0: nothing; 1: type; 2: package private int lambdaOrdinal = 0; + private ReferenceBinding containingAnnotation = null; public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { //{ObjectTeams: // share model from TypeDeclaration: @@ -177,6 +182,7 @@ public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassSc // SH} this.sourceName = scope.referenceContext.name; this.scope = scope; + this.environment = scope.environment(); //{ObjectTeams: ROFI create a package binding for our role files (if any): maybeSetTeamPackage(compoundName, fPackage, scope.environment()); // SH} @@ -190,19 +196,18 @@ public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassSc public SourceTypeBinding(SourceTypeBinding prototype) { super(prototype); + this.prototype = prototype.prototype; - this.compoundName = prototype.compoundName; - this.fPackage = prototype.fPackage; - this.fileName = prototype.fileName; - this.modifiers = prototype.modifiers; - this.sourceName = prototype.sourceName; - + this.prototype.tagBits |= TagBits.HasAnnotatedVariants; + this.tagBits &= ~TagBits.HasAnnotatedVariants; + this.superclass = prototype.superclass; this.superInterfaces = prototype.superInterfaces; this.fields = prototype.fields; this.methods = prototype.methods; this.memberTypes = prototype.memberTypes; this.typeVariables = prototype.typeVariables; + this.environment = prototype.environment; // this.scope = prototype.scope; // Will defeat CompilationUnitDeclaration.cleanUp(TypeDeclaration) && CompilationUnitDeclaration.cleanUp(), so not copied, not an issue for JSR 308. @@ -212,6 +217,8 @@ public SourceTypeBinding(SourceTypeBinding prototype) { this.defaultNullness = prototype.defaultNullness; this.nullnessDefaultInitialized= prototype.nullnessDefaultInitialized; this.lambdaOrdinal = prototype.lambdaOrdinal; + this.containingAnnotation = prototype.containingAnnotation; + this.tagBits |= TagBits.HasUnresolvedMemberTypes; // see memberTypes() //{ObjectTeams: team? if (prototype._teamModel != null) @@ -220,6 +227,9 @@ public SourceTypeBinding(SourceTypeBinding prototype) { } private void addDefaultAbstractMethods() { + + if (this != this.prototype) throw new IllegalStateException(); + if ((this.tagBits & TagBits.KnowsDefaultAbstractMethods) != 0) return; this.tagBits |= TagBits.KnowsDefaultAbstractMethods; @@ -279,7 +289,7 @@ private void addDefaultAbstractMethods() { } if (defaultAbstractsCount > 0) { int length = this.methods.length; - System.arraycopy(this.methods, 0, this.methods = new MethodBinding[length + defaultAbstractsCount], 0, length); + System.arraycopy(this.methods, 0, setMethods(new MethodBinding[length + defaultAbstractsCount]), 0, length); System.arraycopy(defaultAbstracts, 0, this.methods, length, defaultAbstractsCount); // re-sort methods length = length + defaultAbstractsCount; @@ -294,6 +304,9 @@ private void addDefaultAbstractMethods() { * Answer the new field or the existing field if one already existed. */ public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOuterLocalVariable) { + + if (this != this.prototype) throw new IllegalStateException(); + if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) @@ -340,6 +353,9 @@ public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOu * Answer the new field or the existing field if one already existed. */ public FieldBinding addSyntheticFieldForInnerclass(ReferenceBinding enclosingType) { + + if (this != this.prototype) throw new IllegalStateException(); + if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) @@ -457,6 +473,9 @@ final public void computeValueParameterSlotSizes() { * Answer the new field or the existing field if one already existed. */ public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, BlockScope blockScope) { + + if (this != this.prototype) throw new IllegalStateException(); + if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null) @@ -496,6 +515,9 @@ public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, Blo * Answer the new field or the existing field if one already existed. */ public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) { + + if (this != this.prototype) throw new IllegalStateException(); + if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) @@ -540,6 +562,8 @@ public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) { * Answer the new field or the existing field if one already existed. */ public FieldBinding addSyntheticFieldForEnumValues() { + + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) @@ -616,6 +640,7 @@ public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boole :giro*/ public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess, boolean isSuperAccess, boolean externalizedReceiver) { // SH} + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -675,6 +700,7 @@ public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boole * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF */ public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -698,6 +724,7 @@ public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) { * Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type */ public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String key) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) @@ -742,6 +769,7 @@ public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, St * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF */ public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -769,6 +797,7 @@ public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBi return accessMethod; } public SyntheticMethodBinding addSyntheticMethodForEnumInitialization(int begin, int end) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -781,6 +810,7 @@ public SyntheticMethodBinding addSyntheticMethodForEnumInitialization(int begin, return accessMethod; } public SyntheticMethodBinding addSyntheticMethod(LambdaExpression lambda) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -811,6 +841,7 @@ public SyntheticMethodBinding addSyntheticMethod(MethodBinding targetMethod, boo isSuperAccess); } // SH} + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -893,6 +924,7 @@ public SyntheticMethodBinding findOuterRoleMethodSyntheticAccessor(MethodBinding } // SH} public SyntheticMethodBinding addSyntheticArrayMethod(ArrayBinding arrayType, int purpose) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -915,6 +947,7 @@ public SyntheticMethodBinding addSyntheticArrayMethod(ArrayBinding arrayType, in return arrayMethod; } public SyntheticMethodBinding addSyntheticFactoryMethod(MethodBinding privateConstructor, MethodBinding publicConstructor, TypeBinding [] enclosingInstances) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) this.synthetics = new HashMap[MAX_SYNTHETICS]; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) @@ -929,6 +962,7 @@ public SyntheticMethodBinding addSyntheticFactoryMethod(MethodBinding privateCon * Record the fact that bridge methods need to be generated to override certain inherited methods */ public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge, MethodBinding targetMethod) { + if (this != this.prototype) throw new IllegalStateException(); if (isInterface()) return null; // only classes & enums get bridge methods // targetMethod may be inherited //{ObjectTeams: retrieve callin method's real return type: @@ -981,6 +1015,7 @@ public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMe * from a non-public class into a public class (only in 1.6 or greater) */ public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) { + if (this != this.prototype) throw new IllegalStateException(); if (this.scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_5) { return null; } @@ -1033,11 +1068,13 @@ boolean areMethodsInitialized() { return this.methods != Binding.UNINITIALIZED_METHODS; } public int kind() { + if (this != this.prototype) + return this.prototype.kind(); if (this.typeVariables != Binding.NO_TYPE_VARIABLES) return Binding.GENERIC_TYPE; return Binding.TYPE; } -public TypeBinding clone(TypeBinding immaterial, TypeBinding[] irrelevant) { +public TypeBinding clone(TypeBinding immaterial) { return new SourceTypeBinding(this); } @@ -1099,6 +1136,7 @@ public char[] computeUniqueKey(boolean isLeaf) { public // SH} void faultInTypesForFieldsAndMethods() { + if (this != this.prototype) throw new IllegalStateException(); // check @Deprecated annotation getAnnotationTagBits(); // marks as deprecated by side effect ReferenceBinding enclosingType = enclosingType(); @@ -1121,8 +1159,12 @@ void faultInTypesForFieldsAndMethods() { // NOTE: the type of each field of a source type is resolved when needed public FieldBinding[] fields() { - if (this != this.prototype) - return this.prototype.fields(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreFieldsComplete) != 0) + return this.fields; + this.tagBits |= TagBits.AreFieldsComplete; + return this.fields = this.prototype.fields(); + } if ((this.tagBits & TagBits.AreFieldsComplete) != 0) return this.fields; @@ -1173,14 +1215,14 @@ public FieldBinding[] fields() { // ensure fields are consistent reqardless of the error int newSize = resolvedFields.length - failed; if (newSize == 0) - return this.fields = Binding.NO_FIELDS; + return setFields(Binding.NO_FIELDS); FieldBinding[] newFields = new FieldBinding[newSize]; for (int i = 0, j = 0, length = resolvedFields.length; i < length; i++) { if (resolvedFields[i] != null) newFields[j++] = resolvedFields[i]; } - this.fields = newFields; + setFields(newFields); } } this.tagBits |= TagBits.AreFieldsComplete; @@ -1234,6 +1276,8 @@ public char[] genericSignature() { /** * Compute the tagbits for standard annotations. For source types, these could require * lazily resolving corresponding annotation nodes, in case of forward references. + * For type use bindings, this method still returns the tagbits corresponding to the type + * declaration binding. * @see org.eclipse.jdt.internal.compiler.lookup.Binding#getAnnotationTagBits() */ public long getAnnotationTagBits() { @@ -1432,6 +1476,7 @@ public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes //NOTE: the type of a field of a source type is resolved when needed public FieldBinding getField(char[] fieldName, boolean needResolve) { + if (this != this.prototype) return this.prototype.getField(fieldName, needResolve); //{ObjectTeams: could be called before fields are present @@ -1440,7 +1485,7 @@ public FieldBinding getField(char[] fieldName, boolean needResolve) { if (this.fields == Binding.UNINITIALIZED_FIELDS) return null; // SH} - + if ((this.tagBits & TagBits.AreFieldsComplete) != 0) return ReferenceBinding.binarySearch(fieldName, this.fields); @@ -1501,7 +1546,7 @@ public FieldBinding getField(char[] fieldName, boolean needResolve) { // ensure fields are consistent reqardless of the error int newSize = this.fields.length - 1; if (newSize == 0) { - this.fields = Binding.NO_FIELDS; + setFields(Binding.NO_FIELDS); } else { FieldBinding[] newFields = new FieldBinding[newSize]; int index = 0; @@ -1510,7 +1555,7 @@ public FieldBinding getField(char[] fieldName, boolean needResolve) { if (f == field) continue; newFields[index++] = f; } - this.fields = newFields; + setFields(newFields); } } } @@ -1695,6 +1740,7 @@ ReferenceBinding findTypeInTeamPackage(char[] name) { * or null if one does not exist. */ public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null; return (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable); } @@ -1726,7 +1772,7 @@ public FieldBinding getSyntheticClassLiteral(char[] fieldName) { * or null if one does not exist. */ public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) { - + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null; FieldBinding field = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(targetEnclosingType); if (field != null) return field; @@ -1749,6 +1795,7 @@ public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, bool * Answer the bridge method associated for an inherited methods or null if one does not exist */ public SyntheticMethodBinding getSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) { + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) return null; if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) return null; SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge); @@ -1807,6 +1854,11 @@ void initializeForStaticImports() { } private void initializeNullDefault() { + + if (this != this.prototype) { + this.prototype.initializeNullDefault(); + return; + } // ensure nullness defaults are initialized at all enclosing levels: switch (this.nullnessDefaultInitialized) { case 0: @@ -1826,7 +1878,7 @@ public boolean isEquivalentTo(TypeBinding otherType) { if (this != this.prototype) return this.prototype.isEquivalentTo(otherType); - if (this == otherType) return true; + if (TypeBinding.equalsEquals(this, otherType)) return true; if (otherType == null) return false; switch(otherType.kind()) { @@ -1877,9 +1929,22 @@ public boolean isHierarchyConnected() { return this.prototype.isHierarchyConnected(); return (this.tagBits & TagBits.EndHierarchyCheck) != 0; } +public boolean isRepeatableAnnotation() { + if (this != this.prototype) throw new IllegalStateException(); + return this.containingAnnotation != null; +} public ReferenceBinding[] memberTypes() { - if (this != this.prototype) - return this.prototype.memberTypes(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.HasUnresolvedMemberTypes) == 0) + return this.memberTypes; + ReferenceBinding [] members = this.memberTypes = this.prototype.memberTypes(); + int membersLength = members == null ? 0 : members.length; + this.memberTypes = new ReferenceBinding[membersLength]; + for (int i = 0; i < membersLength; i++) { + this.memberTypes[i] = this.environment.createMemberType(members[i], this); + } + this.tagBits &= ~TagBits.HasUnresolvedMemberTypes; + } return this.memberTypes; } @@ -1892,8 +1957,12 @@ public boolean hasMemberTypes() { // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed public MethodBinding[] methods() { - if (this != this.prototype) - return this.prototype.methods(); + if (this != this.prototype) { + if ((this.tagBits & TagBits.AreMethodsComplete) != 0) + return this.methods; + this.tagBits |= TagBits.AreMethodsComplete; + return this.methods = this.prototype.methods(); + } if ((this.tagBits & TagBits.AreMethodsComplete) != 0) return this.methods; @@ -2115,13 +2184,13 @@ public MethodBinding[] methods() { if (failed > 0) { int newSize = resolvedMethods.length - failed; if (newSize == 0) { - this.methods = Binding.NO_METHODS; + setMethods(Binding.NO_METHODS); } else { MethodBinding[] newMethods = new MethodBinding[newSize]; for (int i = 0, j = 0, length = resolvedMethods.length; i < length; i++) if (resolvedMethods[i] != null) newMethods[j++] = resolvedMethods[i]; - this.methods = newMethods; + setMethods(newMethods); } } @@ -2131,6 +2200,21 @@ public MethodBinding[] methods() { } return this.methods; } + +public TypeBinding prototype() { + return this.prototype; +} + +public ReferenceBinding resolveContainerAnnotation() { + + if (this != this.prototype) throw new IllegalStateException(); + + if (this.containingAnnotation instanceof UnresolvedReferenceBinding) { + this.containingAnnotation = (ReferenceBinding)BinaryTypeBinding.resolveType(this.containingAnnotation, this.scope.environment(), false); + } + return this.containingAnnotation; +} + public FieldBinding resolveTypeFor(FieldBinding field) { if (this != this.prototype) @@ -2192,12 +2276,12 @@ public FieldBinding resolveTypeFor(FieldBinding field) { if (sourceLevel >= ClassFileConstants.JDK1_8) { AnnotationBinding [] annotations = field.getAnnotations(); if (annotations != null && annotations != Binding.NO_ANNOTATIONS) { - ASTNode.copySE8AnnotationsToType(initializationScope, field, annotations); + ASTNode.copySE8AnnotationsToType(initializationScope, field, fieldDecl.annotations); } + Annotation.isTypeUseCompatible(fieldDecl.type, this.scope, fieldDecl.annotations); } // apply null default: - LookupEnvironment environment = this.scope.environment(); - if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { + if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { // TODO(SH): different strategy for 1.8, or is "repair" below enough? if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { // enum constants neither have a type declaration nor can they be null @@ -2422,6 +2506,7 @@ public MethodBinding resolveTypesFor(MethodBinding method, boolean fromSynthetic if (parameterType != null && !parameterType.isValidBinding() && ((parameterType.tagBits & TagBits.HasMissingType) == 0)) foundArgProblem = true; // SH} + if (parameterType == null) { foundArgProblem = true; } else if (parameterType == TypeBinding.VOID) { @@ -2523,9 +2608,10 @@ public MethodBinding resolveTypesFor(MethodBinding method, boolean fromSynthetic if (sourceLevel >= ClassFileConstants.JDK1_8) { AnnotationBinding [] annotations = method.getAnnotations(); if (annotations != null && annotations != Binding.NO_ANNOTATIONS) { - ASTNode.copySE8AnnotationsToType(methodDecl.scope, method, annotations); + ASTNode.copySE8AnnotationsToType(methodDecl.scope, method, methodDecl.annotations); } } + Annotation.isTypeUseCompatible(returnType, this.scope, methodDecl.annotations); TypeBinding leafType = methodType.leafComponentType(); if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) method.modifiers |= ExtraCompilerModifiers.AccGenericSignature; @@ -2597,7 +2683,7 @@ public MethodBinding resolveTypesFor(MethodBinding method, boolean fromSynthetic return method; } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391108 -private void rejectTypeAnnotatedVoidMethod(AbstractMethodDeclaration methodDecl) { +private static void rejectTypeAnnotatedVoidMethod(AbstractMethodDeclaration methodDecl) { Annotation[] annotations = methodDecl.annotations; int length = annotations == null ? 0 : annotations.length; for (int i = 0; i < length; i++) { @@ -2609,7 +2695,11 @@ private void rejectTypeAnnotatedVoidMethod(AbstractMethodDeclaration methodDecl) } } } + private void createArgumentBindings(MethodBinding method, CompilerOptions compilerOptions) { + + if (this != this.prototype) throw new IllegalStateException(); + initializeNullDefault(); AbstractMethodDeclaration methodDecl = method.sourceMethod(); if (methodDecl != null) { @@ -2624,8 +2714,11 @@ private void createArgumentBindings(MethodBinding method, CompilerOptions compil } } } + private void evaluateNullAnnotations(long annotationTagBits) { + if (this != this.prototype) throw new IllegalStateException(); + if (this.nullnessDefaultInitialized > 0 || !this.scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) return; boolean isPackageInfo = CharOperation.equals(this.sourceName, TypeConstants.PACKAGE_INFO_NAME); @@ -2672,10 +2765,9 @@ private void evaluateNullAnnotations(long annotationTagBits) { } protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) { - if (this != this.prototype) { - this.prototype.checkRedundantNullnessDefaultRecurse(location, annotations, annotationTagBits); - return; - } + + if (this != this.prototype) throw new IllegalStateException(); + if (this.fPackage.defaultNullness != NO_NULL_DEFAULT) { if ((this.fPackage.defaultNullness == NONNULL_BY_DEFAULT && ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0))) { @@ -2687,9 +2779,9 @@ protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation // return: should caller continue searching? protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[] annotations, long annotationTagBits) { - if (this != this.prototype) - return this.prototype.checkRedundantNullnessDefaultOne(location, annotations, annotationTagBits); - + + if (this != this.prototype) throw new IllegalStateException(); + int thisDefault = this.defaultNullness; if (thisDefault == NONNULL_BY_DEFAULT) { if ((annotationTagBits & TagBits.AnnotationNonNullByDefault) != 0) { @@ -2702,9 +2794,8 @@ protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[ boolean hasNonNullDefault() { - if (this != this.prototype) - return this.prototype.hasNonNullDefault(); - + if (this != this.prototype) throw new IllegalStateException(); + // find the applicable default inside->out: SourceTypeBinding currentType = null; @@ -2751,42 +2842,137 @@ private boolean isFirstRoleCtorArg(AbstractMethodDeclaration methodDecl, MethodB } // SH} public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) { + if (this != this.prototype) + return this.prototype.retrieveAnnotationHolder(binding, forceInitialization); if (forceInitialization) binding.getAnnotationTagBits(); // ensure annotations are up to date return super.retrieveAnnotationHolder(binding, false); } -public void setFields(FieldBinding[] fields) { - this.fields = fields; + +public void setContainingAnnotation(ReferenceBinding value) { + if (this != this.prototype) throw new IllegalStateException(); + this.containingAnnotation = value; +} + +// Propagate writes to all annotated variants so the clones evolve along. +public FieldBinding [] setFields(FieldBinding[] fields) { + if (this != this.prototype) - this.prototype.setFields(fields); + return this.prototype.setFields(fields); + + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.fields = fields; + } + } //{ObjectTeams: // integrate pendingField if (this.pendingField != null) { int l= fields.length; - System.arraycopy(fields, 0, this.fields= new FieldBinding[l+1], 1, l); - this.fields[0]= this.pendingField; + System.arraycopy(fields, 0, fields= new FieldBinding[l+1], 1, l); + fields[0]= this.pendingField; this.pendingField= null; } // in case getField() (or similar func) has already been called reset flag: this.tagBits &= ~(TagBits.AreFieldsSorted | TagBits.AreFieldsComplete); // SH} + return this.fields = fields; } -public void setMethods(MethodBinding[] methods) { + +// We need to specialize member types, can't just propagate. Can't specialize here, clones could created post setMemberTypes() +public ReferenceBinding [] setMemberTypes(ReferenceBinding[] memberTypes) { + + if (this != this.prototype) + return this.prototype.setMemberTypes(memberTypes); + + this.memberTypes = memberTypes; + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.tagBits |= TagBits.HasUnresolvedMemberTypes; + annotatedType.memberTypes(); // recompute. + } + } + return this.memberTypes; +} + +// Propagate writes to all annotated variants so the clones evolve along. +public MethodBinding [] setMethods(MethodBinding[] methods) { + + if (this != this.prototype) + return this.prototype.setMethods(methods); + + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.methods = methods; + } + } //{ObjectTeams: baseCallSurrogate might be stored before regular methods are created // happens when binary role with static callin method is loaded before STATE_BINDINGS_COMPLETE if (this.pendingMethods != null) { assert (this.tagBits & TagBits.AreMethodsSorted) == 0 : "setMethods after sorting"; //$NON-NLS-1$ int len1 = this.pendingMethods.size(); int len2 = methods.length; - this.methods = new MethodBinding[len1+len2]; + System.arraycopy(methods, 0, methods=new MethodBinding[len1+len2], len1, len2); this.pendingMethods.toArray(this.methods); - System.arraycopy(methods, 0, this.methods, len1, len2); this.pendingMethods = null; - } else + } // SH} - this.methods = methods; + return this.methods = methods; +} + +// Propagate writes to all annotated variants so the clones evolve along. +public ReferenceBinding setSuperClass(ReferenceBinding superClass) { + if (this != this.prototype) - this.prototype.setMethods(methods); + return this.prototype.setSuperClass(superClass); + + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.superclass = superClass; + } + } + return this.superclass = superClass; } + +// Propagate writes to all annotated variants so the clones evolve along. +public ReferenceBinding [] setSuperInterfaces(ReferenceBinding [] superInterfaces) { + + if (this != this.prototype) + return this.prototype.setSuperInterfaces(superInterfaces); + + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.superInterfaces = superInterfaces; + } + } + return this.superInterfaces = superInterfaces; +} + +// Propagate writes to all annotated variants so the clones evolve along. +public TypeVariableBinding [] setTypeVariables(TypeVariableBinding [] typeVariables) { + + if (this != this.prototype) + return this.prototype.setTypeVariables(typeVariables); + + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.scope.environment().getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + SourceTypeBinding annotatedType = (SourceTypeBinding) annotatedTypes[i]; + annotatedType.typeVariables = typeVariables; + } + } + return this.typeVariables = typeVariables; +} + //{ObjectTeams: adding generated elements FieldBinding pendingField= null; public void addField(FieldBinding fieldBinding) { @@ -2966,6 +3152,7 @@ public void resolveGeneratedMethod(AbstractMethodDeclaration methodDeclaration, public final int sourceEnd() { if (this != this.prototype) return this.prototype.sourceEnd(); + return this.scope.referenceContext.sourceEnd; } public final int sourceStart() { @@ -2984,21 +3171,29 @@ SimpleLookupTable storedAnnotations(boolean forceInitialize) { //{ObjectTeams: do support annotations for roles for the sake of copying: if (!this.isRole()) // SH} - if (!globalOptions.storeAnnotations && !globalOptions.isAnnotationBasedNullAnalysisEnabled) + if (!globalOptions.storeAnnotations) return null; // not supported during this compile this.storedAnnotations = new SimpleLookupTable(3); } return this.storedAnnotations; } + public ReferenceBinding superclass() { + if (this != this.prototype) + return this.superclass = this.prototype.superclass(); return this.superclass; } + public ReferenceBinding[] superInterfaces() { + if (this != this.prototype) + return this.superInterfaces = this.prototype.superInterfaces(); return this.superInterfaces; } + public SyntheticMethodBinding[] syntheticMethods() { - if (this != this.prototype) - return this.prototype.syntheticMethods(); + + if (this != this.prototype) throw new IllegalStateException(); + //{ObjectTeams: two different kinds of synthetics: /* orig: if (this.synthetics == null @@ -3028,8 +3223,8 @@ public SyntheticMethodBinding[] syntheticMethods() { } } } - } // :giro + } // more synthetics to generate: if (this.synthetics[SourceTypeBinding.ROLE_BRIDGE] != null && this.synthetics[SourceTypeBinding.ROLE_BRIDGE].size() > 0) { @@ -3060,8 +3255,8 @@ public SyntheticMethodBinding[] syntheticMethods() { * Answer the collection of synthetic fields to append into the classfile */ public FieldBinding[] syntheticFields() { - if (this != this.prototype) - return this.prototype.syntheticFields(); + + if (this != this.prototype) throw new IllegalStateException(); if (this.synthetics == null) return null; int fieldSize = this.synthetics[SourceTypeBinding.FIELD_EMUL] == null ? 0 : this.synthetics[SourceTypeBinding.FIELD_EMUL].size(); @@ -3194,13 +3389,14 @@ public String toString() { return buffer.toString(); } public TypeVariableBinding[] typeVariables() { + if (this != this.prototype) + return this.typeVariables = this.prototype.typeVariables(); return this.typeVariables != null ? this.typeVariables : Binding.NO_TYPE_VARIABLES; } void verifyMethods(MethodVerifier verifier) { - if (this != this.prototype) { - this.prototype.verifyMethods(verifier); - return; - } + + if (this != this.prototype) throw new IllegalStateException(); + //{ObjectTeams: shortcut for predefined confined types (override final methods???) if (TypeAnalyzer.isTopConfined(this)) return; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java index beda54550..6fc901aa2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java @@ -96,14 +96,16 @@ public interface TagBits { long PassedBoundCheck = ASTNode.Bit23; // set for parameterized type NOT of the form X<?,?> - long IsBoundParameterizedType = ASTNode.Bit24; + long IsBoundParameterizedType = ASTNode.Bit24; // PTB only. + + long HasAnnotatedVariants = ASTNode.Bit24; // TVB, STB // used by BinaryTypeBinding long HasUnresolvedTypeVariables = ASTNode.Bit25; long HasUnresolvedSuperclass = ASTNode.Bit26; long HasUnresolvedSuperinterfaces = ASTNode.Bit27; long HasUnresolvedEnclosingType = ASTNode.Bit28; - long HasUnresolvedMemberTypes = ASTNode.Bit29; + long HasUnresolvedMemberTypes = ASTNode.Bit29; // Also in use at STB. long HasTypeVariable = ASTNode.Bit30; // set either for type variables (direct) or parameterized types indirectly referencing type variables long HasDirectWildcard = ASTNode.Bit31; // set for parameterized types directly referencing wildcards diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java index d2587b623..199ce238e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java @@ -20,6 +20,7 @@ * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression *******************************************************************************/ @@ -105,7 +106,6 @@ public TypeBinding() { public TypeBinding(TypeBinding prototype) { // faithfully copy all instance state - clone operation should specialize/override suitably. this.id = prototype.id; this.tagBits = prototype.tagBits; - this.typeAnnotations = prototype.typeAnnotations; } /** @@ -221,7 +221,7 @@ public void collectSubstitutes(Scope scope, TypeBinding actualType, InferenceCon make sense for every type in the hierarchy, in which case they are silently ignored. A type may choose to retain a copy of the prototype for reference. */ -public TypeBinding clone(TypeBinding enclosingType, TypeBinding[] typeArguments) { +public TypeBinding clone(TypeBinding enclosingType) { throw new IllegalStateException("TypeBinding#clone() should have been overridden"); //$NON-NLS-1$ } @@ -247,7 +247,7 @@ public int depth() { return 0; } -/* Answer the receiver's enclosing type... null if the receiver is a top level type. +/* Answer the receiver's enclosing type... null if the receiver is a top level type or is an array or a non reference type. */ public ReferenceBinding enclosingType() { return null; @@ -518,10 +518,6 @@ void initializeForStaticImports() { // only applicable to source types } -public boolean isAnnotationType() { - return false; -} - public final boolean isAnonymousType() { return (this.tagBits & TagBits.IsAnonymousType) != 0; } @@ -1084,6 +1080,13 @@ public boolean isReifiable() { } /** + * Answer true if the receiver is a static member type (or toplevel) + */ +public boolean isStatic() { + return false; +} + +/** * Returns true if a given type may be thrown */ public boolean isThrowable() { @@ -1093,13 +1096,13 @@ public boolean isThrowable() { public boolean isTypeArgumentContainedBy(TypeBinding otherType) { //{ObjectTeams: only slightly weaker form of identity: /* orig: - if (this == otherType) + if (TypeBinding.equalsEquals(this, otherType)) :giro */ if (RoleTypeBinding.eq(this, otherType)) // SH} return true; switch (otherType.kind()) { - // handle captured wildcards. + // handle captured wildcards. case Binding.TYPE_PARAMETER: { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=347426 if (!isParameterizedType() || !otherType.isCapture()) { @@ -1168,7 +1171,7 @@ public boolean isTypeArgumentContainedBy(TypeBinding otherType) { TypeBinding otherBound = otherWildcard.bound; switch (otherWildcard.boundKind) { case Wildcard.EXTENDS: - if (otherBound == this) + if (TypeBinding.equalsEquals(otherBound, this)) return true; // ? extends T <= ? extends ? extends T if (upperBound == null) return false; @@ -1403,13 +1406,13 @@ public abstract char[] qualifiedSourceName(); /** * @return the JSR 308 annotations for this type. */ -public AnnotationBinding[] getTypeAnnotations() { +final public AnnotationBinding[] getTypeAnnotations() { return this.typeAnnotations; } public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) { this.tagBits |= TagBits.HasTypeAnnotations; - if (annotations == null || annotations == Binding.NO_ANNOTATIONS) + if (annotations == null || annotations.length == 0) return; this.typeAnnotations = annotations; if (evalNullAnnotations) { @@ -1426,6 +1429,7 @@ public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNull } } } + // we do accept contradictory tagBits here, to support detecting contradictions caused by type substitution } } @@ -1511,5 +1515,16 @@ public static boolean notEquals(TypeBinding that, TypeBinding other) { return false; return true; } +/** Return the primordial type from which the receiver was cloned. Not all types track a prototype, only {@link SourceTypeBinding}, + * {@link BinaryTypeBinding} and {@link UnresolvedReferenceBinding} do so as of now. In fact some types e.g {@link ParameterizedTypeBinding} + * should not do so. Deflecting a query to a prototype would lead to wrong results in the case of {@link ParameterizedTypeBinding} + */ +public TypeBinding prototype() { + return null; +} + +public boolean isUnresolvedType() { + return false; +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java index 938630af4..a33464c45 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java @@ -18,9 +18,9 @@ * bug 400421 - [compiler] Null analysis for fields does not take @com.google.inject.Inject into account * bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions * Bug 405569 - Resource leak check false positive when using DbUtils.closeQuietly - * * Jesper S Moller - Contributions for - * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 + * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -147,6 +147,7 @@ public interface TypeConstants { char[][] JAVA_LANG_DEPRECATED = {JAVA, LANG, "Deprecated".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_ANNOTATION_DOCUMENTED = {JAVA, LANG, ANNOTATION, "Documented".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_ANNOTATION_INHERITED = {JAVA, LANG, ANNOTATION, "Inherited".toCharArray()}; //$NON-NLS-1$ + char[][] JAVA_LANG_ANNOTATION_REPEATABLE = {JAVA, LANG, ANNOTATION, "Repeatable".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_OVERRIDE = {JAVA, LANG, "Override".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_FUNCTIONAL_INTERFACE = {JAVA, LANG, "FunctionalInterface".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_ANNOTATION_RETENTION = {JAVA, LANG, ANNOTATION, "Retention".toCharArray()}; //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java index 2f4428ff0..66b0dc365 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java @@ -18,6 +18,8 @@ * bug 358903 - Filter practically unimportant resource leak warnings * bug 400421 - [compiler] Null analysis for fields does not take @com.google.inject.Inject into account * bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions + * Jesper S Moller <jesper@selskabet.org> - Contributions for + * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -124,13 +126,14 @@ public interface TypeIds { final int T_JavaUtilObjects = 74; // java 8 - final int T_JavaLangFunctionalInterface = 69; + final int T_JavaLangFunctionalInterface = 77; // new in 3.9 to identify known @Inject annotations final int T_JavaxInjectInject = 80; final int T_ComGoogleInjectInject = 81; + // Java 8 - JEP 120 + final int T_JavaLangAnnotationRepeatable = 90; // If you add new type id, make sure to bump up T_LastWellKnownTypeId if there is a cross over. - final int T_LastWellKnownTypeId = 128; final int NoId = Integer.MAX_VALUE; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java new file mode 100644 index 000000000..c33f02e30 --- /dev/null +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2013 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 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; + +public abstract class TypeSystem { + + public boolean isAnnotatedTypeSystem() { + return false; + } + + public abstract AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requireResolved); + + public abstract ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions); + + public ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions, AnnotationBinding[] annotations) { + return getArrayType(leafComponentType, dimensions); + } +//{ObjectTeams: 2 parameters added: +/* orig: + public abstract ParameterizedTypeBinding getParameterizedType (ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType); + :giro */ + public abstract ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, + ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType); + +/* orig: + public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding[] annotations) { + return getParameterizedType(genericType, typeArguments, enclosingType); + :giro */ + public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, + ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding[] annotations) { + return getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType); +// SH} + } + + public abstract RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType); + + public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding[] annotations) { + return getRawType(genericType, enclosingType); + } + + public abstract WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind); + + public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding[] annotations) { + return getWildcard(genericType, rank, bound, otherBounds, boundKind); + } + + public TypeBinding getAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) { + return type; + } + + + public abstract void reset(); + + public abstract void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType); + + public abstract TypeBinding getUnannotatedType(TypeBinding type); + + // Given a type, return all its variously annotated versions. + public TypeBinding[] getAnnotatedTypes(TypeBinding type) { + return Binding.NO_TYPES; + } + + public ReferenceBinding getMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) { + return memberType; // nothing to do for plain vanilla type system. + } +} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java index f91b08529..19d334e5f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java @@ -20,12 +20,14 @@ * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; @@ -48,11 +50,11 @@ public class TypeVariableBinding extends ReferenceBinding { * Denote the first explicit (binding) bound amongst the supertypes (from declaration in source) * If no superclass was specified, then it denotes the first superinterface, or null if none was specified. */ - public TypeBinding firstBound; + public TypeBinding firstBound; // MUST NOT be modified directly, use setter ! // actual resolved variable supertypes (if no superclass bound, then associated to Object) - public ReferenceBinding superclass; - public ReferenceBinding[] superInterfaces; + public ReferenceBinding superclass; // MUST NOT be modified directly, use setter ! + public ReferenceBinding[] superInterfaces; // MUST NOT be modified directly, use setter ! //{ObjectTeams: additions: // bound in <B base R>: public ReferenceBinding roletype; @@ -81,6 +83,8 @@ public class TypeVariableBinding extends ReferenceBinding { this.superInterfaces = prototype.superInterfaces; this.genericTypeSignature = prototype.genericTypeSignature; this.environment = prototype.environment; + prototype.tagBits |= TagBits.HasAnnotatedVariants; + this.tagBits &= ~TagBits.HasAnnotatedVariants; } /** @@ -254,9 +258,9 @@ public class TypeVariableBinding extends ReferenceBinding { } } } - long nullTagBits = this.tagBits & TagBits.AnnotationNullMASK; + long nullTagBits = NullAnnotationMatching.validNullTagBits(this.tagBits); if (nullTagBits != 0) { - long argBits = argumentType.tagBits & TagBits.AnnotationNullMASK; + long argBits = NullAnnotationMatching.validNullTagBits(argumentType.tagBits); if (argBits != nullTagBits) { // System.err.println("TODO(stephan): issue proper error: bound conflict at "+String.valueOf(this.declaringElement.readableName())); } @@ -411,12 +415,11 @@ public class TypeVariableBinding extends ReferenceBinding { return this.superclass.constantPoolName(); // java/lang/Object } - public TypeBinding clone(TypeBinding enclosingType, TypeBinding[] typeArguments) { + public TypeBinding clone(TypeBinding enclosingType) { return new TypeVariableBinding(this); } public String annotatedDebugName() { StringBuffer buffer = new StringBuffer(10); - buffer.append('<'); buffer.append(super.annotatedDebugName()); if (this.superclass != null && this.firstBound == this.superclass) { buffer.append(" extends ").append(this.superclass.annotatedDebugName()); //$NON-NLS-1$ @@ -432,7 +435,6 @@ public class TypeVariableBinding extends ReferenceBinding { buffer.append(this.superInterfaces[i].annotatedDebugName()); } } - buffer.append('>'); return buffer.toString(); } /** @@ -634,7 +636,7 @@ public class TypeVariableBinding extends ReferenceBinding { // System.err.println("TODO(stephan): report proper error: conflict binary TypeVariable vs. first bound"); } } - this.superclass = resolveType; + this.setSuperClass(resolveType); } ReferenceBinding[] interfaces = this.superInterfaces; int length; @@ -657,14 +659,32 @@ public class TypeVariableBinding extends ReferenceBinding { // refresh the firstBound in case it changed if (this.firstBound != null) { if (this.firstBound == oldSuperclass) { - this.firstBound = this.superclass; + this.setFirstBound(this.superclass); } else if (this.firstBound == oldFirstInterface) { - this.firstBound = interfaces[0]; + this.setFirstBound(interfaces[0]); } } this.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; return this; } + + /* TVB should inherit annotations from declaration site. For example given class X<@NonNull T> { @Readonly T t; }, + the type of the field t is "@NonNull @Readonly T". This is not true for capture of the wildcard as the wildcard + cannot be subsequently referenced by virtue of being anonymous. + */ + public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) { + TypeVariableBinding prototype = (TypeVariableBinding) this.environment.getUnannotatedType(this); // also exposes original TVB/capture to type system for id stamping purposes. + if (prototype != this && !this.isCapture()) { + AnnotationBinding [] declarationAnnotations = prototype.getTypeAnnotations(); + final int declarationAnnotationsLength = declarationAnnotations == null ? 0 : declarationAnnotations.length; + if (declarationAnnotationsLength > 0) { + final int annotationsLength = annotations.length; + System.arraycopy(annotations, 0, annotations = new AnnotationBinding[annotationsLength + declarationAnnotationsLength], 0, annotationsLength); + System.arraycopy(declarationAnnotations, 0, annotations, annotationsLength, declarationAnnotationsLength); + } + } + super.setTypeAnnotations(annotations, evalNullAnnotations); + } /** * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#shortReadableName() */ @@ -710,6 +730,7 @@ public class TypeVariableBinding extends ReferenceBinding { return buffer.toString(); } + // May still carry declaration site annotations. public TypeBinding unannotated() { return this.hasTypeAnnotations() ? this.environment.getUnannotatedType(this) : this; } @@ -724,9 +745,9 @@ public class TypeVariableBinding extends ReferenceBinding { } public void evaluateNullAnnotations(Scope scope, TypeParameter parameter) { - long nullTagBits = this.tagBits & TagBits.AnnotationNullMASK; + long nullTagBits = NullAnnotationMatching.validNullTagBits(this.tagBits); if (this.firstBound != null && this.firstBound.isValidBinding()) { - long superNullTagBits = this.firstBound.tagBits & TagBits.AnnotationNullMASK; + long superNullTagBits = NullAnnotationMatching.validNullTagBits(this.firstBound.tagBits); if (superNullTagBits != 0L) { if (nullTagBits == 0L) { nullTagBits |= superNullTagBits; @@ -744,7 +765,7 @@ public class TypeVariableBinding extends ReferenceBinding { if ((length = interfaces.length) != 0) { for (int i = length; --i >= 0;) { ReferenceBinding resolveType = interfaces[i]; - long superNullTagBits = resolveType.tagBits & TagBits.AnnotationNullMASK; + long superNullTagBits = NullAnnotationMatching.validNullTagBits(resolveType.tagBits); if (superNullTagBits != 0L) { if (nullTagBits == 0L) { nullTagBits |= superNullTagBits; @@ -774,4 +795,47 @@ public class TypeVariableBinding extends ReferenceBinding { } return null; } + + /* An annotated type variable use differs from its declaration exactly in its annotations and in nothing else. + Propagate writes to all annotated variants so the clones evolve along. + */ + public TypeBinding setFirstBound(TypeBinding firstBound) { + this.firstBound = firstBound; + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; + annotatedType.firstBound = firstBound; + } + } + return firstBound; + } + /* An annotated type variable use differs from its declaration exactly in its annotations and in nothing else. + Propagate writes to all annotated variants so the clones evolve along. + */ + public ReferenceBinding setSuperClass(ReferenceBinding superclass) { + this.superclass = superclass; + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; + annotatedType.superclass = superclass; + } + } + return superclass; + } + /* An annotated type variable use differs from its declaration exactly in its annotations and in nothing else. + Propagate writes to all annotated variants so the clones evolve along. + */ + public ReferenceBinding [] setSuperInterfaces(ReferenceBinding[] superInterfaces) { + this.superInterfaces = superInterfaces; + if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { + TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { + TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; + annotatedType.superInterfaces = superInterfaces; + } + } + return superInterfaces; + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java index 8050a9fb0..b656910a0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java @@ -32,12 +32,12 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBindin Map<@T4 String, @T5 Object> and @T6 Map<String, Object> and @T7 Map<String, @T8 Object> and Map<String, @T9 Object> would all share the same id since the unadorned naked type in each case is the same: Map<String, Object>. None of this would share the id with Map<String, String>. Briefly put, if you take a certain annotated type and strip it of all annotations to come up with the naked type, that naked type and the annotated type would have the - same id. Alternately, if you take a certain naked type and arrive at the set of all differently annotated types, they would all share the same id while + same id. Alternately, if you take a certain naked type and arrive at the universe of all differently annotated types, they would all share the same id while their bindings could be different - would be different unless they are identically annotated. Thus subsystems that are annotation agnostic could quickly ascertain binding equality by comparing the id field. */ -public class UnannotatedTypeSystem { +public class UnannotatedTypeSystem extends TypeSystem { private int typeid = TypeIds.T_LastWellKnownTypeId; private TypeBinding [][] types; @@ -51,9 +51,9 @@ public class UnannotatedTypeSystem { this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][]; } - TypeBinding getUnannotatedType(TypeBinding type) { + public TypeBinding getUnannotatedType(TypeBinding type) { if (type.id == TypeIds.NoId) { - if (type.hasTypeAnnotations() && !type.isTypeVariable()) + if (type.hasTypeAnnotations()) throw new IllegalStateException(); int typesLength = this.types.length; if (this.typeid == typesLength) @@ -80,6 +80,9 @@ public class UnannotatedTypeSystem { return this.types[type.id][0] = type; } + /* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system + for an ATS, they may and we need to materialize the unannotated versions and work on them. + */ public ArrayBinding getArrayType(TypeBinding leafType, int dimensions) { TypeBinding unannotatedLeafType = getUnannotatedType(leafType); TypeBinding[] cachedInfo = this.types[unannotatedLeafType.id]; // by construction, cachedInfo != null now. @@ -108,6 +111,9 @@ public class UnannotatedTypeSystem { return (ArrayBinding) (this.types[arrayType.id = this.typeid++][0] = arrayType); } + /* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system + for an ATS, they may and we need to materialize the unannotated versions and work on them. + */ //{ObjectTeams: 2 parameters added: /* orig: public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) { @@ -115,7 +121,7 @@ public class UnannotatedTypeSystem { public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType) { // SH} - ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType); + ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType); int typeArgumentsLength = typeArguments == null ? 0: typeArguments.length; TypeBinding [] unannotatedTypeArguments = typeArguments == null ? null : new TypeBinding[typeArgumentsLength]; for (int i = 0; i < typeArgumentsLength; i++) { @@ -193,6 +199,9 @@ public class UnannotatedTypeSystem { } //SH} + /* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system + for an ATS, they may and we need to materialize the unannotated versions and work on them. + */ public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) { ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType); ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType); @@ -223,7 +232,9 @@ public class UnannotatedTypeSystem { return (RawTypeBinding) (this.types[rawTytpe.id = this.typeid++][0] = rawTytpe); } - + /* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system + for an ATS, they may and we need to materialize the unannotated versions and work on them. + */ public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) { if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation genericType = ReferenceBinding.LUB_GENERIC; @@ -264,13 +275,20 @@ public class UnannotatedTypeSystem { return (WildcardBinding) (this.types[wildcard.id = this.typeid++][0] = wildcard); } - - public AnnotationBinding getAnnotationType(ReferenceBinding annotationType) { + /* Return a unique annotation binding for an annotation with either no or all default element-value pairs. + We may return a resolved annotation when requested for unresolved one, but not vice versa. + */ + public AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requiredResolved) { AnnotationBinding annotation = (AnnotationBinding) this.annotationTypes.get(annotationType); if (annotation == null) { - annotation = new AnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS); + if (requiredResolved) + annotation = new AnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS); + else + annotation = new UnresolvedAnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS, this.environment); this.annotationTypes.put(annotationType, annotation); } + if (requiredResolved) + annotation.resolve(); return annotation; } @@ -288,5 +306,14 @@ public class UnannotatedTypeSystem { resolvedType.id = unresolvedTypeId; this.types[unresolvedTypeId][0] = resolvedType; } + if (this.annotationTypes.get(unresolvedType) != null) { // update the key + Object[] keys = this.annotationTypes.keyTable; + for (int i = 0, l = keys.length; i < l; i++) { + if (keys[i] == unresolvedType) { + keys[i] = resolvedType; // hashCode is based on compoundName so this works. + break; + } + } + } } }
\ No newline at end of file diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedAnnotationBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedAnnotationBinding.java index 57952eaa7..b85916734 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedAnnotationBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedAnnotationBinding.java @@ -5,6 +5,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ @@ -19,7 +23,7 @@ UnresolvedAnnotationBinding(ReferenceBinding type, ElementValuePair[] pairs, Loo this.env = env; } -public ReferenceBinding getAnnotationType() { +public void resolve() { // in place resolution. if (this.typeUnresolved) { // the type is resolved when requested boolean wasToleratingMissingTypeProcessingAnnotations = this.env.mayTolerateMissingType; this.env.mayTolerateMissingType = true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=388042 @@ -31,13 +35,16 @@ public ReferenceBinding getAnnotationType() { } this.typeUnresolved = false; } +} +public ReferenceBinding getAnnotationType() { + resolve(); return this.type; } public ElementValuePair[] getElementValuePairs() { if (this.env != null) { if (this.typeUnresolved) { - getAnnotationType(); // resolve the annotation type + resolve(); } // resolve method binding and value type (if unresolved) for each pair for (int i = this.pairs.length; --i >= 0;) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java index ce6670099..4e3c02faf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java @@ -27,7 +27,6 @@ public class UnresolvedReferenceBinding extends ReferenceBinding { ReferenceBinding resolvedType; TypeBinding[] wrappers; UnresolvedReferenceBinding prototype; -TypeBinding enclosingType; //{ObjectTeams: make visible to subclass: protected @@ -48,11 +47,10 @@ public UnresolvedReferenceBinding(UnresolvedReferenceBinding prototype) { this.prototype = prototype.prototype; } -public TypeBinding clone(TypeBinding outerType, TypeBinding[] someTypeArguments) { - if (this.resolvedType != null) +public TypeBinding clone(TypeBinding outerType) { + if (this.resolvedType != null || this.depth() > 0) throw new IllegalStateException(); UnresolvedReferenceBinding copy = new UnresolvedReferenceBinding(this); - copy.enclosingType = outerType; this.addWrapper(copy, null); return copy; } @@ -72,6 +70,9 @@ void addWrapper(TypeBinding wrapper, LookupEnvironment environment) { this.wrappers[length] = wrapper; } } +public boolean isUnresolvedType() { + return true; +} public String debugName() { return toString(); } @@ -84,6 +85,11 @@ public boolean hasTypeBit(int bit) { // shouldn't happen since we are not called before analyseCode(), but play safe: return false; } + +public TypeBinding prototype() { + return this.prototype; +} + //{ObjectTeams: changed to public (was default-vis) public ReferenceBinding resolve(LookupEnvironment environment, boolean convertGenericToRawType) { // SH} @@ -130,8 +136,7 @@ void setResolvedType(ReferenceBinding targetType, LookupEnvironment environment) public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding unannotatedType, LookupEnvironment environment) { if (this.resolvedType != null) return; - ReferenceBinding annotatedType = (ReferenceBinding) unannotatedType.clone(this.enclosingType != null ? this.enclosingType : unannotatedType.enclosingType(), null); - + ReferenceBinding annotatedType = (ReferenceBinding) unannotatedType.clone(null); this.resolvedType = annotatedType; annotatedType.setTypeAnnotations(getTypeAnnotations(), environment.globalOptions.isAnnotationBasedNullAnalysisEnabled); annotatedType.id = unannotatedType.id = this.id; @@ -140,6 +145,7 @@ public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceB this.wrappers[i].swapUnresolved(this, annotatedType, environment); environment.updateCaches(this, annotatedType); } + public String toString() { if (this.hasTypeAnnotations()) return super.annotatedDebugName() + "(unresolved)"; //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java index 463130dd8..1d4846353 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java @@ -16,6 +16,7 @@ * bug 349326 - [1.7] new warning for missing try-with-resources * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource * bug 358903 - Filter practically unimportant resource leak warnings + * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -57,12 +58,6 @@ public class WildcardBinding extends ReferenceBinding { this.modifiers = ClassFileConstants.AccPublic | ExtraCompilerModifiers.AccGenericSignature; // treat wildcard as public this.environment = environment; initialize(genericType, bound, otherBounds); - -// if (!genericType.isGenericType() && !(genericType instanceof UnresolvedReferenceBinding)) { -// RuntimeException e = new RuntimeException("WILDCARD with NON GENERIC"); -// e.printStackTrace(); -// throw e; -// } if (genericType instanceof UnresolvedReferenceBinding) ((UnresolvedReferenceBinding) genericType).addWrapper(this, environment); if (bound instanceof UnresolvedReferenceBinding) @@ -71,19 +66,6 @@ public class WildcardBinding extends ReferenceBinding { this.typeBits = TypeIds.BitUninitialized; } - public WildcardBinding(WildcardBinding prototype) { - super(prototype); - this.genericType = prototype.genericType; - this.rank = prototype.rank; - this.bound = prototype.bound; - this.otherBounds = prototype.otherBounds; - this.genericSignature = prototype.genericSignature; - this.boundKind = prototype.boundKind; - this.superclass = prototype.superclass; - this.superInterfaces = prototype.superInterfaces; - this.typeVariable = prototype.typeVariable; - this.environment = prototype.environment; - } //{ObjectTeams: role wrapping? public TypeBinding maybeWrapQualifiedRoleType(Scope scope, Expression anchorExpr, ASTNode typedNode) { @@ -451,8 +433,8 @@ public class WildcardBinding extends ReferenceBinding { return erasure().constantPoolName(); } - public TypeBinding clone(TypeBinding immaterial, TypeBinding[] irrelevant) { - return new WildcardBinding(this); + public TypeBinding clone(TypeBinding immaterial) { + return new WildcardBinding(this.genericType, this.rank, this.bound, this.otherBounds, this.boundKind, this.environment); } public String annotatedDebugName() { @@ -470,7 +452,7 @@ public class WildcardBinding extends ReferenceBinding { return buffer.append(CharOperation.concat(TypeConstants.WILDCARD_NAME, TypeConstants.WILDCARD_EXTENDS, this.bound.annotatedDebugName().toCharArray())).toString(); buffer.append(this.bound.annotatedDebugName()); for (int i = 0, length = this.otherBounds.length; i < length; i++) { - buffer.append('&').append(this.otherBounds[i].annotatedDebugName()); + buffer.append(" & ").append(this.otherBounds[i].annotatedDebugName()); //$NON-NLS-1$ } return buffer.toString(); default: // SUPER @@ -633,7 +615,8 @@ public class WildcardBinding extends ReferenceBinding { break; case Wildcard.EXTENDS : if (this.otherBounds == null) { - buffer.append(TypeConstants.WILDCARD_NAME).append(TypeConstants.WILDCARD_EXTENDS).append(this.bound.readableName()); + buffer.append(TypeConstants.WILDCARD_NAME).append(TypeConstants.WILDCARD_EXTENDS); + buffer.append(shortNames ? this.bound.shortReadableName(): this.bound.readableName()); } else { buffer.append(this.bound.nullAnnotatedReadableName(options, shortNames)); for (int i = 0, length = this.otherBounds.length; i < length; i++) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java index 52c73a3bf..e158465f6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -29,6 +29,7 @@ * Andy Clement - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation + * Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes *******************************************************************************/ package org.eclipse.jdt.internal.compiler.parser; @@ -50,9 +51,9 @@ import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; @@ -968,6 +969,7 @@ private int stateStackLengthStack[] = new int[0]; private boolean parsingJava8Plus; protected int unstackedAct = ERROR_ACTION; private boolean haltOnSyntaxError = false; +private boolean tolerateDefaultClassMethods = false; //{ObjectTeams: context info while parsing separate role files: @@ -3126,7 +3128,7 @@ protected void consumeCatchFormalParameter() { } // SH} if (extendedDimensions > 0) { - type = type.copyDims(type.dimensions() + extendedDimensions); + type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, null, false); type.sourceEnd = this.endPosition; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391092 if (type instanceof UnionTypeReference) { @@ -4230,6 +4232,7 @@ protected void consumeEnterAnonymousClassBody(boolean qualified) { TypeDeclaration anonymousType = new TypeDeclaration(this.compilationUnit.compilationResult); anonymousType.name = CharOperation.NO_CHAR; anonymousType.bits |= (ASTNode.IsAnonymousType|ASTNode.IsLocalType); + anonymousType.bits |= (typeReference.bits & ASTNode.HasTypeAnnotations); QualifiedAllocationExpression alloc = new QualifiedAllocationExpression(anonymousType); markEnclosingMemberWithLocalType(); pushOnAstStack(anonymousType); @@ -4302,9 +4305,9 @@ protected void consumeEnterVariable() { char[] identifierName = this.identifierStack[this.identifierPtr]; long namePosition = this.identifierPositionStack[this.identifierPtr]; - int extendedDimension = this.intStack[this.intPtr--]; + int extendedDimensions = this.intStack[this.intPtr--]; // pop any annotations on extended dimensions now, so they don't pollute the base dimensions. - Annotation [][] annotationsOnExtendedDimensions = extendedDimension == 0 ? null : getAnnotationsOnDimensions(extendedDimension); + Annotation [][] annotationsOnExtendedDimensions = extendedDimensions == 0 ? null : getAnnotationsOnDimensions(extendedDimensions); AbstractVariableDeclaration declaration; // create the ast node boolean isLocalDeclaration = this.nestedMethod[this.nestedType] != 0; @@ -4322,7 +4325,6 @@ protected void consumeEnterVariable() { this.identifierLengthPtr--; TypeReference type; int variableIndex = this.variablesCounter[this.nestedType]; - int typeDim = 0; if (variableIndex == 0) { // first variable of the declaration (FieldDeclaration or LocalDeclaration) if (isLocalDeclaration) { @@ -4338,14 +4340,14 @@ protected void consumeEnterVariable() { 0, length); } - type = getTypeReference(typeDim = this.intStack[this.intPtr--]); // type dimension + type = getTypeReference(this.intStack[this.intPtr--]); // type dimension if (declaration.declarationSourceStart == -1) { // this is true if there is no modifiers for the local variable declaration declaration.declarationSourceStart = type.sourceStart; } pushOnAstStack(type); } else { - type = getTypeReference(typeDim = this.intStack[this.intPtr--]); // type dimension + type = getTypeReference(this.intStack[this.intPtr--]); // type dimension pushOnAstStack(type); declaration.declarationSourceStart = this.intStack[this.intPtr--]; declaration.modifiers = this.intStack[this.intPtr--]; @@ -4366,7 +4368,6 @@ protected void consumeEnterVariable() { this.javadoc = null; } else { type = (TypeReference) this.astStack[this.astPtr - variableIndex]; - typeDim = type.dimensions(); AbstractVariableDeclaration previousVariable = (AbstractVariableDeclaration) this.astStack[this.astPtr]; declaration.declarationSourceStart = previousVariable.declarationSourceStart; @@ -4378,19 +4379,9 @@ protected void consumeEnterVariable() { } } - if (extendedDimension == 0) { - declaration.type = type; - declaration.bits |= (type.bits & ASTNode.HasTypeAnnotations); - } else { - int dimension = typeDim + extendedDimension; - Annotation [][] annotationsOnAllDimensions = null; - Annotation[][] annotationsOnDimensions = type.getAnnotationsOnDimensions(); - if (annotationsOnDimensions != null || annotationsOnExtendedDimensions != null) { - annotationsOnAllDimensions = getMergedAnnotationsOnDimensions(typeDim, annotationsOnDimensions, extendedDimension, annotationsOnExtendedDimensions); -// declaration.bits |= (type.bits & ASTNode.HasTypeAnnotations); - } - declaration.type = copyDims(type, dimension, annotationsOnAllDimensions); - } + declaration.type = extendedDimensions == 0 ? type : augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false); + declaration.bits |= (type.bits & ASTNode.HasTypeAnnotations); + this.variablesCounter[this.nestedType]++; pushOnAstStack(declaration); // recovery @@ -4416,27 +4407,6 @@ protected void consumeEnterVariable() { this.lastIgnoredToken = -1; } } -protected Annotation[][] getMergedAnnotationsOnDimensions(int dims, Annotation[][] annotationsOnDimensions, - int extendedDims, Annotation[][] annotationsOnExtendedDimensions) { - - if (annotationsOnDimensions == null && annotationsOnExtendedDimensions == null) - return null; - - Annotation [][] mergedAnnotations = new Annotation[dims + extendedDims][]; - - if (annotationsOnDimensions != null) { - for (int i = 0; i < dims; i++) { - mergedAnnotations[i] = annotationsOnDimensions[i]; - } - } - if (annotationsOnExtendedDimensions != null) { - for (int i = dims, j = 0; i < dims + extendedDims; i++, j++) { - mergedAnnotations[i] = annotationsOnExtendedDimensions[j]; - } - } - - return mergedAnnotations; -} protected void consumeEnumBodyNoConstants() { // nothing to do // The 0 on the astLengthStack has been pushed by EnumBodyDeclarationsopt @@ -5179,7 +5149,7 @@ protected void consumeFormalParameter(boolean isVarArgs) { roleRef = getTypeReference(roleFirstDimensions); int roleDimensions = roleFirstDimensions + extendedDimensions + (isVarArgs?1:0); if (roleDimensions > roleFirstDimensions) - roleRef = roleRef.copyDims(roleDimensions); // annotsOnDIms? + roleRef = roleRef.augmentTypeWithAdditionalDimensions(roleDimensions, null, false); // annotsOnDIms? // done role side, the following balances the pushs from consumeBeginLiftingType(): this.genericsIdentifiersLengthPtr--; this.genericsLengthPtr--; @@ -5194,19 +5164,13 @@ protected void consumeFormalParameter(boolean isVarArgs) { type = ltr; } // SH} - final int typeDimensions = firstDimensions + extendedDimensions + (isVarArgs ? 1 : 0); - - if (typeDimensions != firstDimensions) { - // jsr308 type annotations management - Annotation [][] annotationsOnFirstDimensions = firstDimensions == 0 ? null : type.getAnnotationsOnDimensions(); - Annotation [][] annotationsOnAllDimensions = annotationsOnFirstDimensions; - if (annotationsOnExtendedDimensions != null) { - annotationsOnAllDimensions = getMergedAnnotationsOnDimensions(firstDimensions, annotationsOnFirstDimensions, extendedDimensions, annotationsOnExtendedDimensions); - } - if (varArgsAnnotations != null) { - annotationsOnAllDimensions = getMergedAnnotationsOnDimensions(firstDimensions + extendedDimensions, annotationsOnAllDimensions, 1, new Annotation[][]{varArgsAnnotations}); + if (isVarArgs || extendedDimensions != 0) { + if (isVarArgs) { + type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true); + } + if (extendedDimensions != 0) { + type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false); } - type = copyDims(type, typeDimensions, annotationsOnAllDimensions); type.sourceEnd = type.isParameterizedTypeReference() ? this.endStatementPosition : this.endPosition; } if (isVarArgs) { @@ -5855,7 +5819,7 @@ protected void consumeMethodBody() { // MethodBody ::= NestedMethod '{' BlockStatementsopt '}' this.nestedMethod[this.nestedType] --; } -protected void consumeMethodDeclaration(boolean isNotAbstract) { +protected void consumeMethodDeclaration(boolean isNotAbstract, boolean isDefaultMethod) { // MethodDeclaration ::= MethodHeader MethodBody // AbstractMethodDeclaration ::= MethodHeader ';' @@ -5914,6 +5878,9 @@ protected void consumeMethodDeclaration(boolean isNotAbstract) { // a trailing comment behind the end of the method md.bodyEnd = this.endPosition; md.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition); + if (isDefaultMethod && !this.tolerateDefaultClassMethods) { + problemReporter().defaultModifierIllegallySpecified(md.bodyStart, this.endPosition); + } } protected void consumeMethodHeader() { // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt @@ -5983,21 +5950,13 @@ protected void consumeMethodHeaderExtendedDims() { // MethodHeaderExtendedDims ::= Dimsopt // now we update the returnType of the method MethodDeclaration md = (MethodDeclaration) this.astStack[this.astPtr]; - int extendedDims = this.intStack[this.intPtr--]; + int extendedDimensions = this.intStack[this.intPtr--]; if(md.isAnnotationMethod()) { - ((AnnotationMethodDeclaration)md).extendedDimensions = extendedDims; + ((AnnotationMethodDeclaration)md).extendedDimensions = extendedDimensions; } - if (extendedDims != 0) { - TypeReference returnType = md.returnType; + if (extendedDimensions != 0) { md.sourceEnd = this.endPosition; - int dims = returnType.dimensions() + extendedDims; - Annotation [][] annotationsOnDimensions = returnType.getAnnotationsOnDimensions(); - Annotation [][] annotationsOnExtendedDimensions = getAnnotationsOnDimensions(extendedDims); - Annotation [][] annotationsOnAllDimensions = null; - if (annotationsOnDimensions != null || annotationsOnExtendedDimensions != null) { - annotationsOnAllDimensions = getMergedAnnotationsOnDimensions(returnType.dimensions(), annotationsOnDimensions, extendedDims, annotationsOnExtendedDimensions); - } - md.returnType = copyDims(returnType, dims, annotationsOnAllDimensions); + md.returnType = augmentTypeWithAdditionalDimensions(md.returnType, extendedDimensions, getAnnotationsOnDimensions(extendedDimensions), false); if (this.currentToken == TokenNameLBRACE){ md.bodyStart = this.endPosition + 1; } @@ -6654,6 +6613,7 @@ protected void consumeTypeAnnotation() { Annotation annotation = this.typeAnnotationStack[this.typeAnnotationPtr]; problemReporter().invalidUsageOfTypeAnnotations(annotation); } + this.dimensions = this.intStack[this.intPtr--]; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=417660 } protected void consumeOneMoreTypeAnnotation() { // TypeAnnotations ::= TypeAnnotations TypeAnnotation @@ -7338,7 +7298,7 @@ private void rejectIllegalTypeAnnotations(TypeReference typeReference) { problemReporter().misplacedTypeAnnotations(misplacedAnnotations[0], misplacedAnnotations[misplacedAnnotations.length - 1]); } } - annotations = typeReference.getAnnotationsOnDimensions(); + annotations = typeReference.getAnnotationsOnDimensions(true); for (int i = 0, length = annotations == null ? 0 : annotations.length; i < length; i++) { misplacedAnnotations = annotations[i]; if (misplacedAnnotations != null) { @@ -7932,12 +7892,12 @@ protected void consumeRule(int act) { case 230 : if (DEBUG) { System.out.println("MethodDeclaration ::= MethodHeader MethodBody"); } //$NON-NLS-1$ // set to true to consume a method with a body - consumeMethodDeclaration(true); + consumeMethodDeclaration(true, false); break; case 231 : if (DEBUG) { System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON"); } //$NON-NLS-1$ // set to false to consume a method without body - consumeMethodDeclaration(false); + consumeMethodDeclaration(false, false); break; case 232 : if (DEBUG) { System.out.println("MethodHeader ::= MethodHeaderName FormalParameterListopt"); } //$NON-NLS-1$ @@ -11200,6 +11160,9 @@ protected void consumeToken(int type) { this.lParenPos = this.scanner.startPosition; break; case TokenNameAT308: + pushOnIntStack(this.dimensions); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=417660: Stack the dimensions, they get unstacked in consumeTypeAnnotation. + this.dimensions = 0; + //$FALL-THROUGH$ case TokenNameAT : //{ObjectTeams: 3rd variant of '@': case TokenNameATOT: @@ -11296,44 +11259,6 @@ private boolean doingOrgObjectteamsInternalType() { && CharOperation.equals(this.compilationUnit.currentPackage.tokens, IOTConstants.ORG_OBJECTTEAMS); } // SH} -protected void consumeTypeArgument() { - pushOnGenericsStack(getTypeReference(this.intStack[this.intPtr--])); -} -protected void consumeTypeArgumentList() { - concatGenericsLists(); -} -protected void consumeTypeArgumentList1() { - concatGenericsLists(); -} -protected void consumeTypeArgumentList2() { - concatGenericsLists(); -} -protected void consumeTypeArgumentList3() { - concatGenericsLists(); -} -protected void consumeTypeArgumentReferenceType1() { - concatGenericsLists(); - pushOnGenericsStack(getTypeReference(0)); - this.intPtr--; // pop '<' position. -} -protected void consumeTypeArgumentReferenceType2() { - concatGenericsLists(); - pushOnGenericsStack(getTypeReference(0)); - this.intPtr--; -} -protected void consumeTypeArguments() { - concatGenericsLists(); - this.intPtr--; - - if(!this.statementRecoveryActivated && - this.options.sourceLevel < ClassFileConstants.JDK1_5 && - this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) { - int length = this.genericsLengthStack[this.genericsLengthPtr]; - problemReporter().invalidUsageOfTypeArguments( - (TypeReference)this.genericsStack[this.genericsPtr - length + 1], - (TypeReference)this.genericsStack[this.genericsPtr]); - } -} //{ObjectTeams: new syntax for dependent types. protected void consumeTypeAnchor(boolean haveBase) { // TentativeTypeAnchor ::= '@OT' UnannotatableName @@ -11529,6 +11454,44 @@ protected void consumeBoundsOfAnchoredTypeParameter() { parameter.bounds = new TypeReference[] { bound }; } // SH} +protected void consumeTypeArgument() { + pushOnGenericsStack(getTypeReference(this.intStack[this.intPtr--])); +} +protected void consumeTypeArgumentList() { + concatGenericsLists(); +} +protected void consumeTypeArgumentList1() { + concatGenericsLists(); +} +protected void consumeTypeArgumentList2() { + concatGenericsLists(); +} +protected void consumeTypeArgumentList3() { + concatGenericsLists(); +} +protected void consumeTypeArgumentReferenceType1() { + concatGenericsLists(); + pushOnGenericsStack(getTypeReference(0)); + this.intPtr--; // pop '<' position. +} +protected void consumeTypeArgumentReferenceType2() { + concatGenericsLists(); + pushOnGenericsStack(getTypeReference(0)); + this.intPtr--; +} +protected void consumeTypeArguments() { + concatGenericsLists(); + this.intPtr--; + + if(!this.statementRecoveryActivated && + this.options.sourceLevel < ClassFileConstants.JDK1_5 && + this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) { + int length = this.genericsLengthStack[this.genericsLengthPtr]; + problemReporter().invalidUsageOfTypeArguments( + (TypeReference)this.genericsStack[this.genericsPtr - length + 1], + (TypeReference)this.genericsStack[this.genericsPtr]); + } +} protected void consumeTypeDeclarations() { // TypeDeclarations ::= TypeDeclarations TypeDeclaration concatNodeLists(); @@ -12006,12 +11969,8 @@ public MethodDeclaration convertToMethodDeclaration(ConstructorDeclaration c, Co return m; } -protected TypeReference copyDims(TypeReference typeRef, int dim) { - return typeRef.copyDims(dim); -} - -protected TypeReference copyDims(TypeReference typeRef, int dim, Annotation[][]annotationsOnDimensions) { - return typeRef.copyDims(dim, annotationsOnDimensions); +protected TypeReference augmentTypeWithAdditionalDimensions(TypeReference typeReference, int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { + return typeReference.augmentTypeWithAdditionalDimensions(additionalDimensions, additionalAnnotations, isVarargs); } protected FieldDeclaration createFieldDeclaration(char[] fieldDeclarationName, int sourceStart, int sourceEnd) { @@ -14150,6 +14109,7 @@ public void parse(AbstractMethodMappingDeclaration mapping, CompilationUnitDecla // SH} public ASTNode[] parseClassBodyDeclarations(char[] source, int offset, int length, CompilationUnitDeclaration unit) { boolean oldDiet = this.diet; + boolean oldTolerateDefaultClassMethods = this.tolerateDefaultClassMethods; /* automaton initialization */ initialize(); goForClassBodyDeclarations(); @@ -14176,11 +14136,13 @@ public ASTNode[] parseClassBodyDeclarations(char[] source, int offset, int lengt /* run automaton */ try { this.diet = true; + this.tolerateDefaultClassMethods = this.parsingJava8Plus; parse(); } catch (AbortCompilation ex) { this.lastAct = ERROR_ACTION; } finally { this.diet = oldDiet; + this.tolerateDefaultClassMethods = oldTolerateDefaultClassMethods; } ASTNode[] result = null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java index 3d2016181..8743de47f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -387,6 +387,7 @@ public class Scanner implements TerminalTokens { private VanguardScanner vanguardScanner; private VanguardParser vanguardParser; private ConflictedParser activeParser = null; + private boolean consumingEllipsisAnnotations = false; public static final int RoundBracket = 0; public static final int SquareBracket = 1; @@ -418,6 +419,7 @@ public Scanner( this.tokenizeWhiteSpace = tokenizeWhiteSpace; this.sourceLevel = sourceLevel; this.lookBack[0] = this.lookBack[1] = this.nextToken = TokenNameNotAToken; + this.consumingEllipsisAnnotations = false; this.complianceLevel = complianceLevel; this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals; if (taskTags != null) { @@ -1358,6 +1360,8 @@ public int getNextToken() throws InvalidInputException { } if (token == TokenNameLPAREN || token == TokenNameLESS || token == TokenNameAT) { token = disambiguatedToken(token); + } else if (token == TokenNameELLIPSIS) { + this.consumingEllipsisAnnotations = false; } this.lookBack[0] = this.lookBack[1]; this.lookBack[1] = token; @@ -3368,6 +3372,7 @@ public void resetTo(int begin, int end) { this.commentPtr = -1; // reset comment stack this.foundTaskCount = 0; this.lookBack[0] = this.lookBack[1] = this.nextToken = TokenNameNotAToken; + this.consumingEllipsisAnnotations = false; //{ObjectTeams: lookahead on '->': this._insideParameterMapping = false; this._bindoutLookahead = null; @@ -5357,7 +5362,9 @@ protected final boolean maybeAtReferenceExpression() { // Did the '<' we saw jus } return this.activeParser.atConflictScenario(TokenNameLESS); } -protected final boolean maybeAtEllipsisAnnotation() { // Did the '@' we saw just now herald a type annotation on a ... ? Presumed to be at type annotation already. +private final boolean maybeAtEllipsisAnnotationsStart() { // Did the '@' we saw just now herald a type annotation on a ... ? Presumed to be at type annotation already. + if (this.consumingEllipsisAnnotations) + return false; switch (this.lookBack[1]) { case TokenNamenew: case TokenNameCOMMA: @@ -5411,8 +5418,9 @@ private int disambiguatedToken(int token) { } else { // orig: token = TokenNameAT308; - if (maybeAtEllipsisAnnotation()) { + if (maybeAtEllipsisAnnotationsStart()) { if (parser.parse(Goal.VarargTypeAnnotationGoal) == VanguardParser.SUCCESS) { + this.consumingEllipsisAnnotations = true; this.nextToken = TokenNameAT308; return TokenNameAT308DOTDOTDOT; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 608845bc5..dea319297 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -51,7 +51,9 @@ * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment * bug 384567 - [1.5][compiler] Compiler accepts illegal modifiers on package declaration - *******************************************************************************/ + * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable + * bug 412151 - [1.8][compiler] Check repeating annotation's collection type + ********************************************************************************/ package org.eclipse.jdt.internal.compiler.problem; import java.io.CharConversionException; @@ -143,6 +145,7 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; @@ -716,7 +719,7 @@ public static int getIrritant(int problemID) { case IProblem.UnusedTypeParameter: return CompilerOptions.UnusedTypeParameter; - } +} return 0; } /** @@ -1807,6 +1810,13 @@ public void defaultMethodOverridesObjectMethod(MethodBinding currentMethod) { sourceStart, sourceEnd); } +public void defaultModifierIllegallySpecified(int sourceStart, int sourceEnd) { + this.handle( + IProblem.IllegalDefaultModifierSpecification, + NoArgument, NoArgument, + sourceStart, sourceEnd); +} + public void deprecatedField(FieldBinding field, ASTNode location) { int severity = computeSeverity(IProblem.UsingDeprecatedField); if (severity == ProblemSeverities.Ignore) return; @@ -1913,9 +1923,9 @@ public void multiCatchNotBelow17(ASTNode node) { node.sourceStart, node.sourceEnd); } -public void duplicateAnnotation(Annotation annotation) { +public void duplicateAnnotation(Annotation annotation, long sourceLevel) { this.handle( - IProblem.DuplicateAnnotation, + sourceLevel >= ClassFileConstants.JDK1_8 ? IProblem.DuplicateAnnotationNotMarkedRepeatable : IProblem.DuplicateAnnotation, new String[] {new String(annotation.resolvedType.readableName())}, new String[] {new String(annotation.resolvedType.shortReadableName())}, annotation.sourceStart, @@ -7683,6 +7693,81 @@ public void referenceMustBeArrayTypeAt(TypeBinding arrayType, ArrayReference arr arrayRef.sourceStart, arrayRef.sourceEnd); } +public void repeatedAnnotationWithContainer(Annotation annotation, Annotation container) { + this.handle( + IProblem.RepeatedAnnotationWithContainerAnnotation, + new String[] {new String(annotation.resolvedType.readableName()), new String(container.resolvedType.readableName())}, + new String[] {new String(annotation.resolvedType.shortReadableName()), new String(container.resolvedType.shortReadableName())}, + annotation.sourceStart, + annotation.sourceEnd); +} +public void containingAnnotationMustHaveValue(ASTNode markerNode, ReferenceBinding containerAnnotationType) { + this.handle( + IProblem.ContainingAnnotationMustHaveValue, + new String[] {new String(containerAnnotationType.readableName())}, + new String[] {new String(containerAnnotationType.shortReadableName())}, + markerNode.sourceStart, + markerNode.sourceEnd); +} +public void containingAnnotationHasWrongValueType(ASTNode markerNode, ReferenceBinding containerAnnotationType, ReferenceBinding annotationType, TypeBinding returnType) { + this.handle( + IProblem.ContainingAnnotationHasWrongValueType, + new String[] {new String(containerAnnotationType.readableName()), new String(annotationType.readableName()), new String(returnType.readableName())}, + new String[] {new String(containerAnnotationType.shortReadableName()), new String(annotationType.shortReadableName()), new String(returnType.shortReadableName())}, + markerNode.sourceStart, + markerNode.sourceEnd); +} +public void containingAnnotationHasNonDefaultMembers(ASTNode markerNode, ReferenceBinding containerAnnotationType, char[] selector) { + this.handle( + IProblem.ContainingAnnotationHasNonDefaultMembers, + new String[] {new String(containerAnnotationType.readableName()), new String(selector)}, + new String[] {new String(containerAnnotationType.shortReadableName()), new String(selector)}, + markerNode.sourceStart, + markerNode.sourceEnd); +} +public void containingAnnotationHasShorterRetention(ASTNode markerNode, ReferenceBinding annotationType, String annotationRetention, ReferenceBinding containerAnnotationType, String containerRetention) { + this.handle( + IProblem.ContainingAnnotationHasShorterRetention, + new String[] {new String(annotationType.readableName()), annotationRetention, new String(containerAnnotationType.readableName()), containerRetention}, + new String[] {new String(annotationType.shortReadableName()), annotationRetention, new String(containerAnnotationType.shortReadableName()), containerRetention}, + markerNode.sourceStart, + markerNode.sourceEnd); +} +public void repeatableAnnotationHasTargets(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) { + this.handle( + IProblem.RepeatableAnnotationHasTargets, + new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())}, + new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())}, + markerNode.sourceStart, + markerNode.sourceEnd); +} +public void repeatableAnnotationTargetMismatch(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType, String unmetTargets) { + this.handle( + IProblem.RepeatableAnnotationTargetMismatch, + new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName()), unmetTargets}, + new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName()), unmetTargets}, + markerNode.sourceStart, + markerNode.sourceEnd); +} + +public void repeatableAnnotationIsDocumented(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) { + this.handle( + IProblem.RepeatableAnnotationIsDocumented, + new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())}, + new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())}, + markerNode.sourceStart, + markerNode.sourceEnd); +} + +public void repeatableAnnotationIsInherited(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) { + this.handle( + IProblem.RepeatableAnnotationIsInherited, + new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())}, + new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())}, + markerNode.sourceStart, + markerNode.sourceEnd); +} + public void reset() { this.positionScanner = null; } @@ -9661,6 +9746,11 @@ public void nullityMismatch(Expression expression, TypeBinding providedType, Typ nullityMismatchingTypeAnnotation(expression, providedType, requiredType, NullAnnotationMatching.NULL_ANNOTATIONS_UNCHECKED); } public void nullityMismatchIsNull(Expression expression, TypeBinding requiredType) { + if (requiredType instanceof CaptureBinding) { + CaptureBinding capture = (CaptureBinding) requiredType; + if (capture.wildcard != null) + requiredType = capture.wildcard; + } int problemId = IProblem.RequiredNonNullButProvidedNull; String[] arguments = new String[] { annotatedTypeName(requiredType, this.options.nonNullAnnotationName) @@ -14105,4 +14195,12 @@ public void illegalSuperCallBypassingOverride(InvocationSite location, MethodBin location.sourceStart(), location.sourceEnd()); } +public void disallowedTargetForContainerAnnotation(Annotation annotation, TypeBinding containerAnnotationType) { + this.handle( + IProblem.DisallowedTargetForContainerAnnotation, + new String[] {new String(annotation.resolvedType.readableName()), new String(containerAnnotationType.readableName())}, + new String[] {new String(annotation.resolvedType.shortReadableName()), new String(containerAnnotationType.shortReadableName())}, + annotation.sourceStart, + annotation.sourceEnd); +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index c297bb949..fb4a81f27 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -41,6 +41,8 @@ # Jesper S Moller <jesper@selskabet.org> - Contributions for # bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression # bug 384567 - [1.5][compiler] Compiler accepts illegal modifiers on package declaration +# Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable +# Bug 412151 - [1.8][compiler] Check repeating annotation's collection type ############################################################################### 0 = {0} 1 = super cannot be used in java.lang.Object @@ -588,7 +590,7 @@ 605 = Invalid type {0} for the annotation attribute {2}.{1}; only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof 606 = Cycle detected: the annotation type {0} cannot contain attributes of the annotation type itself 607 = Cycle detected: a cycle exists between annotation attributes of {0} and {1} -608 = Duplicate annotation @{0} +608 = Duplicate annotation @{0}. Repeated annotations are allowed only at source level 1.8 or above 609 = The annotation @{0} must define the attribute {1} 610 = Duplicate attribute {0} in annotation @{1} 611 = The attribute {0} is undefined for the annotation type {1} @@ -745,6 +747,18 @@ 895 = The target type of this expression is not a functional interface: more than one of the intersecting interfaces are functional 896 = Static methods are allowed in interfaces only at source level 1.8 or above +897 = Duplicate annotation of non-repeatable type @{0}. Only annotation types marked @Repeatable can be used multiple times at one target. +898 = The repeatable annotation @{0} is disallowed for this location since its container annotation @{1} is disallowed at this location +899 = The repeatable annotation @{0} may not be repeated where its container annotation @{1} is also used directly +902 = The value method in the containing annotation @{0} must be of type {1}[] but is {2} +903 = The containing annotation @{0} must declare a member value() +904 = The containing annotation @{0} must declare a default value for the annotation attribute ''{1}'' +905 = Retention ''{1}'' of @{0} is longer than the retention of the containing annotation @{2}, which is ''{3}'' +906 = The repeatable annotation @{0} has a @Target annotation, @{1} does not +907 = The containing annotation @{1} is allowed at targets where the repeatable annotation @{0} is not: {2} +908 = The repeatable annotation @{0} is marked @Documented, but the containing annotation @{1} is not +909 = The repeatable annotation @{0} is marked @Inherited, but the containing annotation @{1} is not + ### NULL ANNOTATIONS 910 = Null type mismatch: required ''{0}'' but the provided value is null 911 = Null type mismatch: required ''{0}'' but the provided value is inferred as @{1} @@ -811,6 +825,7 @@ 1055 = Illegal reference to super method {0} from type {1}, cannot bypass the more specific override from type {2} 1056 = Illegal combination of modifiers for the interface method {0}; only one of abstract, default, or static permitted 1057 = strictfp is not permitted for abstract interface method {0} +1058 = Default methods are allowed only in interfaces with source level 1.8 or greater. ### ELABORATIONS ## Access restrictions diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java index 7931e510c..1e8e9ba95 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java @@ -60,6 +60,31 @@ public ReferenceBinding get(char[] key) { } return null; } +// Returns old value. +public ReferenceBinding getput(char[] key, ReferenceBinding value) { + ReferenceBinding retVal = null; + int length = this.keyTable.length, + index = CharOperation.hashCode(key) % length; + int keyLength = key.length; + char[] currentKey; + while ((currentKey = this.keyTable[index]) != null) { + if (currentKey.length == keyLength && CharOperation.equals(currentKey, key)) { + retVal = this.valueTable[index]; + this.valueTable[index] = value; + return retVal; + } + if (++index == length) { + index = 0; + } + } + this.keyTable[index] = key; + this.valueTable[index] = value; + + // assumes the threshold is never equal to the size of the table + if (++this.elementSize > this.threshold) + rehash(); + return retVal; +} public ReferenceBinding put(char[] key, ReferenceBinding value) { int length = this.keyTable.length, index = CharOperation.hashCode(key) % length; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java index 22be86314..c5bb21046 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/LiftingTypeReference.java @@ -103,8 +103,9 @@ public class LiftingTypeReference extends TypeReference { } @Override - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { - this.baseReference = this.baseReference.copyDims(dim, annotationsOnDimensions); + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) + { + this.baseReference = this.baseReference.augmentTypeWithAdditionalDimensions(additionalDimensions, additionalAnnotations, isVarargs); // FIXME check consistency return this; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeAnchorReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeAnchorReference.java index 8d32fa035..5565389e6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeAnchorReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/TypeAnchorReference.java @@ -104,12 +104,7 @@ public class TypeAnchorReference extends TypeReference implements InvocationSite } @Override - public TypeReference copyDims(int dim) { - throw new InternalCompilerError("Method not applicable"); - } - - @Override - public TypeReference copyDims(int dim, Annotation[][] annotationsOnDimensions) { + public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { throw new InternalCompilerError("Method not applicable"); } |