Skip to content

Commit

Permalink
PreconditionsHandler reflects Guava Preconditions exception types (#668)
Browse files Browse the repository at this point in the history
This change does not impact CFG construction, since it already assumed that method calls (like the `Preconditions` calls) could throw any unchecked exception and built the CFG accordingly.  Still, it's good to more accurately model which exception type may be thrown by each `Preconditions` method.
  • Loading branch information
carterkozak authored Oct 3, 2022
1 parent 92d94a7 commit 6cd33ba
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public class PreconditionsHandler extends BaseNoOpHandler {
@Nullable private Name preconditionsClass;
@Nullable private Name checkArgumentMethod;
@Nullable private Name checkStateMethod;
@Nullable TypeMirror preconditionErrorType;
@Nullable TypeMirror preconditionCheckArgumentErrorType;
@Nullable TypeMirror preconditionCheckStateErrorType;

@Override
public MethodInvocationNode onCFGBuildPhase1AfterVisitMethodInvocation(
Expand All @@ -31,13 +32,23 @@ public MethodInvocationNode onCFGBuildPhase1AfterVisitMethodInvocation(
preconditionsClass = callee.name.table.fromString(PRECONDITIONS_CLASS_NAME);
checkArgumentMethod = callee.name.table.fromString(CHECK_ARGUMENT_METHOD_NAME);
checkStateMethod = callee.name.table.fromString(CHECK_STATE_METHOD_NAME);
preconditionErrorType = phase.classToErrorType(IllegalArgumentException.class);
preconditionCheckArgumentErrorType = phase.classToErrorType(IllegalArgumentException.class);
preconditionCheckStateErrorType = phase.classToErrorType(IllegalStateException.class);
}
Preconditions.checkNotNull(preconditionErrorType);
Preconditions.checkNotNull(preconditionCheckArgumentErrorType);
Preconditions.checkNotNull(preconditionCheckStateErrorType);
if (callee.enclClass().getQualifiedName().equals(preconditionsClass)
&& (callee.name.equals(checkArgumentMethod) || callee.name.equals(checkStateMethod))
&& callee.getParameters().size() > 0) {
phase.insertThrowOnFalse(originalNode.getArgument(0), preconditionErrorType);
&& !callee.getParameters().isEmpty()) {
// Attempt to match Precondition check methods to the expected exception type, providing as
// much context as possible for static analysis.
// In practice this may not be strictly necessary because the conditional throw is inserted
// after the method invocation, thus analysis must assume that the preconditions call is
// capable of throwing any unchecked throwable.
if (callee.name.equals(checkArgumentMethod)) {
phase.insertThrowOnFalse(originalNode.getArgument(0), preconditionCheckArgumentErrorType);
} else if (callee.name.equals(checkStateMethod)) {
phase.insertThrowOnFalse(originalNode.getArgument(0), preconditionCheckStateErrorType);
}
}
return originalNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,52 @@ public void inconclusiveCheckArgumentTest() {
"}")
.doTest();
}

@Test
public void checkArgumentCatchException() {
makeTestHelperWithArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import javax.annotation.Nullable;",
"import com.google.common.base.Preconditions;",
"class Test {",
" private void foo(@Nullable Object a) {",
" try {",
" Preconditions.checkArgument(a != null);",
" } catch (IllegalArgumentException e) {}",
" // BUG: Diagnostic contains: dereferenced expression a is @Nullable",
" a.toString();",
" }",
"}")
.doTest();
}

@Test
public void checkStateCatchException() {
makeTestHelperWithArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber"))
.addSourceLines(
"Test.java",
"package com.uber;",
"import javax.annotation.Nullable;",
"import com.google.common.base.Preconditions;",
"class Test {",
" private void foo(@Nullable Object a) {",
" try {",
" Preconditions.checkState(a != null);",
" } catch (IllegalStateException e) {}",
" // BUG: Diagnostic contains: dereferenced expression a is @Nullable",
" a.toString();",
" }",
"}")
.doTest();
}
}

0 comments on commit 6cd33ba

Please sign in to comment.