From 8a4bdabe607d70ee57b7e8ac05db8b6d85654d7f Mon Sep 17 00:00:00 2001 From: "Koban, Ralf" Date: Sun, 8 Aug 2021 07:37:01 +0000 Subject: [PATCH 1/3] MiKo_3105 enhanced - Assert.IsNotInstanceOf - Assert.IsAssignableFrom - Assert.IsNotAssignableFrom - StringAssert.AreNotEqualIgnoringCase - StringAssert.IsMatch - StringAssert.DoesNotMatch --- .../Helpers/DiagnosticVerifier.Helper.cs | 55 ++++----- ...5_TestMethodsUseAssertThatAnalyzerTests.cs | 27 +++++ .../MaintainabilityCodeFixProvider.cs | 18 +++ .../MiKo_3105_CodeFixProvider.cs | 107 ++++++++++++++---- 4 files changed, 157 insertions(+), 50 deletions(-) diff --git a/MiKo.Analyzer.Tests/Helpers/DiagnosticVerifier.Helper.cs b/MiKo.Analyzer.Tests/Helpers/DiagnosticVerifier.Helper.cs index d29efc631..8e6bd8790 100644 --- a/MiKo.Analyzer.Tests/Helpers/DiagnosticVerifier.Helper.cs +++ b/MiKo.Analyzer.Tests/Helpers/DiagnosticVerifier.Helper.cs @@ -6,6 +6,7 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.Serialization; +using System.Text.RegularExpressions; using System.Windows.Input; using Microsoft.AspNetCore.Mvc.ModelBinding; @@ -36,7 +37,9 @@ public abstract partial class DiagnosticVerifier private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location); private static readonly MetadataReference SystemCompositionReference = MetadataReference.CreateFromFile(typeof(ImportAttribute).Assembly.Location); + private static readonly MetadataReference SystemLinqReference = MetadataReference.CreateFromFile(typeof(Expression).Assembly.Location); private static readonly MetadataReference SystemRuntimeReference = MetadataReference.CreateFromFile(typeof(DataContractAttribute).Assembly.Location); // needed also for other attributes + private static readonly MetadataReference SystemTextReference = MetadataReference.CreateFromFile(typeof(Regex).Assembly.Location); private static readonly MetadataReference SystemWindowsInputReference = MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location); private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); @@ -47,13 +50,13 @@ public abstract partial class DiagnosticVerifier private static readonly MetadataReference AttributeTargetsReference = MetadataReference.CreateFromFile(typeof(AttributeTargets).Assembly.Location); private static readonly MetadataReference DescriptionAttributeReference = MetadataReference.CreateFromFile(typeof(DescriptionAttribute).Assembly.Location); private static readonly MetadataReference AspNetCoreMvcAbstractionsReference = MetadataReference.CreateFromFile(typeof(IModelBinder).Assembly.Location); - private static readonly MetadataReference ExpressionsReference = MetadataReference.CreateFromFile(typeof(Expression).Assembly.Location); /// /// Avoids error CS0012: The type 'MulticastDelegate' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.} /// Needed by some tests as the code references types from .NET standard 2.0. /// private static readonly MetadataReference NetStandardReference = MetadataReference.CreateFromFile(Assembly.Load("netstandard, Version=2.0.0.0").Location); + private static readonly MetadataReference SystemRuntimeNetStandardReference = MetadataReference.CreateFromFile(Assembly.Load("System.Runtime, Version=0.0.0.0").Location); /// @@ -115,12 +118,12 @@ protected static Document CreateDocument(string source, string language = Langua } /// - /// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. + /// Given classes in the form of strings, their language, and an to apply to it, return the diagnostics found in the string after converting it to a document. /// /// Classes in the form of strings. /// The language the source classes are in. /// The analyzer to be run on the sources. - /// An array of Diagnostics that surfaced in the source code, sorted by Location. + /// An array of s that surfaced in the source code, sorted by . private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) { return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); @@ -130,18 +133,18 @@ private static Diagnostic[] GetSortedDiagnostics(string[] sources, string langua /// Sort diagnostics by location in source document. /// /// The list of Diagnostics to be sorted. - /// An IEnumerable containing the Diagnostics in order of Location. + /// An array of s in order of . private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) { return diagnostics.OrderBy(_ => _.Location.SourceSpan.Start).ToArray(); } /// - /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. + /// Given an array of strings as sources and a language, turn them into a project and return the documents. /// /// Classes in the form of strings. /// The language the source code is in. - /// A Tuple containing the Documents produced from the sources and their TextSpans if relevant. + /// The s produced from the sources. private static Document[] GetDocuments(string[] sources, string language) { if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) @@ -173,26 +176,26 @@ private static Project CreateProject(string[] sources, string language = Languag var projectId = ProjectId.CreateNewId(debugName: TestProjectName); - var solution = new AdhocWorkspace() - .CurrentSolution - .AddProject(projectId, TestProjectName, TestProjectName, language) - .AddMetadataReference(projectId, CorlibReference) - .AddMetadataReference(projectId, SystemCoreReference) - .AddMetadataReference(projectId, SystemCompositionReference) - .AddMetadataReference(projectId, SystemRuntimeReference) - .AddMetadataReference(projectId, SystemWindowsInputReference) - .AddMetadataReference(projectId, AttributeReference) - .AddMetadataReference(projectId, AttributeTargetsReference) - .AddMetadataReference(projectId, DescriptionAttributeReference) - .AddMetadataReference(projectId, AspNetCoreMvcAbstractionsReference) - .AddMetadataReference(projectId, CSharpSymbolsReference) - .AddMetadataReference(projectId, CodeAnalysisReference) - .AddMetadataReference(projectId, NUnitReference) - .AddMetadataReference(projectId, MiKoAnalyzersReference) - .AddMetadataReference(projectId, MiKoAnalyzersTestsReference) - .AddMetadataReference(projectId, NetStandardReference) - .AddMetadataReference(projectId, SystemRuntimeNetStandardReference) - .AddMetadataReference(projectId, ExpressionsReference); + var solution = new AdhocWorkspace().CurrentSolution + .AddProject(projectId, TestProjectName, TestProjectName, language) + .AddMetadataReference(projectId, CorlibReference) + .AddMetadataReference(projectId, SystemCoreReference) + .AddMetadataReference(projectId, SystemCompositionReference) + .AddMetadataReference(projectId, SystemRuntimeReference) + .AddMetadataReference(projectId, SystemWindowsInputReference) + .AddMetadataReference(projectId, AttributeReference) + .AddMetadataReference(projectId, AttributeTargetsReference) + .AddMetadataReference(projectId, DescriptionAttributeReference) + .AddMetadataReference(projectId, AspNetCoreMvcAbstractionsReference) + .AddMetadataReference(projectId, CSharpSymbolsReference) + .AddMetadataReference(projectId, CodeAnalysisReference) + .AddMetadataReference(projectId, NUnitReference) + .AddMetadataReference(projectId, MiKoAnalyzersReference) + .AddMetadataReference(projectId, MiKoAnalyzersTestsReference) + .AddMetadataReference(projectId, NetStandardReference) + .AddMetadataReference(projectId, SystemRuntimeNetStandardReference) + .AddMetadataReference(projectId, SystemLinqReference) + .AddMetadataReference(projectId, SystemTextReference); var count = 0; foreach (var source in sources) diff --git a/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs b/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs index d06ebc94f..565f2d9e9 100644 --- a/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs +++ b/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs @@ -438,6 +438,9 @@ public void DoSomething() [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => StringAssert.AreEqualIgnoringCase(""abc"", s, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => Assert.That(s, Is.EqualTo(""abc"").IgnoreCase, ""my message""); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => StringAssert.AreNotEqualIgnoringCase(""abc"", s, ""my message""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => Assert.That(s, Is.Not.EqualTo(""abc"").IgnoreCase, ""my message""); }")] [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => CollectionAssert.IsSubsetOf(""abc"", s, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(string s) => Assert.That(s, Is.SubsetOf(""abc""), ""my message""); }")] @@ -456,6 +459,12 @@ public void DoSomething() [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.IsInstanceOf(o, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.InstanceOf(), ""my message""); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.IsNotInstanceOf(typeof(object), o, ""my message""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.InstanceOf(), ""my message""); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.IsNotInstanceOf(o, ""my message""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.InstanceOf(), ""my message""); }")] [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable e) => CollectionAssert.IsOrdered(e, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable e) => Assert.That(e, Is.Ordered, ""my message""); }")] @@ -533,6 +542,24 @@ public void DoSomething() [TestCase( "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.Positive(i); }", "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Positive); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.IsAssignableFrom(typeof(object), new object()); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(new object(), Is.AssignableFrom()); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.IsAssignableFrom(new object()); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(new object(), Is.AssignableFrom()); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.IsNotAssignableFrom(typeof(object), new object()); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(new object(), Is.Not.AssignableFrom()); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.IsNotAssignableFrom(new object()); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(new object(), Is.Not.AssignableFrom()); }")] + [TestCase( + @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => StringAssert.IsMatch(""some pattern"", ""actual""); }", + @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(""actual"", Does.Match(""some pattern"")); }")] + [TestCase( + @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => StringAssert.DoesNotMatch(""some pattern"", ""actual""); }", + @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(""actual"", Does.Not.Match(""some pattern"")); }")] public void Code_gets_fixed_(string originalCode, string fixedCode) => VerifyCSharpFix(originalCode, fixedCode); [Test] diff --git a/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs index 61e0da423..5d5d283f3 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs @@ -34,6 +34,14 @@ protected static InvocationExpressionSyntax CreateInvocationSyntax(string typeNa return CreateInvocationSyntax(member); } + protected static InvocationExpressionSyntax CreateInvocationSyntax(string typeName, string propertyName, string methodName, params TypeSyntax[] items) + { + // that's for the method call + var member = CreateSimpleMemberAccessExpressionSyntax(typeName, propertyName, methodName, items); + + return CreateInvocationSyntax(member); + } + protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, string methodName) { var type = SyntaxFactory.IdentifierName(typeName); @@ -57,6 +65,16 @@ protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpression return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, type, method); } + protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, string middlePart, string methodName, TypeSyntax[] items) + { + var type = SyntaxFactory.IdentifierName(typeName); + var method = SyntaxFactory.GenericName(methodName).AddTypeArgumentListArguments(items); + + var expression = CreateSimpleMemberAccessExpressionSyntax(type, middlePart); + + return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, method); + } + protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, params string[] methodNames) { var start = CreateSimpleMemberAccessExpressionSyntax(typeName, methodNames[0]); diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs index 46bddc4a8..c505daab5 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs @@ -43,6 +43,10 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn break; } + + // TODO RKN + // case "FileAssert": + // case "DirectoryAssert": } } @@ -51,6 +55,14 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpressionSyntax syntax, SeparatedSyntaxList args) { + // TODO RKN + // Assert.DoesNotThrow + // Assert.DoesNotThrowAsync + // CollectionAssert.AllItemsAreInstancesOfType + // FileAssert.Exists + // FileAssert.DoesNotExist + // DirectoryAssert.Exists + // DirectoryAssert.DoesNotExist var methodName = syntax.GetName(); switch (methodName) { @@ -60,22 +72,28 @@ private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpre case "AreEqualIgnoringCase": return FixAreEqualIgnoringCase(args); case "AreEquivalent": return FixAreEquivalent(args); case "AreNotEqual": return FixAreNotEqual(args); + case "AreNotEqualIgnoringCase": return FixAreNotEqualIgnoringCase(args); case "AreNotEquivalent": return FixAreNotEquivalent(args); case "AreNotSame": return FixAreNotSame(args); case "AreSame": return FixAreSame(args); case "Contains": return FixContains(typeName, args); case "DoesNotContain": return FixDoesNotContain(typeName, args); + case "DoesNotMatch": return FixStringAssertDoesNotMatch(args); case "DoesNotEndWith": return FixDoesNotEndWith(args); case "DoesNotStartWith": return FixDoesNotStartWith(args); case "EndsWith": return FixEndsWith(args); case "False": return FixIsFalse(args); case "Greater": return FixGreater(args); case "GreaterOrEqual": return FixGreaterOrEqual(args); + case "IsAssignableFrom": return FixIsAssignableFrom(args, syntax.Name); case "IsEmpty": return FixIsEmpty(args); case "IsFalse": return FixIsFalse(args); case "IsInstanceOf": return FixIsInstanceOf(args, syntax.Name); + case "IsMatch": return FixStringAssertIsMatch(args); case "IsNaN": return FixIsNaN(args); + case "IsNotAssignableFrom": return FixIsNotAssignableFrom(args, syntax.Name); case "IsNotEmpty": return FixIsNotEmpty(args); + case "IsNotInstanceOf": return FixIsNotInstanceOf(args, syntax.Name); case "IsNotNull": return FixIsNotNull(args); case "IsNotSubsetOf": return FixIsNotSubsetOf(args); case "IsNotSupersetOf": return FixIsNotSupersetOf(args); @@ -87,10 +105,10 @@ private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpre case "IsTrue": return FixIsTrue(args); case "Less": return FixLess(args); case "LessOrEqual": return FixLessOrEqual(args); - case "Positive": return FixPositive(args); case "Negative": return FixNegative(args); case "NotNull": return FixNotNull(args); case "NotZero": return FixNotZero(args); + case "Positive": return FixPositive(args); case "StartsWith": return FixStartsWith(args); case "True": return FixIsTrue(args); case "Zero": return FixZero(args); @@ -164,6 +182,8 @@ private static InvocationExpressionSyntax FixAreEqualOrSame(SeparatedSyntaxList< private static InvocationExpressionSyntax FixAreNotEqual(SeparatedSyntaxList args) => FixAreNotEqualOrSame(args, "EqualTo"); + private static InvocationExpressionSyntax FixAreNotEqualIgnoringCase(SeparatedSyntaxList args) => AssertThat(args[1], Is("Not", "EqualTo", args[0], "IgnoreCase"), 2, args); + private static InvocationExpressionSyntax FixAreNotEqualOrSame(SeparatedSyntaxList args, string call) { var arg0 = args[0]; @@ -247,24 +267,54 @@ private static InvocationExpressionSyntax FixIsFalse(SeparatedSyntaxList args, SimpleNameSyntax name) + private static InvocationExpressionSyntax FixIsAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("AssignableFrom", args, name); + + private static InvocationExpressionSyntax FixIsNotAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("AssignableFrom", args, name); + + private static InvocationExpressionSyntax FixIsInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("InstanceOf", args, name); + + private static InvocationExpressionSyntax FixIsNotInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("InstanceOf", args, name); + + private static InvocationExpressionSyntax FixGenericIs(string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) + { + var arg0 = args[0]; + + if (name is GenericNameSyntax gns) + { + return AssertThat(arg0, Is(methodName, gns.TypeArgumentList.Arguments.ToArray()), 1, args); + } + + if (arg0.Expression is TypeOfExpressionSyntax t) + { + return AssertThat(args[1], Is(methodName, new[] { t.Type }), 2, args); + } + + // TODO: this code is not tested as the case does not exist + return AssertThat(arg0, Is(methodName), 1, args); + } + + private static InvocationExpressionSyntax FixGenericIsNot(string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) { var arg0 = args[0]; if (name is GenericNameSyntax gns) { - return AssertThat(arg0, Is("InstanceOf", gns.TypeArgumentList.Arguments.ToArray()), 1, args); + return AssertThat(arg0, Is("Not", methodName, gns.TypeArgumentList.Arguments.ToArray()), 1, args); } if (arg0.Expression is TypeOfExpressionSyntax t) { - return AssertThat(args[1], Is("InstanceOf", new[] { t.Type }), 2, args); + return AssertThat(args[1], Is("Not", methodName, new[] { t.Type }), 2, args); } // TODO: this code is not tested as the case does not exist - return AssertThat(arg0, Is("InstanceOf"), 1, args); + return AssertThat(arg0, Is("Not", methodName), 1, args); } + private static InvocationExpressionSyntax FixStringAssertIsMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Match", args[0]), 2, args); + + private static InvocationExpressionSyntax FixStringAssertDoesNotMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "Match", args[0]), 2, args); + private static InvocationExpressionSyntax FixIsOrdered(SeparatedSyntaxList args) => AssertThat(args[0], Is("Ordered"), 1, args); private static InvocationExpressionSyntax FixIsNaN(SeparatedSyntaxList args) => AssertThat(args[0], Is("NaN"), 1, args); @@ -337,7 +387,7 @@ private static InvocationExpressionSyntax FixIsTrue(SeparatedSyntaxList args) => AssertThat(args[0], Is("Zero"), 1, args); private static InvocationExpressionSyntax AssertThat(ExpressionSyntax expression, ArgumentSyntax constraint, int skip, SeparatedSyntaxList arguments) - => AssertThat(SyntaxFactory.Argument(expression), constraint, skip, arguments); + => AssertThat(Argument(expression), constraint, skip, arguments); private static InvocationExpressionSyntax AssertThat(ArgumentSyntax argument, ArgumentSyntax constraint, int skip, SeparatedSyntaxList arguments) { @@ -355,17 +405,31 @@ private static InvocationExpressionSyntax AssertThat(ArgumentSyntax argument, Ar private static InvocationExpressionSyntax AssertThat(params ArgumentSyntax[] arguments) => CreateInvocationSyntax("Assert", "That", arguments); - private static ArgumentSyntax Is(string name) => SyntaxFactory.Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name)); + private static ArgumentSyntax Is(string name) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name)); + + private static ArgumentSyntax Is(string name, ArgumentSyntax argument) => Argument(InvocationIs(name, argument)); - private static ArgumentSyntax Is(string name, ArgumentSyntax argument) => SyntaxFactory.Argument(InvocationIs(name, argument)); + private static ArgumentSyntax Is(string name, ExpressionSyntax expression) => Is(name, Argument(expression)); - private static ArgumentSyntax Is(string name, ExpressionSyntax expression) => Is(name, SyntaxFactory.Argument(expression)); + private static ArgumentSyntax Is(string name, TypeSyntax[] items) => Argument(CreateInvocationSyntax("Is", name, items)); - private static ArgumentSyntax Is(string name, TypeSyntax[] items) => SyntaxFactory.Argument(CreateInvocationSyntax("Is", name, items)); + private static ArgumentSyntax Is(string name, string name1, TypeSyntax[] items) => Argument(CreateInvocationSyntax("Is", name, name1, items)); + + private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name, name1), argument); + + private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument, string name2) + { + var expression = CreateSimpleMemberAccessExpressionSyntax("Is", name, name1); + var invocation = CreateInvocationSyntax(expression, argument); + + return Argument(CreateSimpleMemberAccessExpressionSyntax(invocation, name2)); + } - private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument) + private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string name1) { - return Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name, name1), argument); + var expression = InvocationIs(name, argument); + + return Argument(CreateSimpleMemberAccessExpressionSyntax(expression, name1)); } private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string name1, ArgumentSyntax argument1) @@ -376,29 +440,24 @@ private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string na return Argument(appendixCall, argument1); } - private static ArgumentSyntax Is(string name, string name1, ExpressionSyntax expression) => Is(name, name1, SyntaxFactory.Argument(expression)); - - private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string name1) - { - var expression = InvocationIs(name, argument); - - return SyntaxFactory.Argument(CreateSimpleMemberAccessExpressionSyntax(expression, name1)); - } + private static ArgumentSyntax Is(string name, string name1, ExpressionSyntax expression) => Is(name, name1, Argument(expression)); - private static ArgumentSyntax Is(params string[] names) => SyntaxFactory.Argument(CreateSimpleMemberAccessExpressionSyntax("Is", names)); + private static ArgumentSyntax Is(params string[] names) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", names)); private static InvocationExpressionSyntax InvocationIs(string name, ArgumentSyntax argument) => CreateInvocationSyntax("Is", name, argument); - private static ArgumentSyntax Does(string name, ArgumentSyntax argument) => SyntaxFactory.Argument(CreateInvocationSyntax("Does", name, argument)); + private static ArgumentSyntax Does(string name, ArgumentSyntax argument) => Argument(CreateInvocationSyntax("Does", name, argument)); private static ArgumentSyntax Does(string name, string name1, ArgumentSyntax argument) { return Argument(CreateSimpleMemberAccessExpressionSyntax("Does", name, name1), argument); } - private static ArgumentSyntax Does(params string[] names) => SyntaxFactory.Argument(CreateSimpleMemberAccessExpressionSyntax("Does", names)); + private static ArgumentSyntax Does(params string[] names) => Argument(CreateSimpleMemberAccessExpressionSyntax("Does", names)); + + private static ArgumentSyntax Argument(ExpressionSyntax expression) => SyntaxFactory.Argument(expression); - private static ArgumentSyntax Argument(MemberAccessExpressionSyntax expression, ArgumentSyntax argument) => SyntaxFactory.Argument(CreateInvocationSyntax(expression, argument)); + private static ArgumentSyntax Argument(MemberAccessExpressionSyntax expression, ArgumentSyntax argument) => Argument(CreateInvocationSyntax(expression, argument)); private static bool IsNumeric(ArgumentSyntax argument) => argument.Expression.IsKind(SyntaxKind.NumericLiteralExpression) || (argument.Expression is MemberAccessExpressionSyntax mae && mae.Expression.IsKind(SyntaxKind.PredefinedType)); From 08d40d0ce9fd9de679ff79388b0c2465a67f1e6a Mon Sep 17 00:00:00 2001 From: "Koban, Ralf" Date: Sun, 8 Aug 2021 07:50:41 +0000 Subject: [PATCH 2/3] refactoring --- .../MaintainabilityCodeFixProvider.cs | 58 +++--- .../MiKo_3020_CodeFixProvider.cs | 2 +- .../MiKo_3032_CodeFixProvider.cs | 12 +- .../MiKo_3103_CodeFixProvider.cs | 2 +- .../MiKo_3105_CodeFixProvider.cs | 187 +++++++++--------- 5 files changed, 129 insertions(+), 132 deletions(-) diff --git a/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs index 5d5d283f3..9b6da708c 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MaintainabilityCodeFixProvider.cs @@ -7,42 +7,46 @@ namespace MiKoSolutions.Analyzers.Rules.Maintainability { public abstract class MaintainabilityCodeFixProvider : MiKoCodeFixProvider { - protected static ArgumentListSyntax CreateArgumentList(params ArgumentSyntax[] arguments) => SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments)); + protected static ArgumentSyntax Argument(ExpressionSyntax expression) => SyntaxFactory.Argument(expression); - protected static InvocationExpressionSyntax CreateInvocationSyntax(MemberAccessExpressionSyntax member, params ArgumentSyntax[] arguments) + protected static ArgumentSyntax Argument(MemberAccessExpressionSyntax expression, ArgumentSyntax argument) => Argument(Invocation(expression, argument)); + + protected static ArgumentListSyntax ArgumentList(params ArgumentSyntax[] arguments) => SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments)); + + protected static InvocationExpressionSyntax Invocation(MemberAccessExpressionSyntax member, params ArgumentSyntax[] arguments) { // that's for the argument - var argumentList = CreateArgumentList(arguments); + var argumentList = ArgumentList(arguments); // combine both to complete call return SyntaxFactory.InvocationExpression(member, argumentList); } - protected static InvocationExpressionSyntax CreateInvocationSyntax(string typeName, string methodName, params ArgumentSyntax[] arguments) + protected static InvocationExpressionSyntax Invocation(string typeName, string methodName, params ArgumentSyntax[] arguments) { // that's for the method call - var member = CreateSimpleMemberAccessExpressionSyntax(typeName, methodName); + var member = SimpleMemberAccess(typeName, methodName); - return CreateInvocationSyntax(member, arguments); + return Invocation(member, arguments); } - protected static InvocationExpressionSyntax CreateInvocationSyntax(string typeName, string methodName, params TypeSyntax[] items) + protected static InvocationExpressionSyntax Invocation(string typeName, string methodName, params TypeSyntax[] items) { // that's for the method call - var member = CreateSimpleMemberAccessExpressionSyntax(typeName, methodName, items); + var member = SimpleMemberAccess(typeName, methodName, items); - return CreateInvocationSyntax(member); + return Invocation(member); } - protected static InvocationExpressionSyntax CreateInvocationSyntax(string typeName, string propertyName, string methodName, params TypeSyntax[] items) + protected static InvocationExpressionSyntax Invocation(string typeName, string propertyName, string methodName, params TypeSyntax[] items) { // that's for the method call - var member = CreateSimpleMemberAccessExpressionSyntax(typeName, propertyName, methodName, items); + var member = SimpleMemberAccess(typeName, propertyName, methodName, items); - return CreateInvocationSyntax(member); + return Invocation(member); } - protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, string methodName) + protected static MemberAccessExpressionSyntax SimpleMemberAccess(string typeName, string methodName) { var type = SyntaxFactory.IdentifierName(typeName); var method = SyntaxFactory.IdentifierName(methodName); @@ -50,14 +54,14 @@ protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpression return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, type, method); } - protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(ExpressionSyntax syntax, string name) + protected static MemberAccessExpressionSyntax SimpleMemberAccess(ExpressionSyntax syntax, string name) { var identifierName = SyntaxFactory.IdentifierName(name); return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, syntax, identifierName); } - protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, string methodName, TypeSyntax[] items) + protected static MemberAccessExpressionSyntax SimpleMemberAccess(string typeName, string methodName, TypeSyntax[] items) { var type = SyntaxFactory.IdentifierName(typeName); var method = SyntaxFactory.GenericName(methodName).AddTypeArgumentListArguments(items); @@ -65,46 +69,46 @@ protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpression return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, type, method); } - protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, string middlePart, string methodName, TypeSyntax[] items) + protected static MemberAccessExpressionSyntax SimpleMemberAccess(string typeName, string middlePart, string methodName, TypeSyntax[] items) { var type = SyntaxFactory.IdentifierName(typeName); var method = SyntaxFactory.GenericName(methodName).AddTypeArgumentListArguments(items); - var expression = CreateSimpleMemberAccessExpressionSyntax(type, middlePart); + var expression = SimpleMemberAccess(type, middlePart); return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, method); } - protected static MemberAccessExpressionSyntax CreateSimpleMemberAccessExpressionSyntax(string typeName, params string[] methodNames) + protected static MemberAccessExpressionSyntax SimpleMemberAccess(string typeName, params string[] methodNames) { - var start = CreateSimpleMemberAccessExpressionSyntax(typeName, methodNames[0]); + var start = SimpleMemberAccess(typeName, methodNames[0]); - var result = methodNames.Skip(1).Aggregate(start, CreateSimpleMemberAccessExpressionSyntax); + var result = methodNames.Skip(1).Aggregate(start, SimpleMemberAccess); return result; } - protected static InvocationExpressionSyntax CreateNameofExpression(string identifierName) + protected static InvocationExpressionSyntax NameOf(string identifierName) { var syntax = SyntaxFactory.IdentifierName(identifierName); - return CreateNameofExpression(syntax); + return NameOf(syntax); } - protected static InvocationExpressionSyntax CreateNameofExpression(string typeName, string identifierName) + protected static InvocationExpressionSyntax NameOf(string typeName, string identifierName) { - var syntax = CreateSimpleMemberAccessExpressionSyntax(typeName, identifierName); + var syntax = SimpleMemberAccess(typeName, identifierName); - return CreateNameofExpression(syntax); + return NameOf(syntax); } - private static InvocationExpressionSyntax CreateNameofExpression(ExpressionSyntax syntax) + private static InvocationExpressionSyntax NameOf(ExpressionSyntax syntax) { // nameof has a special RawContextualKind, hence we have to create it via its specific SyntaxKind // (see https://stackoverflow.com/questions/46259039/constructing-nameof-expression-via-syntaxfactory-roslyn) var nameofSyntax = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(SyntaxFactory.TriviaList(), SyntaxKind.NameOfKeyword, "nameof", "nameof", SyntaxFactory.TriviaList())); - return SyntaxFactory.InvocationExpression(nameofSyntax, CreateArgumentList(SyntaxFactory.Argument(syntax))); + return SyntaxFactory.InvocationExpression(nameofSyntax, ArgumentList(SyntaxFactory.Argument(syntax))); } } } \ No newline at end of file diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3020_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3020_CodeFixProvider.cs index acfd3a4e1..073052b28 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3020_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3020_CodeFixProvider.cs @@ -18,6 +18,6 @@ public sealed class MiKo_3020_CodeFixProvider : MaintainabilityCodeFixProvider protected override SyntaxNode GetSyntax(IReadOnlyCollection syntaxNodes) => syntaxNodes.OfType().FirstOrDefault(); - protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syntax, Diagnostic diagnostic) => CreateSimpleMemberAccessExpressionSyntax(nameof(Task), nameof(Task.CompletedTask)); + protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syntax, Diagnostic diagnostic) => SimpleMemberAccess(nameof(Task), nameof(Task.CompletedTask)); } } \ No newline at end of file diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3032_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3032_CodeFixProvider.cs index bc5e69416..496b1b346 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3032_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3032_CodeFixProvider.cs @@ -21,7 +21,7 @@ public sealed class MiKo_3032_CodeFixProvider : MaintainabilityCodeFixProvider protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syntax, Diagnostic diagnostic) { - var expression = CreateNameofExpression(diagnostic); + var expression = NameOf(diagnostic); if (diagnostic.Properties.ContainsKey(MiKo_3032_PropertyChangeEventArgsViaCinchAnalyzer.GetPropertyName)) { @@ -30,25 +30,25 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn if (diagnostic.Properties.ContainsKey(MiKo_3032_PropertyChangeEventArgsViaCinchAnalyzer.CreateArgs)) { - var argument = SyntaxFactory.Argument(expression); + var argument = Argument(expression); var typeSyntax = SyntaxFactory.ParseTypeName(nameof(PropertyChangedEventArgs)); - return SyntaxFactory.ObjectCreationExpression(typeSyntax, CreateArgumentList(argument), null); + return SyntaxFactory.ObjectCreationExpression(typeSyntax, ArgumentList(argument), null); } return syntax; } - private static InvocationExpressionSyntax CreateNameofExpression(Diagnostic diagnostic) + private static InvocationExpressionSyntax NameOf(Diagnostic diagnostic) { diagnostic.Properties.TryGetValue(MiKo_3032_PropertyChangeEventArgsViaCinchAnalyzer.PropertyName, out var propertyName); if (diagnostic.Properties.TryGetValue(MiKo_3032_PropertyChangeEventArgsViaCinchAnalyzer.PropertyTypeName, out var propertyTypeName)) { - return CreateNameofExpression(propertyTypeName, propertyName); + return NameOf(propertyTypeName, propertyName); } - return CreateNameofExpression(propertyName); + return NameOf(propertyName); } } } \ No newline at end of file diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3103_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3103_CodeFixProvider.cs index 9172c2bc2..7aa9e3b04 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3103_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3103_CodeFixProvider.cs @@ -55,7 +55,7 @@ protected sealed override SyntaxNode GetUpdatedSyntax(Document document, SyntaxN return literal; } - return CreateInvocationSyntax(nameof(Guid), nameof(Guid.Parse), SyntaxFactory.Argument(literal)); + return Invocation(nameof(Guid), nameof(Guid.Parse), Argument(literal)); } protected virtual Guid CreateGuid() => Guid.NewGuid(); diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs index c505daab5..ad51c25f0 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs @@ -122,6 +122,8 @@ private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpre private static InvocationExpressionSyntax FixAreEqual(SeparatedSyntaxList args) => FixAreEqualOrSame(args, "EqualTo"); + private static InvocationExpressionSyntax FixAreEqualIgnoringCase(SeparatedSyntaxList args) => AssertThat(args[1], Is("EqualTo", args[0], "IgnoreCase"), 2, args); + private static InvocationExpressionSyntax FixAreEqualOrSame(SeparatedSyntaxList args, string call) { var arg0 = args[0]; @@ -134,20 +136,20 @@ private static InvocationExpressionSyntax FixAreEqualOrSame(SeparatedSyntaxList< case SyntaxKind.NullLiteralExpression: return AssertThat(arg1, Is("Null"), 2, args); case SyntaxKind.StringLiteralExpression: return AssertThat(arg1, Is(call, arg0), 2, args); case SyntaxKind.NumericLiteralExpression: - { - if (args.Count > 2) { - var arg2 = args[2]; - - if (IsNumeric(arg2)) + if (args.Count > 2) { - // seems we have a tolerance parameter - return AssertThat(arg1, Is(call, arg0, "Within", arg2), 3, args); + var arg2 = args[2]; + + if (IsNumeric(arg2)) + { + // seems we have a tolerance parameter + return AssertThat(arg1, Is(call, arg0, "Within", arg2), 3, args); + } } - } - return AssertThat(arg1, Is(call, arg0), 2, args); - } + return AssertThat(arg1, Is(call, arg0), 2, args); + } } switch (arg1.Expression.Kind()) @@ -157,27 +159,25 @@ private static InvocationExpressionSyntax FixAreEqualOrSame(SeparatedSyntaxList< case SyntaxKind.NullLiteralExpression: return AssertThat(arg0, Is("Null"), 2, args); case SyntaxKind.StringLiteralExpression: return AssertThat(arg0, Is(call, arg1), 2, args); case SyntaxKind.NumericLiteralExpression: - { - if (args.Count > 2) { - var arg2 = args[2]; - - if (IsNumeric(arg2)) + if (args.Count > 2) { - // seems we have a tolerance parameter - return AssertThat(arg0, Is(call, arg1, "Within", arg2), 3, args); + var arg2 = args[2]; + + if (IsNumeric(arg2)) + { + // seems we have a tolerance parameter + return AssertThat(arg0, Is(call, arg1, "Within", arg2), 3, args); + } } - } - return AssertThat(arg0, Is(call, arg1), 2, args); - } + return AssertThat(arg0, Is(call, arg1), 2, args); + } } return AssertThat(arg1, Is(call, arg0), 2, args); } - private static InvocationExpressionSyntax FixAreEqualIgnoringCase(SeparatedSyntaxList args) => AssertThat(args[1], Is("EqualTo", args[0], "IgnoreCase"), 2, args); - private static InvocationExpressionSyntax FixAreEquivalent(SeparatedSyntaxList args) => AssertThat(args[1], Is("EquivalentTo", args[0]), 2, args); private static InvocationExpressionSyntax FixAreNotEqual(SeparatedSyntaxList args) => FixAreNotEqualOrSame(args, "EqualTo"); @@ -230,51 +230,6 @@ private static InvocationExpressionSyntax FixAreNotEqualOrSame(SeparatedSyntaxLi private static InvocationExpressionSyntax FixEndsWith(SeparatedSyntaxList args) => AssertThat(args[1], Does("EndWith", args[0]), 2, args); - private static InvocationExpressionSyntax FixGreater(SeparatedSyntaxList args) => AssertThat(args[0], Is("GreaterThan", args[1]), 2, args); - - private static InvocationExpressionSyntax FixGreaterOrEqual(SeparatedSyntaxList args) => AssertThat(args[0], Is("GreaterThanOrEqualTo", args[1]), 2, args); - - private static InvocationExpressionSyntax FixIsEmpty(SeparatedSyntaxList args) => AssertThat(args[0], Is("Empty"), 1, args); - - private static InvocationExpressionSyntax FixIsFalse(SeparatedSyntaxList args) - { - var argument = args[0]; - - if (argument.Expression is BinaryExpressionSyntax b) - { - var leftIsNull = b.Left.IsKind(SyntaxKind.NullLiteralExpression); - var rightIsNull = b.Right.IsKind(SyntaxKind.NullLiteralExpression); - - switch (b.Kind()) - { - case SyntaxKind.EqualsExpression: - return leftIsNull || rightIsNull - ? AssertThat(leftIsNull ? b.Right : b.Left, Is("Not", "Null"), 1, args) - : AssertThat(b.Left, Is("Not", "EqualTo", b.Right), 1, args); - - case SyntaxKind.NotEqualsExpression: - return leftIsNull || rightIsNull - ? AssertThat(leftIsNull ? b.Right : b.Left, Is("Null"), 1, args) - : AssertThat(b.Left, Is("EqualTo", b.Right), 1, args); - - case SyntaxKind.LessThanExpression: return AssertThat(b.Left, Is("GreaterThanOrEqualTo", b.Right), 1, args); - case SyntaxKind.LessThanOrEqualExpression: return AssertThat(b.Left, Is("GreaterThan", b.Right), 1, args); - case SyntaxKind.GreaterThanExpression: return AssertThat(b.Left, Is("LessThanOrEqualTo", b.Right), 1, args); - case SyntaxKind.GreaterThanOrEqualExpression: return AssertThat(b.Left, Is("LessThan", b.Right), 1, args); - } - } - - return AssertThat(argument, Is("False"), 1, args); - } - - private static InvocationExpressionSyntax FixIsAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("AssignableFrom", args, name); - - private static InvocationExpressionSyntax FixIsNotAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("AssignableFrom", args, name); - - private static InvocationExpressionSyntax FixIsInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("InstanceOf", args, name); - - private static InvocationExpressionSyntax FixIsNotInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("InstanceOf", args, name); - private static InvocationExpressionSyntax FixGenericIs(string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) { var arg0 = args[0]; @@ -311,16 +266,55 @@ private static InvocationExpressionSyntax FixGenericIsNot(string methodName, Sep return AssertThat(arg0, Is("Not", methodName), 1, args); } - private static InvocationExpressionSyntax FixStringAssertIsMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Match", args[0]), 2, args); + private static InvocationExpressionSyntax FixGreater(SeparatedSyntaxList args) => AssertThat(args[0], Is("GreaterThan", args[1]), 2, args); - private static InvocationExpressionSyntax FixStringAssertDoesNotMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "Match", args[0]), 2, args); + private static InvocationExpressionSyntax FixGreaterOrEqual(SeparatedSyntaxList args) => AssertThat(args[0], Is("GreaterThanOrEqualTo", args[1]), 2, args); - private static InvocationExpressionSyntax FixIsOrdered(SeparatedSyntaxList args) => AssertThat(args[0], Is("Ordered"), 1, args); + private static InvocationExpressionSyntax FixIsAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("AssignableFrom", args, name); + + private static InvocationExpressionSyntax FixIsEmpty(SeparatedSyntaxList args) => AssertThat(args[0], Is("Empty"), 1, args); + + private static InvocationExpressionSyntax FixIsFalse(SeparatedSyntaxList args) + { + var argument = args[0]; + + if (argument.Expression is BinaryExpressionSyntax b) + { + var leftIsNull = b.Left.IsKind(SyntaxKind.NullLiteralExpression); + var rightIsNull = b.Right.IsKind(SyntaxKind.NullLiteralExpression); + + switch (b.Kind()) + { + case SyntaxKind.EqualsExpression: + return leftIsNull || rightIsNull + ? AssertThat(leftIsNull ? b.Right : b.Left, Is("Not", "Null"), 1, args) + : AssertThat(b.Left, Is("Not", "EqualTo", b.Right), 1, args); + + case SyntaxKind.NotEqualsExpression: + return leftIsNull || rightIsNull + ? AssertThat(leftIsNull ? b.Right : b.Left, Is("Null"), 1, args) + : AssertThat(b.Left, Is("EqualTo", b.Right), 1, args); + + case SyntaxKind.LessThanExpression: return AssertThat(b.Left, Is("GreaterThanOrEqualTo", b.Right), 1, args); + case SyntaxKind.LessThanOrEqualExpression: return AssertThat(b.Left, Is("GreaterThan", b.Right), 1, args); + case SyntaxKind.GreaterThanExpression: return AssertThat(b.Left, Is("LessThanOrEqualTo", b.Right), 1, args); + case SyntaxKind.GreaterThanOrEqualExpression: return AssertThat(b.Left, Is("LessThan", b.Right), 1, args); + } + } + + return AssertThat(argument, Is("False"), 1, args); + } + + private static InvocationExpressionSyntax FixIsInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("InstanceOf", args, name); private static InvocationExpressionSyntax FixIsNaN(SeparatedSyntaxList args) => AssertThat(args[0], Is("NaN"), 1, args); + private static InvocationExpressionSyntax FixIsNotAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("AssignableFrom", args, name); + private static InvocationExpressionSyntax FixIsNotEmpty(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Empty"), 1, args); + private static InvocationExpressionSyntax FixIsNotInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("InstanceOf", args, name); + private static InvocationExpressionSyntax FixIsNotNull(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Null"), 1, args); private static InvocationExpressionSyntax FixIsNotSubsetOf(SeparatedSyntaxList args) => AssertThat(args[1], Is("Not", "SubsetOf", args[0]), 2, args); @@ -331,6 +325,8 @@ private static InvocationExpressionSyntax FixGenericIsNot(string methodName, Sep private static InvocationExpressionSyntax FixIsNullOrEmpty(SeparatedSyntaxList args) => AssertThat(args[0], Is("Null", "Or", "Empty"), 1, args); + private static InvocationExpressionSyntax FixIsOrdered(SeparatedSyntaxList args) => AssertThat(args[0], Is("Ordered"), 1, args); + private static InvocationExpressionSyntax FixIsSubsetOf(SeparatedSyntaxList args) => AssertThat(args[1], Is("SubsetOf", args[0]), 2, args); private static InvocationExpressionSyntax FixIsSupersetOf(SeparatedSyntaxList args) => AssertThat(args[1], Is("SupersetOf", args[0]), 2, args); @@ -370,20 +366,24 @@ private static InvocationExpressionSyntax FixIsTrue(SeparatedSyntaxList args) => AssertThat(args[0], Is("LessThanOrEqualTo", args[1]), 2, args); - private static InvocationExpressionSyntax FixPositive(SeparatedSyntaxList args) => AssertThat(args[0], Is("Positive"), 1, args); - private static InvocationExpressionSyntax FixNegative(SeparatedSyntaxList args) => AssertThat(args[0], Is("Negative"), 1, args); private static InvocationExpressionSyntax FixNotNull(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Null"), 1, args); private static InvocationExpressionSyntax FixNotZero(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Zero"), 1, args); + private static InvocationExpressionSyntax FixPositive(SeparatedSyntaxList args) => AssertThat(args[0], Is("Positive"), 1, args); + private static InvocationExpressionSyntax FixStartsWith(SeparatedSyntaxList args) => AssertThat(args[1], Does("StartWith", args[0]), 2, args); private static InvocationExpressionSyntax FixStringAssertContains(SeparatedSyntaxList args) => AssertThat(args[1], Does("Contain", args[0]), 2, args); private static InvocationExpressionSyntax FixStringAssertDoesNotContain(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "Contain", args[0]), 2, args); + private static InvocationExpressionSyntax FixStringAssertDoesNotMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "Match", args[0]), 2, args); + + private static InvocationExpressionSyntax FixStringAssertIsMatch(SeparatedSyntaxList args) => AssertThat(args[1], Does("Match", args[0]), 2, args); + private static InvocationExpressionSyntax FixZero(SeparatedSyntaxList args) => AssertThat(args[0], Is("Zero"), 1, args); private static InvocationExpressionSyntax AssertThat(ExpressionSyntax expression, ArgumentSyntax constraint, int skip, SeparatedSyntaxList arguments) @@ -403,63 +403,56 @@ private static InvocationExpressionSyntax AssertThat(ArgumentSyntax argument, Ar return AssertThat(args.ToArray()); } - private static InvocationExpressionSyntax AssertThat(params ArgumentSyntax[] arguments) => CreateInvocationSyntax("Assert", "That", arguments); + private static InvocationExpressionSyntax AssertThat(params ArgumentSyntax[] arguments) => Invocation("Assert", "That", arguments); + + private static InvocationExpressionSyntax InvocationIs(string name, ArgumentSyntax argument) => Invocation("Is", name, argument); - private static ArgumentSyntax Is(string name) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name)); + private static ArgumentSyntax Is(string name) => Argument(SimpleMemberAccess("Is", name)); private static ArgumentSyntax Is(string name, ArgumentSyntax argument) => Argument(InvocationIs(name, argument)); private static ArgumentSyntax Is(string name, ExpressionSyntax expression) => Is(name, Argument(expression)); - private static ArgumentSyntax Is(string name, TypeSyntax[] items) => Argument(CreateInvocationSyntax("Is", name, items)); + private static ArgumentSyntax Is(string name, TypeSyntax[] items) => Argument(Invocation("Is", name, items)); - private static ArgumentSyntax Is(string name, string name1, TypeSyntax[] items) => Argument(CreateInvocationSyntax("Is", name, name1, items)); + private static ArgumentSyntax Is(string name, string name1, TypeSyntax[] items) => Argument(Invocation("Is", name, name1, items)); - private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", name, name1), argument); + private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument) => Argument(SimpleMemberAccess("Is", name, name1), argument); private static ArgumentSyntax Is(string name, string name1, ArgumentSyntax argument, string name2) { - var expression = CreateSimpleMemberAccessExpressionSyntax("Is", name, name1); - var invocation = CreateInvocationSyntax(expression, argument); + var expression = SimpleMemberAccess("Is", name, name1); + var invocation = Invocation(expression, argument); - return Argument(CreateSimpleMemberAccessExpressionSyntax(invocation, name2)); + return Argument(SimpleMemberAccess(invocation, name2)); } private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string name1) { var expression = InvocationIs(name, argument); - return Argument(CreateSimpleMemberAccessExpressionSyntax(expression, name1)); + return Argument(SimpleMemberAccess(expression, name1)); } private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string name1, ArgumentSyntax argument1) { var isCall = InvocationIs(name, argument); - var appendixCall = CreateSimpleMemberAccessExpressionSyntax(isCall, name1); + var appendixCall = SimpleMemberAccess(isCall, name1); return Argument(appendixCall, argument1); } private static ArgumentSyntax Is(string name, string name1, ExpressionSyntax expression) => Is(name, name1, Argument(expression)); - private static ArgumentSyntax Is(params string[] names) => Argument(CreateSimpleMemberAccessExpressionSyntax("Is", names)); + private static ArgumentSyntax Is(params string[] names) => Argument(SimpleMemberAccess("Is", names)); - private static InvocationExpressionSyntax InvocationIs(string name, ArgumentSyntax argument) => CreateInvocationSyntax("Is", name, argument); - - private static ArgumentSyntax Does(string name, ArgumentSyntax argument) => Argument(CreateInvocationSyntax("Does", name, argument)); - - private static ArgumentSyntax Does(string name, string name1, ArgumentSyntax argument) - { - return Argument(CreateSimpleMemberAccessExpressionSyntax("Does", name, name1), argument); - } - - private static ArgumentSyntax Does(params string[] names) => Argument(CreateSimpleMemberAccessExpressionSyntax("Does", names)); + private static bool IsNumeric(ArgumentSyntax argument) => argument.Expression.IsKind(SyntaxKind.NumericLiteralExpression) + || (argument.Expression is MemberAccessExpressionSyntax mae && mae.Expression.IsKind(SyntaxKind.PredefinedType)); - private static ArgumentSyntax Argument(ExpressionSyntax expression) => SyntaxFactory.Argument(expression); + private static ArgumentSyntax Does(string name, ArgumentSyntax argument) => Argument(Invocation("Does", name, argument)); - private static ArgumentSyntax Argument(MemberAccessExpressionSyntax expression, ArgumentSyntax argument) => Argument(CreateInvocationSyntax(expression, argument)); + private static ArgumentSyntax Does(string name, string name1, ArgumentSyntax argument) => Argument(SimpleMemberAccess("Does", name, name1), argument); - private static bool IsNumeric(ArgumentSyntax argument) => argument.Expression.IsKind(SyntaxKind.NumericLiteralExpression) - || (argument.Expression is MemberAccessExpressionSyntax mae && mae.Expression.IsKind(SyntaxKind.PredefinedType)); + private static ArgumentSyntax Does(params string[] names) => Argument(SimpleMemberAccess("Does", names)); } } \ No newline at end of file From dee6543acad36553e46beae8cc9cc0c1bec15aa1 Mon Sep 17 00:00:00 2001 From: "Koban, Ralf" Date: Sun, 8 Aug 2021 09:01:18 +0000 Subject: [PATCH 3/3] MiKo_3105 enhanced (resolves #390) - Assert.DoesNotThrow - Assert.DoesNotThrowAsync - Assert.IsNotInstanceOf - Assert.IsAssignableFrom - Assert.IsNotAssignableFrom - CollectionAssert.AllItemsAreInstancesOfType - DirectoryAssert.Exists - DirectoryAssert.DoesNotExist - FileAssert.Exists - FileAssert.DoesNotExist - StringAssert.AreNotEqualIgnoringCase - StringAssert.IsMatch - StringAssert.DoesNotMatch --- ...5_TestMethodsUseAssertThatAnalyzerTests.cs | 128 ++++++++++-------- .../MiKo_3105_CodeFixProvider.cs | 55 +++++--- 2 files changed, 110 insertions(+), 73 deletions(-) diff --git a/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs b/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs index 565f2d9e9..8fb2aa64c 100644 --- a/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs +++ b/MiKo.Analyzer.Tests/Rules/Maintainability/MiKo_3105_TestMethodsUseAssertThatAnalyzerTests.cs @@ -396,6 +396,58 @@ public void DoSomething() @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.LessOrEqual(42, 11, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(42, Is.LessThanOrEqualTo(11), ""my message""); }")] + // AreSame + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreSame(null, o); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Null); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreSame(o, null); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Null); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(false, b); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(b, false); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(b, true); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(true, b); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreSame(42, i); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.SameAs(42)); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreSame(i, 42); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.SameAs(42)); }")] + + // AreNotSame + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreNotSame(null, o); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.Null); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreNotSame(o, null); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.Null); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(false, b); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(b, false); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(b, true); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(true, b); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreNotSame(42, i); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Not.SameAs(42)); }")] + [TestCase( + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreNotSame(i, 42); }", + "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Not.SameAs(42)); }")] + [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.IsNullOrEmpty(o, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Null.Or.Empty, ""my message""); }")] @@ -474,59 +526,6 @@ public void DoSomething() [TestCase( @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable e) => CollectionAssert.AllItemsAreUnique(e, ""my message""); }", @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable e) => Assert.That(e, Is.Unique, ""my message""); }")] - - // AreSame - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreSame(null, o); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Null); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreSame(o, null); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Null); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(false, b); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(b, false); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(b, true); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreSame(true, b); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreSame(42, i); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.SameAs(42)); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreSame(i, 42); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.SameAs(42)); }")] - - // AreNotSame - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreNotSame(null, o); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.Null); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.AreNotSame(o, null); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(object o) => Assert.That(o, Is.Not.Null); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(false, b); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(b, false); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.True); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(b, true); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.AreNotSame(true, b); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(bool b) => Assert.That(b, Is.False); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreNotSame(42, i); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Not.SameAs(42)); }")] - [TestCase( - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.AreNotSame(i, 42); }", - "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Not.SameAs(42)); }")] - [TestCase( "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.Zero(i); }", "using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(int i) => Assert.That(i, Is.Zero); }")] @@ -560,6 +559,29 @@ public void DoSomething() [TestCase( @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => StringAssert.DoesNotMatch(""some pattern"", ""actual""); }", @"using System; using System.Text.RegularExpressions; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(""actual"", Does.Not.Match(""some pattern"")); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable collection) => CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(string)); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do(IEnumerable collection) => Assert.That(collection, Is.All.InstanceOf()); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.DoesNotThrow(() => throw new ArgumentException()); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(() => throw new ArgumentException(), Throws.Nothing); }")] + [TestCase( + @"using System; using System.Threading.Tasks; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.DoesNotThrowAsync(async () => await Task.CompletedTask); }", + @"using System; using System.Threading.Tasks; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(async () => await Task.CompletedTask, Throws.Nothing); }")] + + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => FileAssert.Exists(@""c:\pagefile.sys""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(@""c:\pagefile.sys"", Does.Exist); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => DirectoryAssert.Exists(@""c:\Windows""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(@""c:\Windows"", Does.Exist); }")] + + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => FileAssert.DoesNotExist(@""c:\pagefile.sys""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(@""c:\pagefile.sys"", Does.Not.Exist); }")] + [TestCase( + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => DirectoryAssert.DoesNotExist(@""c:\Windows""); }", + @"using System; using NUnit.Framework; [TestFixture] class TestMe { [Test] void Do() => Assert.That(@""c:\Windows"", Does.Not.Exist); }")] public void Code_gets_fixed_(string originalCode, string fixedCode) => VerifyCSharpFix(originalCode, fixedCode); [Test] diff --git a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs index ad51c25f0..59efd61c5 100644 --- a/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs +++ b/MiKo.Analyzer/Rules/Maintainability/MiKo_3105_CodeFixProvider.cs @@ -30,6 +30,8 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn { case "Assert": case "CollectionAssert": + case "DirectoryAssert": + case "FileAssert": case "StringAssert": { var args = original.ArgumentList.Arguments; @@ -43,10 +45,6 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn break; } - - // TODO RKN - // case "FileAssert": - // case "DirectoryAssert": } } @@ -55,17 +53,10 @@ protected override SyntaxNode GetUpdatedSyntax(Document document, SyntaxNode syn private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpressionSyntax syntax, SeparatedSyntaxList args) { - // TODO RKN - // Assert.DoesNotThrow - // Assert.DoesNotThrowAsync - // CollectionAssert.AllItemsAreInstancesOfType - // FileAssert.Exists - // FileAssert.DoesNotExist - // DirectoryAssert.Exists - // DirectoryAssert.DoesNotExist var methodName = syntax.GetName(); switch (methodName) { + case "AllItemsAreInstancesOfType": return FixAllItemsAreInstancesOfType(args, syntax.Name); case "AllItemsAreNotNull": return FixAllItemsAreNotNull(args); case "AllItemsAreUnique": return FixAllItemsAreUnique(args); case "AreEqual": return FixAreEqual(args); @@ -80,8 +71,12 @@ private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpre case "DoesNotContain": return FixDoesNotContain(typeName, args); case "DoesNotMatch": return FixStringAssertDoesNotMatch(args); case "DoesNotEndWith": return FixDoesNotEndWith(args); + case "DoesNotExist": return FixDoesNotExist(args); case "DoesNotStartWith": return FixDoesNotStartWith(args); + case "DoesNotThrow": return FixDoesNotThrow(args); + case "DoesNotThrowAsync": return FixDoesNotThrow(args); case "EndsWith": return FixEndsWith(args); + case "Exists": return FixExists(args); case "False": return FixIsFalse(args); case "Greater": return FixGreater(args); case "GreaterOrEqual": return FixGreaterOrEqual(args); @@ -116,6 +111,11 @@ private static ExpressionSyntax UpdatedSyntax(string typeName, MemberAccessExpre } } + private static InvocationExpressionSyntax FixAllItemsAreInstancesOfType(SeparatedSyntaxList args, SimpleNameSyntax name) + { + return FixGenericIs("All", "InstanceOf", args, name); + } + private static InvocationExpressionSyntax FixAllItemsAreNotNull(SeparatedSyntaxList args) => AssertThat(args[0], Is("All", "Not", "Null"), 1, args); private static InvocationExpressionSyntax FixAllItemsAreUnique(SeparatedSyntaxList args) => AssertThat(args[0], Is("Unique"), 1, args); @@ -226,10 +226,16 @@ private static InvocationExpressionSyntax FixAreNotEqualOrSame(SeparatedSyntaxLi private static InvocationExpressionSyntax FixDoesNotEndWith(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "EndWith", args[0]), 2, args); + private static InvocationExpressionSyntax FixDoesNotExist(SeparatedSyntaxList args) => AssertThat(args[0], Does("Not", "Exist"), 1, args); + private static InvocationExpressionSyntax FixDoesNotStartWith(SeparatedSyntaxList args) => AssertThat(args[1], Does("Not", "StartWith", args[0]), 2, args); + private static InvocationExpressionSyntax FixDoesNotThrow(SeparatedSyntaxList args) => AssertThat(args[0], Throws("Nothing"), 1, args); + private static InvocationExpressionSyntax FixEndsWith(SeparatedSyntaxList args) => AssertThat(args[1], Does("EndWith", args[0]), 2, args); + private static InvocationExpressionSyntax FixExists(SeparatedSyntaxList args) => AssertThat(args[0], Does("Exist"), 1, args); + private static InvocationExpressionSyntax FixGenericIs(string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) { var arg0 = args[0]; @@ -248,22 +254,29 @@ private static InvocationExpressionSyntax FixGenericIs(string methodName, Separa return AssertThat(arg0, Is(methodName), 1, args); } - private static InvocationExpressionSyntax FixGenericIsNot(string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) + private static InvocationExpressionSyntax FixGenericIs(string propertyName, string methodName, SeparatedSyntaxList args, SimpleNameSyntax name) { var arg0 = args[0]; if (name is GenericNameSyntax gns) { - return AssertThat(arg0, Is("Not", methodName, gns.TypeArgumentList.Arguments.ToArray()), 1, args); + return AssertThat(arg0, Is(propertyName, methodName, gns.TypeArgumentList.Arguments.ToArray()), 1, args); } - if (arg0.Expression is TypeOfExpressionSyntax t) + var arg1 = args[1]; + + if (arg0.Expression is TypeOfExpressionSyntax t0) { - return AssertThat(args[1], Is("Not", methodName, new[] { t.Type }), 2, args); + return AssertThat(arg1, Is(propertyName, methodName, new[] { t0.Type }), 2, args); + } + + if (arg1.Expression is TypeOfExpressionSyntax t1) + { + return AssertThat(arg0, Is(propertyName, methodName, new[] { t1.Type }), 2, args); } // TODO: this code is not tested as the case does not exist - return AssertThat(arg0, Is("Not", methodName), 1, args); + return AssertThat(arg0, Is(propertyName, methodName), 1, args); } private static InvocationExpressionSyntax FixGreater(SeparatedSyntaxList args) => AssertThat(args[0], Is("GreaterThan", args[1]), 2, args); @@ -309,11 +322,11 @@ private static InvocationExpressionSyntax FixIsFalse(SeparatedSyntaxList args) => AssertThat(args[0], Is("NaN"), 1, args); - private static InvocationExpressionSyntax FixIsNotAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("AssignableFrom", args, name); + private static InvocationExpressionSyntax FixIsNotAssignableFrom(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("Not", "AssignableFrom", args, name); private static InvocationExpressionSyntax FixIsNotEmpty(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Empty"), 1, args); - private static InvocationExpressionSyntax FixIsNotInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIsNot("InstanceOf", args, name); + private static InvocationExpressionSyntax FixIsNotInstanceOf(SeparatedSyntaxList args, SimpleNameSyntax name) => FixGenericIs("Not", "InstanceOf", args, name); private static InvocationExpressionSyntax FixIsNotNull(SeparatedSyntaxList args) => AssertThat(args[0], Is("Not", "Null"), 1, args); @@ -447,12 +460,14 @@ private static ArgumentSyntax Is(string name, ArgumentSyntax argument, string na private static ArgumentSyntax Is(params string[] names) => Argument(SimpleMemberAccess("Is", names)); private static bool IsNumeric(ArgumentSyntax argument) => argument.Expression.IsKind(SyntaxKind.NumericLiteralExpression) - || (argument.Expression is MemberAccessExpressionSyntax mae && mae.Expression.IsKind(SyntaxKind.PredefinedType)); + || (argument.Expression is MemberAccessExpressionSyntax mae && mae.Expression.IsKind(SyntaxKind.PredefinedType)); private static ArgumentSyntax Does(string name, ArgumentSyntax argument) => Argument(Invocation("Does", name, argument)); private static ArgumentSyntax Does(string name, string name1, ArgumentSyntax argument) => Argument(SimpleMemberAccess("Does", name, name1), argument); private static ArgumentSyntax Does(params string[] names) => Argument(SimpleMemberAccess("Does", names)); + + private static ArgumentSyntax Throws(string name) => Argument(SimpleMemberAccess("Throws", name)); } } \ No newline at end of file