Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions src/Cli/dotnet/Commands/CliCommandStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,9 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man
<value>Duplicate directives are not supported: {0}</value>
<comment>{0} is the directive type and name.</comment>
</data>
<data name="QuoteInDirective" xml:space="preserve">
<value>Directives currently cannot contain quotes (").</value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, is this specific to double quotes " or does that also account for single quotes '? Might make sense to be a bit more specific.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this is specific to double quotes, I will clarify, thanks. We could disallow single quotes too, I didn't think about that, but it also seems unnecessary (we likely won't want to support single-quoted directive values anyway, only double-quoted, I imagine, same as C# strings).

</data>
<data name="InvalidOptionForStdin" xml:space="preserve">
<value>Cannot specify option '{0}' when also using '-' to read the file from standard input.</value>
<comment>{0} is an option name like '--no-build'.</comment>
Expand Down
9 changes: 8 additions & 1 deletion src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1490,8 +1490,15 @@ public static ImmutableArray<CSharpDirective> FindDirectives(SourceFile sourceFi
Diagnostics = diagnostics,
SourceFile = sourceFile,
DirectiveKind = name.ToString(),
DirectiveText = value.ToString()
DirectiveText = value.ToString(),
};

// Block quotes now so we can later support quoted values without a breaking change. https://github.com/dotnet/sdk/issues/49367
if (value.Contains('"'))
{
diagnostics.AddError(sourceFile, context.Info.Span, CliCommandStrings.QuoteInDirective);
}

if (CSharpDirective.Parse(context) is { } directive)
{
// If the directive is already present, report an error.
Expand Down
5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using System.Security;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis.Text;
Expand Down Expand Up @@ -1168,10 +1169,10 @@ public void Directives_InvalidPropertyName()
{
VerifyConversionThrows(
inputCSharp: """
#:property Name"=Value
#:property 123Name=Value
""",
expectedWildcardPattern: RunFileTests.DirectiveError("/app/Program.cs", 1, CliCommandStrings.PropertyDirectiveInvalidName, """
The '"' character, hexadecimal value 0x22, cannot be included in a name.
Name cannot begin with the '1' character, hexadecimal value 0x31.
"""));
}

Expand Down Expand Up @@ -1221,7 +1222,13 @@ public void Directives_Escaping()
</Project>

""",
expectedCSharp: "");
expectedCSharp: "",
expectedErrors:
[
(1, CliCommandStrings.QuoteInDirective),
(2, CliCommandStrings.QuoteInDirective),
(3, CliCommandStrings.QuoteInDirective),
]);
}

[Fact]
Expand Down Expand Up @@ -1257,7 +1264,11 @@ public void Directives_Whitespace()
# ! /test
#! /program x
# :property Name=Value
""");
""",
expectedErrors:
[
(3, CliCommandStrings.QuoteInDirective),
]);
}

[Fact]
Expand Down Expand Up @@ -1548,10 +1559,15 @@ public void Directives_VersionedSdkFirst()
""");
}

private static void Convert(string inputCSharp, out string actualProject, out string? actualCSharp, bool force, string? filePath)
private const string programPath = "/app/Program.cs";

private static void Convert(string inputCSharp, out string actualProject, out string? actualCSharp, bool force, string? filePath,
bool collectDiagnostics, out ImmutableArray<SimpleDiagnostic>.Builder? actualDiagnostics)
{
var sourceFile = new SourceFile(filePath ?? "/app/Program.cs", SourceText.From(inputCSharp, Encoding.UTF8));
var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !force, DiagnosticBag.ThrowOnFirst());
var sourceFile = new SourceFile(filePath ?? programPath, SourceText.From(inputCSharp, Encoding.UTF8));
actualDiagnostics = null;
var diagnosticBag = collectDiagnostics ? DiagnosticBag.Collect(out actualDiagnostics) : DiagnosticBag.ThrowOnFirst();
var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !force, diagnosticBag);
var projectWriter = new StringWriter();
VirtualProjectBuildingCommand.WriteProjectFile(projectWriter, directives, isVirtualProject: false);
actualProject = projectWriter.ToString();
Expand All @@ -1561,25 +1577,43 @@ private static void Convert(string inputCSharp, out string actualProject, out st
/// <param name="expectedCSharp">
/// <see langword="null"/> means the conversion should not touch the C# content.
/// </param>
private static void VerifyConversion(string inputCSharp, string expectedProject, string? expectedCSharp, bool force = false, string? filePath = null)
private static void VerifyConversion(string inputCSharp, string expectedProject, string? expectedCSharp, bool force = false, string? filePath = null,
IEnumerable<(int LineNumber, string Message)>? expectedErrors = null)
{
Convert(inputCSharp, out var actualProject, out var actualCSharp, force: force, filePath: filePath);
Convert(inputCSharp, out var actualProject, out var actualCSharp, force: force, filePath: filePath,
collectDiagnostics: expectedErrors != null, out var actualDiagnostics);
actualProject.Should().Be(expectedProject);
actualCSharp.Should().Be(expectedCSharp);
VerifyErrors(actualDiagnostics, expectedErrors);
}

private static void VerifyConversionThrows(string inputCSharp, string expectedWildcardPattern)
{
var convert = () => Convert(inputCSharp, out _, out _, force: false, filePath: null);
var convert = () => Convert(inputCSharp, out _, out _, force: false, filePath: null, collectDiagnostics: false, out _);
convert.Should().Throw<GracefulException>().WithMessage(expectedWildcardPattern);
}

private static void VerifyDirectiveConversionErrors(string inputCSharp, IEnumerable<(int LineNumber, string Message)> expectedErrors)
{
var programPath = "/app/Program.cs";
var sourceFile = new SourceFile(programPath, SourceText.From(inputCSharp, Encoding.UTF8));
VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: true, DiagnosticBag.Collect(out var diagnostics));
Assert.All(diagnostics, d => { Assert.Equal(programPath, d.Location.Path); });
diagnostics.Select(d => (d.Location.Span.Start.Line + 1, d.Message)).Should().BeEquivalentTo(expectedErrors);
VerifyErrors(diagnostics, expectedErrors);
}

private static void VerifyErrors(ImmutableArray<SimpleDiagnostic>.Builder? actual, IEnumerable<(int LineNumber, string Message)>? expected)
{
if (actual is null)
{
Assert.Null(expected);
}
else if (expected is null)
{
Assert.Null(actual);
}
else
{
Assert.All(actual, d => { Assert.Equal(programPath, d.Location.Path); });
actual.Select(d => (d.Location.Span.Start.Line + 1, d.Message)).Should().BeEquivalentTo(expected);
}
}
}
Loading