Skip to content

v1.15.0-alpha -- generic names resolve by arity, nested locals, inherited fields (schema v23, re-parse required)

Choose a tag to compare

@Alexl-git Alexl-git released this 17 Sep 18:44
· 1255 commits to main since this release

Archives below are self-contained: the exe, the rules\ folder, and (win64 only) the component converter.

Provenance: engine (drag-lint.exe, Win64 and Win32) and ConvRulesEditor.exe were built from a clean git worktree at 2793f206; nothing uncommitted went into either archive.

REQUIRED after installing: rebuild every existing index. This release moves the index format (schema v22 -> v23, extractor 1.16.0 -> 1.17.0, resolver 1.3.0 -> 1.4.0). A v23 engine refuses a v22 database with index schema v22 < v23 and does not migrate it in place -- run drag-lint index --all --rebuild (or index --project <X.dproj> --db <db> --rebuild per project) before querying, linting or starting the LSP against an existing index.

v1.15.0-alpha -- 2026-09-17

Added

  • glyph-vacuum --root <dir> --out <dir> [--db <db>] [--append] (converter):
    walks every .dfm / .fmx under the root, decodes every streamed graphic
    (a binary .dfm is converted in memory), and writes instances.tsv, the
    decoded images, a per-class classes.tsv (count property, inferred strip N,
    agreement, kind, format and distinct-payload distributions, runtime_refs
    counted through resolved property refs when --db is given) and a
    gallery.html with one card per distinct payload per class, slot separators
    overlaid at width div N. Unparseable files are listed in skipped.tsv, never
    dropped; --append merges a rescan by (dfm_path, object_path, property), so
    a second run is idempotent. The input to docs\GLYPH-CLASSES.md and the
    G[I/N] grammar.
  • ConvRulesEditor: the Unit Rules tab lists each used unit with the section it
    is declared in (interface / implementation) and fills the moment a unit is
    picked -- Browse, combo select or Fill, form or not. The declared-class list
    on the same tab was empty for every input (ScanClassesDeclared started its
    backtrack past the keyword and never met the =).

Changed -- extractor 1.17.0-alpha / schema v23 (re-parses every index)

  • Generic types and methods are indexed under their BARE name; the parameter
    list is in symbols.generic_params. Ancestor edges carry
    ancestor_type_args and resolve by arity before the scope rules:
    TObjectList<T: class> now climbs to System.Generics.Collections.TList<T>
    (was System.Classes.TList); ORM3's 134 TMicObjectBase<I> descendants
    resolve their base. query --name accepts TList<T>, and a dotted name is
    stripped per segment, so Unit.TList<T>.Add finds the METHOD (was the class).
    Arity counts PARAMETERS, not commas: <T: class, constructor> is 1 and
    <S: IUnknown; I: IUnknown> is 2, so edges onto constrained generics resolve.
  • Nested-routine locals and inline var / for var declarations are
    local_var symbols parented to the innermost routine. Two sibling
    for var Item: T in loops of DIFFERENT element types leave Item.M calls
    unresolved (decline) rather than typing both from the first loop.
  • symbol_facts.reads_fields / writes_fields include INHERITED fields
    (own first, nearest ancestor next) via the new facts-inherited index stage.
  • query ancestors --json rows carry type_args ('' on a plain edge). The
    LSP's ephemeral store for a file no index owns now runs the facts-inherited
    stage too, so hover on such a file shows a same-unit inherited field in
    Writes:.

Fixed

  • context --task "modify Class.Member" resolves when exactly one symbol's
    qualified name ends with that dotted suffix (segment-aligned; an ambiguous
    Class.Member still declines). A RECORD's class surface lists every field:
    the lean DFM-component filter now runs only when the owner is a class, so
    modify TTypeAncestor no longer prints one field of eight.
  • A property whose accessor is OVERLOADED (read GetItem beside two GetItem
    declarations) binds the overload whose parameter count is the property's index
    count (+1 for a setter); when the count leaves several, the access records no
    accessor and no call edge instead of the first-declared one (resolver 1.4.0, re-pinned).
  • FindSymbolsByExactName (query --name) splits a dotted input per segment:
    TList<T>.Add finds the METHOD gnB.TList.Add, not the class, and a dotted
    path keeps only rows whose qualified name ends with it.
  • dataset-open-without-close ignores a member named Open that is indexed, passed as
    an argument or assigned -- only a bare X.Open; / X.Open(); statement is a
    dataset open. A record field Open: TArray<...> read as AState.Open[i] fired
    eight times on drag-lint's own source (INBOX 2026-09-17, section 2).
  • GetSymbolFacts / GetSymbolDoc initialise a managed Result with
    Default(), not FillChar (leak when a caller reused the variable).
  • uses-report --name <pattern> matching NO source unit now exits 2 with
    ERROR: uses-report: no index passed contains a source unit named <pattern>
    on stderr and writes no output file (an existing --output is left
    untouched). It used to print 0 source units, 0 rows written and exit 0 --
    a complete-looking report against a corpus that did not contain the subject,
    while outline on the same file and DB refused. Converter gap 2026-09-16
    (stats\draglint-gaps.log, class wrong). Guard:
    tests\autotest\run_uses_report_name_no_match.ps1.