提交 8af036a8 编写于 作者: J Julien Couvreur 提交者: GitHub

Refout: disallow NoPia, best effort determinism, assembly redirect for CopyRefAssembly (#19326)

* Ref assemblies make a best effort to emit with determinism
* Fixing CopyRefAssembly message output
* CopyRefAssembly logs when input isn't ref assembly
* CopyRefAssembly does assembly redirect.
* Compact error codes for C# 7.1
上级 2cf3be85
......@@ -37,11 +37,10 @@ The `/refout` parameter specifies a file path where the ref assembly should be o
The `/refonly` parameter is a flag that indicates that a ref assembly should be output instead of an implementation assembly.
The `/refonly` parameter is not allowed together with the `/refout` parameter, as it doesn't make sense to have both the primary and secondary outputs be ref assemblies. Also, the `/refonly` parameter silently disables outputting PDBs, as ref assemblies cannot be executed.
The `/refonly` parameter translates to `EmitMetadataOnly` being `true`, and `IncludePrivateMembers` being `false` in the `Emit` API (see details below).
Neither `/refonly` nor `/refout` are permitted with `/target:module` or `/addmodule` options.
When the compiler produces documentation, the contents produced will match the APIs that go into the primary output. In other words, the documentation will be filtered down when using the `/refonly` parameter.
Neither `/refonly` nor `/refout` are permitted with `/target:module`, `/addmodule`, or `/link:...` options.
The compilation from the command-line will either produce both assemblies (implementation and ref) or neither. There is no "partial success" scenario.
When the compiler produces documentation, it is un-affected by either the `/refonly` or `/refout` parameters.
### CscTask/CoreCompile
The `CoreCompile` target will support a new output, called `IntermediateRefAssembly`, which parallels the existing `IntermediateAssembly`.
......@@ -65,8 +64,10 @@ Going back to the 4 driving scenarios:
## Future
As mentioned above, there may be further refinements after C# 7.1:
- controlling internals (producing public ref assemblies)
- produce ref assemblies even when there are errors outside method bodies (emitting error types when `EmitOptions.TolerateErrors` is set)
- Controlling internals (producing public ref assemblies)
- Produce ref assemblies even when there are errors outside method bodies (emitting error types when `EmitOptions.TolerateErrors` is set)
- When the compiler produces documentation, the contents produced could be filtered down to match the APIs that go into the primary output. In other words, the documentation could be filtered down when using the `/refonly` parameter.
## Open questions
- should explicit method implementations be included in ref assemblies?
......
......@@ -6730,6 +6730,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot embed types when using /refout or /refonly..
/// </summary>
internal static string ERR_NoEmbeddedTypeWhenRefOutOrRefOnly {
get {
return ResourceManager.GetString("ERR_NoEmbeddedTypeWhenRefOutOrRefOnly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Program does not contain a static &apos;Main&apos; method suitable for an entry point.
/// </summary>
......
......@@ -2300,6 +2300,9 @@ If such a class is used as a base class and if the deriving class defines a dest
<data name="ERR_NoNetModuleOutputWhenRefOutOrRefOnly" xml:space="preserve">
<value>Cannot compile net modules when using /refout or /refonly.</value>
</data>
<data name="ERR_NoEmbeddedTypeWhenRefOutOrRefOnly" xml:space="preserve">
<value>Cannot embed types when using /refout or /refonly.</value>
</data>
<data name="ERR_OvlOperatorExpected" xml:space="preserve">
<value>Overloadable operator expected</value>
</data>
......
......@@ -1178,6 +1178,11 @@ public new CSharpCommandLineArguments Parse(IEnumerable<string> args, string bas
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.ERR_NoRefOutWhenRefOnly);
}
if ((refOnly || outputRefFilePath != null) && metadataReferences.Any(r => r.Properties.EmbedInteropTypes))
{
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly);
}
if (outputKind == OutputKind.NetModule && (refOnly || outputRefFilePath != null))
{
AddDiagnostic(diagnostics, diagnosticOptions, ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly);
......
......@@ -325,7 +325,6 @@ IEnumerable<Cci.MethodImplementation> Cci.ITypeDefinition.GetExplicitImplementat
foreach (var member in this.GetMembers())
{
// PROTOTYPE(refout) Do something here?
if (member.Kind == SymbolKind.Method)
{
var method = (MethodSymbol)member;
......
......@@ -1476,11 +1476,12 @@ internal enum ErrorCode
WRN_Experimental = 8305,
ERR_TupleInferredNamesNotAvailable = 8306,
ERR_NoRefOutWhenRefOnly = 8355,
ERR_NoNetModuleOutputWhenRefOutOrRefOnly = 8356,
ERR_NoRefOutWhenRefOnly = 8307,
ERR_NoNetModuleOutputWhenRefOutOrRefOnly = 8308,
ERR_NoEmbeddedTypeWhenRefOutOrRefOnly = 8309,
ERR_BadDynamicMethodArgDefaultLiteral = 9000,
ERR_DefaultLiteralNotValid = 9001,
WRN_DefaultInSwitch = 9002,
ERR_BadDynamicMethodArgDefaultLiteral = 8310,
ERR_DefaultLiteralNotValid = 8311,
WRN_DefaultInSwitch = 8312,
}
}
......@@ -2886,6 +2886,18 @@ public void ParseOut()
// error CS8301: Do not use refout when using refonly.
Diagnostic(ErrorCode.ERR_NoRefOutWhenRefOnly).WithLocation(1, 1));
parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/link:b", "a.cs" }, baseDirectory);
parsedArgs.Errors.Verify(
// error CS8357: Cannot embed types when using /refout or /refonly.
Diagnostic(ErrorCode.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly).WithLocation(1, 1)
);
parsedArgs = DefaultParse(new[] { "/refonly", "/link:b", "a.cs" }, baseDirectory);
parsedArgs.Errors.Verify(
// error CS8357: Cannot embed types when using /refout or /refonly.
Diagnostic(ErrorCode.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly).WithLocation(1, 1)
);
parsedArgs = DefaultParse(new[] { "/refonly:incorrect", "a.cs" }, baseDirectory);
parsedArgs.Errors.Verify(
// error CS2007: Unrecognized option: '/refonly:incorrect'
......@@ -9067,6 +9079,11 @@ public static void Main()
{
System.Console.Write(""Hello"");
}
/// <summary>Private method</summary>
private static void PrivateMethod()
{
System.Console.Write(""Private"");
}
}");
var outWriter = new StringWriter(CultureInfo.InvariantCulture);
......@@ -9081,7 +9098,7 @@ public static void Main()
MetadataReaderUtils.VerifyPEMetadata(exe,
new[] { "TypeDefinition:<Module>", "TypeDefinition:C" },
new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()" },
new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void PrivateMethod()", "MethodDefinition:Void .ctor()" },
new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute" }
);
......@@ -9099,6 +9116,9 @@ public static void Main()
<member name=""M:C.Main"">
<summary>Main method</summary>
</member>
<member name=""M:C.PrivateMethod"">
<summary>Private method</summary>
</member>
</members>
</doc>";
Assert.Equal(expectedDoc, content.Trim());
......@@ -9170,6 +9190,16 @@ public static void Main()
remove { }
}
private event Action E2;
/// <summary>Private Class Field</summary>
private int field;
/// <summary>Private Struct</summary>
private struct S
{
/// <summary>Private Struct Field</summary>
private int field;
}
}");
var outWriter = new StringWriter(CultureInfo.InvariantCulture);
......@@ -9185,7 +9215,7 @@ public static void Main()
// The types and members that are included needs further refinement.
// See issue https://github.com/dotnet/roslyn/issues/17612
MetadataReaderUtils.VerifyPEMetadata(refDll,
new[] { "TypeDefinition:<Module>", "TypeDefinition:C" },
new[] { "TypeDefinition:<Module>", "TypeDefinition:C", "TypeDefinition:S" },
new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()" },
new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute", "ReferenceAssemblyAttribute" }
);
......@@ -9207,10 +9237,20 @@ public static void Main()
<member name=""M:C.Main"">
<summary>Main method</summary>
</member>
<member name=""F:C.field"">
<summary>Private Class Field</summary>
</member>
<member name=""T:C.S"">
<summary>Private Struct</summary>
</member>
<member name=""F:C.S.field"">
<summary>Private Struct Field</summary>
</member>
</members>
</doc>";
Assert.Equal(expectedDoc, content.Trim());
// Clean up temp files
CleanupAllGeneratedFiles(dir.Path);
}
......
......@@ -261,11 +261,11 @@ internal static void Main()
emitResult.Diagnostics.Verify();
VerifyEntryPoint(output, expectZero: false);
VerifyMethods(output, new[] { "void C.Main()", "C..ctor()" });
VerifyMethods(output, "C", new[] { "void C.Main()", "C..ctor()" });
VerifyMvid(output, hasMvidSection: false);
VerifyEntryPoint(metadataOutput, expectZero: true);
VerifyMethods(metadataOutput, new[] { "C..ctor()" });
VerifyMethods(metadataOutput, "C", new[] { "C..ctor()" });
VerifyMvid(metadataOutput, hasMvidSection: true);
}
......@@ -399,9 +399,9 @@ public class C
Assert.True(emitResult.Success);
emitResult.Diagnostics.Verify();
VerifyMethods(output, new[] { "System.Int32 C.<PrivateSetter>k__BackingField", "System.Int32 C.PrivateSetter.get", "void C.PrivateSetter.set",
VerifyMethods(output, "C", new[] { "System.Int32 C.<PrivateSetter>k__BackingField", "System.Int32 C.PrivateSetter.get", "void C.PrivateSetter.set",
"C..ctor()", "System.Int32 C.PrivateSetter { get; private set; }" });
VerifyMethods(metadataOutput, new[] { "System.Int32 C.PrivateSetter.get", "C..ctor()", "System.Int32 C.PrivateSetter { get; }" });
VerifyMethods(metadataOutput, "C", new[] { "System.Int32 C.PrivateSetter.get", "C..ctor()", "System.Int32 C.PrivateSetter { get; }" });
VerifyMvid(output, hasMvidSection: false);
VerifyMvid(metadataOutput, hasMvidSection: true);
}
......@@ -425,9 +425,9 @@ public class C
Assert.True(emitResult.Success);
emitResult.Diagnostics.Verify();
VerifyMethods(output, new[] { "System.Int32 C.<PrivateGetter>k__BackingField", "System.Int32 C.PrivateGetter.get", "void C.PrivateGetter.set",
VerifyMethods(output, "C", new[] { "System.Int32 C.<PrivateGetter>k__BackingField", "System.Int32 C.PrivateGetter.get", "void C.PrivateGetter.set",
"C..ctor()", "System.Int32 C.PrivateGetter { private get; set; }" });
VerifyMethods(metadataOutput, new[] { "void C.PrivateGetter.set", "C..ctor()", "System.Int32 C.PrivateGetter { set; }" });
VerifyMethods(metadataOutput, "C", new[] { "void C.PrivateGetter.set", "C..ctor()", "System.Int32 C.PrivateGetter { set; }" });
}
}
......@@ -449,9 +449,9 @@ public class C
Assert.True(emitResult.Success);
emitResult.Diagnostics.Verify();
VerifyMethods(output, new[] { "System.Int32 C.this[System.Int32 i].get", "void C.this[System.Int32 i].set",
VerifyMethods(output, "C", new[] { "System.Int32 C.this[System.Int32 i].get", "void C.this[System.Int32 i].set",
"C..ctor()", "System.Int32 C.this[System.Int32 i] { private get; set; }" });
VerifyMethods(metadataOutput, new[] { "void C.this[System.Int32 i].set", "C..ctor()",
VerifyMethods(metadataOutput, "C", new[] { "void C.this[System.Int32 i].set", "C..ctor()",
"System.Int32 C.this[System.Int32 i] { set; }" });
}
}
......@@ -478,9 +478,9 @@ public class C : Base
emitResult.Diagnostics.Verify();
Assert.True(emitResult.Success);
VerifyMethods(output, new[] { "void C.Property.set", "C..ctor()", "System.Int32 C.Property.get", "System.Int32 C.Property { internal get; set; }" });
VerifyMethods(output, "C", new[] { "void C.Property.set", "C..ctor()", "System.Int32 C.Property.get", "System.Int32 C.Property { internal get; set; }" });
// A getter is synthesized on C.Property so that it can be marked as sealed. It is emitted despite being internal because it is virtual.
VerifyMethods(metadataOutput, new[] { "void C.Property.set", "C..ctor()", "System.Int32 C.Property.get", "System.Int32 C.Property { internal get; set; }" });
VerifyMethods(metadataOutput, "C", new[] { "void C.Property.set", "C..ctor()", "System.Int32 C.Property.get", "System.Int32 C.Property { internal get; set; }" });
}
}
......@@ -504,7 +504,7 @@ public class C
);
}
private static void VerifyMethods(MemoryStream stream, string[] expectedMethods)
private static void VerifyMethods(MemoryStream stream, string containingType, string[] expectedMethods)
{
stream.Position = 0;
var metadataRef = AssemblyMetadata.CreateFromImage(stream.ToArray()).GetReference();
......@@ -514,7 +514,7 @@ private static void VerifyMethods(MemoryStream stream, string[] expectedMethods)
AssertEx.Equal(
expectedMethods,
compWithMetadata.GetMember<NamedTypeSymbol>("C").GetMembers().Select(m => m.ToTestDisplayString()));
compWithMetadata.GetMember<NamedTypeSymbol>(containingType).GetMembers().Select(m => m.ToTestDisplayString()));
}
[Fact]
......@@ -824,6 +824,10 @@ string M()
));
}
/// <summary>
/// The client compilation should not be affected (except for some diagnostic differences)
/// by the library assembly only having metadata, or not including private members.
/// </summary>
private void VerifyRefAssemblyClient(string lib_cs, string client_cs, Action<CSharpCompilation> validator, int debugFlag = -1)
{
// Whether the library is compiled in full, as metadata-only, or as a ref assembly should be transparent
......@@ -859,6 +863,55 @@ private static void VerifyRefAssemblyClient(string lib_cs, string source, Action
validator(comp);
}
[Theory]
[InlineData("")]
[InlineData(@"[assembly: System.Reflection.AssemblyVersion(""1"")]")]
[InlineData(@"[assembly: System.Reflection.AssemblyVersion(""1.0.*"")]")]
public void RefAssembly_EmitAsDeterministic(string source)
{
var comp = CreateStandardCompilation(source, options: TestOptions.DebugDll.WithDeterministic(false));
var (image1, refImage1) = emitRefOut();
// The resolution of the PE header time date stamp is seconds, and we want to make sure that has an opportunity to change
// between calls to Emit.
Thread.Sleep(TimeSpan.FromSeconds(1));
var (image2, refImage2) = emitRefOut();
var refImage3 = emitRefOnly();
AssertEx.Equal(refImage1, refImage2);
AssertEx.Equal(refImage1, refImage3);
var comp2 = CreateStandardCompilation(source, options: TestOptions.DebugDll.WithDeterministic(false));
var refImage4 = emitRefOnly();
AssertEx.Equal(refImage1, refImage4);
(ImmutableArray<byte> image, ImmutableArray<byte> refImage) emitRefOut()
{
using (var output = new MemoryStream())
using (var metadataOutput = new MemoryStream())
{
var options = EmitOptions.Default.WithIncludePrivateMembers(false);
comp.VerifyEmitDiagnostics();
var result = comp.Emit(output, metadataPEStream: metadataOutput,
options: options);
return (output.ToImmutable(), metadataOutput.ToImmutable());
}
}
ImmutableArray<byte> emitRefOnly()
{
using (var output = new MemoryStream())
{
var options = EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(false);
comp.VerifyEmitDiagnostics();
var result = comp.Emit(output,
options: options);
return output.ToImmutable();
}
}
}
[Theory]
[InlineData("public int M() { error(); }", true)]
[InlineData("public int M() { error() }", false)] // This may get relaxed. See follow-up issue https://github.com/dotnet/roslyn/issues/17612
......@@ -1057,7 +1110,7 @@ public void EmitMetadataOnly_DisallowOutputtingNetModule()
}
[Fact]
public void EmitMetadata_AllowEmbedding()
public void RefAssembly_AllowEmbeddingPdb()
{
CSharpCompilation comp = CreateCompilation("", references: new[] { MscorlibRef },
options: TestOptions.DebugDll);
......@@ -1069,7 +1122,7 @@ public void EmitMetadata_AllowEmbedding()
options: EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.Embedded).WithIncludePrivateMembers(false));
VerifyEmbeddedDebugInfo(output, new[] { DebugDirectoryEntryType.CodeView, DebugDirectoryEntryType.EmbeddedPortablePdb });
VerifyEmbeddedDebugInfo(metadataOutput, new DebugDirectoryEntryType[] { });
VerifyEmbeddedDebugInfo(metadataOutput, new DebugDirectoryEntryType[] { DebugDirectoryEntryType.Reproducible });
}
void VerifyEmbeddedDebugInfo(MemoryStream stream, DebugDirectoryEntryType[] expected)
......@@ -1083,7 +1136,7 @@ void VerifyEmbeddedDebugInfo(MemoryStream stream, DebugDirectoryEntryType[] expe
}
[Fact]
public void EmitMetadataOnly_DisallowEmbedding()
public void EmitMetadataOnly_DisallowEmbeddingPdb()
{
CSharpCompilation comp = CreateCompilation("", references: new[] { MscorlibRef },
options: TestOptions.DebugDll);
......@@ -1096,6 +1149,30 @@ public void EmitMetadataOnly_DisallowEmbedding()
}
}
[Fact]
public void RefAssembly_DisallowEmbeddingTypes()
{
CSharpCompilation comp = CreateCompilation("", options: TestOptions.DebugDll,
references: new MetadataReference[]
{
TestReferences.SymbolsTests.NoPia.GeneralPia.WithEmbedInteropTypes(true)
});
using (var output = new MemoryStream())
{
Assert.Throws<ArgumentException>(() => comp.Emit(output,
options: EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(false)));
}
using (var output = new MemoryStream())
using (var metadataOutput = new MemoryStream())
{
Assert.Throws<ArgumentException>(() => comp.Emit(output,
metadataPEStream: metadataOutput,
options: EmitOptions.Default.WithIncludePrivateMembers(false)));
}
}
[Fact]
public void EmitMetadata()
{
......
......@@ -1434,7 +1434,7 @@ static void M1()
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7_1);
comp.VerifyDiagnostics(
// (7,14): error CS9000: Cannot use a default literal as an argument to a dynamically dispatched operation.
// (7,14): error CS8310: Cannot use a default literal as an argument to a dynamically dispatched operation.
// d.M2(default);
Diagnostic(ErrorCode.ERR_BadDynamicMethodArgDefaultLiteral, "default").WithLocation(7, 14)
);
......@@ -1524,7 +1524,7 @@ static void Main()
var comp = CreateStandardCompilation(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (6,27): error CS9001: Use of default literal is not valid in this context
// (6,27): error CS8311: Use of default literal is not valid in this context
// foreach (int x in default) { }
Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "default").WithLocation(6, 27),
// (7,27): error CS0186: Use of null is not valid in this context
......@@ -1549,7 +1549,7 @@ static void Main()
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.Regular7_1, references: new[] { SystemCoreRef });
compilation.VerifyDiagnostics(
// (6,35): error CS9001: Use of default literal is not valid in this context
// (6,35): error CS8311: Use of default literal is not valid in this context
// var q = from x in default select x;
Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "select x").WithLocation(6, 35),
// (7,43): error CS1942: The type of the expression in the select clause is incorrect. Type inference failed in the call to 'Select'.
......@@ -1898,7 +1898,7 @@ static void M(int x)
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.
// (12,18): warning CS8312: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.
// case default:
Diagnostic(ErrorCode.WRN_DefaultInSwitch, "default").WithLocation(12, 18)
);
......@@ -1931,7 +1931,7 @@ static void M(object x)
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.
// (12,18): warning CS8312: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate.
// case default:
Diagnostic(ErrorCode.WRN_DefaultInSwitch, "default").WithLocation(12, 18)
);
......
......@@ -183,9 +183,8 @@ static void Main()
[Fact]
public void WarningLevel_1()
{
for (int i = 0; i < 10000; i++)
foreach (ErrorCode errorCode in Enum.GetValues(typeof(ErrorCode)))
{
ErrorCode errorCode = (ErrorCode)i;
string errorCodeName = errorCode.ToString();
if (errorCodeName.StartsWith("WRN", StringComparison.Ordinal))
{
......@@ -215,12 +214,15 @@ public void WarningLevel_2()
Assert.Equal(3, ErrorFacts.GetWarningLevel(ErrorCode.WRN_IsDynamicIsConfusing));
Assert.Equal(2, ErrorFacts.GetWarningLevel(ErrorCode.WRN_NoSources));
// There is space in the range of error codes from 7000-8999 that we might add for new errors in post-Dev10.
// If a new warning is added, this test will fail and adding the new case with the expected error level will be required.
for (int i = 7000; i < 9000; i++)
foreach (ErrorCode errorCode in Enum.GetValues(typeof(ErrorCode)))
{
ErrorCode errorCode = (ErrorCode)i;
if ((int)errorCode < 7000)
{
continue;
}
string errorCodeName = errorCode.ToString();
if (errorCodeName.StartsWith("WRN", StringComparison.Ordinal))
{
......@@ -244,6 +246,7 @@ public void WarningLevel_2()
case ErrorCode.WRN_AlignmentMagnitude:
case ErrorCode.WRN_TupleLiteralNameMismatch:
case ErrorCode.WRN_Experimental:
case ErrorCode.WRN_DefaultInSwitch:
Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode));
break;
case ErrorCode.WRN_MainIgnored:
......
......@@ -20,6 +20,11 @@ public sealed class CopyRefAssembly : Task
[Required]
public string DestinationPath { get; set; }
static CopyRefAssembly()
{
AssemblyResolution.Install();
}
public CopyRefAssembly()
{
TaskResources = ErrorString.ResourceManager;
......@@ -45,20 +50,27 @@ public override bool Execute()
Log.LogMessageFromResources(MessageImportance.High, "CopyRefAssembly_BadSource3", SourcePath, e.Message, e.StackTrace);
}
try
if (source.Equals(Guid.Empty))
{
Log.LogMessageFromResources(MessageImportance.High, "CopyRefAssembly_SourceNotRef1", SourcePath);
}
else
{
Guid destination = ExtractMvid(DestinationPath);
try
{
Guid destination = ExtractMvid(DestinationPath);
if (source.Equals(destination))
if (!source.Equals(Guid.Empty) && source.Equals(destination))
{
Log.LogMessageFromResources(MessageImportance.Low, "CopyRefAssembly_SkippingCopy1", DestinationPath);
return true;
}
}
catch (Exception)
{
Log.LogMessageFromResources(MessageImportance.Low, "CopyRefAssembly_SkippingCopy1", DestinationPath);
return true;
Log.LogMessageFromResources(MessageImportance.High, "CopyRefAssembly_BadDestination1", DestinationPath);
}
}
catch (Exception)
{
Log.LogMessage(MessageImportance.High, "CopyRefAssembly_BadDestination1", DestinationPath);
}
}
return Copy();
......
......@@ -98,6 +98,15 @@ internal class ErrorString {
}
}
/// <summary>
/// Looks up a localized string similar to Could not extract the MVID from &quot;{0}&quot;. Are you sure it is a reference assembly?.
/// </summary>
internal static string CopyRefAssembly_SourceNotRef1 {
get {
return ResourceManager.GetString("CopyRefAssembly_SourceNotRef1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to MSB3053: The assembly alias &quot;{1}&quot; on reference &quot;{0}&quot; contains illegal characters..
/// </summary>
......
......@@ -154,6 +154,9 @@
<data name="CopyRefAssembly_SkippingCopy1" xml:space="preserve">
<value>Reference assembly "{0}" already has latest information. Leaving it untouched.</value>
</data>
<data name="CopyRefAssembly_SourceNotRef1" xml:space="preserve">
<value>Could not extract the MVID from "{0}". Are you sure it is a reference assembly?</value>
</data>
<data name="CopyRefAssembly_BadSource3" xml:space="preserve">
<value>Failed to check the content hash of the source ref assembly '{0}': {1}
{2}</value>
......
......@@ -477,6 +477,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Embedded interop type references should not be given when emitting a ref assembly..
/// </summary>
internal static string EmbedInteropTypesUnexpectedWhenEmittingRefAssembly {
get {
return ResourceManager.GetString("EmbedInteropTypesUnexpectedWhenEmittingRefAssembly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A key in the pathMap is empty..
/// </summary>
......
......@@ -333,6 +333,9 @@
<data name="PdbStreamUnexpectedWhenEmittingMetadataOnly" xml:space="preserve">
<value>PDB stream should not be given when emitting metadata only.</value>
</data>
<data name="EmbedInteropTypesUnexpectedWhenEmittingRefAssembly" xml:space="preserve">
<value>Embedded interop type references should not be given when emitting a ref assembly.</value>
</data>
<data name="MetadataPeStreamUnexpectedWhenEmittingMetadataOnly" xml:space="preserve">
<value>Metadata PE stream should not be given when emitting metadata only.</value>
</data>
......
......@@ -2087,6 +2087,13 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
throw new ArgumentException(CodeAnalysisResources.IncludingPrivateMembersUnexpectedWhenEmittingToMetadataPeStream, nameof(metadataPEStream));
}
if ((metadataPEStream != null || options?.EmitMetadataOnly == true) &&
options?.IncludePrivateMembers == false &&
References.Any(r => r.Properties.EmbedInteropTypes))
{
throw new ArgumentException(CodeAnalysisResources.EmbedInteropTypesUnexpectedWhenEmittingRefAssembly, nameof(metadataPEStream));
}
if (options?.DebugInformationFormat == DebugInformationFormat.Embedded &&
options?.EmitMetadataOnly == true)
{
......@@ -2636,6 +2643,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
bool emitSecondaryAssembly = getMetadataPeStreamOpt != null;
bool includePrivateMembersOnPrimaryOutput = metadataOnly ? includePrivateMembers : true;
bool deterministicPrimaryOutput = (metadataOnly && !includePrivateMembers) || isDeterministic;
if (!Cci.PeWriter.WritePeToStream(
new EmitContext(moduleBeingBuilt, null, metadataDiagnostics, metadataOnly, includePrivateMembersOnPrimaryOutput),
messageProvider,
......@@ -2644,7 +2652,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
nativePdbWriterOpt,
pdbPathOpt,
metadataOnly,
isDeterministic,
deterministicPrimaryOutput,
emitTestCoverageData,
cancellationToken))
{
......@@ -2665,7 +2673,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
nativePdbWriterOpt: null,
pdbPathOpt: null,
metadataOnly: true,
isDeterministic: isDeterministic,
isDeterministic: true,
emitTestCoverageData: false,
cancellationToken: cancellationToken))
{
......
......@@ -247,7 +247,7 @@ public uint GetFakeSymbolTokenForIL(Cci.IReference symbol, SyntaxNode syntaxNode
uint token = _referencesInILMap.GetOrAddTokenFor(symbol, out added);
if (added)
{
ReferenceDependencyWalker.VisitReference(symbol, new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true)); // PROTOTYPE(refout) Not sure about this
ReferenceDependencyWalker.VisitReference(symbol, new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true));
}
return token;
}
......
......@@ -1203,6 +1203,10 @@ lVbRuntimePlus:
AddDiagnostic(diagnostics, ERRID.ERR_NoRefOutWhenRefOnly)
End If
If (refOnly OrElse outputRefFileName IsNot Nothing) AndAlso metadataReferences.Any(Function(r) r.Properties.EmbedInteropTypes) Then
AddDiagnostic(diagnostics, ERRID.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly)
End If
If outputKind = OutputKind.NetModule AndAlso (refOnly OrElse outputRefFileName IsNot Nothing) Then
AddDiagnostic(diagnostics, ERRID.ERR_NoNetModuleOutputWhenRefOutOrRefOnly)
End If
......
......@@ -1733,6 +1733,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_NoRefOutWhenRefOnly = 37300
ERR_NoNetModuleOutputWhenRefOutOrRefOnly = 37301
ERR_NoEmbeddedTypeWhenRefOutOrRefOnly = 37302
'// WARNINGS BEGIN HERE
WRN_UseOfObsoleteSymbol2 = 40000
......
......@@ -8070,6 +8070,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Cannot embed types when using /refout or /refonly..
'''</summary>
Friend ReadOnly Property ERR_NoEmbeddedTypeWhenRefOutOrRefOnly() As String
Get
Return ResourceManager.GetString("ERR_NoEmbeddedTypeWhenRefOutOrRefOnly", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Array bounds cannot appear in type specifiers..
'''</summary>
......
......@@ -5471,6 +5471,9 @@
<data name="ERR_NoRefOutWhenRefOnly" xml:space="preserve">
<value>Do not use refout when using refonly.</value>
</data>
<data name="ERR_NoEmbeddedTypeWhenRefOutOrRefOnly" xml:space="preserve">
<value>Cannot embed types when using /refout or /refonly.</value>
</data>
<data name="ERR_NoNetModuleOutputWhenRefOutOrRefOnly" xml:space="preserve">
<value>Cannot compile net modules when using /refout or /refonly.</value>
</data>
......
......@@ -2923,6 +2923,14 @@ print Goodbye, World"
parsedArgs.Errors.Verify(
Diagnostic(ERRID.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1))
parsedArgs = DefaultParse({"/refout:ref.dll", "/link:b", "a.vb"}, baseDirectory)
parsedArgs.Errors.Verify(
Diagnostic(ERRID.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly).WithLocation(1, 1))
parsedArgs = DefaultParse({"/refonly", "/link:b", "a.vb"}, baseDirectory)
parsedArgs.Errors.Verify(
Diagnostic(ERRID.ERR_NoEmbeddedTypeWhenRefOutOrRefOnly).WithLocation(1, 1))
parsedArgs = DefaultParse({"/refonly", "/target:module", "a.vb"}, baseDirectory)
parsedArgs.Errors.Verify(
Diagnostic(ERRID.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1))
......@@ -8188,6 +8196,10 @@ Public Class C
Public Shared Sub Main()
System.Console.Write(""Hello"")
End Sub
''' <summary>Private method</summary>
Private Shared Sub PrivateMethod()
System.Console.Write(""Private"")
End Sub
End Class")
Dim outWriter = New StringWriter(CultureInfo.InvariantCulture)
......@@ -8202,7 +8214,7 @@ End Class")
MetadataReaderUtils.VerifyPEMetadata(exe,
{"TypeDefinition:<Module>", "TypeDefinition:C"},
{"MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()"},
{"MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()", "MethodDefinition:Void PrivateMethod()"},
{"CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute", "STAThreadAttribute"}
)
......@@ -8222,6 +8234,9 @@ a
<member name=""M:C.Main"">
<summary>Main method</summary>
</member>
<member name=""M:C.PrivateMethod"">
<summary>Private method</summary>
</member>
</members>
</doc>"
Assert.Equal(expectedDoc, content.Trim())
......@@ -8295,6 +8310,14 @@ outWriter.ToString().Trim())
Public Shared Sub Main()
Bad()
End Sub
''' <summary>Field</summary>
Private Dim field As Integer
''' <summary>Field</summary>
Private Structure S
''' <summary>Struct Field</summary>
Private Dim field As Integer
End Structure
End Class")
Dim outWriter = New StringWriter(CultureInfo.InvariantCulture)
......@@ -8310,7 +8333,7 @@ End Class")
' The types and members that are included needs further refinement.
' See issue https://github.com/dotnet/roslyn/issues/17612
MetadataReaderUtils.VerifyPEMetadata(refDll,
{"TypeDefinition:<Module>", "TypeDefinition:C"},
{"TypeDefinition:<Module>", "TypeDefinition:C", "TypeDefinition:S"},
{"MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()"},
{"CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute", "STAThreadAttribute", "ReferenceAssemblyAttribute"}
)
......@@ -8334,6 +8357,15 @@ a
<member name=""M:C.Main"">
<summary>Main method</summary>
</member>
<member name=""F:C.field"">
<summary>Field</summary>
</member>
<member name=""T:C.S"">
<summary>Field</summary>
</member>
<member name=""F:C.S.field"">
<summary>Struct Field</summary>
</member>
</members>
</doc>"
Assert.Equal(expectedDoc, content.Trim())
......
......@@ -886,6 +886,24 @@ End Class"
End Using
End Sub
<Fact>
Public Sub RefAssembly_DisallowEmbeddingTypes()
Dim comp = CreateCompilation("", references:={MscorlibRef.WithEmbedInteropTypes(True)},
options:=TestOptions.DebugDll)
Using output As New MemoryStream()
Assert.Throws(Of ArgumentException)(Function() comp.Emit(output,
options:=EmitOptions.Default.WithEmitMetadataOnly(True).WithIncludePrivateMembers(False)))
End Using
Using output As New MemoryStream()
Using metadataOutput = New MemoryStream()
Assert.Throws(Of ArgumentException)(Function() comp.Emit(output, metadataPEStream:=metadataOutput,
options:=EmitOptions.Default.WithIncludePrivateMembers(False)))
End Using
End Using
End Sub
<Fact>
Public Sub EmitMetadataOnly_DisallowMetadataPeStream()
Dim comp = CreateCompilation("", references:={MscorlibRef},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册