提交 52d770bb 编写于 作者: J Jason Malinowski

Fix null reference exception with convert tuple with inaccessible System.HashCode

ConvertTupleToStruct invokes our existing services for generating
GetHashCode methods; that service checks whether System.HashCode is
available, and if so uses it rather than implementing the hash code
combining manually. The code to generate GetHashCode correctly not just
grabs the type but also tries to check whether type is accessible to
the struct being generated. It's possible for System.HashCode to be
internal if some library you're referencing has embedded it's own copy;
in this case we were trying to check if the System.HashCode was
accessible to the code generation symbol; if the System.HashCode was
internal it then checks the assembly symbols for InternalsVisibleTo,
but since the code generation symbol never had a ContainingAssembly this
would crash with a null reference.

Much of this code is null annotated, but unfortunately we have yet to
annotate ContainingAssembly, so the line of code that let a null get
into the system was here:

https://github.com/dotnet/roslyn/blob/884fdff6f8a87faa7f6e65d762bd6d7b2025da74/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs#L230

My fix is to create the code generation INamedTypeSymbol with a
containing assembly, which allows the rest of the checks to work
correctly.
上级 90273de8
......@@ -1666,6 +1666,81 @@ End Structure
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function
<Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)>
Public Async Function ConvertSingleTupleTypeWithInaccessibleSystemHashCode(host As TestHost) As Task
Dim text = "
<Workspace>
<Project Language=""Visual Basic"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
Namespace System
Friend Class HashCode
End Class
End Namespace
</Document>
</Project>
<Project Language=""Visual Basic"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<ProjectReference>Assembly1</ProjectReference>
<Document>
class Test
sub Method()
dim t1 = [||](a:=1, b:=2)
end sub
end class
</Document>
</Project>
</Workspace>"
Dim expected = "
class Test
sub Method()
dim t1 = New {|Rename:NewStruct|}(a:=1, b:=2)
end sub
end class
Friend Structure NewStruct
Public a As Integer
Public b As Integer
Public Sub New(a As Integer, b As Integer)
Me.a = a
Me.b = b
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not (TypeOf obj Is NewStruct) Then
Return False
End If
Dim other = DirectCast(obj, NewStruct)
Return a = other.a AndAlso
b = other.b
End Function
Public Overrides Function GetHashCode() As Integer
Dim hashCode = 2118541809
hashCode = hashCode * -1521134295 + a.GetHashCode()
hashCode = hashCode * -1521134295 + b.GetHashCode()
Return hashCode
End Function
Public Sub Deconstruct(ByRef a As Integer, ByRef b As Integer)
a = Me.a
b = Me.b
End Sub
Public Shared Widening Operator CType(value As NewStruct) As (a As Integer, b As Integer)
Return (value.a, value.b)
End Operator
Public Shared Widening Operator CType(value As (a As Integer, b As Integer)) As NewStruct
Return New NewStruct(value.a, value.b)
End Operator
End Structure
"
Await TestInRegularAndScriptAsync(text, expected, options:=GetTestOptions(host))
End Function
Protected Overrides Function GetScriptOptions() As ParseOptions
Return Nothing
End Function
......
......@@ -744,7 +744,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
// help create members like Equals/GetHashCode. Then, once we have all the members we
// create the final type.
var namedTypeWithoutMembers = CreateNamedType(
scope, structName, typeParameters, members: default);
semanticModel.Compilation.Assembly, scope, structName, typeParameters, members: default);
var generator = SyntaxGenerator.GetGenerator(document);
var constructor = CreateConstructor(semanticModel, structName, fields, generator);
......@@ -768,7 +768,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
members.Add(GenerateDeconstructMethod(semanticModel, generator, tupleType, constructor));
AddConversions(generator, members, tupleType, namedTypeWithoutMembers);
var namedTypeSymbol = CreateNamedType(scope, structName, typeParameters, members.ToImmutableAndFree());
var namedTypeSymbol = CreateNamedType(semanticModel.Compilation.Assembly, scope, structName, typeParameters, members.ToImmutableAndFree());
return namedTypeSymbol;
}
......@@ -834,6 +834,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
}
private static INamedTypeSymbol CreateNamedType(
IAssemblySymbol containingAssembly,
Scope scope, string structName,
ImmutableArray<ITypeParameterSymbol> typeParameters, ImmutableArray<ISymbol> members)
{
......@@ -842,7 +843,7 @@ private static SyntaxNodeOrToken ConvertArgumentOrToken(SyntaxGenerator generato
: Accessibility.Internal;
return CodeGenerationSymbolFactory.CreateNamedTypeSymbol(
attributes: default, accessibility, modifiers: default,
TypeKind.Struct, structName, typeParameters, members: members);
TypeKind.Struct, structName, typeParameters, members: members, containingAssembly: containingAssembly);
}
private static IMethodSymbol CreateConstructor(
......
......@@ -383,12 +383,13 @@ public static IArrayTypeSymbol CreateArrayTypeSymbol(ITypeSymbol elementType, in
ImmutableArray<INamedTypeSymbol> interfaces = default,
SpecialType specialType = SpecialType.None,
ImmutableArray<ISymbol> members = default,
NullableAnnotation nullableAnnotation = NullableAnnotation.None)
NullableAnnotation nullableAnnotation = NullableAnnotation.None,
IAssemblySymbol containingAssembly = null)
{
members = members.NullToEmpty();
return new CodeGenerationNamedTypeSymbol(
null, attributes, accessibility, modifiers, typeKind, name,
containingAssembly, null, attributes, accessibility, modifiers, typeKind, name,
typeParameters, baseType, interfaces, specialType, nullableAnnotation,
members.WhereAsArray(m => !(m is INamedTypeSymbol)),
members.OfType<INamedTypeSymbol>().Select(n => n.ToCodeGenerationSymbol()).ToImmutableArray(),
......@@ -421,6 +422,7 @@ public static IArrayTypeSymbol CreateArrayTypeSymbol(ITypeSymbol elementType, in
parameters: parameters);
return new CodeGenerationNamedTypeSymbol(
containingAssembly: null,
containingType: null,
attributes: attributes,
declaredAccessibility: accessibility,
......
......@@ -16,6 +16,7 @@ public static CodeGenerationAbstractNamedTypeSymbol ToCodeGenerationSymbol(this
}
return new CodeGenerationNamedTypeSymbol(
namedType.ContainingAssembly,
namedType.ContainingType,
namedType.GetAttributes(),
namedType.DeclaredAccessibility,
......
......@@ -23,7 +23,7 @@ public virtual ImmutableArray<AttributeData> GetReturnTypeAttributes()
DeclarationModifiers modifiers,
string name,
ImmutableArray<AttributeData> returnTypeAttributes)
: base(containingType, attributes, declaredAccessibility, modifiers, name)
: base(containingType?.ContainingAssembly, containingType, attributes, declaredAccessibility, modifiers, name)
{
_returnTypeAttributes = returnTypeAttributes.NullToEmpty();
}
......
......@@ -18,6 +18,7 @@ internal abstract class CodeGenerationAbstractNamedTypeSymbol : CodeGenerationTy
internal readonly ImmutableArray<CodeGenerationAbstractNamedTypeSymbol> TypeMembers;
protected CodeGenerationAbstractNamedTypeSymbol(
IAssemblySymbol containingAssembly,
INamedTypeSymbol containingType,
ImmutableArray<AttributeData> attributes,
Accessibility declaredAccessibility,
......@@ -26,7 +27,7 @@ internal abstract class CodeGenerationAbstractNamedTypeSymbol : CodeGenerationTy
SpecialType specialType,
NullableAnnotation nullableAnnotation,
ImmutableArray<CodeGenerationAbstractNamedTypeSymbol> typeMembers)
: base(containingType, attributes, declaredAccessibility, modifiers, name, specialType, nullableAnnotation)
: base(containingAssembly, containingType, attributes, declaredAccessibility, modifiers, name, specialType, nullableAnnotation)
{
this.TypeMembers = typeMembers;
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration
internal class CodeGenerationArrayTypeSymbol : CodeGenerationTypeSymbol, IArrayTypeSymbol
{
public CodeGenerationArrayTypeSymbol(ITypeSymbol elementType, int rank, NullableAnnotation nullableAnnotation)
: base(null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, nullableAnnotation)
: base(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, nullableAnnotation)
{
this.ElementType = elementType;
this.Rank = rank;
......
......@@ -17,7 +17,7 @@ internal class CodeGenerationConstructedNamedTypeSymbol : CodeGenerationAbstract
CodeGenerationNamedTypeSymbol constructedFrom,
ImmutableArray<ITypeSymbol> typeArguments,
ImmutableArray<CodeGenerationAbstractNamedTypeSymbol> typeMembers)
: base(constructedFrom.ContainingType, constructedFrom.GetAttributes(),
: base(constructedFrom.ContainingAssembly, constructedFrom.ContainingType, constructedFrom.GetAttributes(),
constructedFrom.DeclaredAccessibility, constructedFrom.Modifiers,
constructedFrom.Name, constructedFrom.SpecialType, constructedFrom.NullableAnnotation, typeMembers)
{
......
......@@ -32,7 +32,7 @@ internal class CodeGenerationEventSymbol : CodeGenerationSymbol, IEventSymbol
IMethodSymbol addMethod,
IMethodSymbol removeMethod,
IMethodSymbol raiseMethod)
: base(containingType, attributes, declaredAccessibility, modifiers, name)
: base(containingType?.ContainingAssembly, containingType, attributes, declaredAccessibility, modifiers, name)
{
this.Type = type;
this.ExplicitInterfaceImplementations = explicitInterfaceImplementations.NullToEmpty();
......
......@@ -23,7 +23,7 @@ internal class CodeGenerationFieldSymbol : CodeGenerationSymbol, IFieldSymbol
string name,
bool hasConstantValue,
object constantValue)
: base(containingType, attributes, accessibility, modifiers, name)
: base(containingType?.ContainingAssembly, containingType, attributes, accessibility, modifiers, name)
{
this.Type = type;
this.HasConstantValue = hasConstantValue;
......
......@@ -21,6 +21,7 @@ internal class CodeGenerationNamedTypeSymbol : CodeGenerationAbstractNamedTypeSy
private readonly INamedTypeSymbol _enumUnderlyingType;
public CodeGenerationNamedTypeSymbol(
IAssemblySymbol containingAssembly,
INamedTypeSymbol containingType,
ImmutableArray<AttributeData> attributes,
Accessibility declaredAccessibility,
......@@ -35,7 +36,7 @@ internal class CodeGenerationNamedTypeSymbol : CodeGenerationAbstractNamedTypeSy
ImmutableArray<ISymbol> members,
ImmutableArray<CodeGenerationAbstractNamedTypeSymbol> typeMembers,
INamedTypeSymbol enumUnderlyingType)
: base(containingType, attributes, declaredAccessibility, modifiers, name, specialType, nullableAnnotation, typeMembers)
: base(containingAssembly, containingType, attributes, declaredAccessibility, modifiers, name, specialType, nullableAnnotation, typeMembers)
{
_typeKind = typeKind;
_typeParameters = typeParameters.NullToEmpty();
......@@ -50,7 +51,7 @@ internal class CodeGenerationNamedTypeSymbol : CodeGenerationAbstractNamedTypeSy
protected override CodeGenerationTypeSymbol CloneWithNullableAnnotation(NullableAnnotation nullableAnnotation)
{
return new CodeGenerationNamedTypeSymbol(
this.ContainingType, this.GetAttributes(), this.DeclaredAccessibility,
this.ContainingAssembly, this.ContainingType, this.GetAttributes(), this.DeclaredAccessibility,
this.Modifiers, this.TypeKind, this.Name, _typeParameters, _baseType,
_interfaces, this.SpecialType, nullableAnnotation, _members, this.TypeMembers,
this.EnumUnderlyingType);
......
......@@ -10,12 +10,13 @@ namespace Microsoft.CodeAnalysis.CodeGeneration
internal abstract class CodeGenerationNamespaceOrTypeSymbol : CodeGenerationSymbol, INamespaceOrTypeSymbol
{
protected CodeGenerationNamespaceOrTypeSymbol(
IAssemblySymbol containingAssembly,
INamedTypeSymbol containingType,
ImmutableArray<AttributeData> attributes,
Accessibility declaredAccessibility,
DeclarationModifiers modifiers,
string name)
: base(containingType, attributes, declaredAccessibility, modifiers, name)
: base(containingAssembly, containingType, attributes, declaredAccessibility, modifiers, name)
{
}
......
......@@ -14,7 +14,7 @@ internal class CodeGenerationNamespaceSymbol : CodeGenerationNamespaceOrTypeSymb
private readonly IList<INamespaceOrTypeSymbol> _members;
public CodeGenerationNamespaceSymbol(string name, IList<INamespaceOrTypeSymbol> members)
: base(null, default, Accessibility.NotApplicable, default, name)
: base(null, null, default, Accessibility.NotApplicable, default, name)
{
_members = members ?? SpecializedCollections.EmptyList<INamespaceOrTypeSymbol>();
}
......
......@@ -29,7 +29,7 @@ internal class CodeGenerationParameterSymbol : CodeGenerationSymbol, IParameterS
bool isOptional,
bool hasDefaultValue,
object defaultValue)
: base(containingType, attributes, Accessibility.NotApplicable, new DeclarationModifiers(), name)
: base(containingType?.ContainingAssembly, containingType, attributes, Accessibility.NotApplicable, new DeclarationModifiers(), name)
{
this.RefKind = refKind;
this.IsParams = isParams;
......
......@@ -11,7 +11,7 @@ internal class CodeGenerationPointerTypeSymbol : CodeGenerationTypeSymbol, IPoin
public ITypeSymbol PointedAtType { get; }
public CodeGenerationPointerTypeSymbol(ITypeSymbol pointedAtType)
: base(null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, NullableAnnotation.None)
: base(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, NullableAnnotation.None)
{
this.PointedAtType = pointedAtType;
}
......
......@@ -33,7 +33,7 @@ internal class CodeGenerationPropertySymbol : CodeGenerationSymbol, IPropertySym
ImmutableArray<IParameterSymbol> parametersOpt,
IMethodSymbol getMethod,
IMethodSymbol setMethod)
: base(containingType, attributes, declaredAccessibility, modifiers, name)
: base(containingType?.ContainingAssembly, containingType, attributes, declaredAccessibility, modifiers, name)
{
this.Type = type;
this._refKind = refKind;
......
......@@ -25,12 +25,14 @@ internal abstract class CodeGenerationSymbol : ISymbol
public INamedTypeSymbol ContainingType { get; protected set; }
protected CodeGenerationSymbol(
IAssemblySymbol containingAssembly,
INamedTypeSymbol containingType,
ImmutableArray<AttributeData> attributes,
Accessibility declaredAccessibility,
DeclarationModifiers modifiers,
string name)
{
this.ContainingAssembly = containingAssembly;
this.ContainingType = containingType;
_attributes = attributes.NullToEmpty();
this.DeclaredAccessibility = declaredAccessibility;
......@@ -70,7 +72,7 @@ internal CodeGenerationSymbol WithAdditionalAnnotations(params SyntaxAnnotation[
public virtual ISymbol ContainingSymbol => null;
public IAssemblySymbol ContainingAssembly => null;
public IAssemblySymbol ContainingAssembly { get; }
public static IMethodSymbol ContainingMethod => null;
......
......@@ -30,7 +30,7 @@ internal class CodeGenerationTypeParameterSymbol : CodeGenerationTypeSymbol, ITy
bool hasUnmanagedConstraint,
bool hasNotNullConstraint,
int ordinal)
: base(containingType, attributes, Accessibility.NotApplicable, default, name, SpecialType.None, nullableAnnotation)
: base(containingType?.ContainingAssembly, containingType, attributes, Accessibility.NotApplicable, default, name, SpecialType.None, nullableAnnotation)
{
this.Variance = varianceKind;
this.ConstraintTypes = constraintTypes;
......
......@@ -12,6 +12,7 @@ internal abstract class CodeGenerationTypeSymbol : CodeGenerationNamespaceOrType
public SpecialType SpecialType { get; protected set; }
protected CodeGenerationTypeSymbol(
IAssemblySymbol containingAssembly,
INamedTypeSymbol containingType,
ImmutableArray<AttributeData> attributes,
Accessibility declaredAccessibility,
......@@ -19,7 +20,7 @@ internal abstract class CodeGenerationTypeSymbol : CodeGenerationNamespaceOrType
string name,
SpecialType specialType,
NullableAnnotation nullableAnnotation)
: base(containingType, attributes, declaredAccessibility, modifiers, name)
: base(containingAssembly, containingType, attributes, declaredAccessibility, modifiers, name)
{
this.SpecialType = specialType;
this.NullableAnnotation = nullableAnnotation;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册