Context
`MapMethodAttribute` and `MapPropertyAttribute` already accept `DartTemplate` (e.g. `"$0.toLowerCase()"` / `"$this.length"`), and the frontend stores them on `DeclarativeMappingEntry`. The Dart-side BCL mapper currently honors only the rename form (`DartName`); when an entry has only `DartTemplate`, `IrToDartBclMapper.TryMapCall` falls through and emits the original C# call site untouched.
Scope
- Reuse the existing `IrTemplateExpression` IR node (target-agnostic) when `DartTemplate` is set; build it from the registry entry inside `IrToDartBclMapper`.
- Teach the Dart `IrBodyPrinter` to render `IrTemplateExpression` by substituting `$this`, `$0`, `$1`, … placeholders with the lowered receiver / argument expressions (mirror of the TS `TsTemplate` printer).
- Forward `DartRuntimeImports` through to `DartImportCollector` so opaque template identifiers still pull the right `metano_runtime` show clause.
- Add tests covering: instance template (`$this.foo()`), static template (`bar($0)`), receiver-less template, `$T0` generic-type substitution.
Why this unblocks BCL expansion
Without template rendering, anything more sophisticated than a direct method/property rename has to wait. Issue #173 (BCL surface expansion) depends on this landing first.
Part of #28
Context
`MapMethodAttribute` and `MapPropertyAttribute` already accept `DartTemplate` (e.g. `"$0.toLowerCase()"` / `"$this.length"`), and the frontend stores them on `DeclarativeMappingEntry`. The Dart-side BCL mapper currently honors only the rename form (`DartName`); when an entry has only `DartTemplate`, `IrToDartBclMapper.TryMapCall` falls through and emits the original C# call site untouched.
Scope
Why this unblocks BCL expansion
Without template rendering, anything more sophisticated than a direct method/property rename has to wait. Issue #173 (BCL surface expansion) depends on this landing first.
Part of #28