-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add analyzer to ensure struct have a valid parameterless constructor
- Loading branch information
Showing
11 changed files
with
136 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
codehelp/CodeHelpers/ParameterlessStructs/Analyzer/ParameterlessStructDetector.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis.Operations; | ||
|
||
namespace WPILib.CodeHelpers.ParameterlessStructs.Analyzer; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class ParameterlessStructDetector : DiagnosticAnalyzer | ||
{ | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create([ | ||
ParameterlessStructDiagnostics.ParameterlessConstructorMissing | ||
]); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.EnableConcurrentExecution(); | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
|
||
context.RegisterOperationAction(AnalyzeFieldOperation, OperationKind.FieldInitializer); | ||
context.RegisterOperationAction(AnalyzePropertyOperation, OperationKind.PropertyInitializer); | ||
} | ||
|
||
private static void AnalyzeFieldOperation(OperationAnalysisContext context) | ||
{ | ||
var fieldInitOperation = (IFieldInitializerOperation)context.Operation; | ||
IFieldSymbol? field = fieldInitOperation.InitializedFields.FirstOrDefault(); | ||
if (field is null || field.IsConst || field.IsStatic || fieldInitOperation.Value is null) | ||
{ | ||
return; | ||
} | ||
|
||
if (field.ContainingType?.TypeKind != TypeKind.Struct) | ||
{ | ||
return; | ||
} | ||
|
||
// If we're here, we have an initializer, check to see if we have a default parameterless constructor | ||
var parameterless = field.ContainingType.InstanceConstructors.Where(x => x.Parameters.IsEmpty).First(); | ||
|
||
if (parameterless.IsImplicitlyDeclared) | ||
{ | ||
ReportDiagnostic(context, fieldInitOperation); | ||
} | ||
} | ||
|
||
private static void AnalyzePropertyOperation(OperationAnalysisContext context) | ||
{ | ||
var propertyInitOperation = (IPropertyInitializerOperation)context.Operation; | ||
IPropertySymbol? property = propertyInitOperation.InitializedProperties.FirstOrDefault(); | ||
if (property is null || property.IsStatic || propertyInitOperation.Value is null) | ||
{ | ||
return; | ||
} | ||
|
||
if (property.ContainingType?.TypeKind != TypeKind.Struct) | ||
{ | ||
return; | ||
} | ||
|
||
// If we're here, we have an initializer, check to see if we have a default parameterless constructor | ||
var parameterless = property.ContainingType.InstanceConstructors.Where(x => x.Parameters.IsEmpty).First(); | ||
|
||
if (parameterless.IsImplicitlyDeclared) | ||
{ | ||
ReportDiagnostic(context, propertyInitOperation); | ||
} | ||
} | ||
|
||
private static void ReportDiagnostic(OperationAnalysisContext context, IOperation symbol) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create(ParameterlessStructDiagnostics.ParameterlessConstructorMissing, symbol.Syntax.GetLocation())); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
codehelp/CodeHelpers/ParameterlessStructs/Analyzer/ParameterlessStructDiagnostics.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace WPILib.CodeHelpers.ParameterlessStructs.Analyzer; | ||
|
||
#pragma warning disable RS2008 // Enable analyzer release tracking | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using WPILib.CodeHelpers; | ||
|
||
public static class ParameterlessStructDiagnostics | ||
{ | ||
public class Ids | ||
{ | ||
public const string Prefix = "WPILIB"; | ||
public const string ParameterlessConstructorMissing = Prefix + "1100"; | ||
} | ||
|
||
private const string Category = "ParameterlessStructs"; | ||
|
||
public static readonly DiagnosticDescriptor ParameterlessConstructorMissing = new( | ||
Ids.ParameterlessConstructorMissing, "Struct has field initializers but no parameterless constructor", "Struct has field initializers but no parameterless constructor", Category, DiagnosticSeverity.Warning, false); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters