blob: b83169f89c6047e36821e7c2561225bbc38680a8 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.lint.checks;
import static com.android.tools.lint.checks.AnnotationDetector.ATTR_FROM;
import static com.android.tools.lint.checks.AnnotationDetector.ATTR_TO;
import static com.android.tools.lint.checks.AnnotationDetector.INT_RANGE_ANNOTATION;
import static com.android.tools.lint.detector.api.UastLintUtils.getAnnotationLongValue;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.google.common.annotations.VisibleForTesting;
import org.jetbrains.uast.UAnnotation;
class IntRangeConstraint extends RangeConstraint {
final long from;
final long to;
@NonNull
public static IntRangeConstraint create(@NonNull UAnnotation annotation) {
assert INT_RANGE_ANNOTATION.isEquals(annotation.getQualifiedName());
long from = getAnnotationLongValue(annotation, ATTR_FROM, Long.MIN_VALUE);
long to = getAnnotationLongValue(annotation, ATTR_TO, Long.MAX_VALUE);
return new IntRangeConstraint(from, to);
}
@VisibleForTesting
static IntRangeConstraint atLeast(long value) {
return new IntRangeConstraint(value, Long.MAX_VALUE);
}
@VisibleForTesting
static IntRangeConstraint atMost(long value) {
return new IntRangeConstraint(Long.MIN_VALUE, value);
}
@VisibleForTesting
static IntRangeConstraint range(long from, long to) {
return new IntRangeConstraint(from, to);
}
private IntRangeConstraint(long from, long to) {
this.from = from;
this.to = to;
}
public boolean isValid(long value) {
return value >= from && value <= to;
}
@NonNull
public String describe() {
return describe(null);
}
@NonNull
public String describe(long argument) {
return describe(Long.valueOf(argument));
}
@NonNull
private String describe(@Nullable Long actualValue) {
StringBuilder sb = new StringBuilder(20);
// If we have an actual value, don't describe the full range, only describe
// the parts that are outside the range
if (actualValue != null && !isValid(actualValue)) {
long value = actualValue;
if (value < from) {
sb.append("Value must be \u2265 ");
sb.append(Long.toString(from));
} else {
assert value > to;
sb.append("Value must be \u2264 ");
sb.append(Long.toString(to));
}
sb.append(" (was ").append(value).append(')');
return sb.toString();
}
if (to == Long.MAX_VALUE) {
sb.append("Value must be \u2265 ");
sb.append(Long.toString(from));
} else if (from == Long.MIN_VALUE) {
sb.append("Value must be \u2264 ");
sb.append(Long.toString(to));
} else {
sb.append("Value must be \u2265 ");
sb.append(Long.toString(from));
sb.append(" and \u2264 ");
sb.append(Long.toString(to));
}
if (actualValue != null) {
sb.append(" (is ").append(actualValue).append(')');
}
return sb.toString();
}
@Override
public String toString() {
return describe(null);
}
@Nullable
@Override
public Boolean contains(@NonNull RangeConstraint other) {
if (other instanceof IntRangeConstraint) {
IntRangeConstraint otherRange = (IntRangeConstraint) other;
return otherRange.from >= from && otherRange.to <= to;
} else if (other instanceof FloatRangeConstraint) {
FloatRangeConstraint otherRange = (FloatRangeConstraint) other;
if (!otherRange.fromInclusive && otherRange.from == (double) from
|| !otherRange.toInclusive && otherRange.to == (double) to) {
return false;
}
// Both represent infinity
if (otherRange.to > to && !(Double.isInfinite(otherRange.to) && to == Long.MAX_VALUE)) {
return false;
}
//noinspection RedundantIfStatement
if (otherRange.from < from
&& !(Double.isInfinite(otherRange.from) && from == Long.MIN_VALUE)) {
return false;
}
return true;
}
return null;
}
}