blob: 4ccaf64aede7fa2699df9671ec19548744d84765 [file] [log] [blame]
package org.checkerframework.checker.index.upperbound;
import java.util.HashSet;
import java.util.LinkedHashSet;
import javax.lang.model.element.ExecutableElement;
import org.checkerframework.checker.index.inequality.LessThanChecker;
import org.checkerframework.checker.index.lowerbound.LowerBoundChecker;
import org.checkerframework.checker.index.qual.LTEqLengthOf;
import org.checkerframework.checker.index.qual.LTLengthOf;
import org.checkerframework.checker.index.qual.LTOMLengthOf;
import org.checkerframework.checker.index.qual.SubstringIndexFor;
import org.checkerframework.checker.index.qual.UpperBoundLiteral;
import org.checkerframework.checker.index.samelen.SameLenChecker;
import org.checkerframework.checker.index.searchindex.SearchIndexChecker;
import org.checkerframework.checker.index.substringindex.SubstringIndexChecker;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.signature.qual.FullyQualifiedName;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.value.ValueChecker;
import org.checkerframework.framework.qual.RelevantJavaTypes;
import org.checkerframework.framework.source.SuppressWarningsPrefix;
import org.checkerframework.javacutil.TreeUtils;
/**
* A type-checker for preventing arrays from being accessed with values that are too high.
*
* @checker_framework.manual #index-checker Index Checker
*/
@RelevantJavaTypes({
Byte.class,
Short.class,
Integer.class,
Long.class,
Character.class,
byte.class,
short.class,
int.class,
long.class,
char.class,
})
@SuppressWarningsPrefix({"index", "upperbound"})
public class UpperBoundChecker extends BaseTypeChecker {
/** The SubstringIndexFor.value argument/element. */
public @MonotonicNonNull ExecutableElement substringIndexForValueElement;
/** The SubstringIndexFor.offset argument/element. */
public @MonotonicNonNull ExecutableElement substringIndexForOffsetElement;
/** The LTLengthOf.value argument/element. */
public @MonotonicNonNull ExecutableElement ltLengthOfValueElement;
/** The LTLengthOf.offset argument/element. */
public @MonotonicNonNull ExecutableElement ltLengthOfOffsetElement;
/** The LTEqLengthOf.value argument/element. */
public @MonotonicNonNull ExecutableElement ltEqLengthOfValueElement;
/** The LTOMLengthOf.value argument/element. */
public @MonotonicNonNull ExecutableElement ltOMLengthOfValueElement;
/** The UpperBoundLiteral.value element/field. */
public @MonotonicNonNull ExecutableElement upperBoundLiteralValueElement;
/**
* These collection classes have some subtypes whose length can change and some subtypes whose
* length cannot change. Warnings are skipped at uses of them.
*/
private HashSet<String> collectionBaseTypeNames;
/** Create a new UpperBoundChecker. */
public UpperBoundChecker() {
// These classes are bases for both mutable and immutable sequence collections, which
// contain methods that change the length.
// Upper bound checker warnings are skipped at uses of them.
Class<?>[] collectionBaseClasses = {java.util.List.class, java.util.AbstractList.class};
collectionBaseTypeNames = new HashSet<>(collectionBaseClasses.length);
for (Class<?> collectionBaseClass : collectionBaseClasses) {
collectionBaseTypeNames.add(collectionBaseClass.getName());
}
}
@Override
public void initChecker() {
super.initChecker();
substringIndexForValueElement =
TreeUtils.getMethod(SubstringIndexFor.class, "value", 0, processingEnv);
substringIndexForOffsetElement =
TreeUtils.getMethod(SubstringIndexFor.class, "offset", 0, processingEnv);
ltLengthOfValueElement = TreeUtils.getMethod(LTLengthOf.class, "value", 0, processingEnv);
ltLengthOfOffsetElement = TreeUtils.getMethod(LTLengthOf.class, "offset", 0, processingEnv);
ltEqLengthOfValueElement = TreeUtils.getMethod(LTEqLengthOf.class, "value", 0, processingEnv);
ltOMLengthOfValueElement = TreeUtils.getMethod(LTOMLengthOf.class, "value", 0, processingEnv);
upperBoundLiteralValueElement =
TreeUtils.getMethod(UpperBoundLiteral.class, "value", 0, processingEnv);
}
@Override
public boolean shouldSkipUses(@FullyQualifiedName String typeName) {
if (collectionBaseTypeNames.contains(typeName)) {
return true;
}
return super.shouldSkipUses(typeName);
}
@Override
protected LinkedHashSet<Class<? extends BaseTypeChecker>> getImmediateSubcheckerClasses() {
LinkedHashSet<Class<? extends BaseTypeChecker>> checkers =
super.getImmediateSubcheckerClasses();
checkers.add(SubstringIndexChecker.class);
checkers.add(SearchIndexChecker.class);
checkers.add(SameLenChecker.class);
checkers.add(LowerBoundChecker.class);
checkers.add(ValueChecker.class);
checkers.add(LessThanChecker.class);
return checkers;
}
}