Consolidate general-purpose analyzers
We have some non-MVC analyzers hanging out in the Mvc.Analyzers package. Part of: #12288
This commit is contained in:
parent
b84132638f
commit
010ffe6121
|
|
@ -15,6 +15,7 @@
|
|||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
|
||||
<Nullable>Enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Analyzers;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
|
|
@ -14,8 +13,8 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
for (var i = 0; i < analysis.Options.Length; i++)
|
||||
{
|
||||
var item = analysis.Options[i];
|
||||
if (string.Equals(item.OptionsType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), SymbolNames.MvcOptions) &&
|
||||
string.Equals(item.Property.Name, SymbolNames.EnableEndpointRoutingProperty, StringComparison.Ordinal))
|
||||
if (string.Equals(item.OptionsType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), SymbolNames.MvcOptions.MetadataName) &&
|
||||
string.Equals(item.Property.Name, SymbolNames.MvcOptions.EnableEndpointRoutingPropertyName, StringComparison.Ordinal))
|
||||
{
|
||||
return item.ConstantValue as bool? == false;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
{
|
||||
IApplicationBuilder = compilation.GetTypeByMetadataName(SymbolNames.IApplicationBuilder.MetadataName);
|
||||
IServiceCollection = compilation.GetTypeByMetadataName(SymbolNames.IServiceCollection.MetadataName);
|
||||
MvcOptions = compilation.GetTypeByMetadataName(SymbolNames.MvcOptions.MetadataName);
|
||||
}
|
||||
|
||||
public bool HasRequiredSymbols => IApplicationBuilder != null && IServiceCollection != null;
|
||||
|
|
@ -18,5 +19,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public INamedTypeSymbol IApplicationBuilder { get; }
|
||||
|
||||
public INamedTypeSymbol IServiceCollection { get; }
|
||||
|
||||
public INamedTypeSymbol MvcOptions { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,5 +41,12 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
|
||||
public const string UseSignalRMethodName = "UseSignalR";
|
||||
}
|
||||
|
||||
public static class MvcOptions
|
||||
{
|
||||
public const string MetadataName = "Microsoft.AspNetCore.Mvc.MvcOptions";
|
||||
|
||||
public const string EnableEndpointRoutingPropertyName = "EnableEndpointRouting";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
|
||||
public TestSource Read(string source)
|
||||
{
|
||||
if (!source.EndsWith(".cs"))
|
||||
{
|
||||
source = source + ".cs";
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(ProjectDirectory, "TestFiles", GetType().Name, source);
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// 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 System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Analyzer.Testing;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class AnalyzersDiagnosticAnalyzerRunner : DiagnosticAnalyzerRunner
|
||||
{
|
||||
public AnalyzersDiagnosticAnalyzerRunner(DiagnosticAnalyzer analyzer)
|
||||
{
|
||||
Analyzer = analyzer;
|
||||
}
|
||||
|
||||
public DiagnosticAnalyzer Analyzer { get; }
|
||||
|
||||
public Task<Diagnostic[]> GetDiagnosticsAsync(string source)
|
||||
{
|
||||
return GetDiagnosticsAsync(sources: new[] { source }, Analyzer, Array.Empty<string>());
|
||||
}
|
||||
|
||||
public Task<Diagnostic[]> GetDiagnosticsAsync(Project project)
|
||||
{
|
||||
return GetDiagnosticsAsync(new[] { project }, Analyzer, Array.Empty<string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,22 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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 System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Analyzer.Testing;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
public class StartupAnalyzerTest
|
||||
public class StartupAnalyzerTest : AnalyzerTestBase
|
||||
{
|
||||
public StartupAnalyzerTest()
|
||||
{
|
||||
StartupAnalyzer = new StartupAnalzyer();
|
||||
|
||||
Runner = new MvcDiagnosticAnalyzerRunner(StartupAnalyzer);
|
||||
Runner = new AnalyzersDiagnosticAnalyzerRunner(StartupAnalyzer);
|
||||
|
||||
Analyses = new ConcurrentBag<object>();
|
||||
ConfigureServicesMethods = new ConcurrentBag<IMethodSymbol>();
|
||||
|
|
@ -32,7 +30,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
|
||||
private StartupAnalzyer StartupAnalyzer { get; }
|
||||
|
||||
private MvcDiagnosticAnalyzerRunner Runner { get; }
|
||||
private AnalyzersDiagnosticAnalyzerRunner Runner { get; }
|
||||
|
||||
private ConcurrentBag<object> Analyses { get; }
|
||||
|
||||
|
|
@ -44,7 +42,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_FindsStartupMethods_StartupSignatures_Standard()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("StartupSignatures_Standard");
|
||||
var source = Read("StartupSignatures_Standard");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -60,7 +58,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_FindsStartupMethods_StartupSignatures_MoreVariety()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("StartupSignatures_MoreVariety");
|
||||
var source = Read("StartupSignatures_MoreVariety");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -82,7 +80,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_MvcOptionsAnalysis_UseMvc_FindsEndpointRoutingDisabled()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithDefaultRouteAndEndpointRoutingDisabled");
|
||||
var source = Read("MvcOptions_UseMvcWithDefaultRouteAndEndpointRoutingDisabled");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -102,7 +100,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_MvcOptionsAnalysis_AddMvcOptions_FindsEndpointRoutingDisabled()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithDefaultRouteAndAddMvcOptionsEndpointRoutingDisabled");
|
||||
var source = Read("MvcOptions_UseMvcWithDefaultRouteAndAddMvcOptionsEndpointRoutingDisabled");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -125,7 +123,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_MvcOptionsAnalysis_FindsEndpointRoutingEnabled(string sourceFileName, string mvcMiddlewareName)
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource(sourceFileName);
|
||||
var source = Read(sourceFileName);
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -151,7 +149,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_MvcOptionsAnalysis_MultipleMiddleware()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithOtherMiddleware");
|
||||
var source = Read("MvcOptions_UseMvcWithOtherMiddleware");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -183,7 +181,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_MvcOptionsAnalysis_MultipleUseMvc()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcMultiple");
|
||||
var source = Read("MvcOptions_UseMvcMultiple");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -215,7 +213,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
public async Task StartupAnalyzer_ServicesAnalysis_CallBuildServiceProvider()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("ConfigureServices_BuildServiceProvider");
|
||||
var source = Read("ConfigureServices_BuildServiceProvider");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
|
@ -230,10 +228,5 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM1"], diagnostic.Location);
|
||||
});
|
||||
}
|
||||
|
||||
private TestSource ReadSource(string fileName)
|
||||
{
|
||||
return MvcTestSource.Read(nameof(StartupAnalyzerTest), fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal static class StartupFacts
|
||||
{
|
||||
public static bool IsStartupClass(StartupSymbols symbols, INamedTypeSymbol type)
|
||||
{
|
||||
if (symbols == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbols));
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
// It's not good enough to just look for ConfigureServices or Configure as a hueristic.
|
||||
// ConfigureServices might not appear in trivial cases, and Configure might be named ConfigureDevelopment
|
||||
// or something similar.
|
||||
//
|
||||
// Since we already are analyzing the symbol it should be cheap to do a quick pass over the members.
|
||||
var members = type.GetMembers();
|
||||
for (var i = 0; i < members.Length; i++)
|
||||
{
|
||||
if (members[i] is IMethodSymbol method && (IsConfigureServices(symbols, method) || IsConfigure(symbols, method)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsConfigureServices(StartupSymbols symbols, IMethodSymbol symbol)
|
||||
{
|
||||
if (symbol == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbol));
|
||||
}
|
||||
|
||||
if (symbol.DeclaredAccessibility != Accessibility.Public)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(symbol.Name, "ConfigureServices", StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Parameters.Length != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Parameters[0].Type != symbols.IServiceCollection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsConfigure(StartupSymbols symbols, IMethodSymbol symbol)
|
||||
{
|
||||
if (symbol == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbol));
|
||||
}
|
||||
|
||||
if (symbol.DeclaredAccessibility != Accessibility.Public)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Name == null || !symbol.Name.StartsWith("Configure", StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// IApplicationBuilder can appear in any parameter
|
||||
for (var i = 0; i < symbol.Parameters.Length; i++)
|
||||
{
|
||||
if (symbol.Parameters[i].Type == symbols.IApplicationBuilder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// 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.Analyzers
|
||||
{
|
||||
internal class StartupSymbols
|
||||
{
|
||||
public StartupSymbols(Compilation compilation)
|
||||
{
|
||||
IApplicationBuilder = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Builder.IApplicationBuilder");
|
||||
IServiceCollection = compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.IServiceCollection");
|
||||
MvcOptions = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.MvcOptions");
|
||||
}
|
||||
|
||||
public bool HasRequiredSymbols => IApplicationBuilder != null && IServiceCollection != null;
|
||||
|
||||
public INamedTypeSymbol IApplicationBuilder { get; }
|
||||
public INamedTypeSymbol IServiceCollection { get; }
|
||||
public INamedTypeSymbol MvcOptions { get; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue