-
Notifications
You must be signed in to change notification settings - Fork 2
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
Have InvalidParam
support records
#35
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some context.
@@ -101,6 +110,15 @@ public Description matchMethod(MethodTree methodTree, VisitorState state) { | |||
return Description.NO_MATCH; | |||
} | |||
|
|||
private static MethodTree getGeneratedConstructor(ClassTree classTree) { | |||
return classTree.getMembers().stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For records in some cases the generated constructor could not be found by using ASTHelpers#isGeneratedConstructor
. That's why it's implemented with the contentEquals("<init>")
check.
Perhaps that is a bigger issue we should solve. However, I think that is out of scope for this PR.
.map(MethodTree.class::cast) | ||
.findFirst() | ||
.filter(tree -> tree.getName().contentEquals("<init>")) | ||
.orElseThrow(() -> new IllegalStateException("Records must have a generated ctor")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message could be better.
625a631
to
b565ccc
Compare
@@ -798,6 +798,13 @@ private static boolean isFinal(Symbol symbol) { | |||
return (symbol.flags() & Flags.FINAL) == Flags.FINAL; | |||
} | |||
|
|||
private static final long RECORD_FLAG = 1L << 61; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use Flags.RECORD
yet, because that would fail with JDK 11...
b565ccc
to
2455ece
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any timeline on merging this? 😇 We're peppering our code with @SupressWarning("InvalidParam")
at the moment.
@@ -798,6 +798,13 @@ private static boolean isFinal(Symbol symbol) { | |||
return (symbol.flags() & Flags.FINAL) == Flags.FINAL; | |||
} | |||
|
|||
private static final long RECORD_FLAG = 1L << 61; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static final long RECORD_FLAG = 1L << 61; | |
/** | |
* Flag for a record class, its canonical constructor and components. Can be replaced by | |
* com.sun.tools.javac.code.Flags.RECORD once support minimum JDK version is 14. | |
*/ | |
private static final long RECORD_FLAG = 1L << 61; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I really like the suggestion, I used this one-liner because it's used in the Error Prone project twice like that and wanted to be consistent.
So I'd lean towards leaving it as-is. (When we use this in error-prone-support
we should definitely use this as Javadoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I misread, this is in the ASTHelpers
of course... In that case, it is a good idea to add this. Will commit that.
2455ece
to
341454f
Compare
@@ -807,6 +807,17 @@ private static boolean isFinal(Symbol symbol) { | |||
return (symbol.flags() & Flags.FINAL) == Flags.FINAL; | |||
} | |||
|
|||
/** | |||
* Flag for a record class, its canonical constructor and components. Can be replaced by {@code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
W.r.t. components
: not sure what is meant by that, but based on some tests with the debugger this does not include members. (The original documentation talks about the "state vector"; see below.) Maybe we should leave this out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further debugging, I found that a subset of record members are flagged. I now better understand what is meant, so will update the documentation.
/** Returns true if the given {@link Symbol} is a record. */ | ||
public static boolean isRecord(Symbol symbol) { | ||
return (symbol.flags() & RECORD_FLAG) == RECORD_FLAG; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JDK 17 Javadoc for com.sun.tools.javac.code.Flags.RECORD
says:
/**
* Flag to indicate that a class is a record. The flag is also used to mark fields that are
* part of the state vector of a record and to mark the canonical constructor
*/
Not sure what the state vector is, but tests indicate that this method also returns true
for the canonical constructor. We should either fix that or update the documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Okay, IIUC the state vector comprises the fields that are populated by the canonical constructor.
@@ -74,11 +75,19 @@ public final class InvalidParam extends BugChecker implements ClassTreeMatcher, | |||
public Description matchClass(ClassTree classTree, VisitorState state) { | |||
DocTreePath path = getDocTreePath(state); | |||
if (path != null) { | |||
ImmutableSet<String> parameters = ImmutableSet.of(); | |||
// XXX: `isRecord`... should it also be able to handle `Tree`s? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should defer it for now. We might want to improve this in a follow-up PR where we look at record handling in general.
1e941a9
to
4953d01
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebased and added a commit.
Suggested commit message:
Have `InvalidParam` support records
Fixes #2321.
@@ -101,6 +110,15 @@ public Description matchMethod(MethodTree methodTree, VisitorState state) { | |||
return Description.NO_MATCH; | |||
} | |||
|
|||
private static MethodTree getGeneratedConstructor(ClassTree classTree) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the current implementation:
private static MethodTree getGeneratedConstructor(ClassTree classTree) { | |
private static MethodTree getFirstConstructor(ClassTree classTree) { |
This is not necessarily a generated constructor; see e.g. the normalConstructor_record
test case.
That said, what we what, IIUC, is:
private static MethodTree getGeneratedConstructor(ClassTree classTree) { | |
private static MethodTree getCanonicalRecordConstructor(ClassTree classTree) { |
But this does raise the question: can we reliable assume that the first constructor is always the canonical constructor? It might be better to explicitly test against #isRecord
; will push a proposal.
@@ -807,6 +807,17 @@ private static boolean isFinal(Symbol symbol) { | |||
return (symbol.flags() & Flags.FINAL) == Flags.FINAL; | |||
} | |||
|
|||
/** | |||
* Flag for a record class, its canonical constructor and components. Can be replaced by {@code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further debugging, I found that a subset of record members are flagged. I now better understand what is meant, so will update the documentation.
/** Returns true if the given {@link Symbol} is a record. */ | ||
public static boolean isRecord(Symbol symbol) { | ||
return (symbol.flags() & RECORD_FLAG) == RECORD_FLAG; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Okay, IIUC the state vector comprises the fields that are populated by the canonical constructor.
ImmutableSet<String> parameters = | ||
ASTHelpers.isRecord(ASTHelpers.getSymbol(classTree)) | ||
? getGeneratedConstructor(classTree).getParameters().stream() | ||
.map(v -> v.getName().toString()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.map(v -> v.getName().toString()) | |
.map(p -> p.getName().toString()) |
4953d01
to
16759a4
Compare
InvalidParam
InvalidParam
support records
Filed google#3437. |
16759a4
to
2ccb778
Compare
2ccb778
to
bc2b5da
Compare
bc2b5da
to
128ca4d
Compare
Fixed in google#2321. |
Resolves google#2321.