Skip to content

A null ParameterTemplate in Parameters/PositionalParameters throws NullReferenceException after the declaration is half-written: void M} / record R #198

Closed

Description

@matt-edmondson

What's wrong

ClassTemplate.Validate() runs before anything is written, so that a bad member cannot leave partial output (#164) (ClassTemplate.cs#L105-L118). It never checks parameter lists, though. TemplateRendering.WriteParameterList (TemplateRendering.cs#L199-L209) dereferences each entry partway through writing:

foreach (ParameterTemplate parameterTemplate in parameters)
{
	parameterStrings.Add(RenderFragment(codeBlocker, parameterTemplate.WriteTo));

Collection<ParameterTemplate> accepts null. A null entry therefore throws after the declaration has started, and the class body's using Scope then writes its closing brace straight onto the half-written declaration.

Reproduction

var m = new MethodTemplate { Name = "M", Type = "void", BodyFactory = _ => { } };
m.Parameters.Add(null!);
cb.AddClass(new ClassTemplate { Name = "C", Members = { m } });

This throws NullReferenceException and leaves class C\n{\n\tvoid M}\n in the writer.

var r = new ClassTemplate { Name = "R", Kind = TypeKind.Record };
r.PositionalParameters.Add(null!);
cb.AddClass(r);

This throws NullReferenceException and leaves record R in the writer.

A null DocTag in a member's Documentation.Params behaves the same way. It leaves a closed class that has silently lost the member, which is the #164 symptom; that case overlaps with #188. A null entry in Members or NestedClasses does throw before anything is written, but it throws NullReferenceException. By contrast, AddClasses and AddSourceFile throw ArgumentNullException for a null type.

Why it matters

The library's contract, stated in the remarks on TemplateBase.Validate and in #164/#169, is that a template it refuses leaves nothing behind. Here the caller gets partial output plus an NRE that doesn't name the template.

Suggested fix / acceptance criteria

  • In Validate (class, method, constructor, operator), reject null entries in Members, NestedClasses, Parameters, PositionalParameters and the documentation tag lists with ArgumentException/ArgumentNullException that names the template, before anything is written.
  • Add tests asserting the writer is empty after the exception, for a null method parameter and for a null positional parameter.

Related but distinct: #176 (a throwing BodyFactory leaves } on a half-written member) and #188 (an invalid doc comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions