diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c1b47a240 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,113 @@ +# Common settings that generally should always be used with your language specific settings +# A combination from https://github.com/gitattributes/gitattributes +# We normalize the repo line endings to LF and backstop with .editorconfig + +# Auto detect text files and perform LF normalization +* text=auto eol=lf encoding=UTF-8 + +# +# The above will handle all files NOT found below +# + +# Documents +*.bibtex text diff=bibtex +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.md text diff=markdown +*.mdx text diff=markdown +*.tex text diff=tex +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.txt text +*.sql text +*.epub diff=astextplain + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as text by default. +*.svg text +# If you want to treat it as binary, +# use the following line instead. +# *.svg binary +*.eps binary + +# Scripts +*.bash text +*.fish text +*.sh text +*.zsh text + +# These are explicitly windows files and could use crlf, but all the tools support lf +*.bat text +*.cmd text + + +# Serialisation +*.json text +*.toml text +*.xml text +*.yaml text +*.yml text + +# Archives +*.7z binary +*.gz binary +*.tar binary +*.tgz binary +*.zip binary + +# Text files where line endings should be preserved +*.patch -text + +# +# Exclude files from exporting +# + +.gitattributes export-ignore +.gitignore export-ignore +.gitkeep export-ignore + +# CSharp files +*.cs text diff=csharp +*.cshtml text diff=html +*.csx text diff=csharp +*.sln text +*.csproj text + +# See https://github.com/VerifyTests/Verify?tab=readme-ov-file#text-file-settings +*.verified.txt text eol=lf working-tree-encoding=UTF-8 +*.verified.xml text eol=lf working-tree-encoding=UTF-8 +*.verified.json text eol=lf working-tree-encoding=UTF-8 + +# Basic .gitattributes for a PowerShell repo. + +# Source files +# ============ +*.ps1 text +*.ps1x text +*.psm1 text +*.psd1 text +*.ps1xml text +*.pssc text +*.psrc text +*.cdxml text +# Fix syntax highlighting on GitHub to allow comments +.vscode/*.json linguist-language=JSON-with-Comments \ No newline at end of file diff --git a/Moq.Analyzers.sln b/Moq.Analyzers.sln index 9c1effe21..8d30b87dc 100644 --- a/Moq.Analyzers.sln +++ b/Moq.Analyzers.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.10.34928.147 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers", "Source\Moq.Analyzers\Moq.Analyzers.csproj", "{41ECC571-F586-460A-9BED-23528C8210C4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers.Test", "Source\Moq.Analyzers.Test\Moq.Analyzers.Test.csproj", "{D2348836-7129-4BE5-8AE6-D05FC8C28FC1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {41ECC571-F586-460A-9BED-23528C8210C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41ECC571-F586-460A-9BED-23528C8210C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41ECC571-F586-460A-9BED-23528C8210C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41ECC571-F586-460A-9BED-23528C8210C4}.Release|Any CPU.Build.0 = Release|Any CPU - {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8C917BC1-C0DE-4A46-BEE8-32FD66B447B1} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.34928.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers", "Source\Moq.Analyzers\Moq.Analyzers.csproj", "{41ECC571-F586-460A-9BED-23528C8210C4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Analyzers.Test", "Source\Moq.Analyzers.Test\Moq.Analyzers.Test.csproj", "{D2348836-7129-4BE5-8AE6-D05FC8C28FC1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41ECC571-F586-460A-9BED-23528C8210C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41ECC571-F586-460A-9BED-23528C8210C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41ECC571-F586-460A-9BED-23528C8210C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41ECC571-F586-460A-9BED-23528C8210C4}.Release|Any CPU.Build.0 = Release|Any CPU + {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2348836-7129-4BE5-8AE6-D05FC8C28FC1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8C917BC1-C0DE-4A46-BEE8-32FD66B447B1} + EndGlobalSection +EndGlobal diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt index 723035896..31d23fd13 100644 --- a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1300 - Location: SourceFile(Test0.cs[1376..1391)) + Location: SourceFile(Test0.cs[1369..1384)) Highlight: BaseSampleClass Lines: mock.As(); Severity: Error @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1300 - Location: SourceFile(Test0.cs[1541..1551)) + Location: SourceFile(Test0.cs[1534..1544)) Highlight: OtherClass Lines: mock.As(); Severity: Error diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs index 25dc13d83..380cd32e5 100644 --- a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class AsAcceptOnlyInterfaceAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldPassIfGoodParameters() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/AsAcceptOnlyInterface.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new AsShouldBeUsedOnlyForInterfaceAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class AsAcceptOnlyInterfaceAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldPassIfGoodParameters() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/AsAcceptOnlyInterface.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new AsShouldBeUsedOnlyForInterfaceAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt index efc1df11c..a051d3c69 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1100 - Location: SourceFile(Test0.cs[1120..1127)) + Location: SourceFile(Test0.cs[1090..1097)) Highlight: (int i) Lines: mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1100 - Location: SourceFile(Test0.cs[1201..1223)) + Location: SourceFile(Test0.cs[1170..1192)) Highlight: (string s1, string s2) Lines: mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1100 - Location: SourceFile(Test0.cs[1336..1355)) + Location: SourceFile(Test0.cs[1304..1323)) Highlight: (string s1, int i1) Lines: mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1100 - Location: SourceFile(Test0.cs[1435..1442)) + Location: SourceFile(Test0.cs[1402..1409)) Highlight: (int i) Lines: mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs index e3bcfb8de..a17367204 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class CallbackSignatureShouldMatchMockedMethodAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldPassIfGoodParameters() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class CallbackSignatureShouldMatchMockedMethodAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldPassIfGoodParameters() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs index 7d6a593fd..b1b7fec7e 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs @@ -1,28 +1,28 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.CodeFixes; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class CallbackSignatureShouldMatchMockedMethodCodeFixTests : CodeFixVerifier - { - [Fact] - public Task ShouldSuggestQuickFixIfBadParameters() - { - return Verify(VerifyCSharpFix(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); - } - - protected override CodeFixProvider GetCSharpCodeFixProvider() - { - return new CallbackSignatureShouldMatchMockedMethodCodeFix(); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.CodeFixes; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class CallbackSignatureShouldMatchMockedMethodCodeFixTests : CodeFixVerifier + { + [Fact] + public Task ShouldSuggestQuickFixIfBadParameters() + { + return Verify(VerifyCSharpFix(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); + } + + protected override CodeFixProvider GetCSharpCodeFixProvider() + { + return new CallbackSignatureShouldMatchMockedMethodCodeFix(); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt index 24135f678..a9849422e 100644 --- a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1002 - Location: SourceFile(Test0.cs[1359..1368)) + Location: SourceFile(Test0.cs[1321..1330)) Highlight: (1, true) Lines: var mock1 = new Moq.Mock(1, true); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1002 - Location: SourceFile(Test0.cs[1440..1449)) + Location: SourceFile(Test0.cs[1401..1410)) Highlight: (2, true) Lines: var mock2 = new Mock(2, true); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1002 - Location: SourceFile(Test0.cs[1521..1529)) + Location: SourceFile(Test0.cs[1481..1489)) Highlight: ("1", 3) Lines: var mock3 = new Mock("1", 3); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1002 - Location: SourceFile(Test0.cs[1601..1624)) + Location: SourceFile(Test0.cs[1560..1583)) Highlight: (new int[] { 1, 2, 3 }) Lines: var mock4 = new Mock(new int[] { 1, 2, 3 }); Severity: Warning @@ -32,7 +32,7 @@ Diagnostic 4 Diagnostic 5 Id: Moq1002 - Location: SourceFile(Test0.cs[1721..1751)) + Location: SourceFile(Test0.cs[1675..1705)) Highlight: (MockBehavior.Strict, 4, true) Lines: var mock1 = new Mock(MockBehavior.Strict, 4, true); Severity: Warning @@ -40,7 +40,7 @@ Diagnostic 5 Diagnostic 6 Id: Moq1002 - Location: SourceFile(Test0.cs[1827..1856)) + Location: SourceFile(Test0.cs[1780..1809)) Highlight: (MockBehavior.Loose, 5, true) Lines: var mock2 = new Moq.Mock(MockBehavior.Loose, 5, true); Severity: Warning @@ -48,7 +48,7 @@ Diagnostic 6 Diagnostic 7 Id: Moq1002 - Location: SourceFile(Test0.cs[1932..1960)) + Location: SourceFile(Test0.cs[1884..1912)) Highlight: (MockBehavior.Loose, "2", 6) Lines: var mock3 = new Moq.Mock(MockBehavior.Loose, "2", 6); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs index d4f9c259b..fa0c6a95c 100644 --- a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs @@ -1,28 +1,28 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class ConstructorArgumentsShouldMatchAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldFailIfClassParametersDoNotMatch() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/ConstructorArgumentsShouldMatch.cs"))); - } - - // [Fact] - // public Task ShouldPassIfCustomMockClassIsUsed() - // { - // return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/MockInterfaceWithParametersCustomMockFile.cs"))); - // } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new ConstructorArgumentsShouldMatchAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class ConstructorArgumentsShouldMatchAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldFailIfClassParametersDoNotMatch() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/ConstructorArgumentsShouldMatch.cs"))); + } + + // [Fact] + // public Task ShouldPassIfCustomMockClassIsUsed() + // { + // return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/MockInterfaceWithParametersCustomMockFile.cs"))); + // } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new ConstructorArgumentsShouldMatchAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs b/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs index 3ab882d47..753ffbf66 100644 --- a/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs +++ b/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs @@ -19,14 +19,14 @@ public int Calculate() } public abstract int Calculate(int a, int b, int c); - } - + } + public class SampleClass { public virtual int Calculate(int a, int b) => 0; - } - + } + public class OtherClass { @@ -34,13 +34,13 @@ public class OtherClass } internal class MyUnitTests - { + { private void TestOkAsForInterface() { var mock = new Mock(); mock.As(); - } - + } + private void TestOkAsForInterfaceWithConfiguration() { var mock = new Mock(); diff --git a/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs b/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs index f3def4f43..20a400154 100644 --- a/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs +++ b/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs @@ -1,69 +1,69 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1021 // Simplify lambda expression -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace CallbackSignatureShouldMatchMockedMethod -{ - using System; - using System.Collections.Generic; - using Moq; - - internal interface IFoo - { - int Do(string s); - - int Do(int i, string s, DateTime dt); - - int Do(List l); - } - - internal class MyUnitTests - { - private void TestBadCallbacks() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); - } - - private void TestGoodSetupAndParameterlessCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); - } - - private void TestGoodSetupAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); - } - - private void TestGoodSetupAndReturnsAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); - } - - private void MyGoodSetupAndReturns() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1021 // Simplify lambda expression +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace CallbackSignatureShouldMatchMockedMethod +{ + using System; + using System.Collections.Generic; + using Moq; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void TestBadCallbacks() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); + } + + private void TestGoodSetupAndParameterlessCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); + } + + private void TestGoodSetupAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); + } + + private void TestGoodSetupAndReturnsAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); + } + + private void MyGoodSetupAndReturns() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs b/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs index a2a145a4e..e11481421 100644 --- a/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs +++ b/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs @@ -1,82 +1,82 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1160 // Public constructor in abstract class -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace ConstructorArgumentsShouldMatch -{ - using System; - using System.Collections.Generic; - using Moq; - -#pragma warning disable SA1402 // File may only contain a single class - internal class Foo - { - public Foo(string s) { } - - public Foo(bool b, int i) { } - - public Foo(params DateTime[] dates) { } - - public Foo(List l, string s = "A") { } - } - - internal abstract class FooAbstract - { - public FooAbstract(string s) { } - } - - internal class MyUnitTests -#pragma warning restore SA1402 // File may only contain a single class - { - private void TestBad() - { - var mock1 = new Moq.Mock(1, true); - var mock2 = new Mock(2, true); - var mock3 = new Mock("1", 3); - var mock4 = new Mock(new int[] { 1, 2, 3 }); - } - - private void TestBad2() - { - var mock1 = new Mock(MockBehavior.Strict, 4, true); - var mock2 = new Moq.Mock(MockBehavior.Loose, 5, true); - var mock3 = new Moq.Mock(MockBehavior.Loose, "2", 6); - } - - private void TestGood1() - { - var mock1 = new Moq.Mock(MockBehavior.Default); - var mock2 = new Mock(MockBehavior.Strict); - var mock3 = new Mock(MockBehavior.Loose); - var mock4 = new Moq.Mock(MockBehavior.Default); - - var mock5 = new Mock("3"); - var mock6 = new Moq.Mock("4"); - var mock7 = new Moq.Mock(Moq.MockBehavior.Default, "5"); - var mock8 = new Mock(Moq.MockBehavior.Default, "6"); - - var mock9 = new Moq.Mock(false, 0); - var mock10 = new Moq.Mock(Moq.MockBehavior.Default, true, 1); - - var mock11 = new Mock(DateTime.Now, DateTime.Now); - var mock12 = new Mock(MockBehavior.Default, DateTime.Now, DateTime.Now); - - var mock13 = new Mock(new List(), "7"); - var mock14 = new Mock(new List()); - var mock15 = new Mock(MockBehavior.Default, new List(), "8"); - var mock16 = new Mock(MockBehavior.Default, new List()); - } - - private void TestAbstractGood() - { - var mock1 = new Mock("9"); - var mock2 = new Mock(MockBehavior.Default, "10"); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1160 // Public constructor in abstract class +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace ConstructorArgumentsShouldMatch +{ + using System; + using System.Collections.Generic; + using Moq; + +#pragma warning disable SA1402 // File may only contain a single class + internal class Foo + { + public Foo(string s) { } + + public Foo(bool b, int i) { } + + public Foo(params DateTime[] dates) { } + + public Foo(List l, string s = "A") { } + } + + internal abstract class FooAbstract + { + public FooAbstract(string s) { } + } + + internal class MyUnitTests +#pragma warning restore SA1402 // File may only contain a single class + { + private void TestBad() + { + var mock1 = new Moq.Mock(1, true); + var mock2 = new Mock(2, true); + var mock3 = new Mock("1", 3); + var mock4 = new Mock(new int[] { 1, 2, 3 }); + } + + private void TestBad2() + { + var mock1 = new Mock(MockBehavior.Strict, 4, true); + var mock2 = new Moq.Mock(MockBehavior.Loose, 5, true); + var mock3 = new Moq.Mock(MockBehavior.Loose, "2", 6); + } + + private void TestGood1() + { + var mock1 = new Moq.Mock(MockBehavior.Default); + var mock2 = new Mock(MockBehavior.Strict); + var mock3 = new Mock(MockBehavior.Loose); + var mock4 = new Moq.Mock(MockBehavior.Default); + + var mock5 = new Mock("3"); + var mock6 = new Moq.Mock("4"); + var mock7 = new Moq.Mock(Moq.MockBehavior.Default, "5"); + var mock8 = new Mock(Moq.MockBehavior.Default, "6"); + + var mock9 = new Moq.Mock(false, 0); + var mock10 = new Moq.Mock(Moq.MockBehavior.Default, true, 1); + + var mock11 = new Mock(DateTime.Now, DateTime.Now); + var mock12 = new Mock(MockBehavior.Default, DateTime.Now, DateTime.Now); + + var mock13 = new Mock(new List(), "7"); + var mock14 = new Mock(new List()); + var mock15 = new Mock(MockBehavior.Default, new List(), "8"); + var mock16 = new Mock(MockBehavior.Default, new List()); + } + + private void TestAbstractGood() + { + var mock1 = new Mock("9"); + var mock2 = new Mock(MockBehavior.Default, "10"); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs index 897dde88f..041ed9b88 100644 --- a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs +++ b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs @@ -1,46 +1,46 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoConstructorArgumentsForInterfaceMock_1 -{ - using Moq; - - internal interface IMyService - { - void Do(string s); - } - - internal class MyUnitTests - { - private void TestBad() - { - var mock1 = new Moq.Mock(25, true); - var mock2 = new Mock("123"); - var mock3 = new Mock(25, true); - var mock4 = new Moq.Mock("123"); - } - - private void TestBad2() - { - var mock1 = new Moq.Mock(Moq.MockBehavior.Default, "123"); - var mock2 = new Mock(MockBehavior.Strict, 25, true); - var mock3 = new Mock(Moq.MockBehavior.Default, "123"); - var mock4 = new Moq.Mock(MockBehavior.Loose, 25, true); - } - - private void TestGood1() - { - var mock1 = new Moq.Mock(); - var mock2 = new Moq.Mock(MockBehavior.Default); - var mock3 = new Mock(MockBehavior.Strict); - var mock4 = new Mock(MockBehavior.Loose); - var mock5 = new Moq.Mock(MockBehavior.Default); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace NoConstructorArgumentsForInterfaceMock_1 +{ + using Moq; + + internal interface IMyService + { + void Do(string s); + } + + internal class MyUnitTests + { + private void TestBad() + { + var mock1 = new Moq.Mock(25, true); + var mock2 = new Mock("123"); + var mock3 = new Mock(25, true); + var mock4 = new Moq.Mock("123"); + } + + private void TestBad2() + { + var mock1 = new Moq.Mock(Moq.MockBehavior.Default, "123"); + var mock2 = new Mock(MockBehavior.Strict, 25, true); + var mock3 = new Mock(Moq.MockBehavior.Default, "123"); + var mock4 = new Moq.Mock(MockBehavior.Loose, 25, true); + } + + private void TestGood1() + { + var mock1 = new Moq.Mock(); + var mock2 = new Moq.Mock(MockBehavior.Default); + var mock3 = new Mock(MockBehavior.Strict); + var mock4 = new Mock(MockBehavior.Loose); + var mock5 = new Moq.Mock(MockBehavior.Default); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs index 39a8eb1f5..ee42ce887 100644 --- a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs +++ b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs @@ -1,64 +1,64 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoConstructorArgumentsForInterfaceMock_2 -{ - public enum MockBehavior - { - Default, - Strict, - Loose, - } - - internal interface IMyService - { - void Do(string s); - } - - public class Mock - where T : class - { - public Mock() { } - - public Mock(params object[] ar) { } - - public Mock(MockBehavior behavior) { } - - public Mock(MockBehavior behavior, params object[] args) { } - } - - internal class MyUnitTests - { - private void TestRealMoqWithBadParameters() - { - var mock1 = new Moq.Mock(1, true); - var mock2 = new Moq.Mock("2"); - var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); - var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); - var mock5 = new Moq.Mock(MockBehavior.Default); - var mock6 = new Moq.Mock(MockBehavior.Default); - } - - private void TestRealMoqWithGoodParameters() - { - var mock1 = new Moq.Mock(Moq.MockBehavior.Default); - var mock2 = new Moq.Mock(Moq.MockBehavior.Default); - } - - private void TestFakeMoq() - { - var mock1 = new Mock("4"); - var mock2 = new Mock(5, true); - var mock3 = new Mock(MockBehavior.Strict, 6, true); - var mock4 = new Mock(Moq.MockBehavior.Default, "5"); - var mock5 = new Mock(MockBehavior.Strict); - var mock6 = new Mock(MockBehavior.Loose); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace NoConstructorArgumentsForInterfaceMock_2 +{ + public enum MockBehavior + { + Default, + Strict, + Loose, + } + + internal interface IMyService + { + void Do(string s); + } + + public class Mock + where T : class + { + public Mock() { } + + public Mock(params object[] ar) { } + + public Mock(MockBehavior behavior) { } + + public Mock(MockBehavior behavior, params object[] args) { } + } + + internal class MyUnitTests + { + private void TestRealMoqWithBadParameters() + { + var mock1 = new Moq.Mock(1, true); + var mock2 = new Moq.Mock("2"); + var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); + var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); + var mock5 = new Moq.Mock(MockBehavior.Default); + var mock6 = new Moq.Mock(MockBehavior.Default); + } + + private void TestRealMoqWithGoodParameters() + { + var mock1 = new Moq.Mock(Moq.MockBehavior.Default); + var mock2 = new Moq.Mock(Moq.MockBehavior.Default); + } + + private void TestFakeMoq() + { + var mock1 = new Mock("4"); + var mock2 = new Mock(5, true); + var mock3 = new Mock(MockBehavior.Strict, 6, true); + var mock4 = new Mock(Moq.MockBehavior.Default, "5"); + var mock5 = new Mock(MockBehavior.Strict); + var mock6 = new Mock(MockBehavior.Loose); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs b/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs index 258bf1f39..af007b997 100644 --- a/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs +++ b/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs @@ -1,44 +1,44 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoMethodsInPropertySetup -{ - using Moq; - - public interface IFoo - { - string Prop1 { get; set; } - - string Prop2 { get; } - - string Prop3 { set; } - - string Method(); - } - - public class MyUnitTests - { - private void TestBad() - { - var mock = new Mock(); - mock.SetupGet(x => x.Method()); - mock.SetupSet(x => x.Method()); - } - - private void TestGood() - { - var mock = new Mock(); - mock.SetupGet(x => x.Prop1); - mock.SetupGet(x => x.Prop2); - mock.SetupSet(x => x.Prop1 = "1"); - mock.SetupSet(x => x.Prop3 = "2"); - mock.Setup(x => x.Method()); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace NoMethodsInPropertySetup +{ + using Moq; + + public interface IFoo + { + string Prop1 { get; set; } + + string Prop2 { get; } + + string Prop3 { set; } + + string Method(); + } + + public class MyUnitTests + { + private void TestBad() + { + var mock = new Mock(); + mock.SetupGet(x => x.Method()); + mock.SetupSet(x => x.Method()); + } + + private void TestGood() + { + var mock = new Mock(); + mock.SetupGet(x => x.Prop1); + mock.SetupGet(x => x.Prop2); + mock.SetupSet(x => x.Prop1 = "1"); + mock.SetupSet(x => x.Prop3 = "2"); + mock.Setup(x => x.Method()); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs b/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs index c5405b3a1..80d1f5426 100644 --- a/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs +++ b/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs @@ -1,36 +1,36 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoSealedClassMocks -{ - using System; - using Moq; - - internal sealed class FooSealed - { - private void Do(string s) { } - } - - internal class MyUnitTests - { - private void Test() - { - var mock1 = new Moq.Mock(); - var mock2 = new Mock(); - var mock3 = new Mock(); - var mock4 = new Moq.Mock(); - } - - private void Test2() - { - new Mock>(); - new Mock(); - } - } +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1502 // Element must not be on a single line +#pragma warning disable SA1602 // Undocumented enum values +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable RCS1163 // Unused parameter +#pragma warning disable RCS1213 // Remove unused member declaration +#pragma warning disable IDE0051 // Unused private member +#pragma warning disable IDE0059 // Unnecessary value assignment +#pragma warning disable IDE0060 // Unused parameter +namespace NoSealedClassMocks +{ + using System; + using Moq; + + internal sealed class FooSealed + { + private void Do(string s) { } + } + + internal class MyUnitTests + { + private void Test() + { + var mock1 = new Moq.Mock(); + var mock2 = new Mock(); + var mock3 = new Mock(); + var mock4 = new Moq.Mock(); + } + + private void Test2() + { + new Mock>(); + new Mock(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs b/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs index a011e07cd..c35c0853d 100644 --- a/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs +++ b/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs @@ -23,8 +23,8 @@ public int Calculate() public abstract int Calculate(int a, int b); public abstract int Calculate(int a, int b, int c); - } - + } + public class SampleClass : BaseSampleClass { @@ -38,31 +38,31 @@ public class SampleClass : BaseSampleClass } internal class MyUnitTests - { + { private void TestOkForAbstractMethod() { var mock = new Mock(); mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - + } + private void TestOkForOverrideAbstractMethod() { var mock = new Mock(); mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - + } + private void TestOkForInterfaceMethod() { var mock = new Mock(); mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - + } + private void TestOkForInterfaceProperty() { var mock = new Mock(); mock.Setup(x => x.TestProperty); - } - + } + private void TestOkForVirtualMethod() { var mock = new Mock(); @@ -73,14 +73,14 @@ private void TestBadSetupForNonVirtualMethod() { var mock = new Mock(); mock.Setup(x => x.Calculate()); - } - + } + private void TestBadSetupForSealedMethod() { var mock = new Mock(); mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); - } - + } + private void TestBadSetupForNonVirtualProperty() { var mock = new Mock(); diff --git a/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs b/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs index b7e00e6f9..8b19166b1 100644 --- a/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs +++ b/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs @@ -1,37 +1,37 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable SA1502 // Element must not be on a single line - -namespace SetupShouldNotIncludeAsyncResult -{ - using Moq; - using System.Threading.Tasks; - - public class AsyncClient - { - public virtual Task VoidAsync() => Task.CompletedTask; - public virtual Task GenericAsyncWithConcreteReturn() => Task.FromResult(string.Empty); - } - - internal class MyUnitTests - { - private void TestOkForTask() - { - var mock = new Mock(); - mock.Setup(c => c.VoidAsync()); - } - - private void TestOkForTaskWithConcreteReturn() - { - var mock = new Mock(); - mock.Setup(c => c.GenericAsyncWithConcreteReturn().Result); - } - - private void TestOkForTaskWithConcreteReturnProperSetup() - { - var mock = new Mock(); - mock.Setup(c => c.GenericAsyncWithConcreteReturn()) - .ReturnsAsync(string.Empty); - } - } -} +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1649 // File name must match first type name +#pragma warning disable SA1502 // Element must not be on a single line + +namespace SetupShouldNotIncludeAsyncResult +{ + using Moq; + using System.Threading.Tasks; + + public class AsyncClient + { + public virtual Task VoidAsync() => Task.CompletedTask; + public virtual Task GenericAsyncWithConcreteReturn() => Task.FromResult(string.Empty); + } + + internal class MyUnitTests + { + private void TestOkForTask() + { + var mock = new Mock(); + mock.Setup(c => c.VoidAsync()); + } + + private void TestOkForTaskWithConcreteReturn() + { + var mock = new Mock(); + mock.Setup(c => c.GenericAsyncWithConcreteReturn().Result); + } + + private void TestOkForTaskWithConcreteReturnProperSetup() + { + var mock = new Mock(); + mock.Setup(c => c.GenericAsyncWithConcreteReturn()) + .ReturnsAsync(string.Empty); + } + } +} diff --git a/Source/Moq.Analyzers.Test/GlobalSuppressions.cs b/Source/Moq.Analyzers.Test/GlobalSuppressions.cs index 42c8a121c..47a706e8e 100644 --- a/Source/Moq.Analyzers.Test/GlobalSuppressions.cs +++ b/Source/Moq.Analyzers.Test/GlobalSuppressions.cs @@ -1,10 +1,10 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces must not be omitted", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Not required")] +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces must not be omitted", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Not required")] diff --git a/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.Helper.cs b/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.Helper.cs index d3a40b27a..d830fcd3a 100644 --- a/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.Helper.cs +++ b/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.Helper.cs @@ -1,84 +1,84 @@ -namespace TestHelper -{ - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CodeActions; - using Microsoft.CodeAnalysis.Formatting; - using Microsoft.CodeAnalysis.Simplification; - - /// - /// Diagnostic Producer class with extra methods dealing with applying codefixes - /// All methods are static - /// - public abstract partial class CodeFixVerifier : DiagnosticVerifier - { - /// - /// Apply the inputted CodeAction to the inputted document. - /// Meant to be used to apply codefixes. - /// - /// The Document to apply the fix on - /// A CodeAction that will be applied to the Document. - /// A Document with the changes from the CodeAction - private static Document ApplyFix(Document document, CodeAction codeAction) - { - var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; - var solution = operations.OfType().Single().ChangedSolution; - return solution.GetDocument(document.Id); - } - - /// - /// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection. - /// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row, - /// this method may not necessarily return the new one. - /// - /// The Diagnostics that existed in the code before the CodeFix was applied - /// The Diagnostics that exist in the code after the CodeFix was applied - /// A list of Diagnostics that only surfaced in the code after the CodeFix was applied - private static IEnumerable GetNewDiagnostics(IEnumerable diagnostics, IEnumerable newDiagnostics) - { - var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); - - int oldIndex = 0; - int newIndex = 0; - - while (newIndex < newArray.Length) - { - if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id) - { - ++oldIndex; - ++newIndex; - } - else - { - yield return newArray[newIndex++]; - } - } - } - - /// - /// Get the existing compiler diagnostics on the inputted document. - /// - /// The Document to run the compiler diagnostic analyzers on - /// The compiler diagnostics that were found in the code - private static IEnumerable GetCompilerDiagnostics(Document document) - { - return document.GetSemanticModelAsync().Result.GetDiagnostics(); - } - - /// - /// Given a document, turn it into a string based on the syntax root - /// - /// The Document to be converted to a string - /// A string containing the syntax of the Document after formatting - private static string GetStringFromDocument(Document document) - { - var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; - var root = simplifiedDoc.GetSyntaxRootAsync().Result; - root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); - return root.GetText().ToString(); - } - } +namespace TestHelper +{ + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CodeActions; + using Microsoft.CodeAnalysis.Formatting; + using Microsoft.CodeAnalysis.Simplification; + + /// + /// Diagnostic Producer class with extra methods dealing with applying codefixes + /// All methods are static + /// + public abstract partial class CodeFixVerifier : DiagnosticVerifier + { + /// + /// Apply the inputted CodeAction to the inputted document. + /// Meant to be used to apply codefixes. + /// + /// The Document to apply the fix on + /// A CodeAction that will be applied to the Document. + /// A Document with the changes from the CodeAction + private static Document ApplyFix(Document document, CodeAction codeAction) + { + var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; + var solution = operations.OfType().Single().ChangedSolution; + return solution.GetDocument(document.Id); + } + + /// + /// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection. + /// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row, + /// this method may not necessarily return the new one. + /// + /// The Diagnostics that existed in the code before the CodeFix was applied + /// The Diagnostics that exist in the code after the CodeFix was applied + /// A list of Diagnostics that only surfaced in the code after the CodeFix was applied + private static IEnumerable GetNewDiagnostics(IEnumerable diagnostics, IEnumerable newDiagnostics) + { + var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); + var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); + + int oldIndex = 0; + int newIndex = 0; + + while (newIndex < newArray.Length) + { + if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id) + { + ++oldIndex; + ++newIndex; + } + else + { + yield return newArray[newIndex++]; + } + } + } + + /// + /// Get the existing compiler diagnostics on the inputted document. + /// + /// The Document to run the compiler diagnostic analyzers on + /// The compiler diagnostics that were found in the code + private static IEnumerable GetCompilerDiagnostics(Document document) + { + return document.GetSemanticModelAsync().Result.GetDiagnostics(); + } + + /// + /// Given a document, turn it into a string based on the syntax root + /// + /// The Document to be converted to a string + /// A string containing the syntax of the Document after formatting + private static string GetStringFromDocument(Document document) + { + var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; + var root = simplifiedDoc.GetSyntaxRootAsync().Result; + root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); + return root.GetText().ToString(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.cs b/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.cs index 0c2ff8705..24e39b9de 100644 --- a/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.cs +++ b/Source/Moq.Analyzers.Test/Helpers/CodeFixVerifier.cs @@ -1,108 +1,108 @@ -namespace TestHelper -{ - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CodeActions; - using Microsoft.CodeAnalysis.CodeFixes; - using Microsoft.CodeAnalysis.Diagnostics; - using Microsoft.CodeAnalysis.Formatting; - using Xunit; - - /// - /// Superclass of all Unit tests made for diagnostics with codefixes. - /// Contains methods used to verify correctness of codefixes - /// - public abstract partial class CodeFixVerifier : DiagnosticVerifier - { - /// - /// Returns the codefix being tested (C#) - to be implemented in non-abstract class - /// - /// The CodeFixProvider to be used for CSharp code - protected virtual CodeFixProvider GetCSharpCodeFixProvider() - { - return null; - } - - /// - /// Called to test a C# codefix when applied on the inputted string as a source - /// - /// A class in the form of a string before the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - /// Code with quick fix applied - protected string VerifyCSharpFix(string oldSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) - { - return VerifyFix(LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, codeFixIndex, allowNewCompilerDiagnostics); - } - - /// - /// General verifier for codefixes. - /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes. - /// Then gets the string after the codefix is applied and compares it with the expected result. - /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. - /// - /// The language the source code is in - /// The analyzer to be applied to the source code - /// The codefix to be applied to the code wherever the relevant Diagnostic is found - /// A class in the form of a string before the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - /// Code with quick fix applied - private string VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) - { - var document = CreateDocument(oldSource, language); - var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); - var compilerDiagnostics = GetCompilerDiagnostics(document); - var attempts = analyzerDiagnostics.Length; - - for (int i = 0; i < attempts; ++i) - { - var actions = new List(); - var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); - codeFixProvider.RegisterCodeFixesAsync(context).Wait(); - - if (!actions.Any()) - { - break; - } - - if (codeFixIndex != null) - { - document = ApplyFix(document, actions.ElementAt((int)codeFixIndex)); - break; - } - - document = ApplyFix(document, actions.ElementAt(0)); - analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); - - var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); - - // check if applying the code fix introduced any new compiler diagnostics - if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any()) - { - // Format and get the compiler diagnostics again so that the locations make sense in the output - document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace)); - newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); - - Assert.True( - false, - string.Format( - "Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n", - string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())), - document.GetSyntaxRootAsync().Result.ToFullString())); - } - - // check if there are analyzer diagnostics left after the code fix - if (!analyzerDiagnostics.Any()) - { - break; - } - } - - // after applying all of the code fixes, compare the resulting string to the inputted one - return GetStringFromDocument(document); - } - } +namespace TestHelper +{ + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CodeActions; + using Microsoft.CodeAnalysis.CodeFixes; + using Microsoft.CodeAnalysis.Diagnostics; + using Microsoft.CodeAnalysis.Formatting; + using Xunit; + + /// + /// Superclass of all Unit tests made for diagnostics with codefixes. + /// Contains methods used to verify correctness of codefixes + /// + public abstract partial class CodeFixVerifier : DiagnosticVerifier + { + /// + /// Returns the codefix being tested (C#) - to be implemented in non-abstract class + /// + /// The CodeFixProvider to be used for CSharp code + protected virtual CodeFixProvider GetCSharpCodeFixProvider() + { + return null; + } + + /// + /// Called to test a C# codefix when applied on the inputted string as a source + /// + /// A class in the form of a string before the CodeFix was applied to it + /// Index determining which codefix to apply if there are multiple + /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied + /// Code with quick fix applied + protected string VerifyCSharpFix(string oldSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) + { + return VerifyFix(LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, codeFixIndex, allowNewCompilerDiagnostics); + } + + /// + /// General verifier for codefixes. + /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes. + /// Then gets the string after the codefix is applied and compares it with the expected result. + /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. + /// + /// The language the source code is in + /// The analyzer to be applied to the source code + /// The codefix to be applied to the code wherever the relevant Diagnostic is found + /// A class in the form of a string before the CodeFix was applied to it + /// Index determining which codefix to apply if there are multiple + /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied + /// Code with quick fix applied + private string VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) + { + var document = CreateDocument(oldSource, language); + var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); + var compilerDiagnostics = GetCompilerDiagnostics(document); + var attempts = analyzerDiagnostics.Length; + + for (int i = 0; i < attempts; ++i) + { + var actions = new List(); + var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); + codeFixProvider.RegisterCodeFixesAsync(context).Wait(); + + if (!actions.Any()) + { + break; + } + + if (codeFixIndex != null) + { + document = ApplyFix(document, actions.ElementAt((int)codeFixIndex)); + break; + } + + document = ApplyFix(document, actions.ElementAt(0)); + analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); + + var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); + + // check if applying the code fix introduced any new compiler diagnostics + if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any()) + { + // Format and get the compiler diagnostics again so that the locations make sense in the output + document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace)); + newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); + + Assert.True( + false, + string.Format( + "Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n", + string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())), + document.GetSyntaxRootAsync().Result.ToFullString())); + } + + // check if there are analyzer diagnostics left after the code fix + if (!analyzerDiagnostics.Any()) + { + break; + } + } + + // after applying all of the code fixes, compare the resulting string to the inputted one + return GetStringFromDocument(document); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Helpers/DiagnosticResult.cs b/Source/Moq.Analyzers.Test/Helpers/DiagnosticResult.cs index e88d85139..88c03bab6 100644 --- a/Source/Moq.Analyzers.Test/Helpers/DiagnosticResult.cs +++ b/Source/Moq.Analyzers.Test/Helpers/DiagnosticResult.cs @@ -1,55 +1,55 @@ -namespace TestHelper -{ - using Microsoft.CodeAnalysis; - - /// - /// Struct that stores information about a Diagnostic appearing in a source - /// - public struct DiagnosticResult - { - private DiagnosticResultLocation[] locations; - - public DiagnosticResultLocation[] Locations - { - get - { - return locations ?? (this.locations = new DiagnosticResultLocation[] { }); - } - - set - { - locations = value; - } - } - - public DiagnosticSeverity Severity { get; set; } - - public string Id { get; set; } - - public string Message { get; set; } - - public string Path - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Path : string.Empty; - } - } - - public int Line - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Line : -1; - } - } - - public int Column - { - get - { - return this.Locations.Length > 0 ? this.Locations[0].Column : -1; - } - } - } +namespace TestHelper +{ + using Microsoft.CodeAnalysis; + + /// + /// Struct that stores information about a Diagnostic appearing in a source + /// + public struct DiagnosticResult + { + private DiagnosticResultLocation[] locations; + + public DiagnosticResultLocation[] Locations + { + get + { + return locations ?? (this.locations = new DiagnosticResultLocation[] { }); + } + + set + { + locations = value; + } + } + + public DiagnosticSeverity Severity { get; set; } + + public string Id { get; set; } + + public string Message { get; set; } + + public string Path + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Path : string.Empty; + } + } + + public int Line + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Line : -1; + } + } + + public int Column + { + get + { + return this.Locations.Length > 0 ? this.Locations[0].Column : -1; + } + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Helpers/DiagnosticResultLocation.cs b/Source/Moq.Analyzers.Test/Helpers/DiagnosticResultLocation.cs index d20f3ed6a..9c4dd4739 100644 --- a/Source/Moq.Analyzers.Test/Helpers/DiagnosticResultLocation.cs +++ b/Source/Moq.Analyzers.Test/Helpers/DiagnosticResultLocation.cs @@ -1,33 +1,33 @@ -namespace TestHelper -{ - using System; - - /// - /// Location where the diagnostic appears, as determined by path, line number, and column number. - /// - public struct DiagnosticResultLocation - { - public DiagnosticResultLocation(string path, int line, int column) - { - if (line < -1) - { - throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); - } - - if (column < -1) - { - throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); - } - - this.Path = path; - this.Line = line; - this.Column = column; - } - - public string Path { get; } - - public int Line { get; } - - public int Column { get; } - } +namespace TestHelper +{ + using System; + + /// + /// Location where the diagnostic appears, as determined by path, line number, and column number. + /// + public struct DiagnosticResultLocation + { + public DiagnosticResultLocation(string path, int line, int column) + { + if (line < -1) + { + throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); + } + + if (column < -1) + { + throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); + } + + this.Path = path; + this.Line = line; + this.Column = column; + } + + public string Path { get; } + + public int Line { get; } + + public int Column { get; } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.Helper.cs b/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.Helper.cs index 4093f0a93..3957cce12 100644 --- a/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.Helper.cs +++ b/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.Helper.cs @@ -1,177 +1,177 @@ -namespace TestHelper -{ - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Linq; - using System.Linq.Expressions; - using System.Reflection; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.Diagnostics; - using Microsoft.CodeAnalysis.Text; - using Moq; - - /// - /// Class for turning strings into documents and getting the diagnostics on them - /// All methods are static. - /// - public abstract partial class DiagnosticVerifier - { - private const string DefaultFilePathPrefix = "Test"; - private const string CSharpDefaultFileExt = "cs"; - private const string VisualBasicDefaultExt = "vb"; - private const string TestProjectName = "TestProject"; - - 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 SystemLinqExpressions = MetadataReference.CreateFromFile(typeof(Expression).Assembly.Location); - private static readonly MetadataReference GenericCollectionsReference = MetadataReference.CreateFromFile(typeof(IEnumerable<>).Assembly.Location); - private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); - private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); - private static readonly MetadataReference MoqReference = MetadataReference.CreateFromFile(typeof(Mock).Assembly.Location); - private static readonly MetadataReference NetStandardReference = MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location); - private static readonly MetadataReference SystemRuntimeReference = MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location); - - /// - /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. - /// The returned diagnostics are then ordered by location in the source document. - /// - /// The analyzer to run on the documents. - /// The Documents that the analyzer will be run on. - /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. - protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) - { - var projects = new HashSet(); - foreach (var document in documents) - { - projects.Add(document.Project); - } - - var diagnostics = new List(); - foreach (var project in projects) - { - var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); - var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; - foreach (var diag in diags) - { - if (diag.Location == Location.None || diag.Location.IsInMetadata) - { - diagnostics.Add(diag); - } - else - { - for (int i = 0; i < documents.Length; i++) - { - var document = documents[i]; - var tree = document.GetSyntaxTreeAsync().Result; - if (tree == diag.Location.SourceTree) - { - diagnostics.Add(diag); - } - } - } - } - } - - var results = SortDiagnostics(diagnostics); - diagnostics.Clear(); - return results; - } - - /// - /// Create a Document from a string through creating a project that contains it. - /// - /// Classes in the form of a string. - /// The language the source code is in. - /// A Document created from the source string. - protected static Document CreateDocument(string source, string language = LanguageNames.CSharp) - { - return CreateProject(new[] { source }, language).Documents.First(); - } - - /// - /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer 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 IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. - private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) - { - return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); - } - - /// - /// Sort diagnostics by location in source document. - /// - /// The list of Diagnostics to be sorted. - /// An IEnumerable containing the Diagnostics in order of Location. - private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) - { - return diagnostics.OrderBy(d => d.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. - /// - /// 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. - private static Document[] GetDocuments(string[] sources, string language) - { - if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) - { - throw new ArgumentException("Unsupported Language"); - } - - var project = CreateProject(sources, language); - var documents = project.Documents.ToArray(); - - if (sources.Length != documents.Length) - { - throw new SystemException("Amount of sources did not match amount of Documents created"); - } - - return documents; - } - - /// - /// Create a project using the inputted strings as sources. - /// - /// Classes in the form of strings. - /// The language the source code is in. - /// A Project created out of the Documents created from the source strings. - private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp) - { - const string fileNamePrefix = DefaultFilePathPrefix; - string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt; - - var projectId = ProjectId.CreateNewId(debugName: TestProjectName); - - var solution = new AdhocWorkspace() - .CurrentSolution - .AddProject(projectId, TestProjectName, TestProjectName, language) - .AddMetadataReference(projectId, CorlibReference) - .AddMetadataReference(projectId, SystemCoreReference) - .AddMetadataReference(projectId, CodeAnalysisReference) - .AddMetadataReference(projectId, SystemLinqExpressions) - .AddMetadataReference(projectId, CSharpSymbolsReference) - .AddMetadataReference(projectId, GenericCollectionsReference) - .AddMetadataReference(projectId, SystemRuntimeReference) - .AddMetadataReference(projectId, NetStandardReference) - .AddMetadataReference(projectId, MoqReference); - - int count = 0; - foreach (var source in sources) - { - var newFileName = fileNamePrefix + count + "." + fileExt; - var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); - solution = solution.AddDocument(documentId, newFileName, SourceText.From(source)); - count++; - } - - return solution.GetProject(projectId); - } - } +namespace TestHelper +{ + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Linq; + using System.Linq.Expressions; + using System.Reflection; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.Diagnostics; + using Microsoft.CodeAnalysis.Text; + using Moq; + + /// + /// Class for turning strings into documents and getting the diagnostics on them + /// All methods are static. + /// + public abstract partial class DiagnosticVerifier + { + private const string DefaultFilePathPrefix = "Test"; + private const string CSharpDefaultFileExt = "cs"; + private const string VisualBasicDefaultExt = "vb"; + private const string TestProjectName = "TestProject"; + + 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 SystemLinqExpressions = MetadataReference.CreateFromFile(typeof(Expression).Assembly.Location); + private static readonly MetadataReference GenericCollectionsReference = MetadataReference.CreateFromFile(typeof(IEnumerable<>).Assembly.Location); + private static readonly MetadataReference CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location); + private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location); + private static readonly MetadataReference MoqReference = MetadataReference.CreateFromFile(typeof(Mock).Assembly.Location); + private static readonly MetadataReference NetStandardReference = MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location); + private static readonly MetadataReference SystemRuntimeReference = MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location); + + /// + /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. + /// The returned diagnostics are then ordered by location in the source document. + /// + /// The analyzer to run on the documents. + /// The Documents that the analyzer will be run on. + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. + protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) + { + var projects = new HashSet(); + foreach (var document in documents) + { + projects.Add(document.Project); + } + + var diagnostics = new List(); + foreach (var project in projects) + { + var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); + var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; + foreach (var diag in diags) + { + if (diag.Location == Location.None || diag.Location.IsInMetadata) + { + diagnostics.Add(diag); + } + else + { + for (int i = 0; i < documents.Length; i++) + { + var document = documents[i]; + var tree = document.GetSyntaxTreeAsync().Result; + if (tree == diag.Location.SourceTree) + { + diagnostics.Add(diag); + } + } + } + } + } + + var results = SortDiagnostics(diagnostics); + diagnostics.Clear(); + return results; + } + + /// + /// Create a Document from a string through creating a project that contains it. + /// + /// Classes in the form of a string. + /// The language the source code is in. + /// A Document created from the source string. + protected static Document CreateDocument(string source, string language = LanguageNames.CSharp) + { + return CreateProject(new[] { source }, language).Documents.First(); + } + + /// + /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer 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 IEnumerable of Diagnostics that surfaced in the source code, sorted by Location. + private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) + { + return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); + } + + /// + /// Sort diagnostics by location in source document. + /// + /// The list of Diagnostics to be sorted. + /// An IEnumerable containing the Diagnostics in order of Location. + private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) + { + return diagnostics.OrderBy(d => d.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. + /// + /// 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. + private static Document[] GetDocuments(string[] sources, string language) + { + if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic) + { + throw new ArgumentException("Unsupported Language"); + } + + var project = CreateProject(sources, language); + var documents = project.Documents.ToArray(); + + if (sources.Length != documents.Length) + { + throw new SystemException("Amount of sources did not match amount of Documents created"); + } + + return documents; + } + + /// + /// Create a project using the inputted strings as sources. + /// + /// Classes in the form of strings. + /// The language the source code is in. + /// A Project created out of the Documents created from the source strings. + private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp) + { + const string fileNamePrefix = DefaultFilePathPrefix; + string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt; + + var projectId = ProjectId.CreateNewId(debugName: TestProjectName); + + var solution = new AdhocWorkspace() + .CurrentSolution + .AddProject(projectId, TestProjectName, TestProjectName, language) + .AddMetadataReference(projectId, CorlibReference) + .AddMetadataReference(projectId, SystemCoreReference) + .AddMetadataReference(projectId, CodeAnalysisReference) + .AddMetadataReference(projectId, SystemLinqExpressions) + .AddMetadataReference(projectId, CSharpSymbolsReference) + .AddMetadataReference(projectId, GenericCollectionsReference) + .AddMetadataReference(projectId, SystemRuntimeReference) + .AddMetadataReference(projectId, NetStandardReference) + .AddMetadataReference(projectId, MoqReference); + + int count = 0; + foreach (var source in sources) + { + var newFileName = fileNamePrefix + count + "." + fileExt; + var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); + solution = solution.AddDocument(documentId, newFileName, SourceText.From(source)); + count++; + } + + return solution.GetProject(projectId); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.cs b/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.cs index c64428394..59c791147 100644 --- a/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.cs +++ b/Source/Moq.Analyzers.Test/Helpers/DiagnosticVerifier.cs @@ -1,89 +1,89 @@ -namespace TestHelper -{ - using System.Collections.Generic; - using System.Linq; - using System.Text; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.Diagnostics; - - /// - /// Superclass of all Unit Tests for DiagnosticAnalyzers - /// - public abstract partial class DiagnosticVerifier - { - /// - /// Get the CSharp analyzer being tested - to be implemented in non-abstract class - /// - /// Diagnostics to be used in test - protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return null; - } - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// A class in the form of a string to run the analyzer on - /// String representation of diagnostics results - protected string VerifyCSharpDiagnostic(string source) - { - return VerifyDiagnostics(new[] { source }, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer()); - } - - /// - /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source - /// Note: input a DiagnosticResult for each Diagnostic expected - /// - /// An array of strings to create source documents from to run the analyzers on - /// String representation of diagnostics results - protected string VerifyCSharpDiagnostic(string[] sources) - { - return VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer()); - } - - /// - /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, - /// then verifies each of them. - /// - /// An array of strings to create source documents from to run the analyzers on - /// The language of the classes represented by the source strings - /// The analyzer to be run on the sources - /// String representation of diagnostics results - private string VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) - { - var diagnostics = GetSortedDiagnostics(sources, language, analyzer); - return VerifyDiagnosticResults(diagnostics); - } - - /// - /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. - /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. - /// - /// The Diagnostics found by the compiler after running the analyzer on the source code - /// String representation of diagnostics results - private string VerifyDiagnosticResults(IEnumerable actualResults) - { - StringBuilder result = new StringBuilder(); - int i = 1; - foreach (var diagnostic in actualResults) - { - result.AppendLine("Diagnostic " + i); - result.AppendLine("\tId: " + diagnostic.Id); - result.AppendLine("\tLocation: " + diagnostic.Location); - var sourceSpan = diagnostic.Location.SourceSpan; - var code = diagnostic.Location.SourceTree.GetText(); - result.AppendLine("\tHighlight: " + code.GetSubText(sourceSpan)); - var lineSpan = diagnostic.Location.GetLineSpan(); - result.AppendLine("\tLines: " + string.Join("\n", code.Lines.Where(x => x.LineNumber >= lineSpan.StartLinePosition.Line && x.LineNumber <= lineSpan.EndLinePosition.Line).Select(x => x.ToString().Trim()))); - result.AppendLine("\tSeverity: " + diagnostic.Severity); - result.AppendLine("\tMessage: " + diagnostic.GetMessage()); - result.AppendLine(); - - i += 1; - } - - return result.ToString(); - } - } -} +namespace TestHelper +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.Diagnostics; + + /// + /// Superclass of all Unit Tests for DiagnosticAnalyzers + /// + public abstract partial class DiagnosticVerifier + { + /// + /// Get the CSharp analyzer being tested - to be implemented in non-abstract class + /// + /// Diagnostics to be used in test + protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return null; + } + + /// + /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// A class in the form of a string to run the analyzer on + /// String representation of diagnostics results + protected string VerifyCSharpDiagnostic(string source) + { + return VerifyDiagnostics(new[] { source }, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer()); + } + + /// + /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source + /// Note: input a DiagnosticResult for each Diagnostic expected + /// + /// An array of strings to create source documents from to run the analyzers on + /// String representation of diagnostics results + protected string VerifyCSharpDiagnostic(string[] sources) + { + return VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer()); + } + + /// + /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, + /// then verifies each of them. + /// + /// An array of strings to create source documents from to run the analyzers on + /// The language of the classes represented by the source strings + /// The analyzer to be run on the sources + /// String representation of diagnostics results + private string VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) + { + var diagnostics = GetSortedDiagnostics(sources, language, analyzer); + return VerifyDiagnosticResults(diagnostics); + } + + /// + /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. + /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. + /// + /// The Diagnostics found by the compiler after running the analyzer on the source code + /// String representation of diagnostics results + private string VerifyDiagnosticResults(IEnumerable actualResults) + { + StringBuilder result = new StringBuilder(); + int i = 1; + foreach (var diagnostic in actualResults) + { + result.AppendLine("Diagnostic " + i); + result.AppendLine("\tId: " + diagnostic.Id); + result.AppendLine("\tLocation: " + diagnostic.Location); + var sourceSpan = diagnostic.Location.SourceSpan; + var code = diagnostic.Location.SourceTree.GetText(); + result.AppendLine("\tHighlight: " + code.GetSubText(sourceSpan)); + var lineSpan = diagnostic.Location.GetLineSpan(); + result.AppendLine("\tLines: " + string.Join("\n", code.Lines.Where(x => x.LineNumber >= lineSpan.StartLinePosition.Line && x.LineNumber <= lineSpan.EndLinePosition.Line).Select(x => x.ToString().Trim()))); + result.AppendLine("\tSeverity: " + diagnostic.Severity); + result.AppendLine("\tMessage: " + diagnostic.GetMessage()); + result.AppendLine(); + + i += 1; + } + + return result.ToString(); + } + } +} diff --git a/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj b/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj index ac0e5fb5f..0d3535021 100644 --- a/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj +++ b/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj @@ -1,74 +1,74 @@ - - - - net8.0 - false - - - - 1701;1702;SA1600;SA1402 - - - - false - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - - + + + + net8.0 + false + + + + 1701;1702;SA1600;SA1402 + + + + false + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt index 121043ab3..64c98c443 100644 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1001 - Location: SourceFile(Test0.cs[856..866)) + Location: SourceFile(Test0.cs[834..844)) Highlight: (25, true) Lines: var mock1 = new Moq.Mock(25, true); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1001 - Location: SourceFile(Test0.cs[913..920)) + Location: SourceFile(Test0.cs[890..897)) Highlight: ("123") Lines: var mock2 = new Mock("123"); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1001 - Location: SourceFile(Test0.cs[1008..1018)) + Location: SourceFile(Test0.cs[984..994)) Highlight: (25, true) Lines: var mock3 = new Mock(25, true); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1001 - Location: SourceFile(Test0.cs[1110..1117)) + Location: SourceFile(Test0.cs[1085..1092)) Highlight: ("123") Lines: var mock4 = new Moq.Mock("123"); Severity: Warning @@ -32,7 +32,7 @@ Diagnostic 4 Diagnostic 5 Id: Moq1001 - Location: SourceFile(Test0.cs[1225..1258)) + Location: SourceFile(Test0.cs[1195..1228)) Highlight: (Moq.MockBehavior.Default, "123") Lines: var mock1 = new Moq.Mock(Moq.MockBehavior.Default, "123"); Severity: Warning @@ -40,7 +40,7 @@ Diagnostic 5 Diagnostic 6 Id: Moq1001 - Location: SourceFile(Test0.cs[1305..1336)) + Location: SourceFile(Test0.cs[1274..1305)) Highlight: (MockBehavior.Strict, 25, true) Lines: var mock2 = new Mock(MockBehavior.Strict, 25, true); Severity: Warning @@ -48,7 +48,7 @@ Diagnostic 6 Diagnostic 7 Id: Moq1001 - Location: SourceFile(Test0.cs[1424..1457)) + Location: SourceFile(Test0.cs[1392..1425)) Highlight: (Moq.MockBehavior.Default, "123") Lines: var mock3 = new Mock(Moq.MockBehavior.Default, "123"); Severity: Warning @@ -56,7 +56,7 @@ Diagnostic 7 Diagnostic 8 Id: Moq1001 - Location: SourceFile(Test0.cs[1549..1579)) + Location: SourceFile(Test0.cs[1516..1546)) Highlight: (MockBehavior.Loose, 25, true) Lines: var mock4 = new Moq.Mock(MockBehavior.Loose, 25, true); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt index d48a0c3b7..1216d0c9b 100644 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1001 - Location: SourceFile(Test0.cs[1219..1228)) + Location: SourceFile(Test0.cs[1180..1189)) Highlight: (1, true) Lines: var mock1 = new Moq.Mock(1, true); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1001 - Location: SourceFile(Test0.cs[1320..1325)) + Location: SourceFile(Test0.cs[1280..1285)) Highlight: ("2") Lines: var mock2 = new Moq.Mock("2"); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1001 - Location: SourceFile(Test0.cs[1376..1407)) + Location: SourceFile(Test0.cs[1335..1366)) Highlight: (Moq.MockBehavior.Default, "3") Lines: var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1001 - Location: SourceFile(Test0.cs[1499..1528)) + Location: SourceFile(Test0.cs[1457..1486)) Highlight: (MockBehavior.Loose, 4, true) Lines: var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); Severity: Warning @@ -32,7 +32,7 @@ Diagnostic 4 Diagnostic 5 Id: Moq1001 - Location: SourceFile(Test0.cs[1579..1601)) + Location: SourceFile(Test0.cs[1536..1558)) Highlight: (MockBehavior.Default) Lines: var mock5 = new Moq.Mock(MockBehavior.Default); Severity: Warning @@ -40,7 +40,7 @@ Diagnostic 5 Diagnostic 6 Id: Moq1001 - Location: SourceFile(Test0.cs[1693..1715)) + Location: SourceFile(Test0.cs[1649..1671)) Highlight: (MockBehavior.Default) Lines: var mock6 = new Moq.Mock(MockBehavior.Default); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs index 03cddc0cc..fda735cd2 100644 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs @@ -1,28 +1,28 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class NoConstructorArgumentsForInterfaceMockAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldFailIfMockedInterfaceHasParameters() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_1.cs"))); - } - - [Fact] - public Task ShouldPassIfCustomMockClassIsUsed() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_2.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new NoConstructorArgumentsForInterfaceMockAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class NoConstructorArgumentsForInterfaceMockAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldFailIfMockedInterfaceHasParameters() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_1.cs"))); + } + + [Fact] + public Task ShouldPassIfCustomMockClassIsUsed() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_2.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new NoConstructorArgumentsForInterfaceMockAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt index 85a9ede58..85ddfdaeb 100644 --- a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt +++ b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1101 - Location: SourceFile(Test0.cs[957..967)) + Location: SourceFile(Test0.cs[928..938)) Highlight: x.Method() Lines: mock.SetupGet(x => x.Method()); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1101 - Location: SourceFile(Test0.cs[1002..1012)) + Location: SourceFile(Test0.cs[972..982)) Highlight: x.Method() Lines: mock.SetupSet(x => x.Method()); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs index c908bcd70..fa967dc11 100644 --- a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class NoMethodsInPropertySetupAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task Test() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoMethodsInPropertySetup.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new NoMethodsInPropertySetupAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class NoMethodsInPropertySetupAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task Test() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoMethodsInPropertySetup.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new NoMethodsInPropertySetupAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt index f2677d87d..aa0f8da71 100644 --- a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt +++ b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1000 - Location: SourceFile(Test0.cs[852..861)) + Location: SourceFile(Test0.cs[829..838)) Highlight: FooSealed Lines: var mock1 = new Moq.Mock(); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1000 - Location: SourceFile(Test0.cs[900..909)) + Location: SourceFile(Test0.cs[876..885)) Highlight: FooSealed Lines: var mock2 = new Mock(); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1000 - Location: SourceFile(Test0.cs[948..976)) + Location: SourceFile(Test0.cs[923..951)) Highlight: NoSealedClassMocks.FooSealed Lines: var mock3 = new Mock(); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1000 - Location: SourceFile(Test0.cs[1019..1047)) + Location: SourceFile(Test0.cs[993..1021)) Highlight: NoSealedClassMocks.FooSealed Lines: var mock4 = new Moq.Mock(); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs index e18ea233f..06e4dd047 100644 --- a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class NoSealedClassMocksAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldFailIfFileIsSealed() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoSealedClassMocks.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new NoSealedClassMocksAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class NoSealedClassMocksAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldFailIfFileIsSealed() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoSealedClassMocks.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new NoSealedClassMocksAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt index 9dc3085b9..f8c67a125 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1200 - Location: SourceFile(Test0.cs[2075..2088)) + Location: SourceFile(Test0.cs[2064..2077)) Highlight: x.Calculate() Lines: mock.Setup(x => x.Calculate()); Severity: Error @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1200 - Location: SourceFile(Test0.cs[2241..2303)) + Location: SourceFile(Test0.cs[2228..2290)) Highlight: x.Calculate(It.IsAny(), It.IsAny(), It.IsAny()) Lines: mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); Severity: Error @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1200 - Location: SourceFile(Test0.cs[2462..2472)) + Location: SourceFile(Test0.cs[2447..2457)) Highlight: x.Property Lines: mock.Setup(x => x.Property); Severity: Error diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs index a03a9e191..e47d7312b 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldPassIfGoodParameters() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupOnlyForOverridableMembers.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new SetupShouldBeUsedOnlyForOverridableMembersAnalyzer(); - } - } +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldPassIfGoodParameters() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupOnlyForOverridableMembers.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new SetupShouldBeUsedOnlyForOverridableMembersAnalyzer(); + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt index 8b7fa6a54..33d23abf5 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1201 - Location: SourceFile(Test0.cs[871..912)) + Location: SourceFile(Test0.cs[845..886)) Highlight: c.GenericAsyncWithConcreteReturn().Result Lines: mock.Setup(c => c.GenericAsyncWithConcreteReturn().Result); Severity: Error diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs index b378bd1d7..bd02f3429 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs @@ -1,22 +1,22 @@ -namespace Moq.Analyzers.Test -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis.Diagnostics; - using TestHelper; - using Xunit; - - public class SetupShouldNotIncludeAsyncResultAnalyzerTests : DiagnosticVerifier - { - [Fact] - public Task ShouldPassIfSetupProperly() - { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupShouldNotIncludeAsyncResult.cs"))); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new SetupShouldNotIncludeAsyncResultAnalyzer(); - } - } -} +namespace Moq.Analyzers.Test +{ + using System.IO; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Diagnostics; + using TestHelper; + using Xunit; + + public class SetupShouldNotIncludeAsyncResultAnalyzerTests : DiagnosticVerifier + { + [Fact] + public Task ShouldPassIfSetupProperly() + { + return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupShouldNotIncludeAsyncResult.cs"))); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new SetupShouldNotIncludeAsyncResultAnalyzer(); + } + } +} diff --git a/Source/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs b/Source/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs index 664ecffcc..6be01992f 100644 --- a/Source/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs +++ b/Source/Moq.Analyzers/CallbackSignatureShouldMatchMockedMethodCodeFix.cs @@ -1,73 +1,73 @@ -namespace Moq.Analyzers -{ - using System.Collections.Immutable; - using System.Composition; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CodeActions; - using Microsoft.CodeAnalysis.CodeFixes; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; - - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CallbackSignatureShouldMatchMockedMethodCodeFix))] - [Shared] - public class CallbackSignatureShouldMatchMockedMethodCodeFix : CodeFixProvider - { - public sealed override ImmutableArray FixableDiagnosticIds - { - get { return ImmutableArray.Create(Diagnostics.CallbackSignatureShouldMatchMockedMethodId); } - } - - public sealed override FixAllProvider GetFixAllProvider() - { - return WellKnownFixAllProviders.BatchFixer; - } - - public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - - var diagnostic = context.Diagnostics.First(); - var diagnosticSpan = diagnostic.Location.SourceSpan; - - // Find the type declaration identified by the diagnostic. - var badArgumentListSyntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); - - // Register a code action that will invoke the fix. - context.RegisterCodeFix( - CodeAction.Create( - title: "Fix Moq callback signature", - createChangedDocument: c => FixCallbackSignature(root, context.Document, badArgumentListSyntax, c), - equivalenceKey: "Fix Moq callback signature"), - diagnostic); - } - - private async Task FixCallbackSignature(SyntaxNode root, Document document, ParameterListSyntax oldParameters, CancellationToken cancellationToken) - { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken); - var callbackInvocation = oldParameters?.Parent?.Parent?.Parent?.Parent as InvocationExpressionSyntax; - if (callbackInvocation != null) - { - var setupMethodInvocation = Helpers.FindSetupMethodFromCallbackInvocation(semanticModel, callbackInvocation); - var matchingMockedMethods = Helpers.GetAllMatchingMockedMethodSymbolsFromSetupMethodInvocation(semanticModel, setupMethodInvocation).ToArray(); - - if (matchingMockedMethods.Length == 1) - { - var newParameters = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(matchingMockedMethods[0].Parameters.Select( - p => - { - var type = SyntaxFactory.ParseTypeName(p.Type.ToMinimalDisplayString(semanticModel, oldParameters.SpanStart)); - return SyntaxFactory.Parameter(default(SyntaxList), SyntaxFactory.TokenList(), type, SyntaxFactory.Identifier(p.Name), null); - }))); - - var newRoot = root.ReplaceNode(oldParameters, newParameters); - return document.WithSyntaxRoot(newRoot); - } - } - - return document; - } - } +namespace Moq.Analyzers +{ + using System.Collections.Immutable; + using System.Composition; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CodeActions; + using Microsoft.CodeAnalysis.CodeFixes; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CallbackSignatureShouldMatchMockedMethodCodeFix))] + [Shared] + public class CallbackSignatureShouldMatchMockedMethodCodeFix : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds + { + get { return ImmutableArray.Create(Diagnostics.CallbackSignatureShouldMatchMockedMethodId); } + } + + public sealed override FixAllProvider GetFixAllProvider() + { + return WellKnownFixAllProviders.BatchFixer; + } + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + var diagnostic = context.Diagnostics.First(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + + // Find the type declaration identified by the diagnostic. + var badArgumentListSyntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + + // Register a code action that will invoke the fix. + context.RegisterCodeFix( + CodeAction.Create( + title: "Fix Moq callback signature", + createChangedDocument: c => FixCallbackSignature(root, context.Document, badArgumentListSyntax, c), + equivalenceKey: "Fix Moq callback signature"), + diagnostic); + } + + private async Task FixCallbackSignature(SyntaxNode root, Document document, ParameterListSyntax oldParameters, CancellationToken cancellationToken) + { + var semanticModel = await document.GetSemanticModelAsync(cancellationToken); + var callbackInvocation = oldParameters?.Parent?.Parent?.Parent?.Parent as InvocationExpressionSyntax; + if (callbackInvocation != null) + { + var setupMethodInvocation = Helpers.FindSetupMethodFromCallbackInvocation(semanticModel, callbackInvocation); + var matchingMockedMethods = Helpers.GetAllMatchingMockedMethodSymbolsFromSetupMethodInvocation(semanticModel, setupMethodInvocation).ToArray(); + + if (matchingMockedMethods.Length == 1) + { + var newParameters = SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(matchingMockedMethods[0].Parameters.Select( + p => + { + var type = SyntaxFactory.ParseTypeName(p.Type.ToMinimalDisplayString(semanticModel, oldParameters.SpanStart)); + return SyntaxFactory.Parameter(default(SyntaxList), SyntaxFactory.TokenList(), type, SyntaxFactory.Identifier(p.Name), null); + }))); + + var newRoot = root.ReplaceNode(oldParameters, newParameters); + return document.WithSyntaxRoot(newRoot); + } + } + + return document; + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs b/Source/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs index dda6cf68b..17bf60046 100644 --- a/Source/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs +++ b/Source/Moq.Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs @@ -1,86 +1,86 @@ -namespace Moq.Analyzers -{ - using System.Collections.Immutable; - using System.Linq; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; - using Microsoft.CodeAnalysis.Diagnostics; - - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class ConstructorArgumentsShouldMatchAnalyzer : DiagnosticAnalyzer - { - private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - Diagnostics.ConstructorArgumentsShouldMatchId, - Diagnostics.ConstructorArgumentsShouldMatchTitle, - Diagnostics.ConstructorArgumentsShouldMatchMessage, - Diagnostics.Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics - { - get { return ImmutableArray.Create(Rule); } - } - - public override void Initialize(AnalysisContext context) - { - context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); - } - - private static void Analyze(SyntaxNodeAnalysisContext context) - { - var objectCreation = (ObjectCreationExpressionSyntax)context.Node; - - // TODO Think how to make this piece more elegant while fast - GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; - if (objectCreation.Type is QualifiedNameSyntax) - { - var qualifiedName = objectCreation.Type as QualifiedNameSyntax; - genericName = qualifiedName.Right as GenericNameSyntax; - } - - if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; - - // Quick and dirty check that we are calling new Mock() - if (genericName.Identifier.ToFullString() != "Mock") return; - - // Full check that we are calling new Mock() - var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); - var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; - if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; - if (constructorSymbol.MethodKind != MethodKind.Constructor) return; - if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; - if (constructorSymbol.Parameters == null || constructorSymbol.Parameters.Length == 0) return; - - // Vararg parameter is the one that takes all arguments for mocked class constructor - var varArgsConstructorParameter = constructorSymbol.Parameters.FirstOrDefault(x => x.IsParams); - - // Vararg parameter are not used, so there are no arguments for mocked class constructor - if (varArgsConstructorParameter == null) return; - var varArgsConstructorParameterIdx = constructorSymbol.Parameters.IndexOf(varArgsConstructorParameter); - - // Find mocked type - var typeArguments = genericName.TypeArgumentList.Arguments; - if (typeArguments == null || typeArguments.Count != 1) return; - var mockedTypeSymbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); - var mockedTypeSymbol = mockedTypeSymbolInfo.Symbol as INamedTypeSymbol; - if (mockedTypeSymbol == null || mockedTypeSymbol.TypeKind != TypeKind.Class) return; - - // TODO: Currently detection does not work well for abstract classes because they cannot be instantiated - if (mockedTypeSymbol.IsAbstract) return; - - // Skip first argument if it is not vararg - typically it is MockingBehavior argument - var constructorArguments = objectCreation.ArgumentList.Arguments.Skip(varArgsConstructorParameterIdx == 0 ? 0 : 1).ToArray(); - - // Build fake constructor call to understand how it is resolved - var fakeConstructorCall = SyntaxFactory.ObjectCreationExpression(typeArguments[0], SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(constructorArguments)), null); - var mockedClassConstructorSymbolInfo = context.SemanticModel.GetSpeculativeSymbolInfo(objectCreation.GetLocation().SourceSpan.Start, fakeConstructorCall, SpeculativeBindingOption.BindAsExpression); - if (mockedClassConstructorSymbolInfo.Symbol == null) - { - var diagnostic = Diagnostic.Create(Rule, objectCreation.ArgumentList.GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } - } -} +namespace Moq.Analyzers +{ + using System.Collections.Immutable; + using System.Linq; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ConstructorArgumentsShouldMatchAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + Diagnostics.ConstructorArgumentsShouldMatchId, + Diagnostics.ConstructorArgumentsShouldMatchTitle, + Diagnostics.ConstructorArgumentsShouldMatchMessage, + Diagnostics.Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + { + get { return ImmutableArray.Create(Rule); } + } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); + } + + private static void Analyze(SyntaxNodeAnalysisContext context) + { + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + + // TODO Think how to make this piece more elegant while fast + GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; + if (objectCreation.Type is QualifiedNameSyntax) + { + var qualifiedName = objectCreation.Type as QualifiedNameSyntax; + genericName = qualifiedName.Right as GenericNameSyntax; + } + + if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; + + // Quick and dirty check that we are calling new Mock() + if (genericName.Identifier.ToFullString() != "Mock") return; + + // Full check that we are calling new Mock() + var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); + var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; + if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; + if (constructorSymbol.MethodKind != MethodKind.Constructor) return; + if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; + if (constructorSymbol.Parameters == null || constructorSymbol.Parameters.Length == 0) return; + + // Vararg parameter is the one that takes all arguments for mocked class constructor + var varArgsConstructorParameter = constructorSymbol.Parameters.FirstOrDefault(x => x.IsParams); + + // Vararg parameter are not used, so there are no arguments for mocked class constructor + if (varArgsConstructorParameter == null) return; + var varArgsConstructorParameterIdx = constructorSymbol.Parameters.IndexOf(varArgsConstructorParameter); + + // Find mocked type + var typeArguments = genericName.TypeArgumentList.Arguments; + if (typeArguments == null || typeArguments.Count != 1) return; + var mockedTypeSymbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); + var mockedTypeSymbol = mockedTypeSymbolInfo.Symbol as INamedTypeSymbol; + if (mockedTypeSymbol == null || mockedTypeSymbol.TypeKind != TypeKind.Class) return; + + // TODO: Currently detection does not work well for abstract classes because they cannot be instantiated + if (mockedTypeSymbol.IsAbstract) return; + + // Skip first argument if it is not vararg - typically it is MockingBehavior argument + var constructorArguments = objectCreation.ArgumentList.Arguments.Skip(varArgsConstructorParameterIdx == 0 ? 0 : 1).ToArray(); + + // Build fake constructor call to understand how it is resolved + var fakeConstructorCall = SyntaxFactory.ObjectCreationExpression(typeArguments[0], SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(constructorArguments)), null); + var mockedClassConstructorSymbolInfo = context.SemanticModel.GetSpeculativeSymbolInfo(objectCreation.GetLocation().SourceSpan.Start, fakeConstructorCall, SpeculativeBindingOption.BindAsExpression); + if (mockedClassConstructorSymbolInfo.Symbol == null) + { + var diagnostic = Diagnostic.Create(Rule, objectCreation.ArgumentList.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/Source/Moq.Analyzers/GlobalSuppressions.cs b/Source/Moq.Analyzers/GlobalSuppressions.cs index 42c8a121c..47a706e8e 100644 --- a/Source/Moq.Analyzers/GlobalSuppressions.cs +++ b/Source/Moq.Analyzers/GlobalSuppressions.cs @@ -1,10 +1,10 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces must not be omitted", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Not required")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Not required")] +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File must have header", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:Braces must not be omitted", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Not required")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Not required")] diff --git a/Source/Moq.Analyzers/Moq.Analyzers.csproj b/Source/Moq.Analyzers/Moq.Analyzers.csproj index 0c5e533b7..60aaa0c7c 100644 --- a/Source/Moq.Analyzers/Moq.Analyzers.csproj +++ b/Source/Moq.Analyzers/Moq.Analyzers.csproj @@ -1,77 +1,77 @@ - - - 11.0 - Debug - AnyCPU - AnyCPU - {41ECC571-F586-460A-9BED-23528C8210C4} - Library - Properties - Moq.Analyzers - Moq.Analyzers - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - netstandard2.0 - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - Moq.Analyzers - Andrey "Litee" Lipatkin - https://github.com/Litee/moq.analyzers/blob/master/LICENSE - https://github.com/Litee/moq.analyzers - false - Roslyn analyzer that helps to write unit tests using Moq mocking library by highlighting typical errors and suggesting quick fixes. Port of Resharper extension to Roslyn. Find the full list of detected issues at project GitHub page. - Upgraded to support Visual Studio 2019 - 2015-2019 Andrey Lipatkin - moq, mock, test, analyzers - true - true - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - + + + 11.0 + Debug + AnyCPU + AnyCPU + {41ECC571-F586-460A-9BED-23528C8210C4} + Library + Properties + Moq.Analyzers + Moq.Analyzers + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + netstandard2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + Moq.Analyzers + Andrey "Litee" Lipatkin + https://github.com/Litee/moq.analyzers/blob/master/LICENSE + https://github.com/Litee/moq.analyzers + false + Roslyn analyzer that helps to write unit tests using Moq mocking library by highlighting typical errors and suggesting quick fixes. Port of Resharper extension to Roslyn. Find the full list of detected issues at project GitHub page. + Upgraded to support Visual Studio 2019 + 2015-2019 Andrey Lipatkin + moq, mock, test, analyzers + true + true + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Moq.Analyzers/MoqMethodDescriptor.cs b/Source/Moq.Analyzers/MoqMethodDescriptor.cs index 26003e58d..10c9746b8 100644 --- a/Source/Moq.Analyzers/MoqMethodDescriptor.cs +++ b/Source/Moq.Analyzers/MoqMethodDescriptor.cs @@ -1,55 +1,55 @@ -namespace Moq.Analyzers -{ - using System.Linq; - using System.Text.RegularExpressions; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp.Syntax; - - internal class MoqMethodDescriptor - { - private readonly bool isGeneric; - - public MoqMethodDescriptor(string shortMethodName, Regex fullMethodNamePattern, bool isGeneric=false) - { - this.isGeneric = isGeneric; - ShortMethodName = shortMethodName; - FullMethodNamePattern = fullMethodNamePattern; - } - - private string ShortMethodName { get; } - - private Regex FullMethodNamePattern { get; } - - public bool IsMoqMethod(SemanticModel semanticModel, MemberAccessExpressionSyntax method) - { - var methodName = method?.Name.ToString(); - - // First fast check before walking semantic model - if (DoesShortMethodMatch(methodName) == false) return false; - - var symbolInfo = semanticModel.GetSymbolInfo(method); - if (symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure) - { - return symbolInfo.CandidateSymbols.OfType() - .Any(s => this.FullMethodNamePattern.IsMatch(s.ToString())); - } - else if (symbolInfo.CandidateReason == CandidateReason.None) - { - // TODO: Replace regex with something more elegant - return symbolInfo.Symbol is IMethodSymbol && - this.FullMethodNamePattern.IsMatch(symbolInfo.Symbol.ToString()); - } - - return false; - } - - private bool DoesShortMethodMatch(string methodName) - { - if (isGeneric) - { - return methodName.StartsWith($"{this.ShortMethodName}<"); - } - return methodName == this.ShortMethodName; - } - } +namespace Moq.Analyzers +{ + using System.Linq; + using System.Text.RegularExpressions; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + internal class MoqMethodDescriptor + { + private readonly bool isGeneric; + + public MoqMethodDescriptor(string shortMethodName, Regex fullMethodNamePattern, bool isGeneric=false) + { + this.isGeneric = isGeneric; + ShortMethodName = shortMethodName; + FullMethodNamePattern = fullMethodNamePattern; + } + + private string ShortMethodName { get; } + + private Regex FullMethodNamePattern { get; } + + public bool IsMoqMethod(SemanticModel semanticModel, MemberAccessExpressionSyntax method) + { + var methodName = method?.Name.ToString(); + + // First fast check before walking semantic model + if (DoesShortMethodMatch(methodName) == false) return false; + + var symbolInfo = semanticModel.GetSymbolInfo(method); + if (symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure) + { + return symbolInfo.CandidateSymbols.OfType() + .Any(s => this.FullMethodNamePattern.IsMatch(s.ToString())); + } + else if (symbolInfo.CandidateReason == CandidateReason.None) + { + // TODO: Replace regex with something more elegant + return symbolInfo.Symbol is IMethodSymbol && + this.FullMethodNamePattern.IsMatch(symbolInfo.Symbol.ToString()); + } + + return false; + } + + private bool DoesShortMethodMatch(string methodName) + { + if (isGeneric) + { + return methodName.StartsWith($"{this.ShortMethodName}<"); + } + return methodName == this.ShortMethodName; + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers/NoConstructorArgumentsForInterfaceMockAnalyzer.cs b/Source/Moq.Analyzers/NoConstructorArgumentsForInterfaceMockAnalyzer.cs index bf3aa3a60..107f4b3fd 100644 --- a/Source/Moq.Analyzers/NoConstructorArgumentsForInterfaceMockAnalyzer.cs +++ b/Source/Moq.Analyzers/NoConstructorArgumentsForInterfaceMockAnalyzer.cs @@ -1,72 +1,72 @@ -namespace Moq.Analyzers -{ - using System.Collections.Immutable; - using System.Linq; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; - using Microsoft.CodeAnalysis.Diagnostics; - - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class NoConstructorArgumentsForInterfaceMockAnalyzer : DiagnosticAnalyzer - { - private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - Diagnostics.NoConstructorArgumentsForInterfaceMockId, - Diagnostics.NoConstructorArgumentsForInterfaceMockTitle, - Diagnostics.NoConstructorArgumentsForInterfaceMockMessage, - Diagnostics.Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics - { - get { return ImmutableArray.Create(Rule); } - } - - public override void Initialize(AnalysisContext context) - { - context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); - } - - private static void Analyze(SyntaxNodeAnalysisContext context) - { - var objectCreation = (ObjectCreationExpressionSyntax)context.Node; - - // TODO Think how to make this piece more elegant while fast - GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; - if (objectCreation.Type is QualifiedNameSyntax) - { - var qualifiedName = objectCreation.Type as QualifiedNameSyntax; - genericName = qualifiedName.Right as GenericNameSyntax; - } - - if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; - - // Quick and dirty check - if (genericName.Identifier.ToFullString() != "Mock") return; - - // Full check - var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); - var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; - if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; - if (constructorSymbol.MethodKind != MethodKind.Constructor) return; - if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; - if (constructorSymbol.Parameters == null || constructorSymbol.Parameters.Length == 0) return; - if (!constructorSymbol.Parameters.Any(x => x.IsParams)) return; - - // Find mocked type - var typeArguments = genericName.TypeArgumentList.Arguments; - if (typeArguments == null || typeArguments.Count != 1) return; - var symbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); - var symbol = symbolInfo.Symbol as INamedTypeSymbol; - if (symbol == null) return; - - // Checked mocked type - if (symbol.TypeKind == TypeKind.Interface) - { - var diagnostic = Diagnostic.Create(Rule, objectCreation.ArgumentList.GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } - } -} +namespace Moq.Analyzers +{ + using System.Collections.Immutable; + using System.Linq; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NoConstructorArgumentsForInterfaceMockAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + Diagnostics.NoConstructorArgumentsForInterfaceMockId, + Diagnostics.NoConstructorArgumentsForInterfaceMockTitle, + Diagnostics.NoConstructorArgumentsForInterfaceMockMessage, + Diagnostics.Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + { + get { return ImmutableArray.Create(Rule); } + } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); + } + + private static void Analyze(SyntaxNodeAnalysisContext context) + { + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + + // TODO Think how to make this piece more elegant while fast + GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; + if (objectCreation.Type is QualifiedNameSyntax) + { + var qualifiedName = objectCreation.Type as QualifiedNameSyntax; + genericName = qualifiedName.Right as GenericNameSyntax; + } + + if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; + + // Quick and dirty check + if (genericName.Identifier.ToFullString() != "Mock") return; + + // Full check + var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); + var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; + if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; + if (constructorSymbol.MethodKind != MethodKind.Constructor) return; + if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; + if (constructorSymbol.Parameters == null || constructorSymbol.Parameters.Length == 0) return; + if (!constructorSymbol.Parameters.Any(x => x.IsParams)) return; + + // Find mocked type + var typeArguments = genericName.TypeArgumentList.Arguments; + if (typeArguments == null || typeArguments.Count != 1) return; + var symbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); + var symbol = symbolInfo.Symbol as INamedTypeSymbol; + if (symbol == null) return; + + // Checked mocked type + if (symbol.TypeKind == TypeKind.Interface) + { + var diagnostic = Diagnostic.Create(Rule, objectCreation.ArgumentList.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/Source/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs b/Source/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs index 0e58c1808..a568c7667 100644 --- a/Source/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs +++ b/Source/Moq.Analyzers/NoSealedClassMocksAnalyzer.cs @@ -1,69 +1,69 @@ -namespace Moq.Analyzers -{ - using System.Collections.Immutable; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; - using Microsoft.CodeAnalysis.Diagnostics; - - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class NoSealedClassMocksAnalyzer : DiagnosticAnalyzer - { - private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - Diagnostics.NoSealedClassMocksId, - Diagnostics.NoSealedClassMocksTitle, - Diagnostics.NoSealedClassMocksMessage, - Diagnostics.Category, - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics - { - get { return ImmutableArray.Create(Rule); } - } - - public override void Initialize(AnalysisContext context) - { - context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); - } - - private static void Analyze(SyntaxNodeAnalysisContext context) - { - var objectCreation = (ObjectCreationExpressionSyntax)context.Node; - - // TODO Think how to make this piece more elegant while fast - GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; - if (objectCreation.Type is QualifiedNameSyntax) - { - var qualifiedName = objectCreation.Type as QualifiedNameSyntax; - genericName = qualifiedName.Right as GenericNameSyntax; - } - - if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; - - // Quick and dirty check - if (genericName.Identifier.ToFullString() != "Mock") return; - - // Full check - var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); - var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; - if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; - if (constructorSymbol.MethodKind != MethodKind.Constructor) return; - if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; - - // Find mocked type - var typeArguments = genericName.TypeArgumentList.Arguments; - if (typeArguments == null || typeArguments.Count != 1) return; - var symbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); - var symbol = symbolInfo.Symbol as INamedTypeSymbol; - if (symbol == null) return; - - // Checked mocked type - if (symbol.IsSealed && symbol.TypeKind != TypeKind.Delegate) - { - var diagnostic = Diagnostic.Create(Rule, typeArguments[0].GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } - } -} +namespace Moq.Analyzers +{ + using System.Collections.Immutable; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NoSealedClassMocksAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + Diagnostics.NoSealedClassMocksId, + Diagnostics.NoSealedClassMocksTitle, + Diagnostics.NoSealedClassMocksMessage, + Diagnostics.Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics + { + get { return ImmutableArray.Create(Rule); } + } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.ObjectCreationExpression); + } + + private static void Analyze(SyntaxNodeAnalysisContext context) + { + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + + // TODO Think how to make this piece more elegant while fast + GenericNameSyntax genericName = objectCreation.Type as GenericNameSyntax; + if (objectCreation.Type is QualifiedNameSyntax) + { + var qualifiedName = objectCreation.Type as QualifiedNameSyntax; + genericName = qualifiedName.Right as GenericNameSyntax; + } + + if (genericName?.Identifier == null || genericName.TypeArgumentList == null) return; + + // Quick and dirty check + if (genericName.Identifier.ToFullString() != "Mock") return; + + // Full check + var constructorSymbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation); + var constructorSymbol = constructorSymbolInfo.Symbol as IMethodSymbol; + if (constructorSymbol == null || constructorSymbol.ContainingType == null || constructorSymbol.ContainingType.ConstructedFrom == null) return; + if (constructorSymbol.MethodKind != MethodKind.Constructor) return; + if (constructorSymbol.ContainingType.ConstructedFrom.ToDisplayString() != "Moq.Mock") return; + + // Find mocked type + var typeArguments = genericName.TypeArgumentList.Arguments; + if (typeArguments == null || typeArguments.Count != 1) return; + var symbolInfo = context.SemanticModel.GetSymbolInfo(typeArguments[0]); + var symbol = symbolInfo.Symbol as INamedTypeSymbol; + if (symbol == null) return; + + // Checked mocked type + if (symbol.IsSealed && symbol.TypeKind != TypeKind.Delegate) + { + var diagnostic = Diagnostic.Create(Rule, typeArguments[0].GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/Source/Moq.Analyzers/Resources.Designer.cs b/Source/Moq.Analyzers/Resources.Designer.cs index 5f97d3096..7ed376f12 100644 --- a/Source/Moq.Analyzers/Resources.Designer.cs +++ b/Source/Moq.Analyzers/Resources.Designer.cs @@ -1,64 +1,64 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Moq.Analyzers { - using System; - using System.Reflection; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Moq.Analyzers.Resources", typeof(Resources).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Moq.Analyzers { + using System; + using System.Reflection; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Moq.Analyzers.Resources", typeof(Resources).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Source/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs b/Source/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs index 245c70285..27464ed96 100644 --- a/Source/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs +++ b/Source/Moq.Analyzers/SetupShouldNotIncludeAsyncResultAnalyzer.cs @@ -1,69 +1,69 @@ -namespace Moq.Analyzers -{ - using System; - using System.Collections.Immutable; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; - using Microsoft.CodeAnalysis.Diagnostics; - - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class SetupShouldNotIncludeAsyncResultAnalyzer : DiagnosticAnalyzer - { - private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( - Diagnostics.SetupShouldNotIncludeAsyncResultId, - Diagnostics.SetupShouldNotIncludeAsyncResultTitle, - Diagnostics.SetupShouldNotIncludeAsyncResultMessage, - Diagnostics.Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); - - public override void Initialize(AnalysisContext context) - { - context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.InvocationExpression); - } - - private static void Analyze(SyntaxNodeAnalysisContext context) - { - var setupInvocation = (InvocationExpressionSyntax)context.Node; - - if (setupInvocation.Expression is MemberAccessExpressionSyntax memberAccessExpression && Helpers.IsMoqSetupMethod(context.SemanticModel, memberAccessExpression)) - { - var mockedMemberExpression = Helpers.FindMockedMemberExpressionFromSetupMethod(setupInvocation); - if (mockedMemberExpression == null) - { - return; - } - - var symbolInfo = context.SemanticModel.GetSymbolInfo(mockedMemberExpression); - if (symbolInfo.Symbol is IPropertySymbol || symbolInfo.Symbol is IMethodSymbol) - { - if (IsMethodOverridable(symbolInfo.Symbol) == false && - IsMethodReturnTypeTask(symbolInfo.Symbol) == true) - { - var diagnostic = Diagnostic.Create(Rule, mockedMemberExpression.GetLocation()); - context.ReportDiagnostic(diagnostic); - } - } - } - } - - private static bool IsMethodOverridable(ISymbol methodSymbol) - { - return methodSymbol.IsSealed == false && (methodSymbol.IsVirtual || methodSymbol.IsAbstract || methodSymbol.IsOverride); - } - - private static bool IsMethodReturnTypeTask(ISymbol methodSymbol) - { - var type = methodSymbol.ToDisplayString(); - return type != null && - (type == "System.Threading.Tasks.Task" || - type == "System.Threading.ValueTask" || - type.StartsWith("System.Threading.Tasks.Task<", StringComparison.Ordinal) || - type.StartsWith("System.Threading.Tasks.ValueTask<", StringComparison.Ordinal) && - type.EndsWith(".Result", StringComparison.Ordinal)); - } - } -} +namespace Moq.Analyzers +{ + using System; + using System.Collections.Immutable; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + using Microsoft.CodeAnalysis.Diagnostics; + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class SetupShouldNotIncludeAsyncResultAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + Diagnostics.SetupShouldNotIncludeAsyncResultId, + Diagnostics.SetupShouldNotIncludeAsyncResultTitle, + Diagnostics.SetupShouldNotIncludeAsyncResultMessage, + Diagnostics.Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.InvocationExpression); + } + + private static void Analyze(SyntaxNodeAnalysisContext context) + { + var setupInvocation = (InvocationExpressionSyntax)context.Node; + + if (setupInvocation.Expression is MemberAccessExpressionSyntax memberAccessExpression && Helpers.IsMoqSetupMethod(context.SemanticModel, memberAccessExpression)) + { + var mockedMemberExpression = Helpers.FindMockedMemberExpressionFromSetupMethod(setupInvocation); + if (mockedMemberExpression == null) + { + return; + } + + var symbolInfo = context.SemanticModel.GetSymbolInfo(mockedMemberExpression); + if (symbolInfo.Symbol is IPropertySymbol || symbolInfo.Symbol is IMethodSymbol) + { + if (IsMethodOverridable(symbolInfo.Symbol) == false && + IsMethodReturnTypeTask(symbolInfo.Symbol) == true) + { + var diagnostic = Diagnostic.Create(Rule, mockedMemberExpression.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + } + } + + private static bool IsMethodOverridable(ISymbol methodSymbol) + { + return methodSymbol.IsSealed == false && (methodSymbol.IsVirtual || methodSymbol.IsAbstract || methodSymbol.IsOverride); + } + + private static bool IsMethodReturnTypeTask(ISymbol methodSymbol) + { + var type = methodSymbol.ToDisplayString(); + return type != null && + (type == "System.Threading.Tasks.Task" || + type == "System.Threading.ValueTask" || + type.StartsWith("System.Threading.Tasks.Task<", StringComparison.Ordinal) || + type.StartsWith("System.Threading.Tasks.ValueTask<", StringComparison.Ordinal) && + type.EndsWith(".Result", StringComparison.Ordinal)); + } + } +} diff --git a/Source/Moq.Analyzers/tools/install.ps1 b/Source/Moq.Analyzers/tools/install.ps1 index 425260fad..9e3fbbf48 100644 --- a/Source/Moq.Analyzers/tools/install.ps1 +++ b/Source/Moq.Analyzers/tools/install.ps1 @@ -1,58 +1,58 @@ -param($installPath, $toolsPath, $package, $project) - -if($project.Object.SupportsPackageDependencyResolution) -{ - if($project.Object.SupportsPackageDependencyResolution()) - { - # Do not install analyzers via install.ps1, instead let the project system handle it. - return - } -} - -$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve - -foreach($analyzersPath in $analyzersPaths) -{ - if (Test-Path $analyzersPath) - { - # Install the language agnostic analyzers. - foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) - { - if($project.Object.AnalyzerReferences) - { - $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) - } - } - } -} - -# $project.Type gives the language name like (C# or VB.NET) -$languageFolder = "" -if($project.Type -eq "C#") -{ - $languageFolder = "cs" -} -if($project.Type -eq "VB.NET") -{ - $languageFolder = "vb" -} -if($languageFolder -eq "") -{ - return -} - -foreach($analyzersPath in $analyzersPaths) -{ - # Install language specific analyzers. - $languageAnalyzersPath = join-path $analyzersPath $languageFolder - if (Test-Path $languageAnalyzersPath) - { - foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) - { - if($project.Object.AnalyzerReferences) - { - $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) - } - } - } +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not install analyzers via install.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + if (Test-Path $analyzersPath) + { + # Install the language agnostic analyzers. + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq "") +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Install language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) + } + } + } } \ No newline at end of file diff --git a/Source/Moq.Analyzers/tools/uninstall.ps1 b/Source/Moq.Analyzers/tools/uninstall.ps1 index b165e6e2f..7d9c8cc1d 100644 --- a/Source/Moq.Analyzers/tools/uninstall.ps1 +++ b/Source/Moq.Analyzers/tools/uninstall.ps1 @@ -1,65 +1,65 @@ -param($installPath, $toolsPath, $package, $project) - -if($project.Object.SupportsPackageDependencyResolution) -{ - if($project.Object.SupportsPackageDependencyResolution()) - { - # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. - return - } -} - -$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve - -foreach($analyzersPath in $analyzersPaths) -{ - # Uninstall the language agnostic analyzers. - if (Test-Path $analyzersPath) - { - foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) - { - if($project.Object.AnalyzerReferences) - { - $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) - } - } - } -} - -# $project.Type gives the language name like (C# or VB.NET) -$languageFolder = "" -if($project.Type -eq "C#") -{ - $languageFolder = "cs" -} -if($project.Type -eq "VB.NET") -{ - $languageFolder = "vb" -} -if($languageFolder -eq "") -{ - return -} - -foreach($analyzersPath in $analyzersPaths) -{ - # Uninstall language specific analyzers. - $languageAnalyzersPath = join-path $analyzersPath $languageFolder - if (Test-Path $languageAnalyzersPath) - { - foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) - { - if($project.Object.AnalyzerReferences) - { - try - { - $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) - } - catch - { - - } - } - } - } +param($installPath, $toolsPath, $package, $project) + +if($project.Object.SupportsPackageDependencyResolution) +{ + if($project.Object.SupportsPackageDependencyResolution()) + { + # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. + return + } +} + +$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall the language agnostic analyzers. + if (Test-Path $analyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + } + } +} + +# $project.Type gives the language name like (C# or VB.NET) +$languageFolder = "" +if($project.Type -eq "C#") +{ + $languageFolder = "cs" +} +if($project.Type -eq "VB.NET") +{ + $languageFolder = "vb" +} +if($languageFolder -eq "") +{ + return +} + +foreach($analyzersPath in $analyzersPaths) +{ + # Uninstall language specific analyzers. + $languageAnalyzersPath = join-path $analyzersPath $languageFolder + if (Test-Path $languageAnalyzersPath) + { + foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) + { + if($project.Object.AnalyzerReferences) + { + try + { + $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) + } + catch + { + + } + } + } + } } \ No newline at end of file