All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.checker.nullness.KeyForValue Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java's type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.43.0
Show newest version
package org.checkerframework.checker.nullness;

import com.sun.source.tree.ExpressionTree;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.KeyFor;
import org.checkerframework.framework.flow.CFAbstractAnalysis;
import org.checkerframework.framework.flow.CFAbstractValue;
import org.checkerframework.javacutil.AnnotationUtils;

/**
 * KeyForValue holds additional information about which maps this value is a key for. This extra
 * information is required when adding the @KeyFor qualifier to the type is not a refinement of the
 * type. For example,
 *
 * 
 * {@code Map map = ...;}
 * {@code  T method(T param) { }
 *   if (map.contains(param) {
 *     {@code @NonNull Object o = map.get(param);}
 *     return param;
 *   }
 * }
 * }
* * Inside the if statement, {@code param} is a key for "map". This would normally be represented as * {@code @KeyFor("map") T}, but this is not a subtype of {@code T}, so the type cannot be refined. * Instead, the value for {@code param} includes "map" in the list of keyForMaps. This information * is used in {@link KeyForAnnotatedTypeFactory#isKeyForMap(String, ExpressionTree)}. */ public class KeyForValue extends CFAbstractValue { /** * If the underlying type is a type variable or a wildcard, then this is a set of maps for which * this value is a key. Otherwise, it's null. */ private Set keyForMaps = null; public KeyForValue( CFAbstractAnalysis analysis, Set annotations, TypeMirror underlyingType) { super(analysis, annotations, underlyingType); AnnotationMirror keyfor = AnnotationUtils.getAnnotationByClass(annotations, KeyFor.class); if (keyfor != null && (underlyingType.getKind() == TypeKind.TYPEVAR || underlyingType.getKind() == TypeKind.WILDCARD)) { keyForMaps = new LinkedHashSet<>(); List list = AnnotationUtils.getElementValueArray(keyfor, "value", String.class, true); keyForMaps.addAll(list); } } /** * If the underlying type is a type variable or a wildcard, then this is a set of maps for which * this value is a key. Otherwise, it's null. */ public Set getKeyForMaps() { return keyForMaps; } @Override public KeyForValue leastUpperBound(KeyForValue other) { KeyForValue lub = super.leastUpperBound(other); if (other == null || other.keyForMaps == null || this.keyForMaps == null) { return lub; } // Lub the keyForMaps by intersecting the sets. lub.keyForMaps = new LinkedHashSet<>(); lub.keyForMaps.addAll(this.keyForMaps); lub.keyForMaps.retainAll(other.keyForMaps); if (lub.keyForMaps.isEmpty()) { lub.keyForMaps = null; } return lub; } @Override public KeyForValue mostSpecific(KeyForValue other, KeyForValue backup) { KeyForValue mostSpecific = super.mostSpecific(other, backup); if (mostSpecific == null) { if (other == null) { return this; } // mostSpecific is null if the two types are not comparable. This is normally // because one of this or other is a type variable and annotations is empty, but the // other annotations are not empty. In this case, copy the keyForMaps and to the // value with the no annotations and return it as most specific. if (other.getAnnotations().isEmpty()) { other.addKeyFor(this.keyForMaps); return other; } else if (this.getAnnotations().isEmpty()) { this.addKeyFor(other.keyForMaps); return this; } return null; } mostSpecific.addKeyFor(this.keyForMaps); if (other != null) { mostSpecific.addKeyFor(other.keyForMaps); } return mostSpecific; } private void addKeyFor(Set newKeyForMaps) { if (newKeyForMaps == null || newKeyForMaps.isEmpty()) { return; } if (keyForMaps == null) { keyForMaps = new LinkedHashSet<>(); } keyForMaps.addAll(newKeyForMaps); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy