In my recent work on the dotnet/roslyn repository, I addressed an issue related to the handling of the readonly
keyword for structs. The Roslyn repository is the home of the .NET Compiler Platform, which provides open-source C# and Visual Basic compilers with rich code analysis APIs.
The problem was identified in issue #65834, titled "The DeclarationModifiers class does not properly handle readonly keyword for struct". The existing code was:
var field = symbol as IFieldSymbol;
var property = symbol as IPropertySymbol;
var method = symbol as IMethodSymbol;
var type = symbol as INamedTypeSymbol;
return new DeclarationModifiers(
isStatic: symbol.IsStatic,
isAbstract: symbol.IsAbstract,
isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true,
The issue was that DeclarationModifiers.From(...) was used not just for fields and properties but also for SymbolKind.NamedType with TypeKind.Class and TypeKind.Struct.
To solve this issue, I extended the initialization of isReadOnly in DeclarationModifiers.From to handle the case when ISymbol is a type declaration. Here's the code change I made:
var field = symbol as IFieldSymbol;
var property = symbol as IPropertySymbol;
var method = symbol as IMethodSymbol;
var type = symbol as INamedTypeSy
return new DeclarationModifiers(
isStatic: symbol.IsStatic,
isAbstract: symbol.IsAbstract,
isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true,
isVirtual: symbol.IsVirtual,
isOverride: symbol.IsOverride,
isSealed: symbol.IsSealed,
isConst: field?.IsConst == true,
isUnsafe: symbol.RequiresUnsafeModifier(),
isVolatile: field?.IsVolatile == true,
isExtern: symbol.IsExtern,
isAsync: method?.IsAsync == true,
isRequired: symbol.IsRequired(),
isFile: (symbol as INamedTypeSymbol)?.IsFileLocal == true
);
}
var field = symbol as IFieldSymbol;
var property = symbol as IPropertySymbol;
var method = symbol as IMethodSymbol;
var type = symbol as INamedType
return new DeclarationModifiers(
isStatic: symbol.IsStatic,
isAbstract: symbol.IsAbstract,
isReadOnly: field?.IsReadOnly == true || property?.IsReadOnly == true || type?.IsReadOnly == true || method?.IsReadOnly == true,
isVirtual: symbol.IsVirtual,
isOverride: symbol.IsOverride,
isSealed: symbol.IsSealed,
isConst: field?.IsConst == true,
isUnsafe: symbol.RequiresUnsafeModifier(),
isVolatile: field?.IsVolatile == true,
isExtern: symbol.IsExtern,
isAsync: method?.IsAsync == true,
isRequired: symbol.IsRequired(),
isFile: (symbol as INamedTypeSymbol)?.IsFileLocal == true
);
}
This change ensures that the readonly keyword is correctly handled for structs, improving the accuracy of the code generation.