Repository navigation
uses recover
Finds the units a project uses that have no source in any index -- a vendor library
shipped as compiled units only -- and recovers their uses edges from the C++Builder .hpp
headers the vendor ships beside them. A dcc map file of the project, when given, says which of
those units the linker actually pulled in, and names the linked units no header reaches (the
library's implementation-only dependencies).
No .dcu is ever read (owner ruling x2, 2026-11-08). By default nothing is written: every database is
opened read-only. --apply (1.49) stores what was recovered in the project index; see below.
Design: docs\superpowers\specs\2026-11-08-uses-recover.md.
drag-lint uses-recover --db <db> --hpp-dir <dir>... [--library-db <db>...] [--map <file.map>]
[--project <x.dproj>] [--apply] [--json]
-
--db-- the project index. Everyunit_usesrow whose target has no file is a candidate. -
--hpp-dir-- a folder of.hppheaders (not recursive; repeatable; the first folder that has a header wins). DevExpress ships them inDevExpress\VCL\Library\RS37, EurekaLog inEurekaLog 7\Lib\<platform>\<config>\Studio37. Embarcadero's own RTL/VCL headers exist only when the C++Builder personality is installed. -
--library-db-- a platform library index (repeatable). A unit with source there islibrary, not sourceless. Without it every RTL unit reads as sourceless. -
--map-- a dcc map of the project (-GSsegments or-GDdetailed). EachM=<unit>row is a linked unit. -
--project-- the project's.dproj. ItsDCC_UnitAliasentries (every one, build conditions ignored) and then the aliases the Delphi targets add on Windows (WinTypes/WinProcs=Winapi.Windows,DbiTypes/DbiProcs/DbiErrs=BDE,Generics.*) are applied to the project's ownusesnames: a used alias is classified, and followed, by its target. Each one is listed underaliases. -
--apply-- WRITE the result into--db(see "Storing the edges").
A unit name matches a file by base name, case-insensitive; Delphi's default unit scopes
(System., Vcl., Winapi. ...) are tried for a bare name such as SysUtils. System and
SysInit are dropped from every header (every unit has them).
-
units-- each sourceless unit with a header:reach(direct= the project uses it,header= only another header includes it),used_by, theheaderpath,in_map, and itsusesedges, eachindexed,libraryorsourceless. Sourceless targets are followed. -
no_header-- sourceless units no header folder has; nothing is guessed for them. -
map_only-- linked units that are neither indexed, library nor reached by a header. -
aliases-- with--project: each used alias, its target (to) and the target's status. -
applied-- with--applyonly:files(header rows written),uses(theirunit_usesrows),bound(unit_usesrows now pointing at a header).
A header lists the INTERFACE uses only. A unit with no code or data has no M= row, so
in_map: false means "not seen in the map", not "not linked".
Exit 0 = report printed (zero units included); 2 = no --db / --hpp-dir, or a DB, folder,
map or --project file that is missing or unreadable, or --apply on an index whose schema is
not current; 3 = unknown flag.
The ORM3 CLIENT index (copy) with the Win32 library DB and the EurekaLog, DevExpress and RTL
header folders: 22 sourceless units used directly (all EurekaLog plus the WinProcs / WinTypes
aliases); 20 recovered from headers, 43 more reached through them, 465 edges, in 2.2 s. Without --project
the two aliases stay in no_header; with it they classify as library (Winapi.Windows).
--apply writes the recovered units into --db (the library DBs are never written):
- one
filesrow per recovered header:path= the.hpp,language = 'hpp', no symbols; - its
#includelines asunit_usesrows,section = 'interface',origin_path= the header (System,SysInitand the unit itself dropped, as in the report); - then the uses resolve pass runs: a project row
uses EBasenow hastarget_file_id= theEBase.hpprow, and header rows point at each other.
So cycles, impact, graph and the other unit_uses readers walk through the library
instead of stopping at its edge. A re-index keeps the rows and the binding (the uses pass binds
a still-unbound name to a header row by exact name; an indexed .pas of that name always wins).
Running --apply again is idempotent; a header no longer recovered (its unit got source, or
the folder was dropped from the command line) loses its row. A run without --apply writes
nothing, and the report reads the same before and after --apply.
Not stored: the map facts, unit aliases (a uses WinProcs row stays unbound), and symbols from
the header's declarations (a later phase). Edges are interface uses only.
Measured 2026-11-09 on an ORM3 CLIENT copy (same header folders, --project): 63 header rows, 465 unit_uses rows, 325 rows bound to a header (25 of them the project's own), in 4 s; WinProcs / WinTypesclassify aslibrary. A following index --resolve-only kept all 325 bindings and changed
no call edge (certain 24953 / ambiguous 4277 identical, same ref and target checksums).