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

org.checkerframework.framework.util.FieldInvariants 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.42.0-eisop4
Show newest version
package org.checkerframework.framework.util;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.source.DiagMessage;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.javacutil.BugInCF;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;

/**
 * Represents field invariants, which the user states by writing {@code @FieldInvariant}. Think of
 * this as a set of (field name, qualifier) pairs.
 *
 * 

If a FieldInvariants object is malformed (inconsistent number of fields and qualifiers), * BaseTypeVisitor will issue an error. */ public class FieldInvariants { /** * A list of simple field names. A field may appear more than once in this list. This list has * the same length as {@link #qualifiers}. */ private final List fields; /** * A list of qualifiers that apply to the field at the same index in {@link #fields}. In a * well-formed FieldInvariants, has the same length as {@link #fields}. */ private final List qualifiers; /** The type factory associated with this. */ private final AnnotatedTypeFactory atypeFactory; /** * Creates a new FieldInvariants object. The result is well-formed if the length of qualifiers * is either 1 or equal to length of {@code fields}. * * @param fields list of fields * @param qualifiers list of qualifiers, or a single qualifier that applies to all fields * @param atypeFactory the type factory */ public FieldInvariants( List fields, List qualifiers, AnnotatedTypeFactory atypeFactory) { this(null, fields, qualifiers, atypeFactory); } /** * Creates a new object with all the invariants in {@code other}, plus those specified by {@code * fields} and {@code qualifiers}. The result is well-formed if the length of qualifiers is * either 1 or equal to length of {@code fields}. * * @param other other invariant object, may be null * @param fields list of fields * @param qualifiers list of qualifiers * @param atypeFactory the type factory */ public FieldInvariants( @Nullable FieldInvariants other, List fields, List qualifiers, AnnotatedTypeFactory atypeFactory) { if (qualifiers.size() == 1) { while (fields.size() > qualifiers.size()) { qualifiers.add(qualifiers.get(0)); } } if (other != null) { fields.addAll(other.fields); qualifiers.addAll(other.qualifiers); } this.fields = Collections.unmodifiableList(fields); this.qualifiers = qualifiers; this.atypeFactory = atypeFactory; } /** The simple names of the fields that have a qualifier. May contain duplicates. */ public List getFields() { return fields; } /** * Returns a list of qualifiers for {@code field}. If {@code field} has no qualifiers, returns * an empty list. * * @param field simple field name * @return a list of qualifiers for {@code field}, possibly empty */ public List getQualifiersFor(CharSequence field) { if (!isWellFormed()) { throw new BugInCF("malformed FieldInvariants"); } String fieldString = field.toString(); int index = fields.indexOf(fieldString); if (index == -1) { return Collections.emptyList(); } List list = new ArrayList<>(); for (int i = 0; i < fields.size(); i++) { if (fields.get(i).equals(fieldString)) { list.add(qualifiers.get(i)); } } return list; } /** * Returns true if there is a qualifier for each field in {@code fields}. * * @return true if there is a qualifier for each field in {@code fields} */ public boolean isWellFormed() { return qualifiers.size() == fields.size(); } /** * Returns null if this is stronger than the given FieldInvariants, otherwise returns the error * message. This is stronger if each of its qualifiers is a subtype of (or equal to) the * respective qualfier in the given FieldInvariants. * * @param superInvar the value to check for being a weaker invariant * @return null if this is stronger, otherwise returns an error message */ public @Nullable DiagMessage isStrongerThan(FieldInvariants superInvar) { QualifierHierarchy qualHierarchy = atypeFactory.getQualifierHierarchy(); if (!this.fields.containsAll(superInvar.fields)) { List missingFields = new ArrayList<>(superInvar.fields); missingFields.removeAll(fields); return DiagMessage.error( "field.invariant.not.found.superclass", String.join(", ", missingFields)); } for (String field : superInvar.fields) { List superQualifiers = superInvar.getQualifiersFor(field); List subQualifiers = this.getQualifiersFor(field); for (AnnotationMirror superA : superQualifiers) { AnnotationMirror sub = qualHierarchy.findAnnotationInSameHierarchy(subQualifiers, superA); if (sub == null || !qualHierarchy.isSubtypeQualifiersOnly(sub, superA)) { return DiagMessage.error( "field.invariant.not.subtype.superclass", field, sub, superA); } } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy