Skip to content

Commit

Permalink
Propagate length information from argument to return value of Arrays.…
Browse files Browse the repository at this point in the history
…copyOf() (#3524)
  • Loading branch information
PRITI1999 committed Aug 3, 2020
1 parent e16123b commit c9c65d1
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
40 changes: 40 additions & 0 deletions checker/tests/index/Issue3224.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Test case for https://tinyurl.com/cfissue/3224

import java.util.Arrays;
import org.checkerframework.common.value.qual.IntRange;
import org.checkerframework.common.value.qual.MinLen;

public class Issue3224 {
static class Arrays {
static String[] copyOf(String[] args, int length) {
return args;
}
}

public static void m1(String @MinLen(1) [] args) {
int i = 4;
String @MinLen(1) [] args2 = java.util.Arrays.copyOf(args, i);
}

public static void m2(String @MinLen(1) [] args) {
String @MinLen(1) [] args2 = java.util.Arrays.copyOf(args, args.length);
}

public static void m3(String @MinLen(1) ... args) {
String @MinLen(1) [] args2 = java.util.Arrays.copyOf(args, args.length);
}

public static void m4(String @MinLen(1) [] args, @IntRange(from = 10, to = 200) int len) {
String @MinLen(1) [] args2 = java.util.Arrays.copyOf(args, len);
}

public static void m5(String @MinLen(1) [] args, String[] otherArray) {
// :: error: assignment.type.incompatible
String @MinLen(1) [] args2 = java.util.Arrays.copyOf(args, otherArray.length);
}

public static void m6(String @MinLen(1) [] args) {
// :: error: assignment.type.incompatible
String @MinLen(1) [] args2 = Arrays.copyOf(args, args.length);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@ class ValueMethodIdentifier {
private final List<ExecutableElement> mathMinMethod;
/** The {@code java.lang.Math#max()} methods. */
private final List<ExecutableElement> mathMaxMethod;
/** Arrays.copyOf() methods. */
private final List<ExecutableElement> copyOfMethod;

/**
* Initialize elements with methods that have special handling in the value checker
*
* @param processingEnv the processing environment
*/
public ValueMethodIdentifier(ProcessingEnvironment processingEnv) {
lengthMethod = TreeUtils.getMethod("java.lang.String", "length", 0, processingEnv);
startsWithMethod = TreeUtils.getMethod("java.lang.String", "startsWith", 1, processingEnv);
endsWithMethod = TreeUtils.getMethod("java.lang.String", "endsWith", 1, processingEnv);
mathMinMethod = TreeUtils.getMethods("java.lang.Math", "min", 2, processingEnv);
mathMaxMethod = TreeUtils.getMethods("java.lang.Math", "max", 2, processingEnv);
copyOfMethod = TreeUtils.getMethods("java.util.Arrays", "copyOf", 2, processingEnv);
}

/** Returns true iff the argument is an invocation of Math.min. */
Expand Down Expand Up @@ -59,4 +67,15 @@ public boolean isEndsWithMethod(ExecutableElement method) {
// equals (rather than ElementUtils.ismethod) because String.length cannot be overridden
return method.equals(endsWithMethod);
}

/**
* Determines whether a tree is an invocation of the {@code Arrays.copyOf()} method.
*
* @param tree tree to check
* @param processingEnv the processing environment
* @return true iff the argument is an invocation of {@code Arrays.copyOf()} method.
*/
public boolean isArraysCopyOfInvocation(Tree tree, ProcessingEnvironment processingEnv) {
return TreeUtils.isMethodInvocation(tree, copyOfMethod, processingEnv);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.TypesUtils;
Expand Down Expand Up @@ -398,6 +399,22 @@ public Void visitMethodInvocation(MethodInvocationTree tree, AnnotatedTypeMirror
}
}

if (atypeFactory
.getMethodIdentifier()
.isArraysCopyOfInvocation(tree, atypeFactory.getProcessingEnv())) {
List<? extends ExpressionTree> args = tree.getArguments();
if (args.size() != 2) {
throw new BugInCF(
"Arrays.copyOf() should have 2 arguments. This point should not have reached");
}
Range range =
ValueCheckerUtils.getPossibleValues(
atypeFactory.getAnnotatedType(args.get(1)), atypeFactory);
if (range != null) {
type.replaceAnnotation(atypeFactory.createArrayLenRangeAnnotation(range));
}
}

if (!methodIsStaticallyExecutable(TreeUtils.elementFromUse(tree))
|| !handledByValueChecker(type)) {
return null;
Expand Down

0 comments on commit c9c65d1

Please sign in to comment.