Skip to content

Inherit the state sets and methods of the supertypes' specs - #16

Merged
CatarinaGamboa merged 2 commits into
mainfrom
feat/inherited-specs
Nov 4, 2026
Merged

CatarinaGamboa merged 2 commits into
mainfrom
feat/inherited-specs

Conversation

@CatarinaGamboa

@CatarinaGamboa CatarinaGamboa commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Needed for liquid-java/vscode-liquidjava#173: a state error on a method declared in a subclass's spec, with the state set in a superclass's spec, shows no usable diagram.

Why

parseAll(uri, className) read one type. For java.awt.Frame, whose @StateSet is in the java.awt.Window spec, it found no state set, so there was no diagram. The Window diagram had no setUndecorated.

What

parseAll(List<String> uris, String className) builds one model from several files and merges the specs of the class's supertypes. It follows the rule the verifier uses for state hints since liquid-java/liquidjava#464 (StateMachineBuilder):

  • Supertypes. The class's superclasses, then the interfaces they implement, nearest first. Same walk as the verifier's supertypesOf. JDK classes resolve by reflection.
  • State sets. The class's own first, then its supertypes', nearest first. That is the order of the verifier's StateErrorContext states, so stateSet indexes match.
  • Methods. The class's own refinements, then inherited ones. An inherited refinement is left out when:
    • a nearer spec refines the same method (same name and parameter types), or
    • the nearest type that declares the method is not the spec's class (e.g. Frame redeclares addNotify, so a Window spec's addNotify does not apply), or
    • not every caller can call it (not public).
  • Constructors and factories. Only the class's own.

parseAll(uri, className) now calls it with one file. A file with only one type skips the hierarchy walk, so the editor's own-file diagrams are unchanged. Files that no longer exist are skipped.

Issue example (Window and Frame specs, both in one file or in two), parseAll(..., "java.awt.Frame"):

from to method
notDisplayable notDisplayable setUndecorated
displayable, notDisplayable notDisplayable dispose
displayable, notDisplayable displayable pack

Initial: new Frame(String) → notDisplayable. addNotify and Window(Frame) from the Window spec are left out.

Tests

mvn test: 32 tests, 0 failures, run locally. New:

  • testStateSetAndMethodsInheritedFromTheSuperclassSpec: one file, with addNotify left out on Frame and kept on Window.
  • testSpecsInheritedFromOtherFiles: specs in two files; the subclass file alone still gives nothing.
  • testOverriddenAndPackagePrivateInheritedMethods: source classes; the child's override replaces the parent's, and a package-private parent method is left out.
  • testMethodsInheritedFromASpecWithoutStateSet: JFrame over a method-only Frame spec and Window's state set.
  • testMissingFileDoesNotDiscardTheOthers: a file that no longer exists is skipped.

Release

vscode-liquidjava needs this released as liquidjava-fsm 0.2.3. Its PR bumps to that version.

🤖 Generated with Claude Code

A class whose @stateset is in a superclass's spec, such as java.awt.Frame
with the displayable states declared for java.awt.Window, had no state
machine, and the superclass's machine did not have the subclass's methods.

parseAll(List<String> uris, String className) builds one model from
several files and merges the specs of the class's supertypes in them, as
the verifier does when it builds a receiver's machine: the class's own
state sets first, then those of its supertypes, nearest first. A call
uses the class's own refinement of a method, otherwise that of the
nearest type that declares it, so an inherited refinement is left out
when a nearer spec refines the method, when a nearer type redeclares it,
or when not every caller can call it. Constructors stay the class's own.
parseAll(uri, className) does the same for the specs in one file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A file that no longer exists made the model fail to build, which
discarded the specs in the other files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CatarinaGamboa
CatarinaGamboa merged commit e5099f0 into main Nov 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant