-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a suppressor for CS8618 #11601
base: main
Are you sure you want to change the base?
Add a suppressor for CS8618 #11601
Changes from all commits
0bcc8e6
31485a7
8b1f80a
827a89b
bfa08d7
f7dded1
fbbafbb
0ec81ad
d2c4580
c3869e3
864cbbd
c2d51aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Compiler.Analyzers; | ||
|
||
internal static class AnalyzerIDs | ||
{ | ||
internal const string ComponentParameterNullableWarningSuppressionId = "RZS1001"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<root> | ||
<!-- | ||
Microsoft ResX Schema | ||
|
||
Version 2.0 | ||
|
||
The primary goals of this format is to allow a simple XML format | ||
that is mostly human readable. The generation and parsing of the | ||
various data types are done through the TypeConverter classes | ||
associated with the data types. | ||
|
||
Example: | ||
|
||
... ado.net/XML headers & schema ... | ||
<resheader name="resmimetype">text/microsoft-resx</resheader> | ||
<resheader name="version">2.0</resheader> | ||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | ||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||
<value>[base64 mime encoded serialized .NET Framework object]</value> | ||
</data> | ||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | ||
<comment>This is a comment</comment> | ||
</data> | ||
|
||
There are any number of "resheader" rows that contain simple | ||
name/value pairs. | ||
|
||
Each data row contains a name, and value. The row also contains a | ||
type or mimetype. Type corresponds to a .NET class that support | ||
text/value conversion through the TypeConverter architecture. | ||
Classes that don't support this are serialized and stored with the | ||
mimetype set. | ||
|
||
The mimetype is used for serialized objects, and tells the | ||
ResXResourceReader how to depersist the object. This is currently not | ||
extensible. For a given mimetype the value must be set accordingly: | ||
|
||
Note - application/x-microsoft.net.object.binary.base64 is the format | ||
that the ResXResourceWriter will generate, however the reader can | ||
read any of the formats listed below. | ||
|
||
mimetype: application/x-microsoft.net.object.binary.base64 | ||
value : The object must be serialized with | ||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | ||
: and then encoded with base64 encoding. | ||
|
||
mimetype: application/x-microsoft.net.object.soap.base64 | ||
value : The object must be serialized with | ||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||
: and then encoded with base64 encoding. | ||
|
||
mimetype: application/x-microsoft.net.object.bytearray.base64 | ||
value : The object must be serialized into a byte array | ||
: using a System.ComponentModel.TypeConverter | ||
: and then encoded with base64 encoding. | ||
--> | ||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | ||
<xsd:element name="root" msdata:IsDataSet="true"> | ||
<xsd:complexType> | ||
<xsd:choice maxOccurs="unbounded"> | ||
<xsd:element name="metadata"> | ||
<xsd:complexType> | ||
<xsd:sequence> | ||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | ||
</xsd:sequence> | ||
<xsd:attribute name="name" use="required" type="xsd:string" /> | ||
<xsd:attribute name="type" type="xsd:string" /> | ||
<xsd:attribute name="mimetype" type="xsd:string" /> | ||
<xsd:attribute ref="xml:space" /> | ||
</xsd:complexType> | ||
</xsd:element> | ||
<xsd:element name="assembly"> | ||
<xsd:complexType> | ||
<xsd:attribute name="alias" type="xsd:string" /> | ||
<xsd:attribute name="name" type="xsd:string" /> | ||
</xsd:complexType> | ||
</xsd:element> | ||
<xsd:element name="data"> | ||
<xsd:complexType> | ||
<xsd:sequence> | ||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||
</xsd:sequence> | ||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | ||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||
<xsd:attribute ref="xml:space" /> | ||
</xsd:complexType> | ||
</xsd:element> | ||
<xsd:element name="resheader"> | ||
<xsd:complexType> | ||
<xsd:sequence> | ||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||
</xsd:sequence> | ||
<xsd:attribute name="name" type="xsd:string" use="required" /> | ||
</xsd:complexType> | ||
</xsd:element> | ||
</xsd:choice> | ||
</xsd:complexType> | ||
</xsd:element> | ||
</xsd:schema> | ||
<resheader name="resmimetype"> | ||
<value>text/microsoft-resx</value> | ||
</resheader> | ||
<resheader name="version"> | ||
<value>2.0</value> | ||
</resheader> | ||
<resheader name="reader"> | ||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||
</resheader> | ||
<resheader name="writer"> | ||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||
</resheader> | ||
<data name="ComponentParameterNullableWarningSuppressorDescription" xml:space="preserve"> | ||
<value>Suppress CS8618 when a component parameter is marked with Microsoft.AspNetCore.Components.EditorRequiredAttribute</value> | ||
</data> | ||
</root> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Microsoft.CodeAnalysis.Razor.Compiler.Analyzers; | ||
|
||
#pragma warning disable RS1041 // Compiler extensions should be implemented in assemblies targeting netstandard2.0 | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class ComponentParameterNullableWarningSuppressor : DiagnosticSuppressor | ||
{ | ||
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(AnalyzerResources.ComponentParameterNullableWarningSuppressorDescription), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
|
||
//Suppress CS8618: "Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider declaring the {0} as nullable." | ||
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => [ | ||
new SuppressionDescriptor(AnalyzerIDs.ComponentParameterNullableWarningSuppressionId, "CS8618", Description) | ||
]; | ||
|
||
public override void ReportSuppressions(SuppressionAnalysisContext context) | ||
{ | ||
var editorRequiredSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.EditorRequiredAttribute"); | ||
var parameterSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.ParameterAttribute"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we bail out if this is |
||
if (parameterSymbol is null || editorRequiredSymbol is null) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var diagnostic in context.ReportedDiagnostics) | ||
{ | ||
var node = diagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); | ||
if (node is PropertyDeclarationSyntax propertySyntax && propertySyntax.AttributeLists.Any()) | ||
{ | ||
var symbol = context.GetSemanticModel(propertySyntax.SyntaxTree).GetDeclaredSymbol(propertySyntax, context.CancellationToken); | ||
if (IsValidEditorRequiredParameter(symbol)) | ||
{ | ||
context.ReportSuppression(Suppression.Create(SupportedSuppressions[0], diagnostic)); | ||
} | ||
} | ||
} | ||
|
||
bool IsValidEditorRequiredParameter(ISymbol? symbol) | ||
{ | ||
// public instance property, with a public setter | ||
if (symbol is not IPropertySymbol { DeclaredAccessibility: Accessibility.Public, IsStatic: false, SetMethod: not null and { DeclaredAccessibility: Accessibility.Public } }) | ||
{ | ||
return false; | ||
} | ||
|
||
// has both [Parameter] and [EditorRequired] attributes | ||
bool hasParameter = false, hasRequired = false; | ||
foreach (var attribute in symbol.GetAttributes()) | ||
{ | ||
if (!hasParameter && SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, parameterSymbol)) | ||
{ | ||
hasParameter = true; | ||
if (hasRequired) | ||
{ | ||
break; | ||
} | ||
continue; | ||
} | ||
|
||
if (!hasRequired && SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, editorRequiredSymbol)) | ||
{ | ||
hasRequired = true; | ||
if (hasParameter) | ||
{ | ||
break; | ||
} | ||
continue; | ||
} | ||
} | ||
return hasParameter && hasRequired; | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BOM? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it was missing the BOM and this adds it back. |
||
|
||
<PropertyGroup> | ||
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains the Razor compiler.</Description> | ||
|
@@ -24,6 +24,7 @@ | |
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<EmbeddedResource Update="Analyzers\*.resx" Namespace="Microsoft.CodeAnalysis.Razor.Compiler.Analyzers" /> | ||
<EmbeddedResource Update="CSharp\*.resx" Namespace="Microsoft.CodeAnalysis.Razor" /> | ||
<EmbeddedResource Update="Language\*.resx" Namespace="Microsoft.AspNetCore.Razor.Language" /> | ||
<EmbeddedResource Update="Mvc\*.resx" Namespace="Microsoft.AspNetCore.Mvc.Razor.Extensions" /> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple Qs:
null
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added an early return if we can't find the types, and a test to show behavior in the presence of duplicate attributes.