Skip to content

Replace add_axioms_for_is_empty body with length(s) == 0 form#8915

Open
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix-8019-add_axioms_for_is_empty
Open

Replace add_axioms_for_is_empty body with length(s) == 0 form#8915
tautschnig wants to merge 1 commit into
diffblue:developfrom
tautschnig:fix-8019-add_axioms_for_is_empty

Conversation

@tautschnig

@tautschnig tautschnig commented Mar 28, 2026

Copy link
Copy Markdown
Collaborator

Adopt the encoding the 2017 \deprecated tag on string_constraint_generatort::add_axioms_for_is_empty was pointing at — "should use string_length s == 0 instead" — and drop the deprecation now that the body matches the recommendation.

The previous body introduced a fresh boolean symbol is_empty and constrained it via two existentials is_empty ⇒ |s|=0 and |s|=0 ⇒ is_empty, then returned a typecast of that symbol. The two implications together define is_empty ⇔ (length(s) == 0), so the auxiliary symbol was pure indirection. Replace this with a direct return of length(s) == 0:

std::pair<exprt, string_constraintst>
string_constraint_generatort::add_axioms_for_is_empty(
  const function_application_exprt &f)
{
  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
  PRECONDITION(f.arguments().size() == 1);
  const array_string_exprt s = get_string_expr(array_pool, f.arguments()[0]);
  return {
    typecast_exprt::conditional_cast(
      equal_to(array_pool.get_or_create_length(s), 0), f.type()),
    {}};
}

Observable behaviour is unchanged (the SMT-level value of is_empty(s) still denotes length(s) == 0); the encoding now generates one fewer boolean variable and zero existential constraints per call site. The DEPRECATED macro is removed because the body is no longer the discouraged form.

add_axioms_for_is_empty is restored as a non-deprecated private helper on string_constraint_generatort, and the previously-inlined block in add_axioms_for_function_application is replaced with a single-line dispatch, matching the surrounding else if(id == ID_X) return add_axioms_for_X(expr); pattern of every other branch in the chain.

Test coverage

A new CORE-tagged regression test, jbmc/regression/jbmc-strings/java_isempty_nondet/, exercises add_axioms_for_is_empty for a non-constant string. The pre-existing java_empty/ and ConstantEvaluationIsEmpty/ tests use literal strings, which simplify_string_is_empty in src/util/simplify_expr.cpp constant-folds before the call reaches the string-refinement loop — so they do not cover the helper. The new test passes a nondet String argument through --function test_isempty_nondet.checkIsEmpty, defeating simplification and forcing the dispatch arm to be taken.

Coverage was confirmed by temporarily planting INVARIANT(false, ...) at the start of the helper: the new test triggers the invariant violation in the string-refinement loop, while java_empty/ runs to completion (the simplifier folds the call before the helper is reached). With the real implementation restored, both tests pass.

Fixes: #8019

  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@tautschnig tautschnig self-assigned this Mar 28, 2026
@codecov

codecov Bot commented Mar 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.60%. Comparing base (5453820) to head (9f5e2ba).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #8915   +/-   ##
========================================
  Coverage    80.60%   80.60%           
========================================
  Files         1711     1711           
  Lines       189466   189464    -2     
  Branches        73       73           
========================================
+ Hits        152719   152721    +2     
+ Misses       36747    36743    -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tautschnig tautschnig marked this pull request as ready for review March 31, 2026 12:13
Copilot AI review requested due to automatic review settings March 31, 2026 12:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Removes the deprecated add_axioms_for_is_empty helper from the string constraint generator and keeps is_empty support by inlining its logic in the function-application dispatch.

Changes:

  • Removed the add_axioms_for_is_empty declaration from the public generator interface.
  • Deleted the deprecated add_axioms_for_is_empty implementation from string_constraint_generator_testing.cpp.
  • Inlined the is_empty constraint generation directly into add_axioms_for_function_application.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/solvers/strings/string_constraint_generator.h Drops the deprecated add_axioms_for_is_empty method declaration.
src/solvers/strings/string_constraint_generator_testing.cpp Removes the deprecated method definition and adjusts includes accordingly.
src/solvers/strings/string_constraint_generator_main.cpp Replaces the call to the removed method with equivalent inlined constraint-generation logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/solvers/strings/string_constraint_generator_testing.cpp Outdated
Comment thread src/solvers/strings/string_constraint_generator_main.cpp Outdated
@tautschnig tautschnig force-pushed the fix-8019-add_axioms_for_is_empty branch from 84b72f5 to e534d61 Compare March 31, 2026 12:27
The 2017 DEPRECATED tag on string_constraint_generatort::
add_axioms_for_is_empty pointed at a simpler encoding -- "should use
string_length s == 0 instead". Adopt that encoding now: drop the
auxiliary boolean symbol and the two implications that previously
defined `is_empty <=> (length == 0)`, and just return
`length(s) == 0` directly (with `typecast_exprt::conditional_cast` to
the requested boolean shape, which is a no-op when the call site
already requests `bool_typet`).

This retains observable behaviour (the SMT-level value of `is_empty(s)`
is unchanged) while eliminating one fresh boolean variable and two
existential constraints per call site, and matches what the
deprecation note recommended eight years ago. The `DEPRECATED` macro
on the helper is dropped because the body now is the recommended
encoding.

Restore `add_axioms_for_is_empty` as a non-deprecated private helper on
`string_constraint_generatort` and replace the previously-inlined block
in `add_axioms_for_function_application` with a single-line dispatch,
matching the surrounding `else if(id == ID_X) return add_axioms_for_X(
expr);` pattern of every other branch.

Add jbmc/regression/jbmc-strings/java_isempty_nondet/ to actually
exercise the new helper under cbmc-CORE. The pre-existing
`java_empty` and `ConstantEvaluationIsEmpty` tests use a constant
string literal, which the simplifier folds via
`simplify_string_is_empty` in `src/util/simplify_expr.cpp` before the
call ever reaches the string-refinement loop. The new test passes a
nondet `String` argument through `--function ...checkIsEmpty`, which
defeats simplification and therefore causes the constraint generator
dispatch to actually be hit. With the helper deliberately replaced by
`INVARIANT(false, ...)`, the new test triggers the invariant violation
during string-refinement, confirming that it does cover the changed
code path.

Fixes: diffblue#8019

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
@tautschnig tautschnig force-pushed the fix-8019-add_axioms_for_is_empty branch from e534d61 to 9f5e2ba Compare June 9, 2026 18:45
@tautschnig tautschnig requested a review from kroening as a code owner June 9, 2026 18:45
@tautschnig tautschnig changed the title Remove deprecated add_axioms_for_is_empty method Replace add_axioms_for_is_empty body with length(s) == 0 form Jun 9, 2026
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.

src/solvers/strings/string_constraint_generator_testing.cpp - pair<exprt, string_constraints> string_constraint_generatort::add_axioms_for_is_empty

3 participants