Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new Java 21 features in dataflow #6192

Merged
merged 122 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 102 commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
9bdb6ac
Update for Java 21
mernst Sep 8, 2023
3e46273
Test under Java 21
mernst Sep 9, 2023
58a2617
Lombok doesn't support JDK 21
mernst Sep 9, 2023
c5d2710
Lombok doesn't support JDK 21
mernst Sep 9, 2023
47abe20
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 10, 2023
a049816
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 10, 2023
eebb32a
Clean WPI output
mernst Sep 10, 2023
74d1717
Add quoting
mernst Sep 10, 2023
ad15994
Merge /home/mernst/research/types/checker-framework-fork-mernst-branc…
mernst Sep 10, 2023
a1fd4a9
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 10, 2023
de524ea
WPI documentation
mernst Sep 11, 2023
93f4675
Use prerelease of Gradle 8.4
mernst Sep 11, 2023
c47f178
Improve diagnostics when clean command fails
mernst Sep 11, 2023
bfa6fe5
Merge ../checker-framework-branch-master into jdk21-test
mernst Sep 11, 2023
fc21964
Better diagnostics
mernst Sep 11, 2023
fab08f2
In Java 21 case lables can be
smillst Sep 12, 2023
8b8c704
Fix.
smillst Sep 12, 2023
8a6abdb
wpi-many tests under Java 21
mernst Sep 12, 2023
d4b74e9
Expand comment
mernst Sep 12, 2023
0021eee
Merge ../checker-framework-branch-master into jdk21-test
mernst Sep 12, 2023
4206a1a
Merge ../checker-framework-branch-master into jdk21-test
mernst Sep 12, 2023
0a8b1b8
Reinstate Java 20 support
mernst Sep 13, 2023
eddfeed
Fix cut-and-paste error
mernst Sep 13, 2023
988847b
Expand changelog
mernst Sep 13, 2023
45ff161
Merge branch 'jdk21-test' into java-21-testcase
smillst Sep 13, 2023
cbd5e5f
Merge ../checker-framework-fork-mernst-branch-jdk21-test into install…
mernst Sep 13, 2023
c0f6823
Fix lint.
smillst Sep 13, 2023
bcaa0a5
Revert previous attempt to support case null
smillst Sep 13, 2023
bbe621c
Correction.
smillst Sep 13, 2023
0939842
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 14, 2023
1e10665
Checkpoint.
smillst Sep 14, 2023
eacabbc
Use prerelease Ubuntu, install JDK 17 in each Docker image
mernst Sep 14, 2023
19b0374
All the JEP 441 tests do not crash.
smillst Sep 14, 2023
5e9aa30
Make wpi.sh message less scary
mernst Sep 14, 2023
fd25570
Remove scary progress message
mernst Sep 14, 2023
e937dc9
Add `update-java-alternatives` command
mernst Sep 16, 2023
35e250d
Merge branch 'jdk21-test' of github.com:mernst/checker-framework into…
mernst Sep 16, 2023
0cc911e
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 16, 2023
bdf6b22
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 17, 2023
f518684
Suppress "this-escape" warning
mernst Sep 17, 2023
37da7e6
Suppress "this-escape" warning
mernst Sep 17, 2023
47ee885
Suppress "this-escape" warning
mernst Sep 17, 2023
53665c1
Suppress "this-escape" warning
mernst Sep 17, 2023
2ff5a04
Suppress "this-escape" warning
mernst Sep 17, 2023
f7dca87
Suppress "this-escape" warning
mernst Sep 17, 2023
0096386
Suppress "this-escape" warning
mernst Sep 17, 2023
4ee9b7a
Suppress warnings
mernst Sep 17, 2023
59896b3
Add Javadoc
mernst Sep 17, 2023
f9294a5
Add --add-exports
mernst Sep 17, 2023
d098acb
Merge ../checker-framework-branch-master into install-jdk17-too
mernst Sep 17, 2023
9dc3e3b
Merge ../checker-framework-fork-mernst-branch-install-jdk17-too into …
mernst Sep 17, 2023
142b85f
Fix command-line syntax
mernst Sep 17, 2023
d47e42a
Fix typo
mernst Sep 18, 2023
b7ee23c
Use --add-opens because of reflective access.
smillst Sep 18, 2023
15a94f1
Revert "Use --add-opens because of reflective access."
smillst Sep 18, 2023
554068f
Revert "Fix typo"
smillst Sep 18, 2023
daafb18
Revert "Fix command-line syntax"
smillst Sep 18, 2023
0e533e0
Revert "Add --add-exports"
smillst Sep 18, 2023
22f4359
Checkpoint.
smillst Sep 18, 2023
ad2d8a8
Revert to gradle 8.3
smillst Sep 19, 2023
2817a6a
Revert suppressing this-escape warnings.
smillst Sep 19, 2023
ef231f3
Doesn't crash on JEP 440.
smillst Sep 19, 2023
9219a00
Don't run jdk20 jobs.
smillst Sep 19, 2023
809f770
Merge branch 'jdk21-test' into no-crash-jep441
smillst Sep 20, 2023
d5ffcb3
Merge remote-tracking branch 'origin/master' into no-crash-jep441
smillst Sep 20, 2023
b12e330
Can't format Java 21 language features.
smillst Sep 20, 2023
6a7bda3
Skip more inference types.
smillst Sep 20, 2023
a4a6025
Suppresswarnings.
smillst Sep 20, 2023
da0a1ff
Add nonnull.
smillst Sep 20, 2023
a485f55
Fix.
smillst Sep 20, 2023
13b3c26
Merge branch 'no-crash-jep441' into no-crash-jep440
smillst Sep 20, 2023
54f2244
Tweak.
smillst Sep 21, 2023
4d32cff
Tweak
smillst Sep 21, 2023
aaf78e8
Add a DeconstructorPatternNode.
smillst Sep 21, 2023
747c022
Checkpoint.
smillst Sep 21, 2023
985f144
More skips.
smillst Sep 21, 2023
f6d289b
Check for null.
smillst Sep 21, 2023
8ab15ae
True positives.
smillst Sep 22, 2023
b6208a1
Support guards.
smillst Sep 22, 2023
8606ede
Javadoc.
smillst Sep 22, 2023
c581c68
Update change log.
smillst Sep 22, 2023
a48946d
Fix it.
smillst Sep 22, 2023
7d1e592
More checks for null.
smillst Sep 22, 2023
d08a632
Merge remote-tracking branch 'origin/master' into no-crash-jep440
smillst Sep 22, 2023
84f8e40
Skip some checks.
smillst Sep 22, 2023
576b8ba
Merge branch 'master' into no-crash-jep440
mernst Sep 23, 2023
3f498dd
Prevent nullness errors
mernst Sep 23, 2023
1a00362
Merge /home/mernst/research/types/checker-framework-branch-master int…
mernst Sep 24, 2023
a2347a3
Fix variable name
mernst Sep 24, 2023
bc9a755
Avoid nullness errors
mernst Sep 24, 2023
28c259d
Renaming, documentation
mernst Sep 24, 2023
c0dd312
Merge ../checker-framework-branch-master into no-crash-jep440
mernst Sep 24, 2023
00e5943
Add TODO comments
mernst Sep 24, 2023
6bf7cf6
Fix.
smillst Sep 25, 2023
2a5ea88
Suppress more nullness warnings
mernst Sep 25, 2023
6e647a2
Merge branch 'master' into no-crash-jep440
mernst Sep 25, 2023
bde9c22
Move comments
mernst Sep 25, 2023
72315ba
Merge ../checker-framework-branch-master into no-crash-jep440
mernst Sep 25, 2023
5a5c4e9
Brevity
mernst Sep 25, 2023
6966b55
Merge ../checker-framework-branch-master into no-crash-jep440
mernst Sep 25, 2023
2c8bd83
Add documentation
mernst Sep 25, 2023
51e1ef6
Add import statement
mernst Sep 25, 2023
0084008
Address most of the code review.
smillst Sep 26, 2023
defc2ac
Add comment.
smillst Sep 26, 2023
ddd5c69
Merge branch 'master' into no-crash-jep440
smillst Sep 26, 2023
8d0b32e
Add a passing test case.
smillst Sep 27, 2023
1e0fe82
Merge branch 'no-crash-jep440' of github.com:smillst/checker-framewor…
smillst Sep 27, 2023
bdde443
Move test file.
smillst Sep 27, 2023
e3efbb0
Revert "Avoid nullness errors"
smillst Sep 27, 2023
2037e74
Merge remote-tracking branch 'origin/master' into no-crash-jep440
smillst Sep 27, 2023
285bd8c
Code review tweaks
mernst Sep 27, 2023
0ca68dd
Code review tweaks
mernst Sep 27, 2023
078012e
Merge remote-tracking branch 'origin/master' into no-crash-jep440
smillst Sep 27, 2023
5365302
Merge branch 'no-crash-jep440' of github.com:smillst/checker-framewor…
smillst Sep 27, 2023
0138c87
Rename.
smillst Sep 27, 2023
b183000
Code review.
smillst Sep 27, 2023
69548e8
Revert "Code review tweaks"
smillst Sep 27, 2023
7ace7d7
Put back a small change from the previously reverted commit.
smillst Sep 27, 2023
361cb4a
Merge remote-tracking branch 'origin/master' into no-crash-jep440
smillst Sep 27, 2023
f0ec233
Try to make code clearer.
smillst Sep 27, 2023
cda38b2
Add Javadoc.
smillst Sep 27, 2023
87a4604
Check for var decl more places.
smillst Sep 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ allprojects {
doNotFormat += ['**/java17/', '**/*record*/']
}

// As of 2023-09-24, google-java-format cannot parse Java 21 language features.
// See https://github.com/google/google-java-format/releases.
if (true) {
doNotFormat += ['**/java21/']
}

if (!isJava21orHigher) {
doNotFormat += ['**/java21/']
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() {
if (!Signatures.isBinaryName(qualName)) {
throw new UserError("Malformed qualifier \"%s\" in -Aquals", qualName);
}
qualSet.add(loader.loadExternalAnnotationClass(qualName));
Class<? extends Annotation> annoClass = loader.loadExternalAnnotationClass(qualName);
smillst marked this conversation as resolved.
Show resolved Hide resolved
if (annoClass == null) {
throw new UserError("Cannot load qualifier \"%s\" in -Aquals", qualName);
}
qualSet.add(annoClass);
}

// load directories of qualifiers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public Void visitBinary(BinaryTree tree, Void p) {
public Void visitMethodInvocation(MethodInvocationTree tree, Void p) {
if (isInvocationOfEquals(tree)) {
AnnotatedTypeMirror receiverType = atypeFactory.getReceiverType(tree);
assert receiverType != null : "@AssumeAssertion(nullness)";
smillst marked this conversation as resolved.
Show resolved Hide resolved
AnnotatedTypeMirror comp = atypeFactory.getAnnotatedType(tree.getArguments().get(0));

if (this.checker.getLintOption("dotequals", true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,14 +419,16 @@ public Void visitIf(IfTree tree, Void p) {
public Void visitInstanceOf(InstanceOfTree tree, Void p) {
// The "reference type" is the type after "instanceof".
Tree refTypeTree = tree.getType();
if (refTypeTree.getKind() == Tree.Kind.ANNOTATED_TYPE) {
List<? extends AnnotationMirror> annotations =
TreeUtils.annotationsFromTree((AnnotatedTypeTree) refTypeTree);
if (AnnotationUtils.containsSame(annotations, NULLABLE)) {
checker.reportError(tree, "instanceof.nullable");
}
if (AnnotationUtils.containsSame(annotations, NONNULL)) {
checker.reportWarning(tree, "instanceof.nonnull.redundant");
if (refTypeTree != null) {
if (refTypeTree.getKind() == Tree.Kind.ANNOTATED_TYPE) {
List<? extends AnnotationMirror> annotations =
TreeUtils.annotationsFromTree((AnnotatedTypeTree) refTypeTree);
if (AnnotationUtils.containsSame(annotations, NULLABLE)) {
checker.reportError(tree, "instanceof.nullable");
}
if (AnnotationUtils.containsSame(annotations, NONNULL)) {
checker.reportWarning(tree, "instanceof.nonnull.redundant");
}
}
}
// Don't call super because it will issue an incorrect instanceof.unsafe warning.
Expand Down
2 changes: 1 addition & 1 deletion checker/tests/nullness/java17/SwitchTestIssue5412.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public String foo1a(MyEnum b) {
// The default case is dead code, so it would be possible for type-checking
// to skip it and not issue this warning. But giving the warning is also
// good.
// :: error: (switch.expression)
default -> null;
};
// :: error: (return)
return s;
}

Expand Down
83 changes: 83 additions & 0 deletions checker/tests/nullness/java21/FlowSwitch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// @below-java21-jdk-skip-test
// @infer-jaifs-skip-test
smillst marked this conversation as resolved.
Show resolved Hide resolved
// @infer-ajava-skip-test
// @infer-stubs-skip-test

public class FlowSwitch {

void test1(Integer i) {
String msg = null;
switch (i) {
case -1, 1:
msg = "-1 or 1";
break;
case Integer j when j > 0:
msg = "pos";
break;
case Integer j:
msg = "everything else";
break;
}
msg.toString();
}

void test2(Integer i) {
String msg = null;
switch (i) {
case -1, 1:
msg = "-1 or 1";
break;
default:
msg = "everythingything else";
break;
case 2:
msg = "pos";
break;
}
}

class A {}

class B extends A {}

sealed interface I permits C, D {}

final class C implements I {}

final class D implements I {}

record Pair<T>(T x, T y) {}

void testE(Pair<A> p1) {
B e = switch (p1) {
case Pair<A>(A a, B b) -> b;
case Pair<A>(B b, A a) -> b;
default -> null;
};
B e2 = null;
switch (p1) {
case Pair<A>(A a, B b) -> e2 = b;
case Pair<A>(B b, A a) -> e2 = b;
default -> e2 = new B();
}
e2.toString();
}

void test3(Pair<I> p2) {
String s = null;
I e = null;
switch (p2) {
case Pair<I>(I i, C c) -> {e = c; s="";}
case Pair<I>(I i, D d) -> {e = d; s="";}
}
s.toString();
e.toString();

I e2 = null;
switch (p2) {
case Pair<I>(C c, I i) -> e2 = c;
case Pair<I>(D d, C c) -> e2 = d;
case Pair<I>(D d1, D d2) -> e2 = d2;
}
}
}
29 changes: 29 additions & 0 deletions checker/tests/nullness/java21/SimpleCaseGuard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @below-java21-jdk-skip-test
// @infer-jaifs-skip-test
// @infer-ajava-skip-test
// @infer-stubs-skip-test

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public class SimpleCaseGuard {

@Nullable String field;

void test2(Object obj, boolean b) {
switch (obj) {
case String s when field != null -> {
@NonNull String z = field;
}
case String s -> {
// :: error: (assignment)
@NonNull String z = field;
}
default -> {
// :: error: (assignment)
@NonNull String z = field;
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.sun.source.tree.SynchronizedTree;
import com.sun.source.tree.ThrowTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TryTree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.TypeParameterTree;
Expand Down Expand Up @@ -104,6 +105,7 @@
import org.checkerframework.dataflow.cfg.node.ConditionalAndNode;
import org.checkerframework.dataflow.cfg.node.ConditionalNotNode;
import org.checkerframework.dataflow.cfg.node.ConditionalOrNode;
import org.checkerframework.dataflow.cfg.node.DeconstructorPatternNode;
import org.checkerframework.dataflow.cfg.node.DoubleLiteralNode;
import org.checkerframework.dataflow.cfg.node.EqualToNode;
import org.checkerframework.dataflow.cfg.node.ExplicitThisNode;
Expand Down Expand Up @@ -548,6 +550,8 @@ public Node scan(Tree tree, Void p) {
return visitSwitchExpression17(tree, p);
case "YIELD":
return visitYield17(tree, p);
case "DECONSTRUCTION_PATTERN":
return visitDeconstructionPattern21(tree, p);
default:
// fall through to generic behavior
}
Expand Down Expand Up @@ -606,6 +610,26 @@ public Node visitBindingPattern17(Tree bindingPatternTree, Void p) {
return varNode;
}

/**
* Visit a DeconstructionPatternTree.
*
* @param deconstructionPatternTree a DeconstructionPatternTree, typed as Tree so the Checker
* Framework compiles under JDK &lt; 21
* @param p an unused parameter
* @return the result of visiting the tree
*/
public Node visitDeconstructionPattern21(Tree deconstructionPatternTree, Void p) {
List<? extends Tree> nestedPatternTrees =
TreeUtils.deconstructionPatternTreeGetNestedPatterns(deconstructionPatternTree);
List<Node> nestedPatterns = new ArrayList<>(nestedPatternTrees.size());
for (Tree pattern : nestedPatternTrees) {
nestedPatterns.add(scan(pattern, p));
}

return new DeconstructorPatternNode(
TreeUtils.typeOf(deconstructionPatternTree), deconstructionPatternTree, nestedPatterns);
}

/* --------------------------------------------------------- */
/* Nodes and Labels Management */
/* --------------------------------------------------------- */
Expand Down Expand Up @@ -2327,6 +2351,7 @@ private SwitchBuilder(Tree switchTree) {

// Build CFG for the cases.
int defaultIndex = -1;
boolean exhaustiveAndNoDefault = exhaustiveAndNoDefault();
for (int i = 0; i < numCases; ++i) {
CaseTree caseTree = caseTrees.get(i);
if (TreeUtils.isDefaultCaseTree(caseTree)) {
Expand All @@ -2338,10 +2363,7 @@ private SwitchBuilder(Tree switchTree) {
boolean isLastCaseExceptDefault =
i == numCases - 1
|| (i == numCases - 2 && TreeUtils.isDefaultCaseTree(caseTrees.get(i + 1)));
// This can be extended to handle case statements as well as case rules.
boolean noFallthroughToHere = TreeUtils.isCaseRule(caseTree);
boolean isLastCaseOfExhaustive =
isLastCaseExceptDefault && casesAreExhaustive() && noFallthroughToHere;
boolean isLastCaseOfExhaustive = isLastCaseExceptDefault && exhaustiveAndNoDefault;
smillst marked this conversation as resolved.
Show resolved Hide resolved
buildCase(caseTree, i, isLastCaseOfExhaustive);
}
}
Expand Down Expand Up @@ -2461,10 +2483,15 @@ private void buildCase(CaseTree caseTree, int index, boolean isLastCaseOfExhaust
if (!isTerminalCase) {
// A case expression exists, and it needs to be tested.
ArrayList<Node> exprs = new ArrayList<>();
for (ExpressionTree exprTree : TreeUtils.caseTreeGetExpressions(caseTree)) {
for (Tree exprTree : TreeUtils.caseTreeGetLabels(caseTree)) {
exprs.add(scan(exprTree, null));
}
CaseNode test = new CaseNode(caseTree, selectorExprAssignment, exprs, env.getTypeUtils());

ExpressionTree guardTree = TreeUtils.caseTreeGetGuard(caseTree);
Node guard = (guardTree == null) ? null : scan(guardTree, null);

CaseNode test =
new CaseNode(caseTree, selectorExprAssignment, exprs, guard, env.getTypeUtils());
extendWithNode(test);
extendWithExtendedNode(new ConditionalJump(thisBodyLabel, nextCaseLabel));
}
Expand Down Expand Up @@ -2540,39 +2567,52 @@ private void buildCase(CaseTree caseTree, int index, boolean isLastCaseOfExhaust
}

/**
* Returns true if the cases are exhaustive -- exactly one is executed. There might or might not
* be a `default` case label; if there is, it is never used.
* Returns true if the switch is exhaustive and does not contain a default case.
*
* @return true if the cases are exhaustive
* @return true if the switch is exhaustive and does not contain a default case
*/
private boolean casesAreExhaustive() {
TypeMirror selectorTypeMirror = TreeUtils.typeOf(selectorExprTree);
private boolean exhaustiveAndNoDefault() {
smillst marked this conversation as resolved.
Show resolved Hide resolved
for (CaseTree caseTree : caseTrees) {
if (TreeUtils.isDefaultCaseTree(caseTree)) {
return false;
}
}

switch (selectorTypeMirror.getKind()) {
case BOOLEAN:
// TODO
break;
case DECLARED:
DeclaredType declaredType = (DeclaredType) selectorTypeMirror;
TypeElement declaredTypeElement = (TypeElement) declaredType.asElement();
if (declaredTypeElement.getKind() == ElementKind.ENUM) {
// It's an enumerated type.
List<VariableElement> enumConstants =
ElementUtils.getEnumConstants(declaredTypeElement);
List<Name> caseLabels = new ArrayList<>(enumConstants.size());
for (CaseTree caseTree : caseTrees) {
for (ExpressionTree caseEnumConstant : TreeUtils.caseTreeGetExpressions(caseTree)) {
caseLabels.add(((IdentifierTree) caseEnumConstant).getName());
}
}
// Could also check that the values match.
boolean result = enumConstants.size() == caseLabels.size();
return result;
// There is no default case. Check whether the switch is exhaustive.

// Switch expressions are always exhaustive, but they might have a default case, which is why
// the above loop is not fused with the below loop.
if (!TreeUtils.isSwitchStatement(switchTree)) {
return true;
}

int enumCaseLabels = 0;
for (CaseTree caseTree : caseTrees) {
for (Tree caseLabel : TreeUtils.caseTreeGetLabels(caseTree)) {
// Java guarantees that if one of the cases is the null literal, the switch is exhaustive.
// Also if certain other constructs exist.
if (caseLabel.getKind() == Kind.NULL_LITERAL
|| TreeUtils.isBindingPatternTree(caseLabel)
|| TreeUtils.isDeconstructionPatternTree(caseLabel)) {
return true;
}
break;
default:
break;
if (caseLabel.getKind() == Kind.IDENTIFIER) {
enumCaseLabels++;
}
}
}

TypeMirror selectorTypeMirror = TreeUtils.typeOf(selectorExprTree);
if (selectorTypeMirror.getKind() == TypeKind.DECLARED) {
DeclaredType declaredType = (DeclaredType) selectorTypeMirror;
TypeElement declaredTypeElement = (TypeElement) declaredType.asElement();
if (declaredTypeElement.getKind() == ElementKind.ENUM) {
// The switch expression's type is an enumerated type.
List<VariableElement> enumConstants = ElementUtils.getEnumConstants(declaredTypeElement);
return enumConstants.size() == enumCaseLabels;
}
}

return false;
}
}
Expand Down Expand Up @@ -3798,12 +3838,14 @@ public Node visitTypeParameter(TypeParameterTree tree, Void p) {
public Node visitInstanceOf(InstanceOfTree tree, Void p) {
InstanceOfNode instanceOfNode;
Node operand = scan(tree.getExpression(), p);
TypeMirror refType = TreeUtils.typeOf(tree.getType());
Tree binding = TreeUtils.instanceOfTreeGetPattern(tree);
LocalVariableNode bindingNode =
(LocalVariableNode) ((binding == null) ? null : scan(binding, p));

instanceOfNode = new InstanceOfNode(tree, operand, bindingNode, refType, types);
Tree patternTree = TreeUtils.instanceOfTreeGetPattern(tree);
if (patternTree != null) {
Node pattern = scan(patternTree, p);
instanceOfNode = new InstanceOfNode(tree, operand, pattern, pattern.getType(), types);
} else {
TypeMirror refType = TreeUtils.typeOf(tree.getType());
instanceOfNode = new InstanceOfNode(tree, operand, refType, types);
}
extendWithNode(instanceOfNode);
return instanceOfNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,4 +384,9 @@ public R visitMarker(MarkerNode n, P p) {
public R visitExpressionStatement(ExpressionStatementNode n, P p) {
return visitNode(n, p);
}

@Override
public R visitDeconstructorPattern(DeconstructorPatternNode n, P p) {
return visitNode(n, p);
}
}
Loading