Parcourir la source

Add analyzer to detect TagHelpers in code blocks.

- We detect `__tagHelperRunner.RunAsync` method calls in lambdas, anonymous methods, local functions, and method declarations. Upon detection we verify that the methods are `async Task` returning and if not log an error.
- Added analyzer tests to verify all the scenarios TagHelpers in code blocks can occur in.

#8630
N. Taylor Mullen il y a 6 ans
Parent
commit
202ccebb0d
15 fichiers modifiés avec 1151 ajouts et 1 suppressions
  1. 9 1
      src/Mvc/Mvc.Analyzers/src/DiagnosticDescriptors.cs
  2. 6 0
      src/Mvc/Mvc.Analyzers/src/SymbolNames.cs
  3. 184 0
      src/Mvc/Mvc.Analyzers/src/TagHelpersInCodeBlocksAnalyzer.cs
  4. 1 0
      src/Mvc/Mvc.Analyzers/test/Mvc.Analyzers.Test.csproj
  5. 93 0
      src/Mvc/Mvc.Analyzers/test/TagHelpersInCodeBlocksAnalyzerTest.cs
  6. 80 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInActions.cs
  7. 80 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInNonAsyncFunc.cs
  8. 82 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidClassMethods.cs
  9. 84 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidDelegates.cs
  10. 79 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidLocalFunctions.cs
  11. 81 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncClassMethods.cs
  12. 84 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncDelegates.cs
  13. 81 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncFuncs.cs
  14. 84 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions.cs
  15. 123 0
      src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/SingleDiagnosticIsReturned_ForMultipleTagHelpersInVoidMethod.cs

+ 9 - 1
src/Mvc/Mvc.Analyzers/src/DiagnosticDescriptors.cs

@@ -53,7 +53,15 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers
                 isEnabledByDefault: true,
                 isEnabledByDefault: true,
                 helpLinkUri: "https://aka.ms/AA20pbc");
                 helpLinkUri: "https://aka.ms/AA20pbc");
 
 
-        
         // MVC1005 reserved for startup
         // MVC1005 reserved for startup
+
+        public static readonly DiagnosticDescriptor MVC1006_FunctionsContainingTagHelpersMustBeAsyncAndReturnTask =
+            new DiagnosticDescriptor(
+                "MVC1006",
+                "Methods containing TagHelpers must be async and return Task.",
+                "The method contains a TagHelper and therefore must be async and return a Task.",
+                "Usage",
+                DiagnosticSeverity.Error,
+                isEnabledByDefault: true);
     }
     }
 }
 }

+ 6 - 0
src/Mvc/Mvc.Analyzers/src/SymbolNames.cs

@@ -72,5 +72,11 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers
         public const string ConfigureServicesMethod = "ConfigureServices";
         public const string ConfigureServicesMethod = "ConfigureServices";
 
 
         public const string ConfigureMethod = "Configure";
         public const string ConfigureMethod = "Configure";
+
+        public const string RunAsyncMethodName = "RunAsync";
+
+        public const string TaskTypeName = "System.Threading.Tasks.Task";
+
+        public const string TagHelperRunnerTypeName = "Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner";
     }
     }
 }
 }

+ 184 - 0
src/Mvc/Mvc.Analyzers/src/TagHelpersInCodeBlocksAnalyzer.cs

@@ -0,0 +1,184 @@
+// 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.Generic;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace Microsoft.AspNetCore.Mvc.Analyzers
+{
+    [DiagnosticAnalyzer(LanguageNames.CSharp)]
+    public class TagHelpersInCodeBlocksAnalyzer : DiagnosticAnalyzer
+    {
+        public TagHelpersInCodeBlocksAnalyzer()
+        {
+            TagHelperInCodeBlockDiagnostic = DiagnosticDescriptors.MVC1006_FunctionsContainingTagHelpersMustBeAsyncAndReturnTask;
+            SupportedDiagnostics = ImmutableArray.Create(new[] { TagHelperInCodeBlockDiagnostic });
+        }
+
+        private DiagnosticDescriptor TagHelperInCodeBlockDiagnostic { get; }
+
+        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
+
+        public override void Initialize(AnalysisContext context)
+        {
+            // Generated Razor code is considered auto generated. By default analyzers skip over auto-generated code unless we say otherwise.
+            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
+            context.RegisterCompilationStartAction(context =>
+            {
+                if (!SymbolCache.TryCreate(context.Compilation, out var symbolCache))
+                {
+                    // No-op if we can't find types we care about.
+                    return;
+                }
+
+                InitializeWorker(context, symbolCache);
+            });
+        }
+
+        private void InitializeWorker(CompilationStartAnalysisContext context, SymbolCache symbolCache)
+        {
+            context.RegisterOperationBlockStartAction(startBlockContext =>
+            {
+                var capturedDiagnosticLocations = new HashSet<Location>();
+                startBlockContext.RegisterOperationAction(context =>
+                {
+                    var awaitOperation = (IAwaitOperation)context.Operation;
+
+                    if (awaitOperation.Operation.Kind != OperationKind.Invocation)
+                    {
+                        return;
+                    }
+
+                    var invocationOperation = (IInvocationOperation)awaitOperation.Operation;
+
+                    if (!IsTagHelperRunnerRunAsync(invocationOperation.TargetMethod, symbolCache))
+                    {
+                        return;
+                    }
+
+                    var parent = context.Operation.Parent;
+                    while (parent != null && !IsParentMethod(parent))
+                    {
+                        parent = parent.Parent;
+                    }
+
+                    if (parent == null)
+                    {
+                        return;
+                    }
+
+                    var methodSymbol = (IMethodSymbol?)(parent switch
+                    {
+                        ILocalFunctionOperation localFunctionOperation => localFunctionOperation.Symbol,
+                        IAnonymousFunctionOperation anonymousFunctionOperation => anonymousFunctionOperation.Symbol,
+                        IMethodBodyOperation methodBodyOperation => startBlockContext.OwningSymbol,
+                        _ => null,
+                    });
+
+                    if (methodSymbol == null)
+                    {
+                        // Unsupported operation type.
+                        return;
+                    }
+
+                    if (!methodSymbol.IsAsync ||
+                        !symbolCache.TaskType.IsAssignableFrom(methodSymbol.ReturnType))
+                    {
+                        capturedDiagnosticLocations.Add(parent.Syntax.GetLocation());
+                    }
+
+                }, OperationKind.Await);
+
+                startBlockContext.RegisterOperationBlockEndAction(context =>
+                {
+                    foreach (var location in capturedDiagnosticLocations)
+                    {
+                        context.ReportDiagnostic(
+                            Diagnostic.Create(TagHelperInCodeBlockDiagnostic, location));
+                    }
+                });
+            });
+        }
+
+        private bool IsTagHelperRunnerRunAsync(IMethodSymbol method, SymbolCache symbolCache)
+        {
+            if (method != symbolCache.TagHelperRunnerRunAsyncMethodSymbol)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool IsParentMethod(IOperation operation)
+        {
+            if (operation.Kind == OperationKind.LocalFunction)
+            {
+                return true;
+            }
+
+            if (operation.Kind == OperationKind.MethodBody)
+            {
+                return true;
+            }
+
+            if (operation.Kind == OperationKind.AnonymousFunction)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        private readonly struct SymbolCache
+        {
+            private SymbolCache(
+                IMethodSymbol tagHelperRunnerRunAsyncMethodSymbol,
+                INamedTypeSymbol taskType)
+            {
+                TagHelperRunnerRunAsyncMethodSymbol = tagHelperRunnerRunAsyncMethodSymbol;
+                TaskType = taskType;
+            }
+
+            public IMethodSymbol TagHelperRunnerRunAsyncMethodSymbol { get; }
+
+            public INamedTypeSymbol TaskType { get; }
+
+
+            public static bool TryCreate(Compilation compilation, out SymbolCache symbolCache)
+            {
+                symbolCache = default;
+
+                if (!TryGetType(SymbolNames.TagHelperRunnerTypeName, out var tagHelperRunnerType))
+                {
+                    return false;
+                }
+
+                if (!TryGetType(SymbolNames.TaskTypeName, out var taskType))
+                {
+                    return false;
+                }
+
+                var members = tagHelperRunnerType.GetMembers(SymbolNames.RunAsyncMethodName);
+                if (members.Length == 0)
+                {
+                    return false;
+                }
+
+                var tagHelperRunnerRunAsyncMethod = (IMethodSymbol)members[0];
+
+                symbolCache = new SymbolCache(tagHelperRunnerRunAsyncMethod, taskType);
+                return true;
+
+                bool TryGetType(string typeName, out INamedTypeSymbol typeSymbol)
+                {
+                    typeSymbol = compilation.GetTypeByMetadataName(typeName);
+                    return typeSymbol != null && typeSymbol.TypeKind != TypeKind.Error;
+                }
+            }
+        }
+    }
+}

+ 1 - 0
src/Mvc/Mvc.Analyzers/test/Mvc.Analyzers.Test.csproj

@@ -16,6 +16,7 @@
   <ItemGroup>
   <ItemGroup>
     <None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
     <None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
     <Compile Include="$(SharedSourceRoot)test\SkipOnHelixAttribute.cs" />
     <Compile Include="$(SharedSourceRoot)test\SkipOnHelixAttribute.cs" />
+    <Compile Remove="TestFiles\TagHelpersInCodeBlocksAnalyzerTest\*.*" />
     <Content Include="TestFiles\**\*.*" CopyToPublishDirectory="PreserveNewest" />
     <Content Include="TestFiles\**\*.*" CopyToPublishDirectory="PreserveNewest" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 93 - 0
src/Mvc/Mvc.Analyzers/test/TagHelpersInCodeBlocksAnalyzerTest.cs

@@ -0,0 +1,93 @@
+// 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.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Analyzer.Testing;
+using Microsoft.CodeAnalysis;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.Analyzers
+{
+    public class TagHelpersInCodeBlocksAnalyzerTest
+    {
+        private readonly DiagnosticDescriptor DiagnosticDescriptor = DiagnosticDescriptors.MVC1006_FunctionsContainingTagHelpersMustBeAsyncAndReturnTask;
+
+        private MvcDiagnosticAnalyzerRunner Executor { get; } = new MvcDiagnosticAnalyzerRunner(new TagHelpersInCodeBlocksAnalyzer());
+
+        [Fact]
+        public Task DiagnosticsAreReturned_ForUseOfTagHelpersInActions()
+            => VerifyDefault(ReadTestSource());
+
+        [Fact]
+        public Task DiagnosticsAreReturned_ForUseOfTagHelpersInNonAsyncFunc()
+            => VerifyDefault(ReadTestSource());
+
+        [Fact]
+        public Task DiagnosticsAreReturned_ForUseOfTagHelpersInVoidClassMethods()
+            => VerifyDefault(ReadTestSource());
+
+        [Fact]
+        public Task DiagnosticsAreReturned_ForUseOfTagHelpersInVoidDelegates()
+            => VerifyDefault(ReadTestSource());
+
+        [Fact]
+        public Task DiagnosticsAreReturned_ForUseOfTagHelpersInVoidLocalFunctions()
+            => VerifyDefault(ReadTestSource());
+
+        [Fact]
+        public Task NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncClassMethods()
+            => VerifyNoDiagnosticsAreReturned(ReadTestSource());
+
+        [Fact]
+        public Task NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncDelegates()
+            => VerifyNoDiagnosticsAreReturned(ReadTestSource());
+
+        [Fact]
+        public Task NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncFuncs()
+            => VerifyNoDiagnosticsAreReturned(ReadTestSource());
+
+        [Fact]
+        public Task NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions()
+            => VerifyNoDiagnosticsAreReturned(ReadTestSource());
+
+        [Fact]
+        public Task SingleDiagnosticIsReturned_ForMultipleTagHelpersInVoidMethod()
+            => VerifyDefault(ReadTestSource());
+
+        private async Task VerifyNoDiagnosticsAreReturned(TestSource source)
+        {
+            // Act
+            var result = await Executor.GetDiagnosticsAsync(source.Source);
+
+            // Assert
+            Assert.Empty(result);
+        }
+
+        private async Task VerifyDefault(TestSource testSource)
+        {
+            // Arrange
+            var expectedLocation = testSource.DefaultMarkerLocation;
+
+            // Act
+            var result = await Executor.GetDiagnosticsAsync(testSource.Source);
+
+            // Assert
+            // We want to ignore C# diagnostics because they'll include diagnostics for not awaiting bits correctly. The purpose of this analyzer is to
+            // improve on those error messages but not remove them.
+            var filteredDiagnostics = result.Where(diagnostic => diagnostic.Id.StartsWith("MVC"));
+            Assert.Collection(
+                filteredDiagnostics,
+                diagnostic =>
+                {
+                    Assert.Equal(DiagnosticDescriptor.Id, diagnostic.Id);
+                    Assert.Same(DiagnosticDescriptor, diagnostic.Descriptor);
+                    AnalyzerAssert.DiagnosticLocation(expectedLocation, diagnostic.Location);
+                });
+        }
+
+        private static TestSource ReadTestSource([CallerMemberName] string testMethod = "") =>
+            MvcTestSource.Read(nameof(TagHelpersInCodeBlocksAnalyzerTest), testMethod);
+    }
+}

+ 80 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInActions.cs

@@ -0,0 +1,80 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInActions : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+            WriteLiteral("\r\n");
+  
+    Action sometMethod = /*MM*/() =>
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "d946c1cd0bbc2f1bde41a0f3eb6596ec7dca5c342925", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    };
+
+    sometMethod();
+
+        }
+        #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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 80 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInNonAsyncFunc.cs

@@ -0,0 +1,80 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInNonAsyncFunc : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+            WriteLiteral("\r\n");
+  
+    Func<Task> sometMethod = /*MM*/() =>
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "452e9bab960ded6307b3903ebf73278bb1b2bec32959", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    };
+
+    sometMethod();
+
+        }
+        #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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 82 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidClassMethods.cs

@@ -0,0 +1,82 @@
+namespace AspNetCore
+{
+    #line hidden
+    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;
+    [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"186d75f4b59675515143af9ff43784abaabd24a9", @"/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidClassMethods.cshtml")]
+    public class DiagnosticsAreReturned_ForUseOfTagHelpersInVoidClassMethods : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+  
+    SometMethod();
+
+            WriteLiteral("\r\n");
+        }
+        #pragma warning restore 1998
+            
+    /*MM*/void SometMethod()
+    {
+
+        WriteLiteral("        ");
+        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "186d75f4b59675515143af9ff43784abaabd24a93243", async() => {
+            WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+            WriteLiteral("</p>\r\n        ");
+        }
+        );
+        __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+        __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+        BeginWriteTagHelperAttribute();
+        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+        __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+        if (!__tagHelperExecutionContext.Output.IsContentModified)
+        {
+            await __tagHelperExecutionContext.SetOutputContentAsync();
+        }
+        Write(__tagHelperExecutionContext.Output);
+        __tagHelperExecutionContext = __tagHelperScopeManager.End();
+        WriteLiteral("\r\n");
+    }
+
+        [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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 84 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidDelegates.cs

@@ -0,0 +1,84 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInVoidDelegates : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+            WriteLiteral("\r\n");
+  
+    TestDelegate sometMethod = /*MM*/delegate ()
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "c63f59d4d7a4db461bc9f052a7833885a8d13dcf2972", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    };
+
+    sometMethod();
+
+            WriteLiteral("\r\n");
+        }
+        #pragma warning restore 1998
+            
+    delegate void TestDelegate();
+
+        [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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 79 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/DiagnosticsAreReturned_ForUseOfTagHelpersInVoidLocalFunctions.cs

@@ -0,0 +1,79 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInVoidLocalFunctions : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+  
+    /*MM*/void SometMethod()
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "5a4c42fadc056422c6be6ab14a6bd877e2fa382d2948", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    }
+
+    SometMethod();
+
+        }
+        #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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 81 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncClassMethods.cs

@@ -0,0 +1,81 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInAsyncClassMethods_ : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+  
+    await SometMethod();
+
+            WriteLiteral("\r\n");
+        }
+        #pragma warning restore 1998
+            
+    /*MM*/async Task SometMethod()
+    {
+
+        WriteLiteral("        ");
+        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "8a14df240fb31e930618408064cdb1e343ff38f43283", async() => {
+            WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+            WriteLiteral("</p>\r\n        ");
+        }
+        );
+        __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+        __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+        BeginWriteTagHelperAttribute();
+        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+        __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+        if (!__tagHelperExecutionContext.Output.IsContentModified)
+        {
+            await __tagHelperExecutionContext.SetOutputContentAsync();
+        }
+        Write(__tagHelperExecutionContext.Output);
+        __tagHelperExecutionContext = __tagHelperScopeManager.End();
+        WriteLiteral("\r\n");
+    }
+
+        [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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 84 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncDelegates.cs

@@ -0,0 +1,84 @@
+namespace AspNetCore
+{
+    #line hidden
+    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_ForUseOfTagHelpersInAsyncDelegates_ : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+            WriteLiteral("\r\n");
+  
+    TestDelegate sometMethod = /*MM*/async delegate ()
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "028e6be2d2e1a766b4ea9e3949a9e9797bb524083002", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    };
+
+    await sometMethod();
+
+            WriteLiteral("\r\n");
+        }
+        #pragma warning restore 1998
+            
+    delegate Task TestDelegate();
+
+        [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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 81 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncFuncs.cs

@@ -0,0 +1,81 @@
+namespace AspNetCore
+{
+    #line hidden
+    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;
+    [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"9b77957037efb63a0af38698af1c7de6dc41c4be", @"/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncFuncs.cshtml")]
+    public class NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncFuncs : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+            WriteLiteral("\r\n");
+  
+    Func<Task> sometMethod = /*MM*/async () =>
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "9b77957037efb63a0af38698af1c7de6dc41c4be2965", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    };
+
+    await sometMethod();
+
+        }
+        #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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 84 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions.cs

@@ -0,0 +1,84 @@
+#pragma checksum "C:\Users\nimullen\Documents\Projects\AnalyzerTest\NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions..cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "d5d5a28106f24c1bb31f07635157a3503dfdcb2d"
+// <auto-generated/>
+#pragma warning disable 1591
+[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore.NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions_), @"mvc.1.0.view", @"/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions..cshtml")]
+namespace AspNetCore
+{
+    #line hidden
+    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;
+    [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"d5d5a28106f24c1bb31f07635157a3503dfdcb2d", @"/NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions..cshtml")]
+    public class NoDiagnosticsAreReturned_ForUseOfTagHelpersInAsyncLocalFunctions_ : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+  
+    /*MM*/async Task SometMethod()
+    {
+
+            WriteLiteral("        ");
+            __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "d5d5a28106f24c1bb31f07635157a3503dfdcb2d2978", async() => {
+                WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+                WriteLiteral("</p>\r\n        ");
+            }
+            );
+            __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+            __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+            BeginWriteTagHelperAttribute();
+            __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+            __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+            await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+            if (!__tagHelperExecutionContext.Output.IsContentModified)
+            {
+                await __tagHelperExecutionContext.SetOutputContentAsync();
+            }
+            Write(__tagHelperExecutionContext.Output);
+            __tagHelperExecutionContext = __tagHelperScopeManager.End();
+            WriteLiteral("\r\n");
+    }
+
+    await SometMethod();
+
+        }
+        #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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591

+ 123 - 0
src/Mvc/Mvc.Analyzers/test/TestFiles/TagHelpersInCodeBlocksAnalyzerTest/SingleDiagnosticIsReturned_ForMultipleTagHelpersInVoidMethod.cs

@@ -0,0 +1,123 @@
+namespace AspNetCore
+{
+    #line hidden
+    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 SingleDiagnosticIsReturned_ForMultipleTagHelpersInVoidMethod : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+    {
+        #line hidden
+        #pragma warning disable 0169
+        private string __tagHelperStringValueBuffer;
+        #pragma warning restore 0169
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
+        private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
+        {
+            get
+            {
+                if (__backed__tagHelperScopeManager == null)
+                {
+                    __backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
+                }
+                return __backed__tagHelperScopeManager;
+            }
+        }
+        private global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper;
+        #pragma warning disable 1998
+        public async override global::System.Threading.Tasks.Task ExecuteAsync()
+        {
+            WriteLiteral("\r\n");
+  
+    SometMethod();
+
+            WriteLiteral("\r\n");
+        }
+        #pragma warning restore 1998
+            
+    /*MM*/void SometMethod()
+    {
+
+        WriteLiteral("        ");
+        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "a49ad3383d0802d134e8f9ec401bad4c2f47d14d3250", async() => {
+            WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+            WriteLiteral("</p>\r\n        ");
+        }
+        );
+        __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+        __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+        BeginWriteTagHelperAttribute();
+        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+        __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+        if (!__tagHelperExecutionContext.Output.IsContentModified)
+        {
+            await __tagHelperExecutionContext.SetOutputContentAsync();
+        }
+        Write(__tagHelperExecutionContext.Output);
+        __tagHelperExecutionContext = __tagHelperScopeManager.End();
+        WriteLiteral("\r\n");
+        WriteLiteral("        ");
+        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "a49ad3383d0802d134e8f9ec401bad4c2f47d14d4821", async() => {
+            WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+            WriteLiteral("</p>\r\n        ");
+        }
+        );
+        __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+        __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+        BeginWriteTagHelperAttribute();
+        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+        __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+        if (!__tagHelperExecutionContext.Output.IsContentModified)
+        {
+            await __tagHelperExecutionContext.SetOutputContentAsync();
+        }
+        Write(__tagHelperExecutionContext.Output);
+        __tagHelperExecutionContext = __tagHelperScopeManager.End();
+        WriteLiteral("\r\n");
+        WriteLiteral("        ");
+        __tagHelperExecutionContext = __tagHelperScopeManager.Begin("cache", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "a49ad3383d0802d134e8f9ec401bad4c2f47d14d6392", async() => {
+            WriteLiteral("\r\n            <p>The current time is ");
+                              Write(DateTime.Now);
+
+            WriteLiteral("</p>\r\n        ");
+        }
+        );
+        __Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.TagHelpers.CacheTagHelper>();
+        __tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_TagHelpers_CacheTagHelper);
+        BeginWriteTagHelperAttribute();
+        __tagHelperStringValueBuffer = EndWriteTagHelperAttribute();
+        __tagHelperExecutionContext.AddHtmlAttribute("asp-vary-by-user", Html.Raw(__tagHelperStringValueBuffer), global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.Minimized);
+        await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
+        if (!__tagHelperExecutionContext.Output.IsContentModified)
+        {
+            await __tagHelperExecutionContext.SetOutputContentAsync();
+        }
+        Write(__tagHelperExecutionContext.Output);
+        __tagHelperExecutionContext = __tagHelperScopeManager.End();
+        WriteLiteral("\r\n");
+    }
+
+        [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<dynamic> Html { get; private set; }
+    }
+}
+#pragma warning restore 1591