Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
dc8ee8e
fix typo
aosen-xiong Aug 2, 2023
984656b
fix typo
aosen-xiong Aug 2, 2023
c5f519a
fix typo
aosen-xiong Aug 2, 2023
a6980ca
fix typo
aosen-xiong Aug 2, 2023
b9d3d64
test changes
aosen-xiong Aug 4, 2023
179e55d
Merge branch 'master' into fix-fieldaccess
aosen-xiong Aug 4, 2023
9de8f06
Merge branch 'fix-fieldaccess' of https://github.com/Ao-senXiong/chec…
aosen-xiong Aug 4, 2023
4b73445
apply spotless
aosen-xiong Aug 4, 2023
92248dc
apply spotless
aosen-xiong Aug 4, 2023
00a3855
test pipelines
aosen-xiong Aug 8, 2023
acf6530
Merge branch 'master' into fix-fieldaccess
aosen-xiong Oct 14, 2023
17e79e3
initial commit
aosen-xiong Oct 16, 2023
cc6844f
Merge branch 'master' into fix-fieldaccess
aosen-xiong Oct 17, 2023
63f45e6
Merge branch 'master' into fix-fieldaccess
aosen-xiong Oct 17, 2023
32b0f01
Merge branch 'master' into fix-fieldaccess
aosen-xiong Oct 21, 2023
ef96c4c
Merge branch 'eisop:master' into fix-fieldaccess
aosen-xiong Oct 23, 2023
d7cd564
Merge branch 'master' into fix-fieldaccess
aosen-xiong Dec 12, 2023
709e717
Merge branch 'master' into fix-fieldaccess
aosen-xiong Jun 1, 2024
1424533
Merge branch 'master' into fix-fieldaccess
aosen-xiong Aug 27, 2024
1c55e46
Merge branch 'master' into fix-fieldaccess
aosen-xiong Dec 15, 2024
ec79fa2
Add new Class literalNode and remove hardcode fix
aosen-xiong Dec 15, 2024
d896862
Clean up old hardcoding
aosen-xiong Dec 15, 2024
4990cc9
Override toString to use correct name for class literal
aosen-xiong Dec 15, 2024
2d1aea1
Update expected CFG
aosen-xiong Dec 15, 2024
bc92643
Leave qualified this in another PR
aosen-xiong Dec 15, 2024
fcd6950
Javadoc for NodeVisitor
aosen-xiong Dec 15, 2024
e6b6177
Update expected CFG
aosen-xiong Dec 15, 2024
c89b017
A lot of Javadoc
aosen-xiong Dec 15, 2024
4d04987
Maybe this is the cause of daikon failure
aosen-xiong Dec 15, 2024
9fee97c
Revert the change
aosen-xiong Dec 15, 2024
ea6b44e
Fix broken link
aosen-xiong Dec 15, 2024
a59417e
Don't check Daikon 2 to see if there is other failure
aosen-xiong Dec 15, 2024
5a15cd4
Undo CI
aosen-xiong Dec 15, 2024
47b2f63
Use PrimitiveTypeNode to represent class literal
aosen-xiong Dec 15, 2024
b7c80f1
Remove extra comma
aosen-xiong Dec 15, 2024
f5dec68
Use dummy constructor parameter to prevent ClassCastException
aosen-xiong Dec 15, 2024
ac88eef
Change field tree to Tree type
aosen-xiong Dec 15, 2024
731e05e
Only handle class literal
aosen-xiong Dec 15, 2024
076d3d3
PrimitiveTypeNode Javadoc
aosen-xiong Dec 15, 2024
691d206
Handle class literal seperately
aosen-xiong Dec 16, 2024
699ffd3
Also generate javaexpression for class literal and undo lockvisitor c…
aosen-xiong Dec 16, 2024
838fa79
Don't do cast and comment out unknown condition for testing
aosen-xiong Dec 16, 2024
e5a3cd8
Don't run JSpecify first
aosen-xiong Dec 16, 2024
3527e17
Use ClassLiteralNode again and remove hacks
aosen-xiong Dec 16, 2024
e3a6381
Add ClassLiteral file
aosen-xiong Dec 16, 2024
86d7d43
Don't check jspeicfy yet
aosen-xiong Dec 16, 2024
0ec3a94
Javadoc
aosen-xiong Dec 16, 2024
de55ec0
Javadoc
aosen-xiong Dec 16, 2024
115ba24
Javadoc
aosen-xiong Dec 16, 2024
eda8624
Enable JSpecify check since others already passed
aosen-xiong Dec 17, 2024
8796e13
Merge branch 'master' into fix-fieldaccess
aosen-xiong Jan 6, 2025
feef965
Merge branch 'master' into fix-fieldaccess
aosen-xiong Mar 21, 2025
af57480
Merge branch 'master' into fix-fieldaccess
wmdietl Mar 22, 2025
35818ac
Merge branch 'master' into fix-fieldaccess
aosen-xiong May 19, 2025
3d1e7d9
Merge branch 'master' into fix-fieldaccess
aosen-xiong Jun 18, 2025
3c7616f
Merge branch 'master' into fix-fieldaccess
aosen-xiong Mar 22, 2026
643eb88
Merge branch 'master' into fix-fieldaccess
aosen-xiong Jun 20, 2026
d084001
Clean up class literal CFG node
aosen-xiong Jun 20, 2026
adf6f75
Add visitor Javadocs for class literal node
aosen-xiong Jun 20, 2026
3296a6b
Skip Javadoc lint for class literal visitor change
aosen-xiong Jun 20, 2026
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
Empty file added SKIP-REQUIRE-JAVADOC
Empty file.
15 changes: 15 additions & 0 deletions checker/jtreg/nullness/EISOPissue548/ConservativeClassLiteral.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* @test
* @summary Test class literals in CFGs and their type with conservative nullness.
*
* @compile MyEnum.java
* @compile -processor org.checkerframework.checker.nullness.NullnessChecker -AuseConservativeDefaultsForUncheckedCode=bytecode,-source ConservativeClassLiteral.java
*/

import java.util.EnumSet;

class ConservativeClassLiteral {
EnumSet<MyEnum> none() {
return EnumSet.noneOf(MyEnum.class);
}
}
3 changes: 3 additions & 0 deletions checker/jtreg/nullness/EISOPissue548/MyEnum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
enum MyEnum {
VALUE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) {
@Override
public Void visitMemberSelect(
MemberSelectTree tree, AnnotatedTypeMirror annotatedTypeMirror) {
if (TreeUtils.isArrayLengthAccess(tree)) {
if (TreeUtils.isArrayLengthAccess(tree) || TreeUtils.isClassLiteral(tree)) {
annotatedTypeMirror.replaceAnnotation(INITIALIZED);
}
return super.visitMemberSelect(tree, annotatedTypeMirror);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,10 @@ public Void visitMemberSelect(MemberSelectTree tree, AnnotatedTypeMirror type) {
Element elt = TreeUtils.elementFromUse(tree);
assert elt != null;

// Make primitive variable @NonNull in case the Initialization Checker
// Make primitive variable and class literal @NonNull in case the Initialization Checker
// considers it uninitialized.
if (TypesUtils.isPrimitive(type.getUnderlyingType())) {
if (TypesUtils.isPrimitive(type.getUnderlyingType())
|| TreeUtils.isClassLiteral(tree)) {
type.replaceAnnotation(NONNULL);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import org.checkerframework.dataflow.cfg.node.CatchMarkerNode;
import org.checkerframework.dataflow.cfg.node.CharacterLiteralNode;
import org.checkerframework.dataflow.cfg.node.ClassDeclarationNode;
import org.checkerframework.dataflow.cfg.node.ClassLiteralNode;
import org.checkerframework.dataflow.cfg.node.ClassNameNode;
import org.checkerframework.dataflow.cfg.node.ConditionalAndNode;
import org.checkerframework.dataflow.cfg.node.ConditionalNotNode;
Expand Down Expand Up @@ -3714,6 +3715,12 @@ public Node visitReturn(ReturnTree tree, Void p) {
public Node visitMemberSelect(MemberSelectTree tree, Void p) {
Node expr = scan(tree.getExpression(), p);
if (!TreeUtils.isFieldAccess(tree)) {
if (TreeUtils.isClassLiteral(tree)) {
Node result = new ClassLiteralNode(tree, expr);
extendWithNode(result);
return result;
}

// Could be a selector of a class or package
Element element = TreeUtils.elementFromUse(tree);
if (ElementUtils.isTypeElement(element)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ public R visitPrimitiveType(PrimitiveTypeNode n, P p) {
return visitNode(n, p);
}

@Override
public R visitClassLiteral(ClassLiteralNode n, P p) {
return visitNode(n, p);
}

@Override
public R visitClassName(ClassNameNode n, P p) {
return visitNode(n, p);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.checkerframework.dataflow.cfg.node;

import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.Tree;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.javacutil.TreeUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.Objects;

/** A node for a class literal. For example: {@code String.class}. */
public class ClassLiteralNode extends Node {
/** The tree for the class literal. */
protected final MemberSelectTree tree;

/** The class name of the class literal. */
protected final Node className;

/**
* Create a new ClassLiteralNode.
*
* @param tree the class literal
* @param className the class name for the class literal
*/
public ClassLiteralNode(MemberSelectTree tree, Node className) {
super(TreeUtils.typeOf(tree));
this.tree = tree;
this.className = className;
}

@Override
public @Nullable Tree getTree() {
return tree;
}

/**
* Get the class name of the class literal.
*
* @return the class name of the class literal
*/
public Node getClassName() {
return className;
}

@Override
public <R, P> R accept(NodeVisitor<R, P> visitor, P p) {
return visitor.visitClassLiteral(this, p);
}

@Override
public String toString() {
return tree.toString();
}

@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ClassLiteralNode)) {
return false;
}
ClassLiteralNode other = (ClassLiteralNode) obj;
return getClassName().equals(other.getClassName());
}

@Override
public int hashCode() {
return Objects.hash(getClassName());
}

@Override
@SideEffectFree
public Collection<Node> getOperands() {
return Collections.singleton(className);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ public interface NodeVisitor<R, P> {

R visitPrimitiveType(PrimitiveTypeNode n, P p);

R visitClassLiteral(ClassLiteralNode n, P p);

R visitClassName(ClassNameNode n, P p);

R visitPackageName(PackageNameNode n, P p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.checkerframework.dataflow.cfg.node.ArrayAccessNode;
import org.checkerframework.dataflow.cfg.node.ArrayCreationNode;
import org.checkerframework.dataflow.cfg.node.BinaryOperationNode;
import org.checkerframework.dataflow.cfg.node.ClassLiteralNode;
import org.checkerframework.dataflow.cfg.node.ClassNameNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
Expand Down Expand Up @@ -361,7 +362,7 @@ public static JavaExpression fromNodeFieldAccess(FieldAccessNode node) {
// access.
return new ThisReference(receiverNode.getType());
} else if (fieldName.equals("class")) {
// The CFG represents "className.class" as a FieldAccessNode; bit it is a class literal.
// The CFG represents "className.class" as a FieldAccessNode; but it is a class literal.
return new ClassName(receiverNode.getType());
}
JavaExpression receiver;
Expand Down Expand Up @@ -398,6 +399,9 @@ public static JavaExpression fromNode(Node receiverNode) {
JavaExpression result = null;
if (receiverNode instanceof FieldAccessNode) {
result = fromNodeFieldAccess((FieldAccessNode) receiverNode);
} else if (receiverNode instanceof ClassLiteralNode) {
ClassLiteralNode cl = (ClassLiteralNode) receiverNode;
result = new ClassName(cl.getClassName().getType());
} else if (receiverNode instanceof ThisNode) {
result = new ThisReference(receiverNode.getType());
} else if (receiverNode instanceof SuperNode) {
Expand Down Expand Up @@ -680,7 +684,7 @@ private static JavaExpression fromMemberSelect(MemberSelectTree memberSelectTree
return new ClassName(expressionType);
}
if (TreeUtils.isExplicitThisDereference(memberSelectTree)) {
// the identifier is "class"
// the identifier is "this"
return new ThisReference(expressionType);
}

Expand Down
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ median of four warm-daemon reps per side).

**Closed issues:**

eisop#433, eisop#792, eisop#863, eisop#1801.
eisop#433, eisop#548, eisop#792, eisop#863, eisop#1801.


Version 3.49.5-eisop1 (April 26, 2026)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ public static boolean isClassLiteral(Tree tree) {
* <em>obj</em> . <em>f</em>
* </pre>
*
* This method currently also returns true for class literals and qualified this.
* This method currently also returns true for qualified this.
*
* @param tree a tree that might be a field access
* @return true iff if tree is a field access expression (implicit or explicit)
Expand All @@ -1550,16 +1550,19 @@ public static boolean isFieldAccess(Tree tree) {
* <em>obj</em> . <em>f</em>
* </pre>
*
* This method currently also returns a non-null value for class literals and qualified this.
* This method currently also returns a non-null value for qualified this.
*
* @param tree a tree that might be a field access
* @return the element if tree is a field access expression (implicit or explicit); null
* otherwise
*/
// TODO: fix value for class literals and qualified this, which are not field accesses.
// TODO: fix value for qualified this, which is not a field access.
public static @Nullable VariableElement asFieldAccess(Tree tree) {
if (isClassLiteral(tree)) {
return null;
}
if (tree instanceof MemberSelectTree) {
// explicit member access (or a class literal or a qualified this)
// explicit member access (or a qualified this)
MemberSelectTree memberSelect = (MemberSelectTree) tree;
assert isUseOfElement(memberSelect) : "@AssumeAssertion(nullness): tree kind";
Element el = TreeUtils.elementFromUse(memberSelect);
Expand Down Expand Up @@ -1600,7 +1603,7 @@ public static boolean isFieldAccess(Tree tree) {
/**
* Compute the name of the field that the field access {@code tree} accesses. Requires {@code
* tree} to be a field access, as determined by {@code isFieldAccess} (which currently also
* returns true for class literals and qualified this).
* returns true for qualified this).
*
* @param tree a field access tree
* @return the name of the field accessed by {@code tree}
Expand Down
Loading