| /* |
| * 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; |
| } |
| } |