From 264f9c871e855683bfff76abfafea699e64b59c3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 29 Mar 2018 12:24:16 -0700 Subject: [PATCH] Add an analyzer to warn against the use of IHtmlHelper.Partial and IHtmlHelper.RenderPartial Fixes https://github.com/aspnet/Mvc/issues/7417 --- Mvc.NoFun.sln | 62 ++++-- Mvc.sln | 45 +++- .../ActionsMustNotBeAsyncVoidAnalyzer.cs | 2 +- .../ActionsMustNotBeAsyncVoidFixProvider.cs | 2 +- .../ApiActionsAreAttributeRoutedAnalyzer.cs | 2 +- ...ApiActionsAreAttributeRoutedFixProvider.cs | 2 +- ...ireExplicitModelValidationCheckAnalyzer.cs | 2 +- ...icitModelValidationCheckCodeFixProvider.cs | 2 +- ...ActionsShouldUseActionResultOfTAnalyzer.cs | 2 +- ...ShouldUseActionResultOfTCodeFixProvider.cs | 2 +- .../ApiControllerAnalyzerBase.cs | 0 .../ApiControllerAnalyzerContext.cs | 0 .../CodeAnalysisExtensions.cs | 0 .../ControllerAnalyzerBase.cs | 0 .../ControllerAnalyzerContext.cs | 0 .../DiagnosticDescriptors.cs | 46 ++++ ...pNetCore.Mvc.Analyzers.Experimental.csproj | 25 +++ .../TypeNames.cs | 0 .../AvoidHtmlPartialAnalyzer.cs | 54 +++++ .../DiagnosticDescriptors.cs | 33 +-- .../Microsoft.AspNetCore.Mvc.Analyzers.csproj | 5 - .../SymbolNames.cs | 16 ++ .../ViewFeatureAnalyzerBase.cs | 40 ++++ .../ViewFeaturesAnalyzerContext.cs | 48 +++++ .../ActionsMustNotBeAsyncVoidFacts.cs | 6 +- ...equireExplicitModelValidationCheckFacts.cs | 6 +- .../ApiActionsAreAttributeRoutedFacts.cs | 2 +- ...ApiActionsShouldUseActionResultOfTFacts.cs | 4 +- ...ore.Mvc.Analyzers.Experimental.Test.csproj | 20 ++ .../xunit.runner.json | 3 + .../AvoidHtmlPartialAnalyzerTest.cs | 202 ++++++++++++++++++ .../Infrastructure/AnalyzerTestBase.cs | 48 +++++ .../Infrastructure/Assert.cs | 36 +++- .../Infrastructure/DiagnosticResult.cs | 5 + ...osoft.AspNetCore.Mvc.Analyzers.Test.csproj | 2 +- ...gnosticsAreReturned_ForUseOfHtmlPartial.cs | 33 +++ ...Returned_ForUseOfHtmlPartial_InSections.cs | 35 +++ ...eOfHtmlPartial_WithAdditionalParameters.cs | 33 +++ ...osticsAreReturned_ForUseOfRenderPartial.cs | 33 +++ ...turned_ForUseOfRenderPartial_InSections.cs | 35 +++ ...fRenderPartial_WithAdditionalParameters.cs | 33 +++ ...sticsAreReturned_ForNonUseOfHtmlPartial.cs | 33 +++ ...icsAreReturned_ForUseOfHtmlPartialAsync.cs | 33 +++ ...sAreReturned_ForUseOfRenderPartialAsync.cs | 33 +++ 44 files changed, 944 insertions(+), 81 deletions(-) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ActionsMustNotBeAsyncVoidAnalyzer.cs (96%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ActionsMustNotBeAsyncVoidFixProvider.cs (97%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsAreAttributeRoutedAnalyzer.cs (96%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsAreAttributeRoutedFixProvider.cs (99%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs (98%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs (96%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsShouldUseActionResultOfTAnalyzer.cs (98%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs (97%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiControllerAnalyzerBase.cs (100%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ApiControllerAnalyzerContext.cs (100%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/CodeAnalysisExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ControllerAnalyzerBase.cs (100%) rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/ControllerAnalyzerContext.cs (100%) create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/DiagnosticDescriptors.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj rename src/{Microsoft.AspNetCore.Mvc.Analyzers => Microsoft.AspNetCore.Mvc.Analyzers.Experimental}/TypeNames.cs (100%) create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers/AvoidHtmlPartialAnalyzer.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers/SymbolNames.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeatureAnalyzerBase.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeaturesAnalyzerContext.cs rename test/{Microsoft.AspNetCore.Mvc.Analyzers.Test => Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test}/ActionsMustNotBeAsyncVoidFacts.cs (98%) rename test/{Microsoft.AspNetCore.Mvc.Analyzers.Test => Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test}/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs (98%) rename test/{Microsoft.AspNetCore.Mvc.Analyzers.Test => Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test}/ApiActionsAreAttributeRoutedFacts.cs (99%) rename test/{Microsoft.AspNetCore.Mvc.Analyzers.Test => Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test}/ApiActionsShouldUseActionResultOfTFacts.cs (99%) create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/xunit.runner.json create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/AvoidHtmlPartialAnalyzerTest.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_InSections.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync.cs diff --git a/Mvc.NoFun.sln b/Mvc.NoFun.sln index 601eda5fad..33f4a84d2f 100644 --- a/Mvc.NoFun.sln +++ b/Mvc.NoFun.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27130.2020 +VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" EndProject @@ -104,9 +104,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{44546170-35BF-448F-88F5-4331AE67AEAE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{29454949-4AE0-4B3B-9157-BFC28B7ECD97}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj", "{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental", "src\Microsoft.AspNetCore.Mvc.Analyzers.Experimental\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj", "{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -494,18 +498,6 @@ Global {28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|Mixed Platforms.Build.0 = Release|Any CPU {28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|x86.ActiveCfg = Release|Any CPU {28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|x86.Build.0 = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|x86.ActiveCfg = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Debug|x86.Build.0 = Debug|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|Any CPU.Build.0 = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|x86.ActiveCfg = Release|Any CPU - {29454949-4AE0-4B3B-9157-BFC28B7ECD97}.Release|x86.Build.0 = Release|Any CPU {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -518,6 +510,42 @@ Global {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|Mixed Platforms.Build.0 = Release|Any CPU {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|x86.ActiveCfg = Release|Any CPU {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|x86.Build.0 = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|x86.Build.0 = Debug|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|Any CPU.Build.0 = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|x86.ActiveCfg = Release|Any CPU + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|x86.Build.0 = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|x86.ActiveCfg = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|x86.Build.0 = Debug|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Any CPU.Build.0 = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|x86.ActiveCfg = Release|Any CPU + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|x86.Build.0 = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|x86.ActiveCfg = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|x86.Build.0 = Debug|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|Any CPU.Build.0 = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|x86.ActiveCfg = Release|Any CPU + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -556,8 +584,10 @@ Global {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {0AB46520-F441-4E01-B444-08F4D23F8B1B} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {28D4DA20-6E13-47F9-80AE-D6AA7699CC35} = {44546170-35BF-448F-88F5-4331AE67AEAE} - {29454949-4AE0-4B3B-9157-BFC28B7ECD97} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {30862895-C1FA-49F5-B69A-B0F9F2ECD0F3} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {F8FD2D6A-DCD1-4A7B-B599-B728A12A1754} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {829D9A67-2D07-4CE6-86C0-59F2549B0CFA} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D003597F-372F-4068-A2F0-353BE3C3B39A} diff --git a/Mvc.sln b/Mvc.sln index c413434a40..88dcf6cc45 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -1,6 +1,7 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26831.3000 +VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" EndProject @@ -153,15 +154,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{FDC66952-A3EA-4074-899E-C29816BF7C1F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorBuildWebSite", "test\WebSites\RazorBuildWebSite\RazorBuildWebSite.csproj", "{BF8A3392-C3D2-4813-855A-E906564600E1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorBuildWebSite", "test\WebSites\RazorBuildWebSite\RazorBuildWebSite.csproj", "{BF8A3392-C3D2-4813-855A-E906564600E1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorBuildWebSite.PrecompiledViews", "test\WebSites\RazorBuildWebSite.PrecompiledViews\RazorBuildWebSite.PrecompiledViews.csproj", "{856D7E25-E033-477D-9ABD-0B50CF428C80}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorBuildWebSite.PrecompiledViews", "test\WebSites\RazorBuildWebSite.PrecompiledViews\RazorBuildWebSite.PrecompiledViews.csproj", "{856D7E25-E033-477D-9ABD-0B50CF428C80}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorBuildWebSite.Views", "test\WebSites\RazorBuildWebSite.Views\RazorBuildWebSite.Views.csproj", "{8916DDCA-EC2A-4193-B9F3-78CAA1A96D5A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorBuildWebSite.Views", "test\WebSites\RazorBuildWebSite.Views\RazorBuildWebSite.Views.csproj", "{8916DDCA-EC2A-4193-B9F3-78CAA1A96D5A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{87A3E227-C45E-4141-A59F-402908E651FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{87A3E227-C45E-4141-A59F-402908E651FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental", "src\Microsoft.AspNetCore.Mvc.Analyzers.Experimental\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj", "{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj", "{E83D3745-9BCF-40E8-8D34-AFBA604C2439}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -849,6 +854,30 @@ Global {E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|Mixed Platforms.Build.0 = Release|Any CPU {E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|x86.ActiveCfg = Release|Any CPU {E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|x86.Build.0 = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|x86.ActiveCfg = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|x86.Build.0 = Debug|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Any CPU.Build.0 = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|x86.ActiveCfg = Release|Any CPU + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|x86.Build.0 = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|x86.ActiveCfg = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|x86.Build.0 = Debug|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Any CPU.Build.0 = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|x86.ActiveCfg = Release|Any CPU + {E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -915,6 +944,8 @@ Global {8916DDCA-EC2A-4193-B9F3-78CAA1A96D5A} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {87A3E227-C45E-4141-A59F-402908E651FD} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {E3E09D2F-1FCF-4396-9B09-5A62CA8CC831} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {CBF23034-2249-4FE5-BD48-5F3CEAC0DF61} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {E83D3745-9BCF-40E8-8D34-AFBA604C2439} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A} diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidAnalyzer.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidAnalyzer.cs similarity index 96% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidAnalyzer.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidAnalyzer.cs index 6b08beb7e7..90b2032abb 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidAnalyzer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidAnalyzer.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public static readonly string ReturnTypeKey = "ReturnType"; public ActionsMustNotBeAsyncVoidAnalyzer() - : base(DiagnosticDescriptors.MVC1003_ActionsMustNotBeAsyncVoid) + : base(DiagnosticDescriptors.MVC7003_ActionsMustNotBeAsyncVoid) { } diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidFixProvider.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidFixProvider.cs similarity index 97% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidFixProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidFixProvider.cs index d953859891..f36c18d0e6 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ActionsMustNotBeAsyncVoidFixProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ActionsMustNotBeAsyncVoidFixProvider.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public class ActionsMustNotBeAsyncVoidFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticDescriptors.MVC1003_ActionsMustNotBeAsyncVoid.Id); + ImmutableArray.Create(DiagnosticDescriptors.MVC7003_ActionsMustNotBeAsyncVoid.Id); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedAnalyzer.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedAnalyzer.cs similarity index 96% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedAnalyzer.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedAnalyzer.cs index f6817314f6..59a8eec020 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedAnalyzer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedAnalyzer.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers internal const string MethodNameKey = "MethodName"; public ApiActionsAreAttributeRoutedAnalyzer() - : base(DiagnosticDescriptors.MVC1000_ApiActionsMustBeAttributeRouted) + : base(DiagnosticDescriptors.MVC7000_ApiActionsMustBeAttributeRouted) { } diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedFixProvider.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs similarity index 99% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedFixProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs index e7d697f0a2..e97e593a9f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsAreAttributeRoutedFixProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsAreAttributeRoutedFixProvider.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers }; public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticDescriptors.MVC1000_ApiActionsMustBeAttributeRouted.Id); + ImmutableArray.Create(DiagnosticDescriptors.MVC7000_ApiActionsMustBeAttributeRouted.Id); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs similarity index 98% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs index eb563d7eb5..67eb82bd2b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public class ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer : ApiControllerAnalyzerBase { public ApiActionsDoNotRequireExplicitModelValidationCheckAnalyzer() - : base(DiagnosticDescriptors.MVC1001_ApiActionsHaveBadModelStateFilter) + : base(DiagnosticDescriptors.MVC7001_ApiActionsHaveBadModelStateFilter) { } diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs similarity index 96% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs index 21245fa0b0..3637c47217 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public class ApiActionsDoNotRequireExplicitModelValidationCheckCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticDescriptors.MVC1001_ApiActionsHaveBadModelStateFilter.Id); + ImmutableArray.Create(DiagnosticDescriptors.MVC7001_ApiActionsHaveBadModelStateFilter.Id); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTAnalyzer.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTAnalyzer.cs similarity index 98% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTAnalyzer.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTAnalyzer.cs index b6ba8f6be6..ef00b99527 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTAnalyzer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTAnalyzer.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public static readonly string ReturnTypeKey = "ReturnType"; public ApiActionsShouldUseActionResultOfTAnalyzer() - : base(DiagnosticDescriptors.MVC1002_ApiActionsShouldReturnActionResultOf) + : base(DiagnosticDescriptors.MVC7002_ApiActionsShouldReturnActionResultOf) { } diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs similarity index 97% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs index d75bbed522..792b47227b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiActionsShouldUseActionResultOfTCodeFixProvider.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public class ApiActionsShouldUseActionResultOfTCodeFixProvider : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(DiagnosticDescriptors.MVC1002_ApiActionsShouldReturnActionResultOf.Id); + ImmutableArray.Create(DiagnosticDescriptors.MVC7002_ApiActionsShouldReturnActionResultOf.Id); public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiControllerAnalyzerBase.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiControllerAnalyzerBase.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiControllerAnalyzerBase.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiControllerAnalyzerBase.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ApiControllerAnalyzerContext.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiControllerAnalyzerContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ApiControllerAnalyzerContext.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ApiControllerAnalyzerContext.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/CodeAnalysisExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/CodeAnalysisExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/CodeAnalysisExtensions.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/CodeAnalysisExtensions.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ControllerAnalyzerBase.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ControllerAnalyzerBase.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ControllerAnalyzerBase.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ControllerAnalyzerBase.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ControllerAnalyzerContext.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ControllerAnalyzerContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/ControllerAnalyzerContext.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/ControllerAnalyzerContext.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/DiagnosticDescriptors.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/DiagnosticDescriptors.cs new file mode 100644 index 0000000000..7c8100234c --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/DiagnosticDescriptors.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + public static class DiagnosticDescriptors + { + public static readonly DiagnosticDescriptor MVC7000_ApiActionsMustBeAttributeRouted = + new DiagnosticDescriptor( + "MVC7000", + "Actions on types annotated with ApiControllerAttribute must be attribute routed.", + "Actions on types annotated with ApiControllerAttribute must be attribute routed.", + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MVC7001_ApiActionsHaveBadModelStateFilter = + new DiagnosticDescriptor( + "MVC7001", + "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", + "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MVC7002_ApiActionsShouldReturnActionResultOf = + new DiagnosticDescriptor( + "MVC7002", + "Actions on types annotated with ApiControllerAttribute should return ActionResult.", + "Actions on types annotated with ApiControllerAttribute should return ActionResult.", + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MVC7003_ActionsMustNotBeAsyncVoid = + new DiagnosticDescriptor( + "MVC7003", + "Controller actions must not have async void signature.", + "Controller actions must not have async void signature.", + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj new file mode 100644 index 0000000000..82d88610b4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj @@ -0,0 +1,25 @@ + + + CSharp Analyzers for ASP.NET Core MVC. + aspnetcore;aspnetcoremvc + + false + $(ExperimentalVersionPrefix) + $(ExperimentalVersionSuffix) + $(ExperimentalPackageVersion) + + netstandard2.0 + false + false + false + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/TypeNames.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/TypeNames.cs similarity index 100% rename from src/Microsoft.AspNetCore.Mvc.Analyzers/TypeNames.cs rename to src/Microsoft.AspNetCore.Mvc.Analyzers.Experimental/TypeNames.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/AvoidHtmlPartialAnalyzer.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers/AvoidHtmlPartialAnalyzer.cs new file mode 100644 index 0000000000..3563fa525b --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/AvoidHtmlPartialAnalyzer.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class AvoidHtmlPartialAnalyzer : ViewFeatureAnalyzerBase + { + public AvoidHtmlPartialAnalyzer() + : base(DiagnosticDescriptors.MVC1000_HtmlHelperPartialShouldBeAvoided) + { + } + + protected override void InitializeWorker(ViewFeaturesAnalyzerContext analyzerContext) + { + analyzerContext.Context.RegisterSyntaxNodeAction(context => + { + var invocationExpression = (InvocationExpressionSyntax)context.Node; + var symbol = context.SemanticModel.GetSymbolInfo(invocationExpression, context.CancellationToken).Symbol; + if (symbol == null || symbol.Kind != SymbolKind.Method) + { + return; + } + + var method = (IMethodSymbol)symbol; + if (!analyzerContext.IsHtmlHelperExtensionMethod(method)) + { + return; + } + + if (string.Equals(SymbolNames.PartialMethod, method.Name, StringComparison.Ordinal)) + { + context.ReportDiagnostic(Diagnostic.Create( + SupportedDiagnostic, + invocationExpression.GetLocation(), + new[] { SymbolNames.PartialMethod })); + } + else if (string.Equals(SymbolNames.RenderPartialMethod, method.Name, StringComparison.Ordinal)) + { + context.ReportDiagnostic(Diagnostic.Create( + SupportedDiagnostic, + invocationExpression.GetLocation(), + new[] { SymbolNames.RenderPartialMethod })); + } + }, SyntaxKind.InvocationExpression); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/DiagnosticDescriptors.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers/DiagnosticDescriptors.cs index 3ad7235cec..89465662b4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/DiagnosticDescriptors.cs +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/DiagnosticDescriptors.cs @@ -7,38 +7,11 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers { public static class DiagnosticDescriptors { - public static readonly DiagnosticDescriptor MVC1000_ApiActionsMustBeAttributeRouted = + public static readonly DiagnosticDescriptor MVC1000_HtmlHelperPartialShouldBeAvoided = new DiagnosticDescriptor( "MVC1000", - "Actions on types annotated with ApiControllerAttribute must be attribute routed.", - "Actions on types annotated with ApiControllerAttribute must be attribute routed.", - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public static readonly DiagnosticDescriptor MVC1001_ApiActionsHaveBadModelStateFilter = - new DiagnosticDescriptor( - "MVC1001", - "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", - "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public static readonly DiagnosticDescriptor MVC1002_ApiActionsShouldReturnActionResultOf = - new DiagnosticDescriptor( - "MVC1002", - "Actions on types annotated with ApiControllerAttribute should return ActionResult.", - "Actions on types annotated with ApiControllerAttribute should return ActionResult.", - "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - public static readonly DiagnosticDescriptor MVC1003_ActionsMustNotBeAsyncVoid = - new DiagnosticDescriptor( - "MVC2001", - "Controller actions must not have async void signature.", - "Controller actions must not have async void signature.", + "Use of IHtmlHelper.{0} should be avoided.", + "Use of IHtmlHelper.{0} may result in application deadlocks. Consider using Tag Helper or IHtmlHelper.{0}Async.", "Usage", DiagnosticSeverity.Warning, isEnabledByDefault: true); diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/Microsoft.AspNetCore.Mvc.Analyzers.csproj b/src/Microsoft.AspNetCore.Mvc.Analyzers/Microsoft.AspNetCore.Mvc.Analyzers.csproj index 82d88610b4..fe4ac565a0 100644 --- a/src/Microsoft.AspNetCore.Mvc.Analyzers/Microsoft.AspNetCore.Mvc.Analyzers.csproj +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/Microsoft.AspNetCore.Mvc.Analyzers.csproj @@ -3,11 +3,6 @@ CSharp Analyzers for ASP.NET Core MVC. aspnetcore;aspnetcoremvc - false - $(ExperimentalVersionPrefix) - $(ExperimentalVersionSuffix) - $(ExperimentalPackageVersion) - netstandard2.0 false false diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/SymbolNames.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers/SymbolNames.cs new file mode 100644 index 0000000000..9c49dd24e6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/SymbolNames.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + internal static class SymbolNames + { + public const string IHtmlHelperType = "Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper"; + + public const string HtmlHelperPartialExtensionsType = "Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperPartialExtensions"; + + public const string PartialMethod = "Partial"; + + public const string RenderPartialMethod = "RenderPartial"; + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeatureAnalyzerBase.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeatureAnalyzerBase.cs new file mode 100644 index 0000000000..bade87c8a4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeatureAnalyzerBase.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + public abstract class ViewFeatureAnalyzerBase : DiagnosticAnalyzer + { + public ViewFeatureAnalyzerBase(DiagnosticDescriptor diagnosticDescriptor) + { + SupportedDiagnostic = diagnosticDescriptor; + SupportedDiagnostics = ImmutableArray.Create(new[] { SupportedDiagnostic }); + } + + protected DiagnosticDescriptor SupportedDiagnostic { get; } + + public override ImmutableArray SupportedDiagnostics { get; } + + public sealed override void Initialize(AnalysisContext context) + { + context.RegisterCompilationStartAction(compilationContext => + { + var analyzerContext = new ViewFeaturesAnalyzerContext(compilationContext); + + // Only do work if we can locate IHtmlHelper. + if (analyzerContext.HtmlHelperType == null) + { + return; + } + + InitializeWorker(analyzerContext); + }); + } + + protected abstract void InitializeWorker(ViewFeaturesAnalyzerContext analyzerContext); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeaturesAnalyzerContext.cs b/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeaturesAnalyzerContext.cs new file mode 100644 index 0000000000..096132d67f --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Analyzers/ViewFeaturesAnalyzerContext.cs @@ -0,0 +1,48 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + public class ViewFeaturesAnalyzerContext + { +#pragma warning disable RS1012 // Start action has no registered actions. + public ViewFeaturesAnalyzerContext(CompilationStartAnalysisContext context) +#pragma warning restore RS1012 // Start action has no registered actions. + { + Context = context; + HtmlHelperType = GetType(SymbolNames.IHtmlHelperType); + HtmlHelperPartialExtensionsType = GetType(SymbolNames.HtmlHelperPartialExtensionsType); + } + + public CompilationStartAnalysisContext Context { get; } + + public INamedTypeSymbol HtmlHelperType { get; } + + public INamedTypeSymbol HtmlHelperPartialExtensionsType { get; } + + private INamedTypeSymbol GetType(string name) => Context.Compilation.GetTypeByMetadataName(name); + + public bool IsHtmlHelperExtensionMethod(IMethodSymbol method) + { + if (!method.IsExtensionMethod) + { + return false; + } + + if (method.ReceiverType != HtmlHelperType) + { + return false; + } + + if (method.ContainingType != HtmlHelperPartialExtensionsType) + { + return false; + } + + return true; + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ActionsMustNotBeAsyncVoidFacts.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ActionsMustNotBeAsyncVoidFacts.cs similarity index 98% rename from test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ActionsMustNotBeAsyncVoidFacts.cs rename to test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ActionsMustNotBeAsyncVoidFacts.cs index d5f6bcdf80..1d536be95a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ActionsMustNotBeAsyncVoidFacts.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ActionsMustNotBeAsyncVoidFacts.cs @@ -59,7 +59,7 @@ public class UserViewModel // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC2001", + Id = "MVC7003", Message = "Controller actions must not have async void signature.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 7, 18) } @@ -103,7 +103,7 @@ public class HomeController : Controller // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC2001", + Id = "MVC7003", Message = "Controller actions must not have async void signature.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 7, 18) } @@ -141,7 +141,7 @@ public class HomeController : Controller // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC2001", + Id = "MVC7003", Message = "Controller actions must not have async void signature.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 6, 18) } diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs similarity index 98% rename from test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs rename to test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs index a5f65ee9d0..d74c584349 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApActionsDoNotRequireExplicitModelValidationCheckFacts.cs @@ -204,7 +204,7 @@ public class PetController : ControllerBase // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1001", + Id = "MVC7001", Message = "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 9, 9) } @@ -236,7 +236,7 @@ public class PetController : ControllerBase // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1001", + Id = "MVC7001", Message = "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 13, 9) } @@ -295,7 +295,7 @@ public class PetController : ControllerBase // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1001", + Id = "MVC7001", Message = "Actions on types annotated with ApiControllerAttribute do not require explicit ModelState validity check.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 15, 13) } diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsAreAttributeRoutedFacts.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsAreAttributeRoutedFacts.cs similarity index 99% rename from test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsAreAttributeRoutedFacts.cs rename to test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsAreAttributeRoutedFacts.cs index d0f87dcdb7..c9225692aa 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsAreAttributeRoutedFacts.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsAreAttributeRoutedFacts.cs @@ -130,7 +130,7 @@ public class PetController : Controller // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1000", + Id = "MVC7000", Message = "Actions on types annotated with ApiControllerAttribute must be attribute routed.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 8, 16) } diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsShouldUseActionResultOfTFacts.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsShouldUseActionResultOfTFacts.cs similarity index 99% rename from test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsShouldUseActionResultOfTFacts.cs rename to test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsShouldUseActionResultOfTFacts.cs index 4eafbc8711..5dc16ac2fe 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/ApiActionsShouldUseActionResultOfTFacts.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/ApiActionsShouldUseActionResultOfTFacts.cs @@ -158,7 +158,7 @@ public class PetController: ControllerBase // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1002", + Id = "MVC7002", Message = "Actions on types annotated with ApiControllerAttribute should return ActionResult.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 9, 12) } @@ -207,7 +207,7 @@ public class PetController: ControllerBase // Arrange var expectedDiagnostic = new DiagnosticResult { - Id = "MVC1002", + Id = "MVC7002", Message = "Actions on types annotated with ApiControllerAttribute should return ActionResult.", Severity = DiagnosticSeverity.Warning, Locations = new[] { new DiagnosticResultLocation("Test.cs", 8, 18) } diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj new file mode 100644 index 0000000000..b5d9571c75 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj @@ -0,0 +1,20 @@ + + + + $(StandardTestTfms) + true + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/xunit.runner.json b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/xunit.runner.json new file mode 100644 index 0000000000..1c72a421ad --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "shadowCopy": false +} diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/AvoidHtmlPartialAnalyzerTest.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/AvoidHtmlPartialAnalyzerTest.cs new file mode 100644 index 0000000000..1dc47a4110 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/AvoidHtmlPartialAnalyzerTest.cs @@ -0,0 +1,202 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Analyzers.Infrastructure; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Analyzers +{ + public class AvoidHtmlPartialAnalyzerTest : AnalyzerTestBase + { + private static DiagnosticDescriptor DiagnosticDescriptor = DiagnosticDescriptors.MVC1000_HtmlHelperPartialShouldBeAvoided; + + protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; } = new AvoidHtmlPartialAnalyzer(); + + [Fact] + public async Task NoDiagnosticsAreReturned_FoEmptyScenarios() + { + // Arrange + var project = CreateProject(source: string.Empty); + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Empty(result); + } + + [Fact] + public async Task NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial() + { + // Arrange + var project = CreateProjectFromFile(); + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Empty(result); + } + + [Fact] + public async Task NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync() + { + // Arrange + var project = CreateProjectFromFile(); + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Empty(result); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfHtmlPartial() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync() + { + // Arrange + var project = CreateProjectFromFile(); + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Empty(result); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfRenderPartial() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + + [Fact] + public async Task DiagnosticsAreReturned_ForUseOfRenderPartial_InSections() + { + // Arrange + var project = CreateProjectFromFile(); + var expectedLocation = DefaultMarkerLocation.Value; + + // Act + var result = await GetDiagnosticAsync(project); + + // Assert + Assert.Collection( + result, + diagnostic => + { + + Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id); + Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor); + Assert.DiagnosticLocation(expectedLocation, diagnostic.Location); + }); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/AnalyzerTestBase.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/AnalyzerTestBase.cs index 7a19460d4e..73f2cae3f6 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/AnalyzerTestBase.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/AnalyzerTestBase.cs @@ -4,9 +4,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; @@ -27,6 +30,51 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers.Infrastructure protected virtual CodeFixProvider CodeFixProvider { get; } + public IDictionary MarkerLocations { get; } = new Dictionary(); + + public DiagnosticResultLocation? DefaultMarkerLocation { get; private set; } + + protected Project CreateProjectFromFile([CallerMemberName] string fileName = "") + { + var solutionDirectory = TestPathUtilities.GetSolutionRootDirectory("Mvc"); + var projectDirectory = Path.Combine(solutionDirectory, "test", GetType().Assembly.GetName().Name); + + var filePath = Path.Combine(projectDirectory, "TestFiles", fileName + ".cs"); + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"TestFile {fileName} could not be found at {filePath}.", filePath); + } + + const string MarkerStart = "/*MM"; + const string MarkerEnd = "*/"; + + var lines = File.ReadAllLines(filePath); + for (var i = 0; i < lines.Length; i++) + { + var line = lines[i]; + var markerStartIndex = line.IndexOf(MarkerStart, StringComparison.Ordinal); + if (markerStartIndex != -1) + { + var markerEndIndex = line.IndexOf(MarkerEnd, markerStartIndex, StringComparison.Ordinal); + var markerName = line.Substring(markerStartIndex + 2, markerEndIndex - markerStartIndex - 2); + var resultLocation = new DiagnosticResultLocation(i + 1, markerStartIndex + 1); ; + + if (DefaultMarkerLocation == null) + { + DefaultMarkerLocation = resultLocation; + } + + MarkerLocations[markerName] = resultLocation; + line = line.Substring(0, markerStartIndex) + line.Substring(markerEndIndex + MarkerEnd.Length); + } + + lines[i] = line; + } + + var inputSource = string.Join(Environment.NewLine, lines); + return CreateProject(inputSource); + } + protected Project CreateProject(string source) { var projectId = ProjectId.CreateNewId(debugName: "TestProject"); diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/Assert.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/Assert.cs index 06461614bf..ea57f2f5b8 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/Assert.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/Assert.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers } else { - VerifyDiagnosticLocation(expectedItem, actualItem); + VerifyLocation(expectedItem, actualItem); } if (actualItem.Id != expectedItem.Id) @@ -71,9 +71,21 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers } } - private static void VerifyDiagnosticLocation(DiagnosticResult expected, Diagnostic actual) + private static void VerifyLocation(DiagnosticResult expected, Diagnostic actual) { - var actualSpan = actual.Location.GetLineSpan(); + if (expected.Locations.Length == 0) + { + return; + } + + var expectedLocation = expected.Locations[0]; + Assert.DiagnosticLocation(expectedLocation, actual.Location); + + } + + public static void DiagnosticLocation(DiagnosticResultLocation expected, Location actual) + { + var actualSpan = actual.GetLineSpan(); var actualLinePosition = actualSpan.StartLinePosition; // Only check line position if there is an actual line in the real diagnostic @@ -81,7 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers { if (actualLinePosition.Line + 1 != expected.Line) { - throw new DiagnosticAssertException( + throw new DiagnosticLocationAssertException( expected, actual, $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\""); @@ -93,7 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers { if (actualLinePosition.Character + 1 != expected.Column) { - throw new DiagnosticAssertException( + throw new DiagnosticLocationAssertException( expected, actual, $"Expected diagnostic to start at column \"{expected.Column}\" was actually on line \"{actualLinePosition.Character + 1}\""); @@ -164,5 +176,19 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers public override string Message { get; } } + private class DiagnosticLocationAssertException : Xunit.Sdk.EqualException + { + public DiagnosticLocationAssertException( + DiagnosticResultLocation expected, + Location actual, + string message) + : base(expected, actual) + { + Message = message; + } + + public override string Message { get; } + } + } } diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/DiagnosticResult.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/DiagnosticResult.cs index 4a99be21fb..c1c32bd025 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/DiagnosticResult.cs +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Infrastructure/DiagnosticResult.cs @@ -11,6 +11,11 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers.Infrastructure /// public struct DiagnosticResultLocation { + public DiagnosticResultLocation(int line, int column) + : this("Test.cs", line, column) + { + } + public DiagnosticResultLocation(string path, int line, int column) { if (line < -1) diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj index a7d41638d4..055e5ba25a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj @@ -10,8 +10,8 @@ - + diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial.cs new file mode 100644 index 0000000000..7b00e3249f --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfHtmlPartial : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + Write(/*MM*/Html.Partial("Some-Partial")); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections.cs new file mode 100644 index 0000000000..6daed38d2f --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections.cs @@ -0,0 +1,35 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfHtmlPartial_InSections : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + DefineSection("name", async () => { + Write(/*MM*/Html.Partial("Test")); + }); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters.cs new file mode 100644 index 0000000000..3d26ae36f9 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfHtmlPartial_WithAdditionalParameters : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + Write(/*MM*/Html.Partial("Some-Partial", new object())); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial.cs new file mode 100644 index 0000000000..827b3d938e --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfRenderPartial : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + /*MM1*/Html.RenderPartial("Some-Partial"); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_InSections.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_InSections.cs new file mode 100644 index 0000000000..39c1c4bcbc --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_InSections.cs @@ -0,0 +1,35 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfHtmlRenderPartial_InSections : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + DefineSection("name", async () => { + /*MM*/Html.RenderPartial("Test"); + }); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters.cs new file mode 100644 index 0000000000..cbff6f75ee --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class DiagnosticsAreReturned_ForUseOfRenderPartial_WithAdditionalParameters : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + /*MM*/Html.RenderPartial("Some-Partial", new object()); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial.cs new file mode 100644 index 0000000000..b41217ac90 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class NoDiagnosticsAreReturned_ForNonUseOfHtmlPartial : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + WriteLiteral("Hello world"); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync.cs new file mode 100644 index 0000000000..72e9baf096 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class NoDiagnosticsAreReturned_ForUseOfHtmlPartialAsync : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + await Html.PartialAsync("Some-Partial"); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync.cs b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync.cs new file mode 100644 index 0000000000..e1edee2686 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Analyzers.Test/TestFiles/NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync.cs @@ -0,0 +1,33 @@ +namespace AspNetCore +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class NoDiagnosticsAreReturned_ForUseOfRenderPartialAsync : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { +#pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(0, 25, true); + await Html.RenderPartialAsync("Some-Partial"); + EndContext(); + EndContext(); + } +#pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} +#pragma warning restore 1591