提交 7dffad1a 编写于 作者: T Tomas Matousek

Fixes a couple of issues around import scope compilation

上级 c7ab77d0
......@@ -23,7 +23,6 @@ internal struct ProcessedFieldInitializers
SourceMemberContainerTypeSymbol typeSymbol,
MethodSymbol scriptCtor,
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers,
bool generateDebugInfo,
DiagnosticBag diagnostics,
ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering
{
......@@ -33,7 +32,7 @@ internal struct ProcessedFieldInitializers
ImportChain firstImportChain;
processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers,
diagsForInstanceInitializers, generateDebugInfo, out firstImportChain);
diagsForInstanceInitializers, out firstImportChain);
processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
processedInitializers.FirstImportChain = firstImportChain;
......@@ -50,7 +49,6 @@ internal struct ProcessedFieldInitializers
MethodSymbol scriptCtor,
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers,
DiagnosticBag diagnostics,
bool generateDebugInfo,
out ImportChain firstImportChain)
{
if (initializers.IsEmpty)
......@@ -64,11 +62,11 @@ internal struct ProcessedFieldInitializers
if ((object)scriptCtor == null)
{
BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain);
BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, out firstImportChain);
}
else
{
BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain);
BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, out firstImportChain);
}
return boundInitializers.ToImmutableAndFree();
......@@ -83,7 +81,6 @@ internal struct ProcessedFieldInitializers
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers,
ArrayBuilder<BoundInitializer> boundInitializers,
DiagnosticBag diagnostics,
bool generateDebugInfo,
out ImportChain firstDebugImports)
{
firstDebugImports = null;
......@@ -118,7 +115,7 @@ internal struct ProcessedFieldInitializers
Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type
fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios
if (generateDebugInfo && firstDebugImports == null)
if (firstDebugImports == null)
{
firstDebugImports = parentBinder.ImportChain;
}
......@@ -138,7 +135,7 @@ internal struct ProcessedFieldInitializers
/// </summary>
private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor,
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers, ArrayBuilder<BoundInitializer> boundInitializers, DiagnosticBag diagnostics,
bool generateDebugInfo, out ImportChain firstDebugImports)
out ImportChain firstDebugImports)
{
Debug.Assert((object)scriptCtor != null);
......@@ -177,7 +174,7 @@ internal struct ProcessedFieldInitializers
Binder scriptClassBinder = binderFactory.GetBinder(initializerNode);
Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass);
if (generateDebugInfo && firstDebugImports == null)
if (firstDebugImports == null)
{
firstDebugImports = scriptClassBinder.ImportChain;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -27,17 +22,29 @@ public ImportChain(Imports imports, ImportChain parentOpt)
ParentOpt = parentOpt;
}
ImmutableArray<Cci.UsedNamespaceOrType> Cci.IImportScope.GetUsedNamespaces(EmitContext context)
ImmutableArray<Cci.UsedNamespaceOrType> Cci.IImportScope.GetUsedNamespaces()
{
if (_lazyTranslatedImports.IsDefault)
// The imports should have been translated during code gen.
Debug.Assert(!_lazyTranslatedImports.IsDefault);
return _lazyTranslatedImports;
}
public Cci.IImportScope Translate(Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics)
{
for (var scope = this; scope != null; scope = scope.ParentOpt)
{
ImmutableInterlocked.InterlockedInitialize(ref _lazyTranslatedImports, TranslateImports(context));
if (!scope._lazyTranslatedImports.IsDefault)
{
break;
}
ImmutableInterlocked.InterlockedInitialize(ref scope._lazyTranslatedImports, scope.TranslateImports(moduleBuilder, diagnostics));
}
return _lazyTranslatedImports;
return this;
}
private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(EmitContext context)
private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics)
{
var usedNamespaces = ArrayBuilder<Cci.UsedNamespaceOrType>.GetInstance();
......@@ -61,12 +68,13 @@ private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(EmitContext con
if (namespaceOrType.IsNamespace)
{
var ns = (NamespaceSymbol)namespaceOrType;
var assemblyRef = TryGetAssemblyScope(context, ns);
var assemblyRef = TryGetAssemblyScope(ns, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef));
}
else
else if (!namespaceOrType.ContainingAssembly.IsLinked)
{
var typeRef = GetTypeReference(context, (TypeSymbol)namespaceOrType);
// We skip alias imports of embedded types to be consistent with imports of aliased embedded types and with VB.
var typeRef = GetTypeReference((TypeSymbol)namespaceOrType, nsOrType.UsingDirective, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef));
}
}
......@@ -79,18 +87,21 @@ private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(EmitContext con
{
var alias = pair.Key;
var symbol = pair.Value.Alias;
var syntax = pair.Value.UsingDirective;
Debug.Assert(!symbol.IsExtern);
NamespaceOrTypeSymbol target = symbol.Target;
if (target.Kind == SymbolKind.Namespace)
{
var ns = (NamespaceSymbol)target;
var assemblyRef = TryGetAssemblyScope(context, ns);
var assemblyRef = TryGetAssemblyScope(ns, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef, alias));
}
else
else if (!target.ContainingAssembly.IsLinked)
{
var typeRef = GetTypeReference(context, (TypeSymbol)target);
// We skip alias imports of embedded types to avoid breaking existing code that
// imports types that can't be embedded but doesn't use them anywhere else in the code.
var typeRef = GetTypeReference((TypeSymbol)target, syntax, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, alias));
}
}
......@@ -99,17 +110,17 @@ private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(EmitContext con
return usedNamespaces.ToImmutableAndFree();
}
private static Cci.ITypeReference GetTypeReference(EmitContext context, TypeSymbol type)
private static Cci.ITypeReference GetTypeReference(TypeSymbol type, SyntaxNode syntaxNode, Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics)
{
return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics);
return moduleBuilder.Translate(type, syntaxNode, diagnostics);
}
private Cci.IAssemblyReference TryGetAssemblyScope(EmitContext context, NamespaceSymbol @namespace)
private Cci.IAssemblyReference TryGetAssemblyScope(NamespaceSymbol @namespace, Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics)
{
AssemblySymbol containingAssembly = @namespace.ContainingAssembly;
if ((object)containingAssembly != null && (object)containingAssembly != context.ModuleBuilder.CommonCompilation.Assembly)
if ((object)containingAssembly != null && (object)containingAssembly != moduleBuilder.CommonCompilation.Assembly)
{
var referenceManager = ((CSharpCompilation)context.ModuleBuilder.CommonCompilation).GetBoundReferenceManager();
var referenceManager = ((CSharpCompilation)moduleBuilder.CommonCompilation).GetBoundReferenceManager();
foreach (var referencedAssembly in referenceManager.ReferencedAssembliesMap.Values)
{
......@@ -117,7 +128,7 @@ private Cci.IAssemblyReference TryGetAssemblyScope(EmitContext context, Namespac
{
if (!referencedAssembly.DeclarationsAccessibleWithoutAlias())
{
return context.ModuleBuilder.Translate(containingAssembly, context.Diagnostics);
return moduleBuilder.Translate(containingAssembly, diagnostics);
}
}
}
......
......@@ -70,7 +70,7 @@ private enum IndirectReturnState : byte
PEModuleBuilder moduleBuilder,
DiagnosticBag diagnostics,
OptimizationLevel optimizations,
bool emittingPdbs)
bool emittingPdb)
{
Debug.Assert((object)method != null);
Debug.Assert(boundBody != null);
......@@ -98,7 +98,7 @@ private enum IndirectReturnState : byte
// user code that can be stepped thru, or changed during EnC.
//
// This setting only affects generating PDB sequence points, it shall not affect generated IL in any way.
_emitPdbSequencePoints = emittingPdbs && method.GenerateDebugInfo;
_emitPdbSequencePoints = emittingPdb && method.GenerateDebugInfo;
if (_optimizations == OptimizationLevel.Release)
{
......
......@@ -2322,7 +2322,7 @@ internal override StrongNameKeys StrongNameKeys
CommonPEModuleBuilder moduleBuilder,
Stream win32Resources,
Stream xmlDocStream,
bool generateDebugInfo,
bool emittingPdb,
DiagnosticBag diagnostics,
Predicate<ISymbol> filterOpt,
CancellationToken cancellationToken)
......@@ -2354,12 +2354,9 @@ internal override StrongNameKeys StrongNameKeys
}
else
{
if (generateDebugInfo && moduleBeingBuilt != null)
if (emittingPdb && !StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics))
{
if (!StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics))
{
return false;
}
return false;
}
// Perform initial bind of method bodies in spite of earlier errors. This is the same
......@@ -2371,7 +2368,7 @@ internal override StrongNameKeys StrongNameKeys
MethodCompiler.CompileMethodBodies(
this,
moduleBeingBuilt,
generateDebugInfo,
emittingPdb,
hasDeclarationErrors,
diagnostics: methodBodyDiagnosticBag,
filterOpt: filterOpt,
......
......@@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CSharp
internal sealed class MethodCompiler : CSharpSymbolVisitor<TypeCompilationState, object>
{
private readonly CSharpCompilation _compilation;
private readonly bool _generateDebugInfo;
private readonly bool _emittingPdb;
private readonly CancellationToken _cancellationToken;
private readonly DiagnosticBag _diagnostics;
private readonly bool _hasDeclarationErrors;
......@@ -73,7 +73,7 @@ private void SetGlobalErrorIfTrue(bool arg)
}
// Internal for testing only.
internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool generateDebugInfo, bool hasDeclarationErrors,
internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool emittingPdb, bool hasDeclarationErrors,
DiagnosticBag diagnostics, Predicate<Symbol> filterOpt, CancellationToken cancellationToken)
{
Debug.Assert(compilation != null);
......@@ -81,7 +81,7 @@ private void SetGlobalErrorIfTrue(bool arg)
_compilation = compilation;
_moduleBeingBuiltOpt = moduleBeingBuiltOpt;
_generateDebugInfo = generateDebugInfo;
_emittingPdb = emittingPdb;
_cancellationToken = cancellationToken;
_diagnostics = diagnostics;
_filterOpt = filterOpt;
......@@ -89,7 +89,7 @@ private void SetGlobalErrorIfTrue(bool arg)
_hasDeclarationErrors = hasDeclarationErrors;
SetGlobalErrorIfTrue(hasDeclarationErrors);
if (generateDebugInfo)
if (emittingPdb)
{
_debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
}
......@@ -233,7 +233,7 @@ internal static MethodSymbol DefineScriptEntryPoint(CSharpCompilation compilatio
diagnostics: diagnostics,
debugDocumentProvider: null,
importChainOpt: null,
generateDebugInfo: false);
emittingPdb: false);
moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody);
moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint);
......@@ -376,10 +376,10 @@ private void CompileNamedType(NamedTypeSymbol symbol)
if ((object)sourceTypeSymbol != null)
{
_cancellationToken.ThrowIfCancellationRequested();
Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, _generateDebugInfo, _diagnostics, ref processedStaticInitializers);
Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, _diagnostics, ref processedStaticInitializers);
_cancellationToken.ThrowIfCancellationRequested();
Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, _generateDebugInfo, _diagnostics, ref processedInstanceInitializers);
Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, _diagnostics, ref processedInstanceInitializers);
if (compilationState.Emitting)
{
......@@ -625,7 +625,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
diagnosticsThisMethod,
_debugDocumentProvider,
methodWithBody.ImportChainOpt,
generateDebugInfo: _generateDebugInfo && method.GenerateDebugInfo);
emittingPdb: _emittingPdb);
}
_diagnostics.AddRange(diagnosticsThisMethod);
......@@ -719,7 +719,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i
diagnostics: diagnosticsThisMethod,
debugDocumentProvider: _debugDocumentProvider,
importChainOpt: null,
generateDebugInfo: false);
emittingPdb: false);
_moduleBeingBuiltOpt.SetMethodBody(accessor, emittedBody);
// Definition is already in the symbol table, so don't call moduleBeingBuilt.AddCompilerGeneratedDefinition
......@@ -841,7 +841,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty &&
!HasThisConstructorInitializer(methodSymbol);
body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, _generateDebugInfo, out importChain);
body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, out importChain);
// lower initializers just once. the lowered tree will be reused when emitting all constructors
// with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers
......@@ -869,22 +869,18 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
}
}
#if DEBUG
// If the method is a synthesized static or instance constructor, then debugImports will be null and we will use the value
// from the first field initializer.
if (_generateDebugInfo)
if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) &&
methodSymbol.IsImplicitlyDeclared && body == null)
{
if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) &&
methodSymbol.IsImplicitlyDeclared && body == null)
{
// There was no body to bind, so we didn't get anything from BindMethodBody.
Debug.Assert(importChain == null);
}
// Either there were no field initializers or we grabbed debug imports from the first one.
Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstImportChain != null);
// There was no body to bind, so we didn't get anything from BindMethodBody.
Debug.Assert(importChain == null);
}
// Either there were no field initializers or we grabbed debug imports from the first one.
Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstImportChain != null);
#endif
importChain = importChain ?? processedInitializers.FirstImportChain;
......@@ -1082,7 +1078,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
diagsForCurrentMethod,
_debugDocumentProvider,
importChain,
_generateDebugInfo && methodSymbol.GenerateDebugInfo);
_emittingPdb);
_moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody);
}
......@@ -1242,7 +1238,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
DiagnosticBag diagnostics,
DebugDocumentProvider debugDocumentProvider,
ImportChain importChainOpt,
bool generateDebugInfo)
bool emittingPdb)
{
// Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings.
Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not expecting errors");
......@@ -1257,7 +1253,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
{
Cci.AsyncMethodBodyDebugInfo asyncDebugInfo = null;
var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, generateDebugInfo);
var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, emittingPdb);
// We need to save additional debugging information for MoveNext of an async state machine.
var stateMachineMethod = method as SynthesizedStateMachineMethod;
......@@ -1284,6 +1280,11 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
codeGen.Generate();
}
// Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata
// and we don't want to emit different metadata depending on whether or we emit with PDB stream.
// TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class.
var importScopeOpt = importChainOpt?.Translate(moduleBuilder, diagnosticsForThisMethod);
var localVariables = builder.LocalSlotManager.LocalsInOrder();
if (localVariables.Length > 0xFFFE)
......@@ -1329,7 +1330,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
builder.RealizedExceptionHandlers,
builder.GetAllScopes(),
builder.HasDynamicLocal,
importChainOpt,
importScopeOpt,
lambdaDebugInfo,
closureDebugInfo,
stateMachineTypeOpt?.Name,
......@@ -1395,11 +1396,11 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics)
{
ImportChain unused;
return BindMethodBody(method, compilationState, diagnostics, false, out unused);
return BindMethodBody(method, compilationState, diagnostics, out unused);
}
// NOTE: can return null if the method has no body.
private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ImportChain importChain)
private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, out ImportChain importChain)
{
importChain = null;
......@@ -1457,10 +1458,7 @@ private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSta
Binder binder = new ExecutableCodeBinder(blockSyntax, sourceMethod, inMethodBinder);
body = binder.BindBlock(blockSyntax, diagnostics);
if (generateDebugInfo)
{
importChain = binder.ImportChain;
}
importChain = binder.ImportChain;
if (inMethodBinder.IsDirectlyInIterator)
{
......
......@@ -72,7 +72,7 @@ internal static class EmitHelpers
moduleBeingBuilt,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: true,
emittingPdb: true,
diagnostics: diagnostics,
filterOpt: changes.RequiresCompilation,
cancellationToken: cancellationToken))
......
......@@ -117,7 +117,7 @@ internal sealed override AssemblySymbol CorLibrary
protected sealed override IEnumerable<string> LinkedAssembliesDebugInfo => SpecializedCollections.EmptyEnumerable<string>();
// C# currently doesn't emit compilation level imports (TODO: scripting).
protected override ImmutableArray<Cci.UsedNamespaceOrType> GetImports(EmitContext context) => ImmutableArray<Cci.UsedNamespaceOrType>.Empty;
protected override ImmutableArray<Cci.UsedNamespaceOrType> GetImports() => ImmutableArray<Cci.UsedNamespaceOrType>.Empty;
// C# doesn't allow to define default namespace for compilation.
protected override string DefaultNamespace => null;
......
......@@ -12570,7 +12570,7 @@ static System.Action M()
var methodBodyCompiler = new MethodCompiler(
compilation: compilation,
moduleBeingBuiltOpt: module,
generateDebugInfo: false,
emittingPdb: false,
hasDeclarationErrors: false,
diagnostics: diagnostics,
filterOpt: null,
......
......@@ -3,9 +3,13 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.MetadataUtilities;
using Roslyn.Test.Utilities;
using Xunit;
using ProprietaryTestResources = Microsoft.CodeAnalysis.Test.Resources.Proprietary;
......@@ -2130,5 +2134,208 @@ static void Main()
Assert.Equal(1, reader.GetTableRowCount(TableIndex.TypeSpec));
});
}
[Fact]
public void EmittingPdbVsNot()
{
string source = @"
using System;
using X = System.IO.FileStream;
class C
{
int x = 1;
static int y = 1;
C()
{
Console.WriteLine();
}
}
";
var c = CreateCompilationWithMscorlib(source, assemblyName: "EmittingPdbVsNot", options: TestOptions.ReleaseDll);
var peStream1 = new MemoryStream();
var peStream2 = new MemoryStream();
var pdbStream = new MemoryStream();
var emitResult1 = c.Emit(peStream: peStream1, pdbStream: pdbStream);
var emitResult2 = c.Emit(peStream: peStream2);
SharedCompilationUtils.VerifyMetadataEqualModuloMvid(peStream1, peStream2);
}
[Fact]
public void ImportedNoPiaTypes()
{
var sourceLib = @"
using System;
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: Guid(""11111111-1111-1111-1111-111111111111"")]
[assembly: ImportedFromTypeLib(""Foo"")]
[assembly: TypeLibVersion(1, 0)]
namespace N
{
public enum E
{
Value1 = 1
}
public struct S1
{
public int A1;
public int A2;
}
public struct S2
{
public const int Value2 = 2;
}
public struct SBad
{
public int A3;
public const int Value3 = 3;
}
[ComImport, Guid(""22222222-2222-2222-2222-222222222222"")]
public interface I
{
void F();
}
public interface IBad
{
void F();
}
}
";
var source = @"
using System;
using static N.E;
using static N.SBad;
using Z1 = N.S1;
using Z2 = N.S2;
using ZBad = N.SBad;
using NI = N.I;
using NIBad = N.IBad;
class C
{
NI i;
void M()
{
Console.WriteLine(Value1);
Console.WriteLine(Z2.Value2);
Console.WriteLine(new Z1());
}
}
";
var libRef = CreateCompilationWithMscorlib(sourceLib, assemblyName: "ImportedNoPiaTypesAssemblyName").EmitToImageReference(embedInteropTypes: true);
var compilation = CreateCompilationWithMscorlib(source, new[] { libRef });
var v = CompileAndVerify(compilation);
v.Diagnostics.Verify(
// (14,8): warning CS0169: The field 'C.i' is never used
// NI i;
Diagnostic(ErrorCode.WRN_UnreferencedField, "i").WithArguments("C.i"),
// (5,1): hidden CS8019: Unnecessary using directive.
// using static N.SBad;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static N.SBad;"),
// (10,1): hidden CS8019: Unnecessary using directive.
// using NIBad = N.IBad;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using NIBad = N.IBad;"),
// (8,1): hidden CS8019: Unnecessary using directive.
// using ZBad = N.SBad;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using ZBad = N.SBad;"));
// Usings of embedded types are currently ommitted:
v.VerifyPdb("C.M", @"
<symbols>
<methods>
<method containingType=""C"" name=""M"">
<customDebugInfo>
<using>
<namespace usingCount=""1"" />
</using>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""18"" startColumn=""9"" endLine=""18"" endColumn=""35"" document=""0"" />
<entry offset=""0xb"" startLine=""19"" startColumn=""9"" endLine=""19"" endColumn=""38"" document=""0"" />
<entry offset=""0x11"" startLine=""20"" startColumn=""9"" endLine=""20"" endColumn=""37"" document=""0"" />
<entry offset=""0x24"" startLine=""21"" startColumn=""5"" endLine=""21"" endColumn=""6"" document=""0"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x25"">
<namespace name=""System"" />
</scope>
</method>
</methods>
</symbols>");
}
[Fact]
public void ImportedTypeWithUnknownBase()
{
var sourceLib1 = @"
namespace N
{
public class A { }
}
";
var sourceLib2 = @"
namespace N
{
public class B : A { }
}
";
var source = @"
using System;
using X = N.B;
class C
{
void M()
{
Console.WriteLine();
}
}
";
var libRef1 = CreateCompilationWithMscorlib(sourceLib1).EmitToImageReference();
var libRef2 = CreateCompilationWithMscorlib(sourceLib2, new[] { libRef1 }, assemblyName: "LibRef2").EmitToImageReference();
var compilation = CreateCompilationWithMscorlib(source, new[] { libRef2 });
var v = CompileAndVerify(compilation, emitters: TestEmitters.CCI);
v.Diagnostics.Verify(
// (3,1): hidden CS8019: Unnecessary using directive.
// using X = N.B;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using X = N.B;"));
v.VerifyPdb("C.M", @"
<symbols>
<methods>
<method containingType=""C"" name=""M"">
<customDebugInfo>
<using>
<namespace usingCount=""2"" />
</using>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""9"" startColumn=""9"" endLine=""9"" endColumn=""29"" document=""0"" />
<entry offset=""0x5"" startLine=""10"" startColumn=""5"" endLine=""10"" endColumn=""6"" document=""0"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x6"">
<namespace name=""System"" />
<alias name=""X"" target=""N.B, LibRef2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"" kind=""type"" />
</scope>
</method>
</methods>
</symbols>");
}
}
}
......@@ -293,16 +293,9 @@ private static ImmutableArray<BoundInitializer> BindInitializersWithoutDiagnosti
scriptCtor: null,
initializers: initializers,
diagnostics: diagnostics,
generateDebugInfo: false,
firstImportChain: out unused);
var filteredDiag = diagnostics.AsEnumerable();
foreach (var diagnostic in filteredDiag)
{
Console.WriteLine(diagnostic);
}
Assert.True(filteredDiag.IsEmpty());
diagnostics.Verify();
return boundInitializers;
}
......
......@@ -1250,7 +1250,7 @@ internal bool IsRealSigned
CommonPEModuleBuilder moduleBuilder,
Stream win32Resources,
Stream xmlDocStream,
bool generateDebugInfo,
bool emittingPdb,
DiagnosticBag diagnostics,
Predicate<ISymbol> filterOpt,
CancellationToken cancellationToken);
......@@ -1259,7 +1259,7 @@ internal bool IsRealSigned
CommonPEModuleBuilder moduleBuilder,
Stream win32Resources,
Stream xmlDocStream,
bool generateDebugInfo,
bool emittingPdb,
DiagnosticBag diagnostics,
Predicate<ISymbol> filterOpt,
CancellationToken cancellationToken)
......@@ -1270,7 +1270,7 @@ internal bool IsRealSigned
moduleBuilder,
win32Resources,
xmlDocStream,
generateDebugInfo,
emittingPdb,
diagnostics,
filterOpt,
cancellationToken);
......@@ -1303,7 +1303,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
moduleBeingBuilt,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: false,
emittingPdb: false,
diagnostics: discardedDiagnostics,
filterOpt: null,
cancellationToken: cancellationToken);
......@@ -1576,7 +1576,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
moduleBeingBuilt,
win32Resources,
xmlDocumentationStream,
generateDebugInfo: pdbStreamProvider != null,
emittingPdb: pdbStreamProvider != null,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: cancellationToken))
......
......@@ -8,6 +8,7 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Emit.NoPia;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Emit
......@@ -24,6 +25,7 @@ internal abstract class CommonPEModuleBuilder
internal abstract CommonModuleCompilationState CommonModuleCompilationState { get; }
internal abstract void CompilationFinished();
internal abstract ImmutableDictionary<Cci.ITypeDefinition, ImmutableArray<Cci.ITypeDefinitionMember>> GetSynthesizedMembers();
internal abstract CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt { get; }
}
/// <summary>
......@@ -237,54 +239,16 @@ internal sealed override Cci.ITypeReference Translate(ITypeSymbol symbol, Syntax
return Translate((TTypeSymbol)symbol, (TSyntaxNode)syntaxNodeOpt, diagnostics);
}
internal OutputKind OutputKind
{
get
{
return _outputKind;
}
}
internal OutputKind OutputKind => _outputKind;
internal TSourceModuleSymbol SourceModule => _sourceModule;
internal TCompilation Compilation => _compilation;
internal TSourceModuleSymbol SourceModule
{
get
{
return _sourceModule;
}
}
internal TCompilation Compilation
{
get
{
return _compilation;
}
}
internal override Compilation CommonCompilation
{
get
{
return _compilation;
}
}
internal override CommonModuleCompilationState CommonModuleCompilationState
{
get
{
return this.CompilationState;
}
}
internal sealed override Compilation CommonCompilation => _compilation;
internal sealed override CommonModuleCompilationState CommonModuleCompilationState => CompilationState;
internal sealed override CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt => EmbeddedTypesManagerOpt;
// General entry point method. May be a PE entry point or a submission entry point.
internal sealed override Cci.IMethodReference EntryPoint
{
get
{
return _entryPoint;
}
}
internal sealed override Cci.IMethodReference EntryPoint => _entryPoint;
internal void SetEntryPoint(TMethodSymbol value)
{
......@@ -778,8 +742,8 @@ ImmutableArray<Cci.AssemblyReferenceAlias> Cci.IModule.GetAssemblyReferenceAlias
IEnumerable<string> Cci.IModule.LinkedAssembliesDebugInfo => LinkedAssembliesDebugInfo;
protected abstract IEnumerable<string> LinkedAssembliesDebugInfo { get; }
ImmutableArray<Cci.UsedNamespaceOrType> Cci.IModule.GetImports(EmitContext context) => GetImports(context);
protected abstract ImmutableArray<Cci.UsedNamespaceOrType> GetImports(EmitContext context);
ImmutableArray<Cci.UsedNamespaceOrType> Cci.IModule.GetImports() => GetImports();
protected abstract ImmutableArray<Cci.UsedNamespaceOrType> GetImports();
string Cci.IModule.DefaultNamespace => DefaultNamespace;
protected abstract string DefaultNamespace { get; }
......
......@@ -305,7 +305,7 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken,
// NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method
// that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal
// custom debug info (e.g. there will be no information about the usings that were in scope).
if (!isIterator)
if (!isIterator && methodBody.ImportScope != null)
{
IMethodDefinition forwardToMethod;
if (customDebugInfoWriter.ShouldForwardNamespaceScopes(Context, methodBody, methodToken, out forwardToMethod))
......@@ -375,7 +375,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody)
{
for (var scope = namespaceScopes; scope != null; scope = scope.Parent)
{
foreach (var import in scope.GetUsedNamespaces(Context))
foreach (var import in scope.GetUsedNamespaces())
{
if (import.TargetNamespaceOpt == null && import.TargetTypeOpt == null)
{
......@@ -396,7 +396,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody)
// file and namespace level
for (IImportScope scope = namespaceScopes; scope != null; scope = scope.Parent)
{
foreach (UsedNamespaceOrType import in scope.GetUsedNamespaces(Context))
foreach (UsedNamespaceOrType import in scope.GetUsedNamespaces())
{
var importString = TryEncodeImport(import, lazyDeclaredExternAliases, isProjectLevel: false);
if (importString != null)
......@@ -424,7 +424,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody)
UsingNamespace("&" + assemblyName, module);
}
foreach (UsedNamespaceOrType import in module.GetImports(Context))
foreach (UsedNamespaceOrType import in module.GetImports())
{
var importString = TryEncodeImport(import, null, isProjectLevel: true);
if (importString != null)
......
......@@ -34,7 +34,7 @@ public CustomDebugInfoWriter(PdbWriter pdbWriter)
/// </summary>
public bool ShouldForwardNamespaceScopes(EmitContext context, IMethodBody methodBody, uint methodToken, out IMethodDefinition forwardToMethod)
{
if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody) || methodBody.ImportScope == null)
if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody))
{
// SerializeNamespaceScopeMetadata will do the actual forwarding in case this is a CSharp method.
// VB on the other hand adds a "@methodtoken" to the scopes instead.
......@@ -351,7 +351,7 @@ private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody me
BinaryWriter cmw = new BinaryWriter(customMetadata);
for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent)
{
usingCounts.Add((ushort)scope.GetUsedNamespaces(context).Length);
usingCounts.Add((ushort)scope.GetUsedNamespaces().Length);
}
// ACASEY: This originally wrote (uint)12, (ushort)1, (ushort)0 in the
......@@ -414,7 +414,7 @@ private bool ShouldForwardToPreviousMethodWithUsingInfo(EmitContext context, IMe
var s2 = previousScopes;
while (s1 != null && s2 != null)
{
if (!s1.GetUsedNamespaces(context).SequenceEqual(s2.GetUsedNamespaces(context)))
if (!s1.GetUsedNamespaces().SequenceEqual(s2.GetUsedNamespaces()))
{
return false;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Emit;
namespace Microsoft.Cci
{
......@@ -13,7 +12,7 @@ internal interface IImportScope
/// <summary>
/// Zero or more used namespaces. These correspond to using directives in C# or Imports syntax in VB.
/// </summary>
ImmutableArray<UsedNamespaceOrType> GetUsedNamespaces(EmitContext context);
ImmutableArray<UsedNamespaceOrType> GetUsedNamespaces();
/// <summary>
/// Parent import scope, or null.
......
......@@ -47,7 +47,7 @@ public override void Visit(IModule module)
this.Visit(module.GetResources(Context));
}
VisitImports(module.GetImports(Context));
VisitImports(module.GetImports());
}
public void VisitMethodBodyReference(IReference reference)
......@@ -101,7 +101,7 @@ protected override void ProcessMethodBody(IMethodDefinition method)
{
if (_alreadySeenScopes.Add(scope))
{
VisitImports(scope.GetUsedNamespaces(Context));
VisitImports(scope.GetUsedNamespaces());
}
else
{
......
......@@ -414,7 +414,7 @@ ulong SizeOfStackReserve
/// <summary>
/// Project level imports (VB only, TODO: C# scripts).
/// </summary>
ImmutableArray<UsedNamespaceOrType> GetImports(EmitContext context);
ImmutableArray<UsedNamespaceOrType> GetImports();
/// <summary>
/// Default namespace (VB only).
......
......@@ -47,7 +47,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
moduleBuilder As PEModuleBuilder,
diagnostics As DiagnosticBag,
optimizations As OptimizationLevel,
emittingPdbs As Boolean)
emittingPdb As Boolean)
Debug.Assert(method IsNot Nothing)
Debug.Assert(boundBody IsNot Nothing)
......@@ -55,14 +55,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Debug.Assert(moduleBuilder IsNot Nothing)
Debug.Assert(diagnostics IsNot Nothing)
Me._method = method
Me._block = boundBody
Me._builder = builder
Me._module = moduleBuilder
Me._diagnostics = diagnostics
_method = method
_block = boundBody
_builder = builder
_module = moduleBuilder
_diagnostics = diagnostics
' Always optimize synthesized methods that don't contain user code.
Me._optimizations = If(method.GenerateDebugInfo, optimizations, OptimizationLevel.Release)
_optimizations = If(method.GenerateDebugInfo, optimizations, OptimizationLevel.Release)
' Emit sequence points unless
' - the PDBs are not being generated
......@@ -70,14 +70,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
' user code that can be stepped thru, or changed during EnC.
'
' This setting only affects generating PDB sequence points, it shall Not affect generated IL in any way.
Me._emitPdbSequencePoints = emittingPdbs AndAlso method.GenerateDebugInfo
_emitPdbSequencePoints = emittingPdb AndAlso method.GenerateDebugInfo
If Me._optimizations = OptimizationLevel.Release Then
Me._block = Optimizer.Optimize(method, boundBody, Me._stackLocals)
If _optimizations = OptimizationLevel.Release Then
_block = Optimizer.Optimize(method, boundBody, _stackLocals)
End If
Me._checkCallsForUnsafeJITOptimization = (Me._method.ImplementationAttributes And MethodSymbol.DisableJITOptimizationFlags) <> MethodSymbol.DisableJITOptimizationFlags
Debug.Assert(Not Me._module.JITOptimizationIsDisabled(Me._method))
_checkCallsForUnsafeJITOptimization = (_method.ImplementationAttributes And MethodSymbol.DisableJITOptimizationFlags) <> MethodSymbol.DisableJITOptimizationFlags
Debug.Assert(Not _module.JITOptimizationIsDisabled(_method))
End Sub
Public Sub Generate()
......
......@@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private ReadOnly _compilation As VisualBasicCompilation
Private ReadOnly _cancellationToken As CancellationToken
Private ReadOnly _generateDebugInfo As Boolean
Private ReadOnly _emittingPdb As Boolean
Private ReadOnly _diagnostics As DiagnosticBag
Private ReadOnly _hasDeclarationErrors As Boolean
Private ReadOnly _namespaceScopeBuilder As NamespaceScopeBuilder
......@@ -78,28 +78,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' moduleBeingBuilt can be Nothing in order to just analyze methods for errors.
Private Sub New(compilation As VisualBasicCompilation,
moduleBeingBuiltOpt As PEModuleBuilder,
generateDebugInfo As Boolean,
emittingPdb As Boolean,
doEmitPhase As Boolean,
hasDeclarationErrors As Boolean,
diagnostics As DiagnosticBag,
filter As Predicate(Of Symbol),
cancellationToken As CancellationToken)
Me._compilation = compilation
Me._moduleBeingBuiltOpt = moduleBeingBuiltOpt
Me._diagnostics = diagnostics
Me._hasDeclarationErrors = hasDeclarationErrors
Me._cancellationToken = cancellationToken
Me._doEmitPhase = doEmitPhase
Me._generateDebugInfo = generateDebugInfo
Me._filterOpt = filter
If generateDebugInfo Then
Me._debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
_compilation = compilation
_moduleBeingBuiltOpt = moduleBeingBuiltOpt
_diagnostics = diagnostics
_hasDeclarationErrors = hasDeclarationErrors
_cancellationToken = cancellationToken
_doEmitPhase = doEmitPhase
_emittingPdb = emittingPdb
_filterOpt = filter
If emittingPdb Then
_debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
End If
If compilation.Options.ConcurrentBuild Then
Me._compilerTasks = New ConcurrentStack(Of Task)()
_compilerTasks = New ConcurrentStack(Of Task)()
End If
End Sub
......@@ -155,7 +155,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim compiler = New MethodCompiler(compilation,
moduleBeingBuiltOpt:=Nothing,
generateDebugInfo:=False,
emittingPdb:=False,
doEmitPhase:=doEmitPhase,
hasDeclarationErrors:=hasDeclarationErrors,
diagnostics:=diagnostics,
......@@ -187,7 +187,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' </summary>
Friend Shared Sub CompileMethodBodies(compilation As VisualBasicCompilation,
moduleBeingBuiltOpt As PEModuleBuilder,
generateDebugInfo As Boolean,
emittingPdb As Boolean,
hasDeclarationErrors As Boolean,
filter As Predicate(Of Symbol),
diagnostics As DiagnosticBag,
......@@ -208,13 +208,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
#End If
Dim compiler = New MethodCompiler(compilation,
moduleBeingBuiltOpt,
generateDebugInfo,
doEmitPhase:=True,
hasDeclarationErrors:=hasDeclarationErrors,
diagnostics:=diagnostics,
filter:=filter,
cancellationToken:=cancellationToken)
moduleBeingBuiltOpt,
emittingPdb,
doEmitPhase:=True,
hasDeclarationErrors:=hasDeclarationErrors,
diagnostics:=diagnostics,
filter:=filter,
cancellationToken:=cancellationToken)
compilation.SourceModule.GlobalNamespace.Accept(compiler)
compiler.WaitForWorkers()
......@@ -305,7 +305,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=Nothing,
diagnostics:=diagnostics,
generateDebugInfo:=False)
emittingPdb:=False)
moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody)
moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint)
......@@ -855,7 +855,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=Nothing,
diagnostics:=diagnosticsThisMethod,
generateDebugInfo:=False)
emittingPdb:=False)
_diagnostics.AddRange(diagnosticsThisMethod)
diagnosticsThisMethod.Free()
......@@ -919,7 +919,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
lazyVariableSlotAllocator,
debugDocumentProvider:=Nothing,
diagnostics:=diagnosticsThisMethod,
generateDebugInfo:=False)
emittingPdb:=False)
End If
lambdaDebugInfoBuilder.Free()
......@@ -968,7 +968,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=_debugDocumentProvider,
diagnostics:=diagnosticsThisMethod,
generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
emittingPdb:=_emittingPdb)
_diagnostics.AddRange(diagnosticsThisMethod)
diagnosticsThisMethod.Free()
......@@ -1451,7 +1451,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
lazyVariableSlotAllocator,
_debugDocumentProvider,
diagnostics,
generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
emittingPdb:=_emittingPdb)
If diagnostics IsNot diagsForCurrentMethod Then
DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod)
......@@ -1474,10 +1474,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt As VariableSlotAllocator,
debugDocumentProvider As DebugDocumentProvider,
diagnostics As DiagnosticBag,
generateDebugInfo As Boolean) As MethodBody
emittingPdb As Boolean) As MethodBody
Dim compilation = moduleBuilder.Compilation
Dim localSlotManager = New localSlotManager(variableSlotAllocatorOpt)
Dim localSlotManager = New LocalSlotManager(variableSlotAllocatorOpt)
Dim optimizations = compilation.Options.OptimizationLevel
If method.IsEmbedded Then
......@@ -1490,7 +1490,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Debug.Assert(Not diagnostics.HasAnyErrors)
Dim asyncDebugInfo As Cci.AsyncMethodBodyDebugInfo = Nothing
Dim codeGen = New codeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, generateDebugInfo)
Dim codeGen = New CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, emittingPdb)
' We need to save additional debugging information for MoveNext of an async state machine.
Dim stateMachineMethod = TryCast(method, SynthesizedStateMachineMethod)
......@@ -1523,6 +1523,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
codeGen.Generate()
End If
' Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata
' and we don't want to emit different metadata depending on whether or we emit with PDB stream.
' TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class.
Dim importScopeOpt = If(method.Syntax IsNot Nothing AndAlso method.Syntax.SyntaxTree IsNot VisualBasicSyntaxTree.DummySyntaxTree.Dummy,
moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree).Translate(moduleBuilder, diagnostics),
Nothing)
If diagnostics.HasAnyErrors() Then
Return Nothing
End If
......@@ -1539,29 +1546,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
GetStateMachineSlotDebugInfo(moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), stateMachineHoistedLocalSlots, stateMachineAwaiterSlots)
End If
Dim namespaceScopes = If(generateDebugInfo, moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree), Nothing)
' edgeInclusive must be true as that is what VB EE expects.
'<PdbUtil.cpp>
'HRESULT()
'PdbUtil::IsScopeInOffset(
' _In_ ISymUnmanagedScope* pScope,
' _In_ DWORD offset,
' _Out_ bool* inOffset)
'{
' VerifyInPtr(pScope);
' VerifyOutPtr(inOffset);
' HRESULT hr;
' ULONG32 start, end;
' IfFailGo( pScope->GetStartOffset(&start) );
' IfFailGo( pScope->GetEndOffset(&end) );
' *inOffset = (end >= offset) && (offset >= start); <==== HERE
'Error:
' return hr;
'}
Dim localScopes = builder.GetAllScopes()
Return New MethodBody(builder.RealizedIL,
......@@ -1574,7 +1558,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
builder.RealizedExceptionHandlers,
localScopes,
hasDynamicLocalVariables:=False,
importScopeOpt:=namespaceScopes,
importScopeOpt:=importScopeOpt,
lambdaDebugInfo:=lambdaDebugInfo,
closureDebugInfo:=closureDebugInfo,
stateMachineTypeNameOpt:=stateMachineTypeOpt?.Name, ' TODO: remove or update AddedOrChangedMethodInfo
......
......@@ -11,10 +11,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Sub
Public Shared Function BuildNamespaceScope(
context As EmitContext,
moduleBuilder As Emit.PEModuleBuilder,
xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition),
aliasImports As IEnumerable(Of AliasAndImportsClausePosition),
memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition)
memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition),
diagnostics As DiagnosticBag
) As ImmutableArray(Of Cci.UsedNamespaceOrType)
Dim scopeBuilder = ArrayBuilder(Of Cci.UsedNamespaceOrType).GetInstance
......@@ -31,8 +32,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim target = aliasImport.Alias.Target
If target.IsNamespace Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol), aliasOpt:=aliasImport.Alias.Name))
Else
Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol))
ElseIf Not target.ContainingAssembly.IsLinked
' We skip alias imports of embedded types to avoid breaking existing code that
' imports types that can't be embedded but doesn't use them anywhere else in the code.
Dim typeRef = GetTypeReference(DirectCast(target, NamedTypeSymbol), moduleBuilder, diagnostics)
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, aliasOpt:=aliasImport.Alias.Name))
End If
Next
......@@ -44,8 +47,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim target = import.NamespaceOrType
If target.IsNamespace Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol)))
Else
Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol))
ElseIf Not target.ContainingAssembly.IsLinked
' We skip imports of embedded types to avoid breaking existing code that
' imports types that can't be embedded but doesn't use them anywhere else in the code.
Dim typeRef = GetTypeReference(DirectCast(target, NamedTypeSymbol), moduleBuilder, diagnostics)
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef))
End If
Next
......@@ -54,8 +59,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return scopeBuilder.ToImmutableAndFree()
End Function
Private Shared Function GetTypeReference(context As EmitContext, type As TypeSymbol) As Cci.ITypeReference
Return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics)
Private Shared Function GetTypeReference(type As TypeSymbol, moduleBuilder As CommonPEModuleBuilder, diagnostics As DiagnosticBag) As Cci.ITypeReference
Return moduleBuilder.Translate(type, Nothing, diagnostics)
End Function
End Class
End Namespace
......@@ -2207,7 +2207,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
moduleBuilder As CommonPEModuleBuilder,
win32Resources As Stream,
xmlDocStream As Stream,
generateDebugInfo As Boolean,
emittingPdb As Boolean,
diagnostics As DiagnosticBag,
filterOpt As Predicate(Of ISymbol),
cancellationToken As CancellationToken) As Boolean
......@@ -2220,6 +2220,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.EmbeddedSymbolManager.MarkAllDeferredSymbolsAsReferenced(Me)
moduleBeingBuilt.TranslateImports(diagnostics)
If moduleBeingBuilt.EmitOptions.EmitMetadataOnly Then
If hasDeclarationErrors Then
Return False
......@@ -2233,12 +2235,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
SynthesizedMetadataCompiler.ProcessSynthesizedMembers(Me, moduleBeingBuilt, cancellationToken)
Else
' start generating PDB checksums if we need to emit PDBs
If generateDebugInfo AndAlso moduleBeingBuilt IsNot Nothing Then
If Not StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics) Then
Return False
End If
If emittingPdb AndAlso Not StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics) Then
Return False
End If
' Perform initial bind of method bodies in spite of earlier errors. This is the same
......@@ -2250,13 +2249,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
MethodCompiler.CompileMethodBodies(
Me,
moduleBeingBuilt,
generateDebugInfo,
emittingPdb,
hasDeclarationErrors,
filterOpt,
methodBodyDiagnosticBag,
cancellationToken)
Dim assemblyName = FileNameUtilities.ChangeExtension(moduleBeingBuilt.EmitOptions.OutputNameOverride, extension:=Nothing)
DocumentationCommentCompiler.WriteDocumentationCommentXml(Me, assemblyName, xmlDocStream, methodBodyDiagnosticBag, cancellationToken)
......
......@@ -63,7 +63,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
If compilation.Compile(moduleBeingBuilt,
win32Resources:=Nothing,
xmlDocStream:=Nothing,
generateDebugInfo:=True,
emittingPdb:=True,
diagnostics:=diagnostics,
filterOpt:=AddressOf changes.RequiresCompilation,
cancellationToken:=cancellationToken) Then
......
......@@ -22,7 +22,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Private ReadOnly _metadataName As String
Private _lazyExportedTypes As ImmutableArray(Of TypeExport(Of NamedTypeSymbol))
Private _lazyImports As ImmutableArray(Of Cci.UsedNamespaceOrType)
Private _lazyTranslatedImports As ImmutableArray(Of Cci.UsedNamespaceOrType)
Private _lazyDefaultNamespace As String
' These fields will only be set when running tests. They allow realized IL for a given method to be looked up by method display name.
......@@ -99,15 +99,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Get
End Property
Protected NotOverridable Overrides Function GetImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType)
If _lazyImports.IsDefault Then
Protected NotOverridable Overrides Function GetImports() As ImmutableArray(Of Cci.UsedNamespaceOrType)
' Imports should have been translated in code gen phase.
Debug.Assert(Not _lazyTranslatedImports.IsDefault)
Return _lazyTranslatedImports
End Function
Public Sub TranslateImports(diagnostics As DiagnosticBag)
If _lazyTranslatedImports.IsDefault Then
ImmutableInterlocked.InterlockedInitialize(
_lazyImports,
NamespaceScopeBuilder.BuildNamespaceScope(context, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports))
_lazyTranslatedImports,
NamespaceScopeBuilder.BuildNamespaceScope(Me, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports, diagnostics))
End If
Return _lazyImports
End Function
End Sub
Protected NotOverridable Overrides ReadOnly Property DefaultNamespace As String
Get
......
......@@ -430,19 +430,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Public Function GetUsedNamespaces(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType) Implements Cci.IImportScope.GetUsedNamespaces
Public Function Translate(moduleBuilder As Emit.PEModuleBuilder, diagnostics As DiagnosticBag) As Cci.IImportScope
If _lazyTranslatedImports.IsDefault Then
ImmutableInterlocked.InterlockedInitialize(_lazyTranslatedImports, TranslateImports(context))
ImmutableInterlocked.InterlockedInitialize(_lazyTranslatedImports, TranslateImports(moduleBuilder, diagnostics))
End If
Return Me
End Function
Public Function GetUsedNamespaces() As ImmutableArray(Of Cci.UsedNamespaceOrType) Implements Cci.IImportScope.GetUsedNamespaces
' The imports should have been translated during code gen.
Debug.Assert(Not _lazyTranslatedImports.IsDefault)
Return _lazyTranslatedImports
End Function
Private Function TranslateImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType)
Return NamespaceScopeBuilder.BuildNamespaceScope(context,
Private Function TranslateImports(moduleBuilder As Emit.PEModuleBuilder, diagnostics As DiagnosticBag) As ImmutableArray(Of Cci.UsedNamespaceOrType)
Return NamespaceScopeBuilder.BuildNamespaceScope(moduleBuilder,
XmlNamespaces,
If(AliasImports IsNot Nothing, AliasImports.Values, Nothing),
MemberImports)
MemberImports,
diagnostics)
End Function
End Class
End Namespace
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.IO
Imports Microsoft.CodeAnalysis.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.PDB
......@@ -354,6 +355,207 @@ End Namespace
</symbols>)
End Sub
<Fact>
Public Sub EmittingPdbVsNot()
Dim source =
<compilation name="EmittingPdbVsNot">
<file>
Imports System
Imports X = System.IO.FileStream
Class C
Dim x As Integer = 1
Shared y As Integer = 1
Sub New()
Console.WriteLine()
End Sub
End Class
</file>
</compilation>
Dim c = CreateCompilationWithMscorlib(source, options:=TestOptions.ReleaseDll)
Dim peStream1 = New MemoryStream()
Dim peStream2 = New MemoryStream()
Dim pdbStream = New MemoryStream()
Dim emitResult1 = c.Emit(peStream:=peStream1, pdbStream:=pdbStream)
Dim emitResult2 = c.Emit(peStream:=peStream2)
SharedCompilationUtils.VerifyMetadataEqualModuloMvid(peStream1, peStream2)
End Sub
<Fact>
Public Sub ImportedNoPiaTypes()
Dim sourceLib =
<compilation name="ImportedNoPiaTypesAssemblyName">
<file><![CDATA[
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
<Assembly:Guid("11111111-1111-1111-1111-111111111111")>
<Assembly:ImportedFromTypeLib("Foo")>
<Assembly:TypeLibVersion(1, 0)>
Namespace N
Public Enum E
Value1 = 1
End Enum
Public Structure S1
Public A1 As Integer
Public A2 As Integer
End Structure
Public Structure S2
Public Const Value2 As Integer = 2
End Structure
Public Structure SBad
Public A3 As Integer
Public Const Value3 As Integer = 3
End Structure
<ComImport, Guid("22222222-2222-2222-2222-222222222222")>
Public Interface I
Sub F()
End Interface
Public Interface IBad
Sub F()
End Interface
End Namespace
]]>
</file>
</compilation>
Dim source =
<compilation>
<file>
Imports System
Imports N.E
Imports N.SBad
Imports Z1 = N.S1
Imports Z2 = N.S2
Imports ZBad = N.SBad
Imports NI = N.I
Imports NIBad = N.IBad
Class C
Dim i As NI
Sub M
Console.WriteLine(Value1)
Console.WriteLine(Z2.Value2)
Console.WriteLine(New Z1())
End Sub
End Class
</file>
</compilation>
Dim globalImports = GlobalImport.Parse(
"GlobalNIBad = N.IBad",
"GlobalZ1 = N.S1",
"GlobalZ2 = N.S2",
"GlobalZBad = N.SBad",
"GlobalNI = N.I")
Dim libRef = CreateCompilationWithMscorlib(sourceLib).EmitToImageReference(embedInteropTypes:=True)
Dim compilation = CreateCompilationWithMscorlibAndReferences(source, {libRef}, options:=TestOptions.DebugDll.WithGlobalImports(globalImports))
Dim v = CompileAndVerify(compilation)
v.Diagnostics.Verify(
Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports N.SBad"),
Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports ZBad = N.SBad"),
Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports NIBad = N.IBad"))
' Imports of embedded types are currently ommitted:
v.VerifyPdb("C.M",
<symbols>
<methods>
<method containingType="C" name="M">
<sequencePoints>
<entry offset="0x0" startLine="13" startColumn="5" endLine="13" endColumn="10" document="0"/>
<entry offset="0x1" startLine="14" startColumn="9" endLine="14" endColumn="34" document="0"/>
<entry offset="0x8" startLine="15" startColumn="9" endLine="15" endColumn="37" document="0"/>
<entry offset="0xf" startLine="16" startColumn="9" endLine="16" endColumn="36" document="0"/>
<entry offset="0x23" startLine="17" startColumn="5" endLine="17" endColumn="12" document="0"/>
</sequencePoints>
<scope startOffset="0x0" endOffset="0x24">
<namespace name="System" importlevel="file"/>
<defunct name="&amp;ImportedNoPiaTypesAssemblyName"/>
<currentnamespace name=""/>
</scope>
</method>
</methods>
</symbols>)
End Sub
<Fact>
Public Sub ImportedTypeWithUnknownBase()
Dim sourceLib1 =
<compilation>
<file>
Namespace N
Public Class A
End Class
End Namespace
</file>
</compilation>
Dim sourceLib2 =
<compilation name="LibRef2">
<file>
Namespace N
Public Class B
Inherits A
End Class
End Namespace
</file>
</compilation>
Dim source =
<compilation>
<file>
Imports System
Imports X = N.B
Class C
Sub M()
Console.WriteLine()
End Sub
End Class
</file>
</compilation>
Dim libRef1 = CreateCompilationWithMscorlib(sourceLib1).EmitToImageReference()
Dim libRef2 = CreateCompilationWithMscorlibAndReferences(sourceLib2, {libRef1}).EmitToImageReference()
Dim compilation = CreateCompilationWithMscorlibAndReferences(source, {libRef2})
Dim v = CompileAndVerify(compilation, emitters:=TestEmitters.CCI)
v.Diagnostics.Verify(
Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports X = N.B"))
v.VerifyPdb("C.M",
<symbols>
<methods>
<method containingType="C" name="M">
<sequencePoints>
<entry offset="0x0" startLine="6" startColumn="9" endLine="6" endColumn="28" document="0"/>
<entry offset="0x5" startLine="7" startColumn="5" endLine="7" endColumn="12" document="0"/>
</sequencePoints>
<scope startOffset="0x0" endOffset="0x6">
<alias name="X" target="N.B" kind="namespace" importlevel="file"/>
<namespace name="System" importlevel="file"/>
<currentnamespace name=""/>
</scope>
</method>
</methods>
</symbols>)
End Sub
End Class
End Namespace
......
......@@ -157,7 +157,7 @@ internal sealed class CompilationContext
module,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: false,
emittingPdb: false,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: CancellationToken.None);
......@@ -220,7 +220,7 @@ internal sealed class CompilationContext
module,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: false,
emittingPdb: false,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: CancellationToken.None);
......@@ -405,7 +405,7 @@ private static string GetNextMethodName(ArrayBuilder<MethodSymbol> builder)
module,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: false,
emittingPdb: false,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: CancellationToken.None);
......
......@@ -154,7 +154,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
moduleBuilder,
win32Resources:=Nothing,
xmlDocStream:=Nothing,
generateDebugInfo:=False,
emittingPdb:=False,
diagnostics:=diagnostics,
filterOpt:=Nothing,
cancellationToken:=CancellationToken.None)
......@@ -250,15 +250,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
' "Me" for non-shared methods that are not display class methods
' or display class methods where the display class contains "$VB$Me".
If Not m.IsShared AndAlso (Not m.ContainingType.IsClosureOrStateMachineType() OrElse _displayClassVariables.ContainsKey(GeneratedNames.MakeStateMachineCapturedMeName())) Then
Dim methodName = GetNextMethodName(methodBuilder)
Dim method = Me.GetMeMethod(container, methodName)
localBuilder.Add(New VisualBasicLocalAndMethod("Me", "Me", methodName, DkmClrCompilationResultFlags.None)) ' NOTE: writable in Dev11.
methodBuilder.Add(method)
End If
Dim methodName = GetNextMethodName(methodBuilder)
Dim method = Me.GetMeMethod(container, methodName)
localBuilder.Add(New VisualBasicLocalAndMethod("Me", "Me", methodName, DkmClrCompilationResultFlags.None)) ' NOTE: writable in Dev11.
methodBuilder.Add(method)
End If
End If
' Hoisted method parameters (represented as locals in the EE).
If Not _hoistedParameterNames.IsEmpty Then
' Hoisted method parameters (represented as locals in the EE).
If Not _hoistedParameterNames.IsEmpty Then
Dim localIndex As Integer = 0
For Each local In _localsForBinding
......@@ -327,7 +327,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
moduleBuilder,
win32Resources:=Nothing,
xmlDocStream:=Nothing,
generateDebugInfo:=False,
emittingPdb:=False,
diagnostics:=diagnostics,
filterOpt:=Nothing,
cancellationToken:=CancellationToken.None)
......
......@@ -84,7 +84,7 @@ internal static class CommonCompilationExtensions
moduleBeingBuilt,
win32Resources: null,
xmlDocStream: null,
generateDebugInfo: false,
emittingPdb: false,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: cancellationToken))
......
......@@ -381,6 +381,7 @@ public static void ThrowsArgumentException(string parameterName, Action del)
throw new Exception("No exception was thrown.");
}
// compares against a baseline
public static void AssertEqualToleratingWhitespaceDifferences(
string expected,
string actual,
......@@ -397,6 +398,32 @@ public static void ThrowsArgumentException(string parameterName, Action del)
}
}
// compares two results (no baseline)
public static void AssertResultsEqual(string result1, string result2)
{
if (result1 != result2)
{
string message;
if (DiffToolAvailable)
{
string file1 = Path.GetTempFileName();
File.WriteAllText(file1, result1);
string file2 = Path.GetTempFileName();
File.WriteAllText(file2, result2);
message = MakeDiffToolLink(file1, file2);
}
else
{
message = GetAssertMessage(result1, result2);
}
Assert.True(false, message);
}
}
public static void AssertContainsToleratingWhitespaceDifferences(string expectedSubString, string actualString)
{
expectedSubString = NormalizeWhitespace(expectedSubString);
......@@ -481,7 +508,7 @@ public static string GetAssertMessage<T>(IEnumerable<T> expected, IEnumerable<T>
message.AppendLine(DiffUtil.DiffReport(expected, actual, comparer, itemInspector, itemSeparator));
string link;
if (TryGenerateExpectedSourceFielAndGetDiffLink(actualString, expected.Count(), expectedValueSourcePath, expectedValueSourceLine, out link))
if (TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expected.Count(), expectedValueSourcePath, expectedValueSourceLine, out link))
{
message.AppendLine(link);
}
......@@ -489,10 +516,10 @@ public static string GetAssertMessage<T>(IEnumerable<T> expected, IEnumerable<T>
return message.ToString();
}
internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualString, int expectedLineCount, string expectedValueSourcePath, int expectedValueSourceLine, out string link)
internal static bool TryGenerateExpectedSourceFileAndGetDiffLink(string actualString, int expectedLineCount, string expectedValueSourcePath, int expectedValueSourceLine, out string link)
{
// add a link to a .cmd file that opens a diff tool:
if (!string.IsNullOrEmpty(s_diffToolPath) && expectedValueSourcePath != null && expectedValueSourceLine != 0)
if (DiffToolAvailable && expectedValueSourcePath != null && expectedValueSourceLine != 0)
{
var actualFile = Path.GetTempFileName();
var testFileLines = File.ReadAllLines(expectedValueSourcePath);
......@@ -501,10 +528,7 @@ internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualSt
File.AppendAllText(actualFile, actualString);
File.AppendAllLines(actualFile, testFileLines.Skip(expectedValueSourceLine + expectedLineCount));
var compareCmd = Path.GetTempFileName() + ".cmd";
File.WriteAllText(compareCmd, string.Format("\"{0}\" \"{1}\" \"{2}\"", s_diffToolPath, actualFile, expectedValueSourcePath));
link = "file://" + compareCmd;
link = MakeDiffToolLink(actualFile, expectedValueSourcePath);
s_diffLinks.Value.Add(Tuple.Create(expectedValueSourcePath, expectedValueSourceLine, link));
return true;
......@@ -514,6 +538,16 @@ internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualSt
return false;
}
internal static bool DiffToolAvailable => !string.IsNullOrEmpty(s_diffToolPath);
internal static string MakeDiffToolLink(string actualFilePath, string expectedFilePath)
{
var compareCmd = Path.GetTempFileName() + ".cmd";
File.WriteAllText(compareCmd, string.Format("\"{0}\" \"{1}\" \"{2}\"", s_diffToolPath, actualFilePath, expectedFilePath));
return "file://" + compareCmd;
}
private static readonly Lazy<List<Tuple<string, int, string>>> s_diffLinks = new Lazy<List<Tuple<string, int, string>>>(() =>
{
AppDomain.CurrentDomain.DomainUnload += (_, __) =>
......
......@@ -84,7 +84,7 @@ private static string GetXmlString(XElement node, bool expectedIsXmlLiteral)
string expectedString = expectedIsXmlLiteral ? expected.Replace(" />\r\n", "/>\r\n") : string.Format("@\"{0}\"", expected.Replace("\"", "\"\""));
string link;
if (AssertEx.TryGenerateExpectedSourceFielAndGetDiffLink(actualString, expectedString.Count(c => c == '\n') + 1, expectedValueSourcePath, expectedValueSourceLine, out link))
if (AssertEx.TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expectedString.Count(c => c == '\n') + 1, expectedValueSourcePath, expectedValueSourceLine, out link))
{
assertText.AppendLine(link);
}
......
......@@ -38,7 +38,7 @@ public static class CompilationExtensions
getHostDiagnostics: null,
cancellationToken: default(CancellationToken));
Assert.True(emitResult.Success, "Diagnostics:\r\n" + string.Join("\r\n, ", emitResult.Diagnostics.Select(d => d.ToString())));
Assert.True(emitResult.Success, "Diagnostics:\r\n" + string.Join("\r\n", emitResult.Diagnostics.Select(d => d.ToString())));
if (expectedWarnings != null)
{
......
......@@ -8,12 +8,14 @@
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Emit;
using PDB::Roslyn.Test.MetadataUtilities;
using PDB::Roslyn.Test.PdbUtilities;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -54,7 +56,7 @@ internal static CompilationTestData.MethodData GetMethodData(this CompilationTes
return methodData;
}
internal static void VerifyIL(
this CompilationTestData.MethodData method,
string expectedIL,
......@@ -194,6 +196,39 @@ public static void ValidateDebugDirectory(Stream peStream, string pdbPath)
Assert.Equal(0, reader.ReadByte());
}
public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2)
{
peStream1.Position = 0;
peStream2.Position = 0;
var peReader1 = new PEReader(peStream1);
var peReader2 = new PEReader(peStream2);
var md1 = peReader1.GetMetadata().GetContent();
var md2 = peReader2.GetMetadata().GetContent();
var mdReader1 = peReader1.GetMetadataReader();
var mdReader2 = peReader2.GetMetadataReader();
var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid;
var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid;
var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1);
var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1);
if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16)))
{
var mdw1 = new StringWriter();
var mdw2 = new StringWriter();
new MetadataVisualizer(mdReader1, mdw1).Visualize();
new MetadataVisualizer(mdReader2, mdw2).Visualize();
mdw1.Flush();
mdw2.Flush();
AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString());
}
}
internal static string GetMethodIL(this CompilationTestData.MethodData method)
{
return ILBuilderVisualizer.ILBuilderToString(method.ILBuilder);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册