Skip to content

Commit 9d95566

Browse files
committed
[XSG] Use absolute file paths when generating #line
1 parent 56d144c commit 9d95566

File tree

5 files changed

+55
-9
lines changed

5 files changed

+55
-9
lines changed

src/Controls/src/SourceGen/PrePost.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@ class PrePost : IDisposable
1515
/// <param name="iXmlLineInfo"></param>
1616
/// <param name="fileName"></param>
1717
/// <returns></returns>
18-
public static PrePost NewLineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, string? fileName)
18+
public static PrePost NewLineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, ProjectItem? projectItem)
1919
{
20-
static void LineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, string? fileName)
21-
=> codeWriter.WriteLineNoTabs($"#line {(iXmlLineInfo.LineNumber != -1 ? iXmlLineInfo.LineNumber : 1)} \"{fileName}\"");
20+
// Emit #line with an absolute path since relative paths have undefined behavior (https://github.com/dotnet/roslyn/issues/71202#issuecomment-1874649780)
21+
static void LineInfo(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo, ProjectItem? projectItem)
22+
=> codeWriter.WriteLineNoTabs($"#line {(iXmlLineInfo.LineNumber != -1 ? iXmlLineInfo.LineNumber : 1)} \"{projectItem?.AbsolutePath}\"");
2223

2324
static void LineDefault(IndentedTextWriter codeWriter, IXmlLineInfo iXmlLineInfo)
2425
=> codeWriter.WriteLineNoTabs("#line default");
2526

26-
return new(() => LineInfo(codeWriter, iXmlLineInfo, fileName), () => LineDefault(codeWriter, iXmlLineInfo));
27+
return new(() => LineInfo(codeWriter, iXmlLineInfo, projectItem), () => LineDefault(codeWriter, iXmlLineInfo));
2728
}
2829

2930
public static PrePost NoBlock() =>

src/Controls/src/SourceGen/ProjectItem.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
namespace Microsoft.Maui.Controls.SourceGen;
88
record ProjectItem(AdditionalText AdditionalText, AnalyzerConfigOptions Options)
99
{
10+
private readonly AdditionalText _additionalText = AdditionalText;
11+
1012
public string Configuration
1113
=> Options.GetValueOrDefault("build_property.Configuration", "Debug");
1214

@@ -62,9 +64,12 @@ public string NoWarn
6264
public string? RelativePath
6365
=> Options.GetValueOrNull("build_metadata.additionalfiles.RelativePath");
6466

67+
public string? AbsolutePath
68+
=> _additionalText.Path;
69+
6570
public string? TargetFramework
6671
=> Options.GetValueOrNull("build_property.targetFramework");
6772

6873
public string? TargetPath
69-
=> Options.GetValueOrDefault("build_metadata.additionalfiles.TargetPath", AdditionalText.Path);
74+
=> Options.GetValueOrDefault("build_metadata.additionalfiles.TargetPath", _additionalText.Path);
7075
}

src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,14 +474,14 @@ static void Set(IndentedTextWriter writer, LocalVariable parentVar, string local
474474

475475
if (node is ValueNode valueNode)
476476
{
477-
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)node, context.ProjectItem.RelativePath) : PrePost.NoBlock())
477+
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)node, context.ProjectItem) : PrePost.NoBlock())
478478
{
479479
var valueString = valueNode.ConvertTo(property, context, parentVar);
480480
writer.WriteLine($"{parentVar.Name}.{EscapeIdentifier(localName)} = {valueString};");
481481
}
482482
}
483483
else if (node is ElementNode elementNode)
484-
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)node, context.ProjectItem.RelativePath) : PrePost.NoBlock())
484+
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)node, context.ProjectItem) : PrePost.NoBlock())
485485
writer.WriteLine($"{parentVar.Name}.{EscapeIdentifier(localName)} = ({property.Type.ToFQDisplayString()}){(HasDoubleImplicitConversion(context.Variables[elementNode].Type, property.Type, context, out var conv) ? "(" + conv!.ReturnType.ToFQDisplayString() + ")" : string.Empty)}{context.Variables[elementNode].Name};");
486486
}
487487

@@ -610,7 +610,7 @@ static void Add(IndentedTextWriter writer, LocalVariable parentVar, XmlName prop
610610
if (HasDoubleImplicitConversion(context.Variables[valueNode].Type, itemType, context, out var conv))
611611
cast = "(" + conv!.ReturnType.ToFQDisplayString() + ")";
612612

613-
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)valueNode, context.ProjectItem.RelativePath) : PrePost.NoBlock())
613+
using (context.ProjectItem.EnableLineInfo ? PrePost.NewLineInfo(writer, (IXmlLineInfo)valueNode, context.ProjectItem) : PrePost.NoBlock())
614614
writer.WriteLine($"{parentObj}.Add(({itemType.ToFQDisplayString()}){cast}{context.Variables[valueNode].Name});");
615615
}
616616

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using NUnit.Framework;
5+
6+
namespace Microsoft.Maui.Controls.SourceGen.UnitTests.InitializeComponent;
7+
8+
public class LineInfoTests : SourceGenXamlInitializeComponentTestBase
9+
{
10+
[Test]
11+
public void DiagnosticShowsLocationInInputXamlFile()
12+
{
13+
var xaml =
14+
"""
15+
<?xml version="1.0" encoding="UTF-8"?>
16+
<ContentPage
17+
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
18+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
19+
x:Class="Test.TestPage">
20+
<ContentPage.Resources>
21+
<ResourceDictionary>
22+
<ResourceDictionary.MergedDictionaries>
23+
<ResourceDictionary Source="Resources/Styles\Colors.xaml" />
24+
</ResourceDictionary.MergedDictionaries>
25+
</ResourceDictionary>
26+
</ContentPage.Resources>
27+
</ContentPage>
28+
""";
29+
30+
var (result, _) = RunGenerator(xaml, string.Empty);
31+
32+
var generatedCode = result.GeneratedTrees.Single(tree => tree.FilePath.EndsWith("_Test.xaml.xsg.cs")).ToString();
33+
var expectedFilePath = Path.Combine(Environment.CurrentDirectory, "Test.xaml");
34+
Assert.IsTrue(generatedCode.Contains(@$"#line 9 ""{expectedFilePath}""", StringComparison.Ordinal));
35+
}
36+
}

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/SourceGenXamlInitializeComponentTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.IO;
13
using System.Linq;
24
using Microsoft.CodeAnalysis;
35
using Microsoft.CodeAnalysis.CSharp;
@@ -16,7 +18,9 @@ protected record AdditionalXamlFile(string Path, string Content, string? Relativ
1618
{
1719
var compilation = CreateMauiCompilation();
1820
compilation = compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(code));
19-
var result = RunGenerator<CodeBehindGenerator>(compilation, new AdditionalXamlFile("Test.xaml", xaml, TargetFramework: targetFramework, NoWarn: noWarn));
21+
var workingDirectory = Environment.CurrentDirectory;
22+
var xamlFile = new AdditionalXamlFile(Path.Combine(workingDirectory, "Test.xaml"), xaml, RelativePath: "Test.xaml", TargetFramework: targetFramework, NoWarn: noWarn);
23+
var result = RunGenerator<CodeBehindGenerator>(compilation, xamlFile);
2024
var generated = result.Results.SingleOrDefault().GeneratedSources.SingleOrDefault(gs => gs.HintName.EndsWith(".xsg.cs")).SourceText?.ToString();
2125

2226
return (result, generated);

0 commit comments

Comments
 (0)