Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* Copyright (c) 2012, 2020 GK Software SE, 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:
* Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.compiler.CharOperation;
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.ast.NullAnnotationMatching.CheckMode;
import org.eclipse.jdt.internal.compiler.ast.RecordComponent;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
/**
* Extracted slice from MethodVerifier15, which is responsible only for implicit null annotations.
* First, if enabled, it detects overridden methods from which null annotations are inherited.
* Next, also default nullness is filled into remaining empty slots.
* After all implicit annotations have been filled in compatibility is checked and problems are complained.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class ImplicitNullAnnotationVerifier {
public static void ensureNullnessIsKnown(MethodBinding methodBinding, Scope scope) {
if ((methodBinding.tagBits & TagBits.IsNullnessKnown) == 0) {
LookupEnvironment environment2 = scope.environment();
// ensure nullness of methodBinding is known (but we are not interested in reporting problems against methodBinding)
new ImplicitNullAnnotationVerifier(environment2, environment2.globalOptions.inheritNullAnnotations)
.checkImplicitNullAnnotations(methodBinding, null/*srcMethod*/, false, scope);
}
}
/**
* Simple record to store nullness info for one argument or return type
* while iterating over a set of overridden methods.
*/
static class InheritedNonNullnessInfo {
Boolean inheritedNonNullness;
MethodBinding annotationOrigin;
boolean complained;
}
// delegate which to ask for recursive analysis of super methods
// can be 'this', but is never a MethodVerifier (to avoid infinite recursion).
ImplicitNullAnnotationVerifier buddyImplicitNullAnnotationsVerifier;
private final boolean inheritNullAnnotations;
protected LookupEnvironment environment;
public ImplicitNullAnnotationVerifier(LookupEnvironment environment, boolean inheritNullAnnotations) {
this.buddyImplicitNullAnnotationsVerifier = this;
this.inheritNullAnnotations = inheritNullAnnotations;
this.environment = environment;
}
// for sub-classes:
ImplicitNullAnnotationVerifier(LookupEnvironment environment) {
CompilerOptions options = environment.globalOptions;
this.buddyImplicitNullAnnotationsVerifier = new ImplicitNullAnnotationVerifier(environment, options.inheritNullAnnotations);
this.inheritNullAnnotations = options.inheritNullAnnotations;
this.environment = environment;
}
/**
* Check and fill in implicit annotations from overridden methods and from default.
* Precondition: caller has checked whether annotation-based null analysis is enabled.
*/
public void checkImplicitNullAnnotations(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, boolean complain, Scope scope) {
// check inherited nullness from superclass and superInterfaces
try {
ReferenceBinding currentType = currentMethod.declaringClass;
if (currentType.id == TypeIds.T_JavaLangObject) {
return;
}
boolean usesTypeAnnotations = scope.environment().usesNullTypeAnnotations();
boolean needToApplyReturnNonNullDefault =
currentMethod.hasNonNullDefaultForReturnType(srcMethod);
ParameterNonNullDefaultProvider needToApplyParameterNonNullDefault =
currentMethod.hasNonNullDefaultForParameter(srcMethod);
boolean needToApplyNonNullDefault = needToApplyReturnNonNullDefault | needToApplyParameterNonNullDefault.hasAnyNonNullDefault();
// compatibility & inheritance do not consider constructors / static methods:
boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic();
complain &= isInstanceMethod;
if (!needToApplyNonNullDefault
&& !complain
&& !(this.inheritNullAnnotations && isInstanceMethod)) {
return; // short cut, no work to be done
}
if (isInstanceMethod) {
List superMethodList = new ArrayList();
// need super types connected:
if (currentType instanceof SourceTypeBinding && !currentType.isHierarchyConnected() && !currentType.isAnonymousType()) {
((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
}
int paramLen = currentMethod.parameters.length;
findAllOverriddenMethods(currentMethod.original(), currentMethod.selector, paramLen,
currentType, new HashSet(), superMethodList);
// prepare interim storage for nullness info so we don't pollute currentMethod before we know its conflict-free:
InheritedNonNullnessInfo[] inheritedNonNullnessInfos = new InheritedNonNullnessInfo[paramLen+1]; // index 0 is for the return type
for (int i=0; i= 0;) {
MethodBinding currentSuper = (MethodBinding) superMethodList.get(i);
if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) {
// recurse to prepare currentSuper
checkImplicitNullAnnotations(currentSuper, null, false, scope); // TODO (stephan) complain=true if currentSuper is source method??
}
checkNullSpecInheritance(currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, null, scope, inheritedNonNullnessInfos);
needToApplyNonNullDefault = false;
}
// transfer collected information into currentMethod:
InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0];
if (!info.complained) {
long tagBits = 0;
if (info.inheritedNonNullness == Boolean.TRUE) {
tagBits = TagBits.AnnotationNonNull;
} else if (info.inheritedNonNullness == Boolean.FALSE) {
tagBits = TagBits.AnnotationNullable;
}
if (tagBits != 0) {
if (!usesTypeAnnotations) {
currentMethod.tagBits |= tagBits;
} else {
if (!currentMethod.returnType.isBaseType()) {
LookupEnvironment env = scope.environment();
currentMethod.returnType = env.createAnnotatedType(currentMethod.returnType, env.nullAnnotationsFromTagBits(tagBits));
}
}
}
}
for (int i=0; i and X extends Object> as the same 'type'
if (one.isParameterizedType() && two.isParameterizedType())
return one.isEquivalentTo(two) && two.isEquivalentTo(one);
// Can skip this since we resolved each method before comparing it, see computeSubstituteMethod()
// if (one instanceof UnresolvedReferenceBinding)
// return ((UnresolvedReferenceBinding) one).resolvedType == two;
// if (two instanceof UnresolvedReferenceBinding)
// return ((UnresolvedReferenceBinding) two).resolvedType == one;
return false; // all other type bindings are identical
}
}