Skip to content

Resolve field reads by declaring type and target object - #392

Open
CatarinaGamboa wants to merge 1 commit into
mainfrom
fix/322-field-resolution
Open

CatarinaGamboa wants to merge 1 commit into
mainfrom
fix/322-field-resolution

Conversation

@CatarinaGamboa

Copy link
Copy Markdown
Collaborator

Fixes #321, fixes #322.

Field reads could pick up the refinement of the wrong variable, so real violations passed:

Fixtures: ErrorFieldOfOtherClass, ErrorFieldOfOtherObject (plain read, sum, +=, if condition), ErrorLocalShadowsConstant (enum constant and static final int), and the control CorrectFieldReadResolution. Without the fix the two latter Error fixtures pass verification and the control gives a false error.

Not fixed here (writes, needs its own issue): other.val = 9 is checked against the declared refinement but also updates this#C.val, so val = 7; other.val = 9; then @Refinement("_ == 9") int k = val; verifies. The same write path handles other.val++, compound assignments, and the typestate ghost-field update in AuxStateHandler.updateGhostField, which assumes this.

Also observed: test files that each declare an enum with the same simple name can clash within one JVM run ("Sorts ...A$Format and ...B$Format are incompatible"), so some state persists across test files. The fixtures use distinct enum names to avoid it.

Validation: mvn test passes all 414 tests (253 TestExamples cases).

🤖 Generated with Claude Code

A field read first looked up the field's simple name in the context. Since
#327 fields live there only under their qualified name, so that lookup could
only find an unrelated local with the same name: Format.JPG was read as the
local JPG (#321). That branch is removed.

The context variable this#C.f tracks the value of the field of the current
object, but reads of the same field on another object (other.val) used it
too, so facts about this.val leaked into other.val (#322). Utils gains
accessesTrackedField, true for static fields and for this/super/Outer.this
targets; field reads on any other target use the field's declared
refinement instead, in visitCtFieldRead and in the operand and compound
assignment paths of OperationsChecker. Limits.max vs this.max (the first
#322 reproducer) was already fixed by the qualified names of #327 and gets
a regression test.

Fixes #321
Fixes #322

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CatarinaGamboa

Copy link
Copy Markdown
Collaborator Author

lgtm

@rcosta358 rcosta358 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm


} else if (context.hasVariable(Utils.qualifyFieldName(fieldRead.getVariable()))) {
// fields live in the context under their qualified name only: a variable with the field's simple name is an
// unrelated local (#321), and the tracked value is that of this object, not of another one (#322)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// unrelated local (#321), and the tracked value is that of this object, not of another one (#322)
// unrelated local, the tracked value is that of this object, not of another one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants