Improve the documentation of ElementFactory.#2027
Merged
copybara-service[bot] merged 1 commit intomainfrom Feb 20, 2026
Merged
Conversation
Currently, the documentation references some Javadoc about how a given lowercase-e element may be represented by different `Element` instances over time. However, I think that's a red herring for the problem that we're solving: - The doc doesn't necessarily imply that older instance become "invalid," only that they should be compared with `equals` instead of `==`. (And I suspect that we've done as much all along. As a bonus, using `equals` probably isn't even technically necessary today, at least if we depend on implementation details of javac—though of course we shouldn't.) - The doc doesn't necessarily imply that there's anything special about the boundary between rounds. Thus, as far as the Javadoc for `Element` is concerned, the compiler could switch which instance it returns *during* a round just as easily as it could use different instances across rounds. And thus, the doc isn't explicit on whether we should treat a given `Element` as having a lifetime of exactly the round in which we looked it up. But this code does appear to be a response to a real behavior in javac—and perhaps especially [in Eclipse](https://bugs.eclipse.org/bugs/show_bug.cgi?id=480936). (I haven't looked into Turbine.) There does in fact appear to be an undocumented(?) restriction on the the lifetime of an `Element` instance: - [JDK-6191665](https://bugs.openjdk.org/browse/JDK-6191665) - [JDK-7026845](https://bugs.openjdk.org/browse/JDK-7026845?focusedId=12082299&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12082299) (The behavior of `Element` instances across rounds [might have changed for Java 7](https://bugs.openjdk.org/browse/JDK-8144105), but the behavior seen in Java 7 appears to have persisted despite [some changes to reuse state across rounds in Java 9](https://bugs.openjdk.org/browse/JDK-8038455).) Notably, while `Element` documents that callers should use `Element.equals` instead of identity comparison, it appears that even `Element.equals` does not consider two distinct `Element` instances for "the same declaration" to be equal. (As of this writing, javac does not appear to override `equals` in [its `Element` implementations](https://github.com/openjdk/jdk/blob/2a71f89bc8d72be8095113695e541f4f38acdeca/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java) at all.) Concretely, we've seen that an `ExecutableElement` from one round may have an enclosing element whose enclosed-elements list does not contain anything equal to that `ExecutableElement`. That specific quirk may or may not be a problem, but it's further evidence that such usage is unsupported. (For what it's worth, I edited our `ElementFactory` implementations to always return the original `Element`, and I got no failures in a TAP Global Presubmit run except for those in `BasicAnnotationProcessorTest`, which depends on the quirk discussed just above. That quirk comes up only because `ElementFactory` looks up the enclosing element as part of its equality logic, so I'd expect all tests to pass if we were to replace `ElementFactory` with `Element`. It would be nice to have test coverage that demonstrated a clearer need for `ElementFactory`. We could add some by directly performing an equality comparison on an `ExecutableElement` from a different round, but it would be nice to have a better sense of how that might matter in practice and how widespread the problem is—e.g., whether it also affects `TypeMirror` instances. But given that we know Eclipse behaves differently from javac, we might well see the problems when testing under ejc, which I think we might have some setup for?) (One use case that probably works for modern versions of javac (but quite likely still not Eclipse) is that of storing only `ClassSymbol`/`TypeElement` instances, which [are currently reused across rounds](https://bugs.openjdk.org/browse/JDK-6191665?focusedId=13519728&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13519728).) (followup to e20db25 / #1348) RELNOTES=n/a PiperOrigin-RevId: 872912877
9f22fb9 to
fecb834
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Improve the documentation of
ElementFactory.Currently, the documentation references some Javadoc about how a given lowercase-e element may be represented by different
Elementinstances over time. However, I think that's a red herring for the problem that we're solving:equalsinstead of==. (And I suspect that we've done as much all along. As a bonus, usingequalsprobably isn't even technically necessary today, at least if we depend on implementation details of javac—though of course we shouldn't.)Elementis concerned, the compiler could switch which instance it returns during a round just as easily as it could use different instances across rounds. And thus, the doc isn't explicit on whether we should treat a givenElementas having a lifetime of exactly the round in which we looked it up.But this code does appear to be a response to a real behavior in javac—and perhaps especially in Eclipse. (I haven't looked into Turbine.) There does in fact appear to be an undocumented(?) restriction on the the lifetime of an
Elementinstance:(The behavior of
Elementinstances across rounds might have changed for Java 7, but the behavior seen in Java 7 appears to have persisted despite some changes to reuse state across rounds in Java 9.)Notably, while
Elementdocuments that callers should useElement.equalsinstead of identity comparison, it appears that evenElement.equalsdoes not consider two distinctElementinstances for "the same declaration" to be equal. (As of this writing, javac does not appear to overrideequalsin itsElementimplementations at all.)Concretely, we've seen that an
ExecutableElementfrom one round may have an enclosing element whose enclosed-elements list does not contain anything equal to thatExecutableElement. That specific quirk may or may not be a problem, but it's further evidence that such usage is unsupported.(For what it's worth, I edited our
ElementFactoryimplementations to always return the originalElement, and I got no failures in a TAP Global Presubmit run except for those inBasicAnnotationProcessorTest, which depends on the quirk discussed just above. That quirk comes up only becauseElementFactorylooks up the enclosing element as part of its equality logic, so I'd expect all tests to pass if we were to replaceElementFactorywithElement. It would be nice to have test coverage that demonstrated a clearer need forElementFactory. We could add some by directly performing an equality comparison on anExecutableElementfrom a different round, but it would be nice to have a better sense of how that might matter in practice and how widespread the problem is—e.g., whether it also affectsTypeMirrorinstances. But given that we know Eclipse behaves differently from javac, we might well see the problems when testing under ejc, which I think we might have some setup for?)(One use case that probably works for modern versions of javac (but quite likely still not Eclipse) is that of storing only
ClassSymbol/TypeElementinstances, which are currently reused across rounds.)(followup to e20db25 / #1348)
RELNOTES=n/a