提交 ad621a70 编写于 作者: T Tomáš Matoušek

Merge pull request #4887 from tmat/NeutralCulture

Handling of neutral culture in AssemblyIdentity
......@@ -213,7 +213,7 @@ class CLS
Diagnostic(ErrorCode.ERR_AnonymousTypeNotAvailable, "new"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CompilationChain_AnonymousTypeTemplates()
{
var s0 = CreateSubmission("var x = new { a = 1 }; ");
......@@ -236,7 +236,7 @@ public void CompilationChain_AnonymousTypeTemplates()
Assert.False(sx.AnonymousTypeManager.AreTemplatesSealed);
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CompilationChain_DynamicSiteDelegates()
{
// TODO: references should be inherited
......@@ -260,7 +260,7 @@ public void CompilationChain_DynamicSiteDelegates()
Assert.False(sx.AnonymousTypeManager.AreTemplatesSealed);
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void Submissions_EmitToPeStream()
{
var s0 = CreateSubmission("int a = 1;");
......@@ -271,7 +271,7 @@ public void Submissions_EmitToPeStream()
s12.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionGenericInterfaceImplementation_Generic()
{
var c0 = CreateSubmission(@"
......@@ -293,7 +293,7 @@ public void m<TT>(int x, TT y)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionGenericInterfaceImplementation_Explicit_GenericMethod()
{
var c0 = CreateSubmission(@"
......@@ -315,7 +315,7 @@ void I<int>.m<S>(int x, S y)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionGenericInterfaceImplementation_Explicit()
{
var c0 = CreateSubmission(@"
......@@ -337,7 +337,7 @@ void I<int>.m(int x)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionGenericInterfaceImplementation_Explicit_NoGenericParametersInSignature()
{
var c0 = CreateSubmission(@"
......@@ -359,7 +359,7 @@ void I<int>.m(byte x)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void GenericInterfaceImplementation_Explicit_NoGenericParametersInSignature()
{
var c0 = CreateSubmission(@"
......@@ -376,7 +376,7 @@ void I<int>.m(byte x)
c0.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionInterfaceImplementation_Explicit_NoGenericParametersInSignature()
{
var c0 = CreateSubmission(@"
......@@ -398,7 +398,7 @@ void I.m(byte x)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CrossSubmissionNestedGenericInterfaceImplementation_Explicit()
{
var c0 = CreateSubmission(@"
......@@ -423,7 +423,7 @@ void C<int>.I.m(int x)
c1.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void NestedGenericInterfaceImplementation_Explicit()
{
var c0 = CreateSubmission(@"
......@@ -443,7 +443,7 @@ void C<int>.I.m(int x)
c0.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ExternalInterfaceImplementation_Explicit()
{
var c0 = CreateSubmission(@"
......@@ -465,7 +465,7 @@ IEnumerator IEnumerable.GetEnumerator()
c0.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void AbstractAccessors()
{
var c0 = CreateSubmission(@"
......@@ -478,7 +478,7 @@ public abstract class C
c0.VerifyEmitDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ExprStmtWithMethodCall()
{
var s0 = CreateSubmission("int Foo() { return 2;}");
......
......@@ -83,7 +83,7 @@ public void MainInScript1()
Diagnostic(ErrorCode.WRN_MainIgnored, "Main").WithArguments("Main()"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void NoReferences()
{
var submission = CSharpCompilation.CreateSubmission("test", syntaxTree: SyntaxFactory.ParseSyntaxTree("1", options: TestOptions.Interactive), returnType: typeof(int));
......@@ -104,7 +104,7 @@ public void NoReferences()
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Object").WithLocation(1, 1));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void Namespaces()
{
var c = CreateSubmission(@"
......@@ -292,7 +292,7 @@ public void UsingStaticClass()
}
[WorkItem(3817, "https://github.com/dotnet/roslyn/issues/3817")]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void LabelLookup()
{
var source = "using System; 1";
......@@ -302,7 +302,7 @@ public void LabelLookup()
}
[WorkItem(543890)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ThisIndexerAccessInSubmission()
{
string test = @"
......@@ -335,7 +335,7 @@ public void ThisIndexerAccessInSubmission()
/// </summary>
[WorkItem(530986)]
[WorkItem(1010871)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void LookupSymbols()
{
var text = "1 + ";
......@@ -365,7 +365,7 @@ public void LookupSymbols()
Assert.False(symbols.Any(s => s.Name == "Roslyn"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void HostObjectBinding_Diagnostics()
{
var submission = CreateSubmission("x",
......@@ -413,7 +413,7 @@ public void DelegateAddition()
}
[WorkItem(870885)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void Bug870885()
{
var source = @"var o = o.F;";
......@@ -426,7 +426,7 @@ public void Bug870885()
}
[WorkItem(949595)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void GlobalAttributes()
{
var source = @"
......@@ -442,7 +442,7 @@ public void GlobalAttributes()
Diagnostic(ErrorCode.ERR_GlobalAttributesNotAllowed, "module"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void SealedOverride()
{
var source0 = @"
......@@ -465,7 +465,7 @@ class Y : M
CompileAndVerify(c1);
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void PrivateNested()
{
var c0 = CreateSubmission(@"public class C { private static int foo() { return 1; } }");
......@@ -476,7 +476,7 @@ public void PrivateNested()
Diagnostic(ErrorCode.ERR_BadAccess, "foo").WithArguments("C.foo()"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void InconsistentAccessibilityChecks()
{
var c0 = CreateSubmission(@"
......@@ -548,7 +548,7 @@ public class E { }
Diagnostic(ErrorCode.ERR_BadVisFieldType, "x").WithArguments("x", "B"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CompilationChain_Fields()
{
var c0 = CreateSubmission(@"
......@@ -562,7 +562,7 @@ public void CompilationChain_Fields()
c2.VerifyDiagnostics(Diagnostic(ErrorCode.ERR_ObjectRequired, "i").WithArguments("i"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void CompilationChain_InStaticContext()
{
var c0 = CreateSubmission(@"
......@@ -585,7 +585,7 @@ public void CompilationChain_InStaticContext()
Diagnostic(ErrorCode.ERR_ObjectRequired, "z").WithArguments("z()"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void AccessToGlobalMemberFromNestedClass1()
{
var c0 = CreateSubmission(@"
......@@ -602,7 +602,7 @@ class D
Diagnostic(ErrorCode.ERR_ObjectRequired, "foo").WithArguments("foo()"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void AccessToGlobalMemberFromNestedClass2()
{
var c0 = CreateSubmission(@"
......@@ -623,7 +623,7 @@ class D
/// <summary>
/// Previous submission has to have no errors.
/// </summary>
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void Submissions_ExecutionOrder3()
{
var s0 = CreateSubmission("int a = \"x\";");
......@@ -635,7 +635,7 @@ public void Submissions_ExecutionOrder3()
}
[WorkItem(3795, "https://github.com/dotnet/roslyn/issues/3795")]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ErrorInUsing()
{
var submission = CreateSubmission("using Unknown;");
......@@ -650,7 +650,7 @@ public void ErrorInUsing()
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void HostObjectBinding_MissingHostObjectContext()
{
var c = CreateSubmission("Z()", new[] { HostRef });
......@@ -660,7 +660,7 @@ public void HostObjectBinding_MissingHostObjectContext()
Diagnostic(ErrorCode.ERR_NameNotInContext, "Z").WithArguments("Z"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void HostObjectBinding_InStaticContext()
{
var source = @"
......@@ -684,7 +684,7 @@ public void HostObjectBinding_InStaticContext()
Diagnostic(ErrorCode.ERR_ObjectRequired, "Z").WithArguments(typeName + ".C.Z()"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void WRN_LowercaseEllSuffix()
{
var c = CreateSubmission("int i = 42l;");
......@@ -696,7 +696,7 @@ public void WRN_LowercaseEllSuffix()
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "42l").WithArguments("long", "int"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ERR_RecursivelyTypedVariable()
{
var c = CreateSubmission("var x = x;");
......@@ -706,7 +706,7 @@ public void ERR_RecursivelyTypedVariable()
Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x").WithArguments("x"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ERR_VariableUsedBeforeDeclaration()
{
var c = CreateSubmission("var x = 1; { var x = x;}");
......@@ -716,7 +716,7 @@ public void ERR_VariableUsedBeforeDeclaration()
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ERR_ReturnNotAllowedInScript()
{
var c1 = CreateSubmission("return;");
......@@ -732,7 +732,7 @@ public void ERR_ReturnNotAllowedInScript()
Diagnostic(ErrorCode.ERR_ReturnNotAllowedInScript, "return"));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ERR_FieldCantBeRefAny()
{
var c = CreateSubmission(@"
......@@ -750,7 +750,7 @@ public void ERR_FieldCantBeRefAny()
}
[WorkItem(529387)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void IsVariable_PreviousSubmission()
{
var c0 = CreateSubmission("var x = 1;");
......@@ -762,7 +762,7 @@ public void IsVariable_PreviousSubmission()
Diagnostic(ErrorCode.ERR_FixedNeeded, "&x").WithLocation(1, 1));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void IsVariable_HostObject()
{
var c0 = CreateSubmission("&x", new[] { HostRef }, hostObjectType: typeof(B2));
......@@ -774,7 +774,7 @@ public void IsVariable_HostObject()
}
[WorkItem(530404)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void DiagnosticsPass()
{
var source = "(System.Linq.Expressions.Expression<System.Func<object>>)(() => null ?? new object())";
......@@ -787,7 +787,7 @@ public void DiagnosticsPass()
}
[WorkItem(527850)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ArithmeticOperators_MultiplicationExpression()
{
var s0 = CreateSubmission("int i = 5;");
......@@ -804,7 +804,7 @@ public void ArithmeticOperators_MultiplicationExpression()
[WorkItem(527850)]
[WorkItem(522569)]
[WorkItem(4737)]
[ClrOnlyFact(ClrOnlyReason.Submission, Skip = "4737")]
[Fact(Skip = "4737")]
public void TopLevelLabel()
{
var s0 = CreateSubmission(@"
......@@ -815,7 +815,7 @@ public void TopLevelLabel()
}
[WorkItem(541210)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void TopLevelGoto()
{
var s0 = CreateSubmission("goto Object;");
......@@ -826,7 +826,7 @@ public void TopLevelGoto()
}
[WorkItem(541166)]
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void DefineExtensionMethods()
{
var references = new[] { TestReferences.NetFx.v4_0_30319.System_Core };
......
......@@ -1383,7 +1383,7 @@ class A
Diagnostic(ErrorCode.WRN_MainIgnored, "Main").WithArguments("A.Main()").WithLocation(4, 17));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void GetEntryPoint_Submission()
{
var source = @"1 + 1";
......@@ -1402,7 +1402,7 @@ public void GetEntryPoint_Submission()
entryPoint.Diagnostics.Verify();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void GetEntryPoint_Submission_MainIgnored()
{
var source = @"
......@@ -1926,7 +1926,7 @@ public void ConsistentParseOptions()
});
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void SubmissionCompilation_Errors()
{
var genericParameter = typeof(List<>).GetGenericArguments()[0];
......@@ -1969,7 +1969,7 @@ private static void TestSubmissionResult(CSharpCompilation s, SpecialType? expec
Assert.Equal(expectedHasValue, hasValue);
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void SubmissionResultType()
{
var submission = CSharpCompilation.CreateSubmission("sub");
......@@ -1992,7 +1992,7 @@ public void SubmissionResultType()
/// <summary>
/// Previous submission has to have no errors.
/// </summary>
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void PreviousSubmissionWithError()
{
var s0 = CreateSubmission("int a = \"x\";");
......
......@@ -359,7 +359,7 @@ public void InfoAndWarnAsError()
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System;").WithWarningAsError(false));
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void UnusedUsingInteractive()
{
var tree = Parse("using System;", options: TestOptions.Interactive);
......
......@@ -3685,7 +3685,7 @@ class C
compilation.VerifyDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void InteractiveExtensionMethods()
{
var parseOptions = TestOptions.Interactive;
......
......@@ -98,7 +98,7 @@ public void ExternAliasInScript()
comp.VerifyDiagnostics();
}
[ClrOnlyFact(ClrOnlyReason.Submission)]
[Fact]
public void ExternAliasInInteractive_Error()
{
var src = "extern alias Bar;";
......
......@@ -145,6 +145,12 @@ public void GetDisplayName()
string dnFull = id.GetDisplayName(fullKey: true);
Assert.Equal("Foo, Version=0.0.0.0, Culture=neutral, PublicKey=" + StrPublicKey1, dnFull);
id = new AssemblyIdentity("Foo", cultureName: "neutral");
Assert.Equal("Foo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", id.GetDisplayName());
id = new AssemblyIdentity("Foo", cultureName: " '\t\r\n\\=, ");
Assert.Equal(@"Foo, Version=0.0.0.0, Culture="" \'\t\r\n\\\=\, "", PublicKeyToken=null", id.GetDisplayName());
}
[Fact]
......@@ -228,7 +234,7 @@ public void TryParseDisplayName_QuotingAndEscaping()
TestParseSimpleName("a'b, Version=1.0.0.0", expected: null);
TestParseSimpleName("'', Version=1.0.0.0", expected: null);
TestParseSimpleName("''a'', Version=1.0.0.0", expected: null);
// Unicode quotes
TestParseSimpleName("\u201ca\u201d", expected: "\u201ca\u201d");
TestParseSimpleName("\\u201c;a\\u201d;", expected: "\u201ca\u201d");
......@@ -380,6 +386,10 @@ public void TryParseDisplayName()
new AssemblyIdentity("foo", new Version(1, 0, 0, 1), publicKeyOrToken: RoPublicKey1, hasPublicKey: true),
NVK);
TestParseDisplayName(@"Foo, Version=0.0.0.0, Culture="" \'\t\r\n\\\=\, "", PublicKeyToken=null",
new AssemblyIdentity("Foo", cultureName: " '\t\r\n\\=, "),
NVCT);
// duplicates
TestParseDisplayName("foo, Version=1.0.0.0, Version=1.0.0.0", null);
TestParseDisplayName("foo, Version=1.0.0.0, Version=2.0.0.0", null);
......@@ -500,6 +510,9 @@ public void TryParseDisplayName_Culture()
TestParseDisplayName("foo, Culture=*", new AssemblyIdentity("foo"), N);
TestParseDisplayName("foo, Culture=*, Culture=en-US, Version=1.0.0.1", null);
TestParseDisplayName("Foo, Version=1.0.0.0, Culture='neutral', PublicKeyToken=null",
new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), cultureName: null), NVCT);
}
[Fact]
......
......@@ -57,6 +57,19 @@ public void Equality()
Assert.Equal(win1.GetHashCode(), win3.GetHashCode());
}
[Fact]
public void Equality_InvariantCulture()
{
var neutral1 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "NEUtral", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false);
var neutral2 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), null, RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false);
var neutral3 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "neutral", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false);
var invariant = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false);
Assert.True(neutral1.Equals(invariant));
Assert.True(neutral2.Equals(invariant));
Assert.True(neutral3.Equals(invariant));
}
[Fact]
public void FromAssemblyDefinitionInvalidParameters()
{
......@@ -103,6 +116,20 @@ public void FromAssemblyDefinition()
Assert.Equal(AssemblyContentType.WindowsRuntime, id.ContentType);
}
[Fact]
public void FromAssemblyDefinition_InvariantCulture()
{
var name = new AssemblyName("foo");
name.Flags = AssemblyNameFlags.None;
name.CultureInfo = CultureInfo.InvariantCulture;
name.ContentType = AssemblyContentType.Default;
name.Version = new Version(1, 2, 3, 4);
name.ProcessorArchitecture = ProcessorArchitecture.X86;
var id = AssemblyIdentity.FromAssemblyDefinition(name);
Assert.Equal("", id.CultureName);
}
[Fact]
public void Properties()
{
......@@ -171,12 +198,12 @@ public void IsStrongName()
var id2 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false);
Assert.True(id2.IsStrongName);
var id3 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: false);
var id3 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false);
Assert.False(id3.IsStrongName);
// for WinRT references "strong name" doesn't make sense:
var id4 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.WindowsRuntime);
var id4 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.WindowsRuntime);
Assert.False(id4.IsStrongName);
var id5 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.WindowsRuntime);
......@@ -191,7 +218,7 @@ public void InvalidConstructorArgs()
Assert.Throws<ArgumentException>(() => new AssemblyIdentity(null));
Assert.Throws<ArgumentException>(
() => new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray.Create<byte>(), hasPublicKey: true, isRetargetable: false));
() => new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", ImmutableArray<byte>.Empty, hasPublicKey: true, isRetargetable: false));
Assert.Throws<ArgumentException>(
() => new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", new byte[] { 1, 2, 3 }.AsImmutableOrNull(), hasPublicKey: false, isRetargetable: false));
......@@ -201,17 +228,17 @@ public void InvalidConstructorArgs()
new Version(),
new Version(0, 0),
new Version(0, 0, 0),
new Version(Int32.MaxValue, 0, 0, 0),
new Version(0, Int32.MaxValue, 0, 0),
new Version(0, 0, Int32.MaxValue, 0),
new Version(0, 0, 0, Int32.MaxValue),
new Version(int.MaxValue, 0, 0, 0),
new Version(0, int.MaxValue, 0, 0),
new Version(0, 0, int.MaxValue, 0),
new Version(0, 0, 0, int.MaxValue),
})
{
Assert.Throws<ArgumentOutOfRangeException>(() => new AssemblyIdentity("Foo", v));
}
Assert.Throws<ArgumentOutOfRangeException>(() => new AssemblyIdentity("Foo", contentType: (AssemblyContentType)(-1)));
Assert.Throws<ArgumentOutOfRangeException>(() => new AssemblyIdentity("Foo", contentType: (AssemblyContentType)Int32.MaxValue));
Assert.Throws<ArgumentOutOfRangeException>(() => new AssemblyIdentity("Foo", contentType: (AssemblyContentType)int.MaxValue));
Assert.Throws<ArgumentException>(() =>
new AssemblyIdentity("Foo", publicKeyOrToken: RoPublicKey1, hasPublicKey: true, isRetargetable: true, contentType: AssemblyContentType.WindowsRuntime));
......@@ -232,7 +259,7 @@ public void MetadataConstructor()
Assert.Equal(AssemblyContentType.Default, id.ContentType);
// invalid content type:
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: false, contentType: (AssemblyContentType)2, noThrow: true);
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false, contentType: (AssemblyContentType)2, noThrow: true);
Assert.Equal(AssemblyNameFlags.None, id.Flags);
Assert.Equal("", id.CultureName);
Assert.Equal(false, id.HasPublicKey);
......@@ -241,7 +268,7 @@ public void MetadataConstructor()
Assert.Equal(AssemblyContentType.Default, id.ContentType);
// default Retargetable=No if content type is WinRT
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: true, contentType: AssemblyContentType.WindowsRuntime, noThrow: true);
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: true, contentType: AssemblyContentType.WindowsRuntime, noThrow: true);
Assert.Equal("Foo", id.Name);
Assert.Equal(new Version(1, 2, 3, 4), id.Version);
Assert.Equal(AssemblyNameFlags.None, id.Flags);
......@@ -251,12 +278,16 @@ public void MetadataConstructor()
Assert.Equal(AssemblyContentType.WindowsRuntime, id.ContentType);
// invalid culture:
//EDMAURER the compiler doesn't enforce that the culture be anything in particular. AssemblyIdentity should preserve user input even if it
//is of dubious utility.
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "blah,", ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true);
// The native compiler doesn't enforce that the culture be anything in particular.
// AssemblyIdentity should preserve user input even if it is of dubious utility.
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "blah,", ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true);
Assert.Equal("blah,", id.CultureName);
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "*", ImmutableArray.Create<byte>(), hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true);
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "*", ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true);
Assert.Equal("*", id.CultureName);
id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "neutral", ImmutableArray<byte>.Empty, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true);
Assert.Equal("", id.CultureName);
}
[Fact]
......@@ -301,6 +332,13 @@ public void ToAssemblyName()
}
}
[Fact]
public void ToAssemblyName_Errors()
{
var ai = new AssemblyIdentity("foo", cultureName: "*");
Assert.Throws<CultureNotFoundException>(() => ai.ToAssemblyName());
}
[Fact]
public void Keys()
{
......
......@@ -19,6 +19,8 @@ namespace Microsoft.CodeAnalysis
/// </remarks>
public partial class AssemblyIdentity
{
internal const string InvariantCultureDisplay = "neutral";
/// <summary>
/// Returns the display name of the assembly identity.
/// </summary>
......@@ -71,7 +73,14 @@ private string BuildDisplayName(bool fullKey)
sb.Append(_version.Revision);
sb.Append(", Culture=");
sb.Append(_cultureName.Length != 0 ? _cultureName : "neutral");
if (_cultureName.Length == 0)
{
sb.Append(InvariantCultureDisplay);
}
else
{
EscapeName(sb, _cultureName);
}
if (fullKey && HasPublicKey)
{
......@@ -258,7 +267,7 @@ public static bool TryParseDisplayName(string displayName, out AssemblyIdentity
continue;
}
culture = string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase) ? null : propertyValue;
culture = string.Equals(propertyValue, InvariantCultureDisplay, StringComparison.OrdinalIgnoreCase) ? null : propertyValue;
parsedParts |= AssemblyIdentityParts.Culture;
}
else if (string.Equals(propertyName, "PublicKey", StringComparison.OrdinalIgnoreCase))
......
......@@ -55,12 +55,17 @@ public sealed partial class AssemblyIdentity : IEquatable<AssemblyIdentity>
/// </summary>
/// <param name="name">The simple name of the assembly.</param>
/// <param name="version">The version of the assembly.</param>
/// <param name="cultureName">The name of the culture to associate with the assembly.</param>
/// <param name="cultureName">
/// The name of the culture to associate with the assembly.
/// Specify null, <see cref="string.Empty"/>, or "neutral" (any casing) to represent <see cref="System.Globalization.CultureInfo.InvariantCulture"/>.
/// The name can be an arbitrary string that doesn't contain NUL character, the legality of the culture name is not validated.
/// </param>
/// <param name="publicKeyOrToken">The public key or public key token of the assembly.</param>
/// <param name="hasPublicKey">Indicates whether <paramref name="publicKeyOrToken"/> represents a public key.</param>
/// <param name="isRetargetable">Indicates whether the assembly is retargetable.</param>
/// <param name="contentType">Specifies the binding model for how this object will be treated in comparisons.</param>
/// <exception cref="ArgumentException">If <paramref name="name"/> is null, empty or contains an embedded null character.</exception>
/// <exception cref="ArgumentException">If <paramref name="name"/> is null, empty or contains a NUL character.</exception>
/// <exception cref="ArgumentException">If <paramref name="cultureName"/> contains a NUL character.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="contentType"/> is not a value of the <see cref="AssemblyContentType"/> enumeration.</exception>
/// <exception cref="ArgumentException"><paramref name="version"/> contains values that are not greater than or equal to zero and less than or equal to ushort.MaxValue.</exception>
/// <exception cref="ArgumentException"><paramref name="hasPublicKey"/> is true and <paramref name="publicKeyOrToken"/> is not set.</exception>
......@@ -118,7 +123,7 @@ public sealed partial class AssemblyIdentity : IEquatable<AssemblyIdentity>
_name = name;
_version = version ?? NullVersion;
_cultureName = cultureName ?? string.Empty;
_cultureName = NormalizeCultureName(cultureName);
_isRetargetable = isRetargetable;
_contentType = contentType;
InitializeKey(publicKeyOrToken, hasPublicKey, out _publicKey, out _lazyPublicKeyToken);
......@@ -139,7 +144,7 @@ public sealed partial class AssemblyIdentity : IEquatable<AssemblyIdentity>
_name = name;
_version = version ?? NullVersion;
_cultureName = cultureName ?? string.Empty;
_cultureName = NormalizeCultureName(cultureName);
_isRetargetable = false;
_contentType = AssemblyContentType.Default;
InitializeKey(publicKeyOrToken, hasPublicKey, out _publicKey, out _lazyPublicKeyToken);
......@@ -162,13 +167,29 @@ public sealed partial class AssemblyIdentity : IEquatable<AssemblyIdentity>
_name = name;
_version = version ?? NullVersion;
_cultureName = cultureName ?? string.Empty;
_cultureName = NormalizeCultureName(cultureName);
_contentType = IsValid(contentType) ? contentType : AssemblyContentType.Default;
_isRetargetable = isRetargetable && _contentType != AssemblyContentType.WindowsRuntime;
InitializeKey(publicKeyOrToken, hasPublicKey, out _publicKey, out _lazyPublicKeyToken);
}
static private void InitializeKey(ImmutableArray<byte> publicKeyOrToken, bool hasPublicKey,
private static string NormalizeCultureName(string cultureName)
{
// Treat "neutral" culture as invariant culture name, although it is technically not a legal culture name.
//
// A few reasons:
// 1) Invariant culture is displayed as "neutral" in the identity display name.
// Thus a) an identity with culture "neutral" wouldn't roundrip serialization to display name.
// b) an identity with culture "neutral" wouldn't compare equal to invariant culture identity,
// yet their display names are the same which is confusing.
//
// 2) The implementation of AssemblyName.CultureName on Mono incorrectly returns "neutral" for invariant culture identities.
return cultureName == null || AssemblyIdentityComparer.CultureComparer.Equals(cultureName, InvariantCultureDisplay) ?
string.Empty : cultureName;
}
private static void InitializeKey(ImmutableArray<byte> publicKeyOrToken, bool hasPublicKey,
out ImmutableArray<byte> publicKey, out ImmutableArray<byte> publicKeyToken)
{
if (hasPublicKey)
......@@ -185,10 +206,12 @@ public sealed partial class AssemblyIdentity : IEquatable<AssemblyIdentity>
internal static bool IsValidCultureName(string name)
{
// NOTE: if these checks change, the error messages emitted by the compilers when
// this case is detected will also need to change. They currently directly
// name the presence of the NUL character as the reason that the culture
// name is invalid.
// The native compiler doesn't enforce that the culture be anything in particular.
// AssemblyIdentity should preserve user input even if it is of dubious utility.
// Note: If these checks change, the error messages emitted by the compilers when
// this case is detected will also need to change. They currently directly
// name the presence of the NUL character as the reason that the culture name is invalid.
return name == null || name.IndexOf('\0') < 0;
}
......@@ -477,7 +500,7 @@ internal static AssemblyIdentity FromAssemblyDefinition(AssemblyName name)
// AssemblyDef always has full key or no key:
var publicKeyBytes = name.GetPublicKey();
ImmutableArray<byte> publicKey = (publicKeyBytes != null) ? ImmutableArray.Create(publicKeyBytes) : ImmutableArray<byte>.Empty;
return new AssemblyIdentity(
name.Name,
name.Version,
......
......@@ -1720,7 +1720,7 @@ End Namespace
Assert.Throws(Of ArgumentException)(Function() VisualBasicCompilation.Create(assemblyName, {tree1, tree3}, {MscorlibRef}, CompilationOptions))
End Sub
<ClrOnlyFact(ClrOnlyReason.Submission)>
<Fact>
Public Sub SubmissionCompilation_Errors()
Dim genericParameter = GetType(List(Of)).GetGenericArguments()(0)
Dim open = GetType(Dictionary(Of,)).MakeGenericType(GetType(Integer), genericParameter)
......@@ -1753,7 +1753,7 @@ End Namespace
Assert.Throws(Of ArgumentException)(Function() VisualBasicCompilation.CreateSubmission("a", options:=TestOptions.ReleaseDll.WithDelaySign(False)))
End Sub
<ClrOnlyFact(ClrOnlyReason.Submission)>
<Fact>
Public Sub SubmissionResultType()
Dim submission = VisualBasicCompilation.CreateSubmission("sub")
Dim hasValue As Boolean
......@@ -1803,7 +1803,7 @@ End Sub
''' <summary>
''' Previous submission has to have no errors.
''' </summary>
<ClrOnlyFact(ClrOnlyReason.Submission)>
<Fact>
Public Sub PreviousSubmissionWithError()
Dim s0 = CreateSubmission("Dim a As X = 1")
......
......@@ -301,7 +301,7 @@ Imports System
CreateCompilationWithMscorlib(source, parseOptions:=New VisualBasicParseOptions(documentationMode:=DocumentationMode.Diagnose)).AssertTheseDiagnostics(<errors></errors>, suppressInfos:=False)
End Sub
<ClrOnlyFact(ClrOnlyReason.Submission)>
<Fact>
Public Sub UnusedImportInteractive()
Dim tree = Parse("Imports System", options:=TestOptions.Interactive)
Dim compilation = VisualBasicCompilation.CreateSubmission("sub1", tree, {MscorlibRef_v4_0_30316_17626})
......
......@@ -35,9 +35,6 @@ public enum ClrOnlyReason
// Can't sign.
Signing,
// Can't find System.Object when compiling a submission (not understood).
Submission,
}
public class ClrOnlyFact : FactAttribute
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册