Copyright (c) 2000, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation 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. Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" Bug 438012 - [1.8][null] Bogus Warning: The nullness annotation is redundant with a default that applies to this location Bug 466713 - Null Annotations: NullPointerException using as Type Param Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly
/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * 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. * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" * Bug 438012 - [1.8][null] Bogus Warning: The nullness annotation is redundant with a default that applies to this location * Bug 466713 - Null Annotations: NullPointerException using <int @Nullable []> as Type Param * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly *******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.*; public class Argument extends LocalDeclaration { // prefix for setter method (to recognize special hiding argument) private final static char[] SET = "set".toCharArray(); //$NON-NLS-1$ public Argument(char[] name, long posNom, TypeReference tr, int modifiers) { super(name, (int) (posNom >>> 32), (int) posNom); this.declarationSourceEnd = (int) posNom; this.modifiers = modifiers; this.type = tr; if (tr != null) { this.bits |= (tr.bits & ASTNode.HasTypeAnnotations); } this.bits |= (IsLocalDeclarationReachable | IsArgument); } public Argument(char[] name, long posNom, TypeReference tr, int modifiers, boolean typeElided) { super(name, (int) (posNom >>> 32), (int) posNom); this.declarationSourceEnd = (int) posNom; this.modifiers = modifiers; this.type = tr; if (tr != null) { this.bits |= (tr.bits & ASTNode.HasTypeAnnotations); } this.bits |= (IsLocalDeclarationReachable | IsArgument | IsTypeElided); } @Override public boolean isRecoveredFromLoneIdentifier() { return false; } public TypeBinding createBinding(MethodScope scope, TypeBinding typeBinding) { if (this.binding == null) { // for default constructors and fake implementation of abstract methods this.binding = new LocalVariableBinding(this, typeBinding, this.modifiers, scope); } else if (!this.binding.type.isValidBinding()) { AbstractMethodDeclaration methodDecl = scope.referenceMethod(); if (methodDecl != null) { MethodBinding methodBinding = methodDecl.binding; if (methodBinding != null) { methodBinding.tagBits |= TagBits.HasUnresolvedArguments; } } } if ((this.binding.tagBits & TagBits.AnnotationResolved) == 0) { resolveAnnotations(scope, this.annotations, this.binding, true); if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { Annotation.isTypeUseCompatible(this.type, scope, this.annotations); 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) } public TypeBinding bind(MethodScope scope, TypeBinding typeBinding, boolean used) { TypeBinding newTypeBinding = createBinding(scope, typeBinding); // basically a no-op if createBinding() was called before // record the resolved type into the type reference Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); if (existingVariable != null && existingVariable.isValidBinding()){ final boolean localExists = existingVariable instanceof LocalVariableBinding; if (localExists && this.hiddenVariableDepth == 0) { if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) { scope.problemReporter().lambdaRedeclaresArgument(this); } else { scope.problemReporter().redefineArgument(this); } } else { boolean isSpecialArgument = false; if (existingVariable instanceof FieldBinding) { if (scope.isInsideConstructor()) { isSpecialArgument = true; // constructor argument } else { AbstractMethodDeclaration methodDecl = scope.referenceMethod(); if (methodDecl != null && CharOperation.prefixEquals(SET, methodDecl.selector)) { isSpecialArgument = true; // setter argument } } } scope.problemReporter().localVariableHiding(this, existingVariable, isSpecialArgument); } } scope.addLocalVariable(this.binding); this.binding.useFlag = used ? LocalVariableBinding.USED : LocalVariableBinding.UNUSED; return newTypeBinding; }
See Also:
  • getKind.getKind()
/** * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() */
@Override public int getKind() { return (this.bits & ASTNode.IsArgument) != 0 ? PARAMETER : LOCAL_VARIABLE; } @Override public boolean isArgument() { return true; } public boolean isVarArgs() { return this.type != null && (this.type.bits & IsVarArgs) != 0; } public boolean hasElidedType() { return (this.bits & IsTypeElided) != 0; } public boolean hasNullTypeAnnotation(AnnotationPosition position) { // parser associates SE8 annotations to the declaration return TypeReference.containsNullAnnotation(this.annotations) || (this.type != null && this.type.hasNullTypeAnnotation(position)); // just in case } @Override public StringBuffer print(int indent, StringBuffer output) { printIndent(indent, output); printModifiers(this.modifiers, output); if (this.annotations != null) { printAnnotations(this.annotations, output); output.append(' '); } if (this.type == null) { output.append("<no type> "); //$NON-NLS-1$ } else { this.type.print(0, output).append(' '); } return output.append(this.name); } @Override public StringBuffer printStatement(int indent, StringBuffer output) { return print(indent, output).append(';'); } public TypeBinding resolveForCatch(BlockScope scope) { // resolution on an argument of a catch clause // provide the scope with a side effect : insertion of a LOCAL // that represents the argument. The type must be from JavaThrowable TypeBinding exceptionType = this.type.resolveType(scope, true /* check bounds*/); boolean hasError; if (exceptionType == null) { hasError = true; } else { hasError = false; switch(exceptionType.kind()) { case Binding.PARAMETERIZED_TYPE : if (exceptionType.isBoundParameterizedType()) { hasError = true; scope.problemReporter().invalidParameterizedExceptionType(exceptionType, this); // fall thru to create the variable - avoids additional errors because the variable is missing } break; case Binding.TYPE_PARAMETER : scope.problemReporter().invalidTypeVariableAsException(exceptionType, this); hasError = true; // fall thru to create the variable - avoids additional errors because the variable is missing break; } if (exceptionType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null && exceptionType.isValidBinding()) { scope.problemReporter().cannotThrowType(this.type, exceptionType); hasError = true; // fall thru to create the variable - avoids additional errors because the variable is missing } } Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); if (existingVariable != null && existingVariable.isValidBinding()){ if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { scope.problemReporter().redefineArgument(this); } else { scope.problemReporter().localVariableHiding(this, existingVariable, false); } } if ((this.type.bits & ASTNode.IsUnionType) != 0) { this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers | ClassFileConstants.AccFinal, false); // argument decl, but local var (where isArgument = false) this.binding.tagBits |= TagBits.MultiCatchParameter; } else { this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers, false); // argument decl, but local var (where isArgument = false) } resolveAnnotations(scope, this.annotations, this.binding, true); Annotation.isTypeUseCompatible(this.type, scope, this.annotations); if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled && (this.type.hasNullTypeAnnotation(AnnotationPosition.ANY) || TypeReference.containsNullAnnotation(this.annotations))) { scope.problemReporter().nullAnnotationUnsupportedLocation(this.type); } scope.addLocalVariable(this.binding); this.binding.setConstant(Constant.NotAConstant); if (hasError) return null; return exceptionType; } @Override public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { if (this.annotations != null) { int annotationsLength = this.annotations.length; for (int i = 0; i < annotationsLength; i++) this.annotations[i].traverse(visitor, scope); } if (this.type != null) this.type.traverse(visitor, scope); } visitor.endVisit(this, scope); } public void traverse(ASTVisitor visitor, ClassScope scope) { if (visitor.visit(this, scope)) { if (this.annotations != null) { int annotationsLength = this.annotations.length; for (int i = 0; i < annotationsLength; i++) this.annotations[i].traverse(visitor, scope); } if (this.type != null) this.type.traverse(visitor, scope); } visitor.endVisit(this, scope); } }