Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,21 @@ internal static ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentitiesHel
}
}
break;
case ErrorCode.ERR_DottedTypeNameNotFoundInNS:
if (arguments.Count == 2)
{
var namespaceName = arguments[0] as string;
var containingNamespace = arguments[1] as NamespaceSymbol;
if (namespaceName != null && (object)containingNamespace != null &&
containingNamespace.ConstituentNamespaces.Any(n => n.ContainingAssembly.Identity.IsWindowsAssemblyIdentity()))
{
// This is just a heuristic, but it has the advantage of being portable, particularly
// across different versions of (desktop) windows.
var identity = new AssemblyIdentity($"{containingNamespace.ToDisplayString()}.{namespaceName}", contentType: System.Reflection.AssemblyContentType.WindowsRuntime);
return ImmutableArray.Create(identity);
}
}
break;
case ErrorCode.ERR_DynamicAttributeMissing:
case ErrorCode.ERR_DynamicRequiredTypesMissing:
// MSDN says these might come from System.Dynamic.Runtime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,15 +380,95 @@ static void M()
Assert.Equal(expectedMissingAssemblyIdentity, actualMissingAssemblyIdentities.Single());
}

[WorkItem(1114866)]
[ConditionalFact(typeof(OSVersionWin8))]
public void NotYetLoadedWinMds()
{
var source =
@"class C
{
static void M(Windows.Storage.StorageFolder f)
{
}
}";
var comp = CreateCompilationWithMscorlib(source, WinRtRefs, TestOptions.DebugDll);
var runtimeAssemblies = ExpressionCompilerTestHelpers.GetRuntimeWinMds("Windows.Storage");
Assert.True(runtimeAssemblies.Any());
var context = CreateMethodContextWithReferences(comp, "C.M", ImmutableArray.Create(MscorlibRef).Concat(runtimeAssemblies));

const string expectedError = "error CS0234: The type or namespace name 'UI' does not exist in the namespace 'Windows' (are you missing an assembly reference?)";
var expectedMissingAssemblyIdentity = new AssemblyIdentity("Windows.UI", contentType: System.Reflection.AssemblyContentType.WindowsRuntime);

ResultProperties resultProperties;
string actualError;
ImmutableArray<AssemblyIdentity> actualMissingAssemblyIdentities;
context.CompileExpression(
InspectionContextFactory.Empty,
"typeof(@Windows.UI.Colors)",
DkmEvaluationFlags.None,
DiagnosticFormatter.Instance,
out resultProperties,
out actualError,
out actualMissingAssemblyIdentities,
EnsureEnglishUICulture.PreferredOrNull,
testData: null);
Assert.Equal(expectedError, actualError);
Assert.Equal(expectedMissingAssemblyIdentity, actualMissingAssemblyIdentities.Single());
}

/// <remarks>
/// Windows.UI.Xaml is the only (win8) winmd with more than two parts.
/// </remarks>
[WorkItem(1114866)]
[ConditionalFact(typeof(OSVersionWin8))]
public void NotYetLoadedWinMds_MultipleParts()
{
var source =
@"class C
{
static void M(Windows.UI.Colors c)
{
}
}";
var comp = CreateCompilationWithMscorlib(source, WinRtRefs, TestOptions.DebugDll);
var runtimeAssemblies = ExpressionCompilerTestHelpers.GetRuntimeWinMds("Windows.UI");
Assert.True(runtimeAssemblies.Any());
var context = CreateMethodContextWithReferences(comp, "C.M", ImmutableArray.Create(MscorlibRef).Concat(runtimeAssemblies));

const string expectedError = "error CS0234: The type or namespace name 'Xaml' does not exist in the namespace 'Windows.UI' (are you missing an assembly reference?)";
var expectedMissingAssemblyIdentity = new AssemblyIdentity("Windows.UI.Xaml", contentType: System.Reflection.AssemblyContentType.WindowsRuntime);

ResultProperties resultProperties;
string actualError;
ImmutableArray<AssemblyIdentity> actualMissingAssemblyIdentities;
context.CompileExpression(
InspectionContextFactory.Empty,
"typeof(Windows.@UI.Xaml.Application)",
DkmEvaluationFlags.None,
DiagnosticFormatter.Instance,
out resultProperties,
out actualError,
out actualMissingAssemblyIdentities,
EnsureEnglishUICulture.PreferredOrNull,
testData: null);
Assert.Equal(expectedError, actualError);
Assert.Equal(expectedMissingAssemblyIdentity, actualMissingAssemblyIdentities.Single());
}

private EvaluationContext CreateMethodContextWithReferences(Compilation comp, string methodName, params MetadataReference[] references)
{
return CreateMethodContextWithReferences(comp, methodName, ImmutableArray.CreateRange(references));
}

private EvaluationContext CreateMethodContextWithReferences(Compilation comp, string methodName, ImmutableArray<MetadataReference> references)
{
byte[] exeBytes;
byte[] pdbBytes;
ImmutableArray<MetadataReference> unusedReferences;
var result = comp.EmitAndGetReferences(out exeBytes, out pdbBytes, out unusedReferences);
Assert.True(result);

var runtime = CreateRuntimeInstance(GetUniqueName(), ImmutableArray.CreateRange(references), exeBytes, new SymReader(pdbBytes));
var runtime = CreateRuntimeInstance(GetUniqueName(), references, exeBytes, new SymReader(pdbBytes));
return CreateMethodContext(runtime, methodName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ internal static bool IsWindowsAssemblyName(string assemblyName)
return assemblyName.Equals("windows", StringComparison.OrdinalIgnoreCase);
}

internal static bool IsWindowsAssemblyIdentity(this AssemblyIdentity assemblyIdentity)
{
return IsWindowsAssemblyName(assemblyIdentity.Name) &&
assemblyIdentity.ContentType == System.Reflection.AssemblyContentType.WindowsRuntime;
}

internal static LocalInfo<TTypeSymbol> GetLocalInfo<TModuleSymbol, TTypeSymbol, TMethodSymbol, TFieldSymbol, TSymbol>(
this MetadataDecoder<TModuleSymbol, TTypeSymbol, TMethodSymbol, TFieldSymbol, TSymbol> metadataDecoder,
byte[] signature)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,17 +562,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
End Sub

Friend Overrides Function GetMissingAssemblyIdentities(diagnostic As Diagnostic) As ImmutableArray(Of AssemblyIdentity)
Return GetMissingAssemblyIdentitiesHelper(CType(diagnostic.Code, ERRID), diagnostic.Arguments)
Return GetMissingAssemblyIdentitiesHelper(CType(diagnostic.Code, ERRID), diagnostic.Arguments, Me.Compilation.GlobalNamespace)
End Function

''' <remarks>
''' Friend for testing.
''' </remarks>
Friend Shared Function GetMissingAssemblyIdentitiesHelper(code As ERRID, arguments As IReadOnlyList(Of Object)) As ImmutableArray(Of AssemblyIdentity)
Select Case code
Friend Shared Function GetMissingAssemblyIdentitiesHelper(code As ERRID, arguments As IReadOnlyList(Of Object), globalNamespace As NamespaceSymbol) As ImmutableArray(Of AssemblyIdentity)
Select Case code
Case ERRID.ERR_UnreferencedAssemblyEvent3, ERRID.ERR_UnreferencedAssembly3
For Each argument As Object In arguments
Dim identity = If(TryCast(argument, AssemblyIdentity), TryCast(argument, AssemblySymbol)?.Identity)
Dim identity = If(TryCast(argument, AssemblyIdentity), TryCast(argument, AssemblySymbol)?.Identity)
If IsValidMissingAssemblyIdentity(identity) Then
Return ImmutableArray.Create(identity)
End If
Expand All @@ -584,6 +584,49 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Return ImmutableArray.Create(identity)
End If
End If
Case ERRID.ERR_NameNotMember2
If arguments.Count = 2 Then
Dim namespaceName = TryCast(arguments(0), String)
Dim containingNamespace = TryCast(arguments(1), NamespaceSymbol)
If namespaceName IsNot Nothing AndAlso containingNamespace IsNot Nothing AndAlso HasConstituentFromWindowsAssembly(containingNamespace) Then
' This is just a heuristic, but it has the advantage of being portable, particularly
' across different versions of (desktop) windows.
Dim identity = New AssemblyIdentity($"{containingNamespace.ToDisplayString}.{namespaceName}", contentType:=AssemblyContentType.WindowsRuntime)
Return ImmutableArray.Create(identity)
End If
End If
Case ERRID.ERR_UndefinedType1
If arguments.Count = 1 Then
Dim qualifiedName = TryCast(arguments(0), String)
If Not String.IsNullOrEmpty(qualifiedName) Then
Dim nameParts = qualifiedName.Split("."c)
Dim numParts = nameParts.Length
Dim pos = 0
If CaseInsensitiveComparison.Comparer.Equals(nameParts(0), "global") Then
pos = 1
Debug.Assert(pos < numParts)
End If
Dim currNamespace = globalNamespace
While pos < numParts
Dim nextNamespace = currNamespace.GetMembers(nameParts(pos)).OfType(Of NamespaceSymbol).SingleOrDefault()
If nextNamespace Is Nothing Then
Exit While
End If
pos += 1
currNamespace = nextNamespace
End While

If currNamespace IsNot globalNamespace AndAlso HasConstituentFromWindowsAssembly(currNamespace) AndAlso pos < numParts Then
Dim nextNamePart = nameParts(pos)
If nextNamePart.All(AddressOf SyntaxFacts.IsIdentifierPartCharacter) Then
' This is just a heuristic, but it has the advantage of being portable, particularly
' across different versions of (desktop) windows.
Dim identity = New AssemblyIdentity($"{currNamespace.ToDisplayString}.{nameParts(pos)}", contentType:=AssemblyContentType.WindowsRuntime)
Return ImmutableArray.Create(identity)
End If
End If
End If
End If
Case ERRID.ERR_XmlFeaturesNotAvailable
Return ImmutableArray.Create(SystemIdentity, SystemCoreIdentity, SystemXmlIdentity, SystemXmlLinqIdentity)
Case ERRID.ERR_MissingRuntimeHelper
Expand All @@ -593,6 +636,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Return Nothing
End Function

Private Shared Function HasConstituentFromWindowsAssembly(namespaceSymbol As NamespaceSymbol) As Boolean
Return namespaceSymbol.ConstituentNamespaces.Any(Function(n) n.ContainingAssembly.Identity.IsWindowsAssemblyIdentity)
End Function

Private Shared Function IsValidMissingAssemblyIdentity(identity As AssemblyIdentity) As Boolean
Return identity IsNot Nothing AndAlso Not identity.Equals(MissingCorLibrarySymbol.Instance.Identity)
End Function
Expand Down
Loading