diff --git a/docs/Rules/MA0067.md b/docs/Rules/MA0067.md index 5b540ab4..1df9b404 100644 --- a/docs/Rules/MA0067.md +++ b/docs/Rules/MA0067.md @@ -5,7 +5,9 @@ Sources: [UseGuidEmptyAnalyzer.cs](https://github.com/meziantou/Meziantou.Analyz ````csharp _ = new Guid(); // non-compliant -_ = default(Guid); // non-compliant +_ = new Guid("00000000-0000-0000-0000-000000000000"); // non-compliant +_ = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // non-compliant +_ = Guid.Parse("{00000000-0000-0000-0000-000000000000}"); // non-compliant _ = Guid.Empty; // compliant ```` diff --git a/src/Meziantou.Analyzer/Rules/UseGuidEmptyAnalyzer.cs b/src/Meziantou.Analyzer/Rules/UseGuidEmptyAnalyzer.cs index dfd16568..b77f35f0 100644 --- a/src/Meziantou.Analyzer/Rules/UseGuidEmptyAnalyzer.cs +++ b/src/Meziantou.Analyzer/Rules/UseGuidEmptyAnalyzer.cs @@ -28,17 +28,67 @@ public override void Initialize(AnalysisContext context) context.RegisterCompilationStartAction(compilationContext => { - compilationContext.RegisterOperationAction(AnalyzeObjectCreationOperation, OperationKind.ObjectCreation); + var guidType = compilationContext.Compilation.GetBestTypeByMetadataName("System.Guid"); + if (guidType is null) + return; + + compilationContext.RegisterOperationAction(ctx => AnalyzeObjectCreationOperation(ctx, guidType), OperationKind.ObjectCreation); + compilationContext.RegisterOperationAction(ctx => AnalyzeInvocationOperation(ctx, guidType), OperationKind.Invocation); }); } - private static void AnalyzeObjectCreationOperation(OperationAnalysisContext context) + private static void AnalyzeObjectCreationOperation(OperationAnalysisContext context, INamedTypeSymbol guidType) { var operation = (IObjectCreationOperation)context.Operation; - var guidType = context.Compilation.GetBestTypeByMetadataName("System.Guid"); - if (operation.Type.IsEqualTo(guidType) && operation.Arguments.Length == 0) + + if (operation.Constructor is null || !operation.Constructor.ContainingType.IsEqualTo(guidType)) + return; + + if (operation.Arguments.Length == 0) + { + context.ReportDiagnostic(Rule, operation); + return; + } + + if (operation.Arguments is [{ Value.Type.SpecialType: SpecialType.System_String, Value.ConstantValue: { HasValue: true, Value: string value } }]) + { + if (System.Guid.TryParse(value, out var guid) && guid == System.Guid.Empty) + { + context.ReportDiagnostic(Rule, operation); + } + + return; + } + + if (operation.Arguments.Length == 11 && IsAllZero(operation.Arguments)) { context.ReportDiagnostic(Rule, operation); } } + + private static bool IsAllZero(ImmutableArray arguments) + { + foreach (var argument in arguments) + { + if (!argument.Value.ConstantValue.HasValue || !NumericHelpers.IsZero(argument.Value.ConstantValue.Value)) + return false; + } + + return true; + } + + private static void AnalyzeInvocationOperation(OperationAnalysisContext context, INamedTypeSymbol guidType) + { + var invocation = (IInvocationOperation)context.Operation; + if (!invocation.TargetMethod.ContainingType.IsEqualTo(guidType)) + return; + + if (invocation is { TargetMethod.Name: "Parse", Arguments: [{ Value.Type.SpecialType: SpecialType.System_String, Value.ConstantValue: { HasValue: true, Value: string value } }] }) + { + if (System.Guid.TryParse(value, out var guid) && guid == System.Guid.Empty) + { + context.ReportDiagnostic(Rule, invocation); + } + } + } } diff --git a/tests/Meziantou.Analyzer.Test/Rules/UseGuidEmptyAnalyzerTests.cs b/tests/Meziantou.Analyzer.Test/Rules/UseGuidEmptyAnalyzerTests.cs index ee17c659..49c844d0 100644 --- a/tests/Meziantou.Analyzer.Test/Rules/UseGuidEmptyAnalyzerTests.cs +++ b/tests/Meziantou.Analyzer.Test/Rules/UseGuidEmptyAnalyzerTests.cs @@ -14,6 +14,15 @@ private static ProjectBuilder CreateProjectBuilder() [Theory] [InlineData("new System.Guid()")] + [InlineData("new System.Guid(\"00000000-0000-0000-0000-000000000000\")")] + [InlineData("new System.Guid(\"{00000000-0000-0000-0000-000000000000}\")")] + [InlineData("new System.Guid(\"00000000000000000000000000000000\")")] + [InlineData("new System.Guid(\"(00000000-0000-0000-0000-000000000000)\")")] + [InlineData("new System.Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)")] + [InlineData("System.Guid.Parse(\"00000000-0000-0000-0000-000000000000\")")] + [InlineData("System.Guid.Parse(\"{00000000-0000-0000-0000-000000000000}\")")] + [InlineData("System.Guid.Parse(\"00000000000000000000000000000000\")")] + [InlineData("System.Guid.Parse(\"(00000000-0000-0000-0000-000000000000)\")")] public async Task ShouldReportError(string code) { await CreateProjectBuilder() @@ -40,6 +49,9 @@ void Test() [Theory] [InlineData("new System.Guid(\"\")")] + [InlineData("new System.Guid(\"10752bc4-c151-50f5-f27b-df92d8af5a61\")")] + [InlineData("System.Guid.Parse(\"10752bc4-c151-50f5-f27b-df92d8af5a61\")")] + [InlineData("new System.Guid(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)")] public async Task ShouldNotReportError(string code) { await CreateProjectBuilder()