In several places, MrDocs uses mutable state with no clear owner. This is worth paying down incrementally as the surrounding code is touched. There are two related strands.
Global singletons. The clearest example is the generator registry: getGeneratorRegistryImpl in src/lib/Support/GeneratorRegistryImpl.cpp returns a reference to a function-local static GeneratorRegistryImpl, a singleton that lives for the whole process and is never cleared. In the unit-test binary, this means a generator registered by one test stays registered for the rest of the process, so the first registration of an id wins process-wide and two tests cannot install competing generators of the same id. It works for the current uses, but it is shared mutable state with no owner and no reset point.
Ownerless shared state. Many pipeline steps take references to the same long-lived objects (config, corpus, thread pool, reference directories) and thread them through every layer, rather than one owner holding the data while the steps operate on what they are handed. For example DoGenerateAction carries config, dirs, and threadPool through the whole flow, and ConfigImpl holds a ThreadPool&. The lifetimes are implicit and the ownership is diffuse.
Why it is worth addressing eventually:
- Tests leak state across cases (the registry above), so test isolation and ordering are more fragile than they should be.
- Implicit lifetimes make it harder to reason about who owns what and for how long.
- It stands in the way of running more than one independent build in a single process.
In several places, MrDocs uses mutable state with no clear owner. This is worth paying down incrementally as the surrounding code is touched. There are two related strands.
Global singletons. The clearest example is the generator registry:
getGeneratorRegistryImplin src/lib/Support/GeneratorRegistryImpl.cpp returns a reference to a function-local staticGeneratorRegistryImpl, a singleton that lives for the whole process and is never cleared. In the unit-test binary, this means a generator registered by one test stays registered for the rest of the process, so the first registration of an id wins process-wide and two tests cannot install competing generators of the same id. It works for the current uses, but it is shared mutable state with no owner and no reset point.Ownerless shared state. Many pipeline steps take references to the same long-lived objects (config, corpus, thread pool, reference directories) and thread them through every layer, rather than one owner holding the data while the steps operate on what they are handed. For example
DoGenerateActioncarriesconfig,dirs, andthreadPoolthrough the whole flow, andConfigImplholds aThreadPool&. The lifetimes are implicit and the ownership is diffuse.Why it is worth addressing eventually: