Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.TypeSpec.Generator.Primitives;
using Microsoft.TypeSpec.Generator.Providers;
using Microsoft.TypeSpec.Generator.Statements;

Expand All @@ -10,16 +11,25 @@ public sealed record MemberExpression(ValueExpression? Inner, string MemberName)
{
public ValueExpression? Inner { get; internal set; } = Inner;
public string MemberName { get; private set; } = MemberName;
internal CodeWriterDeclaration? Declaration { get; set; }
internal override void Write(CodeWriter writer)
{
if (Inner is not null)
{
Inner.Write(writer);
writer.AppendRaw(".");
}
// workaround to avoid Roslyn reducing properties named Object to object
// Should come up with a better approach - https://github.com/microsoft/typespec/issues/4724
writer.AppendRaw(MemberName == "Object" && Inner == null ? $"this.{MemberName}" : MemberName);

if (Declaration is not null)
{
writer.Append(Declaration, isDeclaration: false);
}
else
{
// workaround to avoid Roslyn reducing properties named Object to object
// Should come up with a better approach - https://github.com/microsoft/typespec/issues/4724
writer.AppendRaw(MemberName == "Object" && Inner == null ? $"this.{MemberName}" : MemberName);
}
}

internal override ValueExpression? Accept(LibraryVisitor visitor, MethodProvider method)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ public void Update(
_variable?.Update(name: name);
_asMember?.Update(memberName: name);
_declaration = null;
if (_asMember != null)
{
_asMember.Declaration = Declaration;
}
InitializeParameter();
}

Expand Down Expand Up @@ -148,6 +152,6 @@ private void InitializeParameter()
}

private MemberExpression? _asMember;
public static implicit operator MemberExpression(FieldProvider field) => field._asMember ??= new MemberExpression(null, field.Name);
public static implicit operator MemberExpression(FieldProvider field) => field._asMember ??= new MemberExpression(null, field.Name) { Declaration = field.Declaration };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1004,16 +1004,20 @@ public CodeScope AmbientScope()
return codeWriterScope;
}

internal void Append(CodeWriterDeclaration declaration)
internal void Append(CodeWriterDeclaration declaration, bool isDeclaration = true)
{
if (declaration.HasBeenDeclared(_scopes))
{
WriteIdentifier(declaration.GetActualName(_scopes.Peek()));
}
else
else if (isDeclaration)
{
WriteDeclaration(declaration);
}
else
{
WriteIdentifier(declaration.RequestedName);
}
}

internal void WriteTypeModifiers(TypeSignatureModifiers modifiers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,35 @@ public void ScopeDeclaredTwiceForMethodSignatureParam()
Assert.AreEqual(Helpers.GetExpectedFromFile(), codeWriter.ToString(false));
}

[Test]
public void FieldDedupUpdatesReferencesViaMemberExpression()
{
var type = new TestTypeProvider();
var field1 = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(string), "_scope", type);
var field2 = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(string), "_scope", type);

using var codeWriter = new CodeWriter();
// Write both field declarations - the second should be deduped to _scope0
codeWriter.WriteField(field1);
codeWriter.WriteField(field2);
// Write a reference to the second field via AsValueExpression (implicit MemberExpression)
field2.AsValueExpression.Write(codeWriter);
Assert.AreEqual(Helpers.GetExpectedFromFile(), codeWriter.ToString(false));
}

[Test]
public void FieldReferenceBeforeDeclarationUsesRequestedName()
{
var type = new TestTypeProvider();
var field = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(string), "_token", type);

using var codeWriter = new CodeWriter();
// Write a reference BEFORE the field declaration — should use the original name, not create a declaration
field.AsValueExpression.Write(codeWriter);
codeWriter.WriteField(field);
Assert.AreEqual(Helpers.GetExpectedFromFile(), codeWriter.ToString(false));
}

private Dictionary<CodeWriter.CodeScope, string> GetDeclarationScopes(CodeWriterDeclaration declaration)
{
var namesDictionaryField = typeof(CodeWriterDeclaration).GetField("_actualNames", BindingFlags.NonPublic | BindingFlags.Instance);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
private readonly string _scope;
private readonly string _scope0;
_scope0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_tokenprivate readonly string _token;