From 3a68e6540d97218e77ffe200a8e3ca903cbde1a2 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 30 Oct 2018 16:39:06 -0700 Subject: [PATCH 01/14] Merge branch 'release/2.1' into release/2.2 --- .../src/Internal.AspNetCore.Analyzers.csproj | 16 + .../src/PubternalityAnalyzer.cs | 278 ++++++++++++++++++ .../src/PubturnalityDescriptors.cs | 24 ++ ...Internal.AspNetCore.Analyzers.Tests.csproj | 14 + .../test/PubternabilityAnalyzerTests.cs | 259 ++++++++++++++++ .../src/Assert.cs | 55 ++++ .../src/CodeFixRunner.cs | 71 +++++ .../src/DiagnosticAnalyzerRunner.cs | 121 ++++++++ .../src/DiagnosticLocation.cs | 39 +++ .../src/DiagnosticProject.cs | 86 ++++++ .../src/DiagnosticVerifier.cs | 213 ++++++++++++++ ...crosoft.AspNetCore.Analyzer.Testing.csproj | 22 ++ .../src/TestSource.cs | 51 ++++ ...icrosoft.AspNetCore.Analyzer.Testing.props | 7 + 14 files changed, 1256 insertions(+) create mode 100644 src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj create mode 100644 src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs create mode 100644 src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs create mode 100644 src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj create mode 100644 src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs create mode 100644 src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/build/Microsoft.AspNetCore.Analyzer.Testing.props diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj new file mode 100644 index 0000000000..1814c4c69f --- /dev/null +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj @@ -0,0 +1,16 @@ + + + + ASP.NET Core internal use analyzers. + netstandard1.3 + $(PackageTags);analyzers + $(NoWarn);CS1591 + false + analyzers/dotnet/cs/ + + + + + + + diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs new file mode 100644 index 0000000000..8a1a3efdee --- /dev/null +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs @@ -0,0 +1,278 @@ +// 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.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Internal.AspNetCore.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class PubternalityAnalyzer : DiagnosticAnalyzer + { + public PubternalityAnalyzer() + { + SupportedDiagnostics = ImmutableArray.Create(new[] + { + PubturnalityDescriptors.PUB0001, + PubturnalityDescriptors.PUB0002 + }); + } + + public override ImmutableArray SupportedDiagnostics { get; } + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(analysisContext => + { + analysisContext.RegisterSymbolAction(symbolAnalysisContext => AnalyzeTypeUsage(symbolAnalysisContext), SymbolKind.Namespace); + analysisContext.RegisterSyntaxNodeAction(syntaxContext => AnalyzeTypeUsage(syntaxContext), SyntaxKind.IdentifierName); + }); + } + + private void AnalyzeTypeUsage(SymbolAnalysisContext context) + { + var ns = (INamespaceSymbol)context.Symbol; + if (IsInternal(ns)) + { + return; + } + + foreach (var namespaceOrTypeSymbol in ns.GetMembers()) + { + if (namespaceOrTypeSymbol.IsType) + { + CheckType((ITypeSymbol)namespaceOrTypeSymbol, context); + } + } + } + + private void CheckType(ITypeSymbol typeSymbol, SymbolAnalysisContext context) + { + if (IsPrivate(typeSymbol) || IsPrivate(typeSymbol.ContainingType)) + { + return; + } + + if (typeSymbol.BaseType != null) + { + CheckType(context, typeSymbol.BaseType, typeSymbol.DeclaringSyntaxReferences); + } + + foreach (var member in typeSymbol.GetMembers()) + { + CheckMember(context, member); + } + + foreach (var innerType in typeSymbol.GetTypeMembers()) + { + CheckType(innerType, context); + } + + if (typeSymbol is INamedTypeSymbol namedTypeSymbol) + { + // Check delegate signatures + if (namedTypeSymbol.DelegateInvokeMethod != null) + { + CheckMethod(context, namedTypeSymbol.DelegateInvokeMethod); + } + } + } + + private void CheckMember(SymbolAnalysisContext context, ISymbol symbol) + { + if (IsPrivate(symbol)) + { + return; + } + + switch (symbol) + { + case IFieldSymbol fieldSymbol: + { + CheckType(context, fieldSymbol.Type, fieldSymbol.DeclaringSyntaxReferences); + break; + } + case IPropertySymbol propertySymbol: + { + CheckType(context, propertySymbol.Type, propertySymbol.DeclaringSyntaxReferences); + break; + } + case IMethodSymbol methodSymbol: + { + // Skip compiler generated members that we already explicitly check + switch (methodSymbol.MethodKind) + { + case MethodKind.EventAdd: + case MethodKind.EventRaise: + case MethodKind.EventRemove: + case MethodKind.PropertyGet: + case MethodKind.PropertySet: + case MethodKind.DelegateInvoke: + case MethodKind.Ordinary when methodSymbol.ContainingType.TypeKind == TypeKind.Delegate: + return; + } + + CheckMethod(context, methodSymbol); + break; + } + case IEventSymbol eventSymbol: + CheckType(context, eventSymbol.Type, eventSymbol.DeclaringSyntaxReferences); + break; + } + } + + private void CheckMethod(SymbolAnalysisContext context, IMethodSymbol methodSymbol) + { + if (IsPrivate(methodSymbol)) + { + return; + } + + foreach (var parameter in methodSymbol.Parameters) + { + CheckType(context, parameter.Type, parameter.DeclaringSyntaxReferences); + } + + CheckType(context, methodSymbol.ReturnType, methodSymbol.DeclaringSyntaxReferences); + } + + private static bool IsPrivate(ISymbol symbol) + { + return symbol != null && + (symbol.DeclaredAccessibility == Accessibility.Private || + symbol.DeclaredAccessibility == Accessibility.Internal || + IsInternal(symbol.ContainingNamespace)); + } + + private void CheckAttributes(SymbolAnalysisContext context, ImmutableArray attributes) + { + foreach (var attributeData in attributes) + { + CheckType(context, attributeData.AttributeClass, attributeData.ApplicationSyntaxReference); + } + } + + private void CheckType(SymbolAnalysisContext context, ITypeSymbol symbol, SyntaxReference syntax) + { + var pubternalType = GetPubternalType(symbol); + if (pubternalType != null) + { + ReportPUB0001(context, pubternalType, syntax); + } + } + private void CheckType(SymbolAnalysisContext context, ITypeSymbol symbol, ImmutableArray syntaxReferences) + { + var pubternalType = GetPubternalType(symbol); + if (pubternalType != null) + { + foreach (var syntaxReference in syntaxReferences) + { + ReportPUB0001(context, pubternalType, syntaxReference); + } + } + } + + private static void ReportPUB0001(SymbolAnalysisContext context, ITypeSymbol pubternalType, SyntaxReference syntax) + { + var syntaxNode = syntax.GetSyntax(); + var location = syntaxNode.GetLocation(); + + if (syntaxNode is BaseTypeDeclarationSyntax baseTypeDeclarationSyntax) + { + location = baseTypeDeclarationSyntax.Identifier.GetLocation(); + } + + if (syntaxNode is DelegateDeclarationSyntax delegateDeclarationSyntax) + { + location = delegateDeclarationSyntax.ReturnType.GetLocation(); + } + + if (syntaxNode is BasePropertyDeclarationSyntax propertyDeclaration) + { + location = propertyDeclaration.Type.GetLocation(); + } + + if (syntaxNode is MethodDeclarationSyntax method) + { + location = method.ReturnType.GetLocation(); + } + + if (syntaxNode is VariableDeclaratorSyntax variableDeclarator) + { + if (variableDeclarator.Parent is VariableDeclarationSyntax fieldDeclaration) + { + location = fieldDeclaration.Type.GetLocation(); + } + } + + context.ReportDiagnostic(Diagnostic.Create(PubturnalityDescriptors.PUB0001, location, pubternalType.ToDisplayString())); + } + + private ITypeSymbol GetPubternalType(ITypeSymbol symbol) + { + if (IsInternal(symbol.ContainingNamespace)) + { + return symbol; + } + else + { + if (symbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType) + { + foreach (var argument in namedTypeSymbol.TypeArguments) + { + var argumentSymbol = GetPubternalType(argument); + if (argumentSymbol != null) + { + return argumentSymbol; + } + } + } + } + + return null; + } + + private void AnalyzeTypeUsage(SyntaxNodeAnalysisContext syntaxContext) + { + var identifier = (IdentifierNameSyntax)syntaxContext.Node; + + var symbolInfo = ModelExtensions.GetTypeInfo(syntaxContext.SemanticModel, identifier, syntaxContext.CancellationToken); + if (symbolInfo.Type == null) + { + return; + } + + var type = symbolInfo.Type; + if (!IsInternal(type.ContainingNamespace)) + { + // don't care about non-pubternal type references + return; + } + + if (!syntaxContext.ContainingSymbol.ContainingAssembly.Equals(type.ContainingAssembly)) + { + syntaxContext.ReportDiagnostic(Diagnostic.Create(PubturnalityDescriptors.PUB0002, identifier.GetLocation(), type.ToDisplayString())); + } + } + + private static bool IsInternal(INamespaceSymbol ns) + { + while (ns != null) + { + if (ns.Name == "Internal") + { + return true; + } + + ns = ns.ContainingNamespace; + } + + return false; + } + } +} diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs new file mode 100644 index 0000000000..4b99afd7eb --- /dev/null +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs @@ -0,0 +1,24 @@ +// 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 Internal.AspNetCore.Analyzers +{ + internal class PubturnalityDescriptors + { + public static DiagnosticDescriptor PUB0001 = new DiagnosticDescriptor( + "PUB0001", + "Pubternal type in public API", + "Pubternal type ('{0}') usage in public API", + "Usage", + DiagnosticSeverity.Warning, true); + + public static DiagnosticDescriptor PUB0002 = new DiagnosticDescriptor( + "PUB0002", + "Cross assembly pubternal reference", + "Cross assembly pubternal type ('{0}') reference", + "Usage", + DiagnosticSeverity.Error, false); + } +} diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj new file mode 100644 index 0000000000..5795e1e43d --- /dev/null +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj @@ -0,0 +1,14 @@ + + + + $(StandardTestTfms) + true + Analyzers + + + + + + + + diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs new file mode 100644 index 0000000000..58ffafc0e9 --- /dev/null +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs @@ -0,0 +1,259 @@ +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.AspNetCore.Analyzer.Testing; +using Xunit; +using Xunit.Abstractions; + +namespace Internal.AspNetCore.Analyzers.Tests +{ + public class PubternabilityAnalyzerTests : DiagnosticVerifier + { + + private const string InternalDefinitions = @" +namespace A.Internal.Namespace +{ + public class C {} + public delegate C CD (); + public class CAAttribute: System.Attribute {} + + public class Program + { + public static void Main() {} + } +}"; + public PubternabilityAnalyzerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + + [Theory] + [MemberData(nameof(PublicMemberDefinitions))] + public async Task PublicExposureOfPubternalTypeProducesPUB0001(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + public class T + {{ + {member} + }} +}}"); + var diagnostic = Assert.Single(await GetDiagnostics(code.Source)); + Assert.Equal("PUB0001", diagnostic.Id); + AnalyzerAssert.DiagnosticLocation(code.DefaultMarkerLocation, diagnostic.Location); + } + + [Theory] + [MemberData(nameof(PublicMemberWithAllowedDefinitions))] + public async Task PublicExposureOfPubternalMembersSometimesAllowed(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + public class T + {{ + {member} + }} +}}"); + Assert.Empty(await GetDiagnostics(code.Source)); + } + + + [Theory] + [MemberData(nameof(PublicTypeDefinitions))] + public async Task PublicExposureOfPubternalTypeProducesInTypeDefinitionPUB0001(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + {member} +}}"); + var diagnostic = Assert.Single(await GetDiagnostics(code.Source)); + Assert.Equal("PUB0001", diagnostic.Id); + AnalyzerAssert.DiagnosticLocation(code.DefaultMarkerLocation, diagnostic.Location); + } + + [Theory] + [MemberData(nameof(PublicMemberDefinitions))] + public async Task PrivateUsageOfPubternalTypeDoesNotProduce(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + internal class T + {{ + {member} + }} +}}"); + var diagnostics = await GetDiagnostics(code.Source); + Assert.Empty(diagnostics); + } + + [Theory] + [MemberData(nameof(PrivateMemberDefinitions))] + public async Task PrivateUsageOfPubternalTypeDoesNotProduceInPublicClasses(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + public class T + {{ + {member} + }} +}}"); + var diagnostics = await GetDiagnostics(code.Source); + Assert.Empty(diagnostics); + } + + + [Theory] + [MemberData(nameof(PublicTypeWithAllowedDefinitions))] + public async Task PublicExposureOfPubternalTypeSometimesAllowed(string member) + { + var code = GetSourceFromNamespaceDeclaration($@" +namespace A +{{ + {member} +}}"); + var diagnostics = await GetDiagnostics(code.Source); + Assert.Empty(diagnostics); + } + + [Theory] + [MemberData(nameof(PrivateMemberDefinitions))] + [MemberData(nameof(PublicMemberDefinitions))] + public async Task DefinitionOfPubternalCrossAssemblyProducesPUB0002(string member) + { + var code = TestSource.Read($@" +using A.Internal.Namespace; +namespace A +{{ + internal class T + {{ + {member} + }} +}}"); + + var diagnostic = Assert.Single(await GetDiagnosticWithProjectReference(code.Source)); + Assert.Equal("PUB0002", diagnostic.Id); + AnalyzerAssert.DiagnosticLocation(code.DefaultMarkerLocation, diagnostic.Location); + } + + [Theory] + [MemberData(nameof(TypeUsages))] + public async Task UsageOfPubternalCrossAssemblyProducesPUB0002(string usage) + { + var code = TestSource.Read($@" +using A.Internal.Namespace; +namespace A +{{ + public class T + {{ + private void M() + {{ + {usage} + }} + }} +}}"); + var diagnostic = Assert.Single(await GetDiagnosticWithProjectReference(code.Source)); + Assert.Equal("PUB0002", diagnostic.Id); + AnalyzerAssert.DiagnosticLocation(code.DefaultMarkerLocation, diagnostic.Location); + } + + public static IEnumerable PublicMemberDefinitions => + ApplyModifiers(MemberDefinitions, "public", "protected"); + + public static IEnumerable PublicMemberWithAllowedDefinitions => + ApplyModifiers(AllowedMemberDefinitions, "public"); + + public static IEnumerable PublicTypeDefinitions => + ApplyModifiers(TypeDefinitions, "public"); + + public static IEnumerable PublicTypeWithAllowedDefinitions => + ApplyModifiers(AllowedDefinitions, "public"); + + public static IEnumerable PrivateMemberDefinitions => + ApplyModifiers(MemberDefinitions, "private", "internal"); + + public static IEnumerable TypeUsages => + ApplyModifiers(TypeUsageStrings, string.Empty); + + public static string[] MemberDefinitions => new [] + { + "/*MM*/C c;", + "T(/*MM*/C c) {}", + "/*MM*/CD c { get; }", + "event /*MM*/CD c;", + "delegate /*MM*/C WOW();" + }; + + public static string[] TypeDefinitions => new [] + { + "delegate /*MM*/C WOW();", + "class /*MM*/T: P { } public class P {}", + "class /*MM*/T: C {}", + "class T { public class /*MM*/T1: C { } }" + }; + + public static string[] AllowedMemberDefinitions => new [] + { + "T([CA]int c) {}", + "[CA] MOD int f;", + "[CA] MOD int f { get; set; }", + "[CA] MOD class CC { }" + }; + + public static string[] AllowedDefinitions => new [] + { + "class T: I { } interface I {}" + }; + + public static string[] TypeUsageStrings => new [] + { + "/*MM*/var c = new C();", + "/*MM*/CD d = () => null;", + "var t = typeof(/*MM*/CAAttribute);" + }; + + private static IEnumerable ApplyModifiers(string[] code, params string[] mods) + { + foreach (var mod in mods) + { + foreach (var s in code) + { + if (s.Contains("MOD")) + { + yield return new object[] { s.Replace("MOD", mod) }; + } + else + { + yield return new object[] { mod + " " + s }; + } + } + } + } + + private TestSource GetSourceFromNamespaceDeclaration(string namespaceDefinition) + { + return TestSource.Read("using A.Internal.Namespace;" + InternalDefinitions + namespaceDefinition); + } + + private Task GetDiagnosticWithProjectReference(string code) + { + var libraray = CreateProject(InternalDefinitions); + + var mainProject = CreateProject(code).AddProjectReference(new ProjectReference(libraray.Id)); + + return GetDiagnosticsAsync(mainProject.Documents.ToArray(), new PubternalityAnalyzer(), new [] { "PUB0002" }); + } + + private Task GetDiagnostics(string code) + { + return GetDiagnosticsAsync(new[] { code }, new PubternalityAnalyzer(), new [] { "PUB0002" }); + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs new file mode 100644 index 0000000000..1d866f9b5a --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs @@ -0,0 +1,55 @@ +// 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 Xunit.Sdk; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + public class AnalyzerAssert + { + public static void DiagnosticLocation(DiagnosticLocation 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 + if (actualLinePosition.Line > 0) + { + if (actualLinePosition.Line + 1 != expected.Line) + { + throw new DiagnosticLocationAssertException( + expected, + actual, + $"Expected diagnostic to be on line \"{expected.Line}\" was actually on line \"{actualLinePosition.Line + 1}\""); + } + } + + // Only check column position if there is an actual column position in the real diagnostic + if (actualLinePosition.Character > 0) + { + if (actualLinePosition.Character + 1 != expected.Column) + { + throw new DiagnosticLocationAssertException( + expected, + actual, + $"Expected diagnostic to start at column \"{expected.Column}\" was actually on column \"{actualLinePosition.Character + 1}\""); + } + } + } + + private class DiagnosticLocationAssertException : EqualException + { + public DiagnosticLocationAssertException( + DiagnosticLocation expected, + Location actual, + string message) + : base(expected, actual) + { + Message = message; + } + + public override string Message { get; } + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs new file mode 100644 index 0000000000..c56618774e --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs @@ -0,0 +1,71 @@ +// 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.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + public class CodeFixRunner + { + public static CodeFixRunner Default { get; } = new CodeFixRunner(); + + public async Task ApplyCodeFixAsync( + CodeFixProvider codeFixProvider, + Document document, + Diagnostic analyzerDiagnostic, + int codeFixIndex = 0) + { + var actions = new List(); + var context = new CodeFixContext(document, analyzerDiagnostic, (a, d) => actions.Add(a), CancellationToken.None); + await codeFixProvider.RegisterCodeFixesAsync(context); + + Assert.NotEmpty(actions); + + var updatedSolution = await ApplyFixAsync(actions[codeFixIndex]); + + var updatedProject = updatedSolution.GetProject(document.Project.Id); + await EnsureCompilable(updatedProject); + + var updatedDocument = updatedSolution.GetDocument(document.Id); + var sourceText = await updatedDocument.GetTextAsync(); + return sourceText.ToString(); + } + + private async Task EnsureCompilable(Project project) + { + var compilationOptions = ConfigureCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var compilation = await project + .WithCompilationOptions(compilationOptions) + .GetCompilationAsync(); + var diagnostics = compilation.GetDiagnostics(); + if (diagnostics.Length != 0) + { + var message = string.Join( + Environment.NewLine, + diagnostics.Select(d => CSharpDiagnosticFormatter.Instance.Format(d))); + throw new InvalidOperationException($"Compilation failed:{Environment.NewLine}{message}"); + } + } + + private static async Task ApplyFixAsync(CodeAction codeAction) + { + var operations = await codeAction.GetOperationsAsync(CancellationToken.None); + return Assert.Single(operations.OfType()).ChangedSolution; + } + + protected virtual CompilationOptions ConfigureCompilationOptions(CompilationOptions options) + { + return options.WithOutputKind(OutputKind.DynamicallyLinkedLibrary); + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs new file mode 100644 index 0000000000..df3b01d413 --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs @@ -0,0 +1,121 @@ +// 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 System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Xunit; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + /// + /// Base type for executing a . Derived types implemented in the test assembly will + /// correctly resolve reference assemblies required for compilaiton. + /// + public abstract class DiagnosticAnalyzerRunner + { + /// + /// Given classes in the form of strings, and an DiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. + /// + /// Classes in the form of strings + /// The analyzer to be run on the sources + /// Additional diagnostics to enable at Info level + /// + /// When true, returns all diagnostics including compilation errors. + /// Otherwise; only returns analyzer diagnostics. + /// + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + protected Task GetDiagnosticsAsync( + string[] sources, + DiagnosticAnalyzer analyzer, + string[] additionalEnabledDiagnostics, + bool getAllDiagnostics = true) + { + var project = DiagnosticProject.Create(GetType().Assembly, sources); + return GetDiagnosticsAsync(new[] { project }, analyzer, additionalEnabledDiagnostics); + } + + /// + /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. + /// The returned diagnostics are then ordered by location in the source document. + /// + /// The Documents that the analyzer will be run on + /// The analyzer to run on the documents + /// Additional diagnostics to enable at Info level + /// + /// When true, returns all diagnostics including compilation errors. + /// Otherwise only returns analyzer diagnostics. + /// + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + protected async Task GetDiagnosticsAsync( + IEnumerable projects, + DiagnosticAnalyzer analyzer, + string[] additionalEnabledDiagnostics, + bool getAllDiagnostics = true) + { + var diagnostics = new List(); + foreach (var project in projects) + { + var compilation = await project.GetCompilationAsync(); + + // Enable any additional diagnostics + var options = ConfigureCompilationOptions(compilation.Options); + if (additionalEnabledDiagnostics.Length > 0) + { + options = compilation.Options + .WithSpecificDiagnosticOptions( + additionalEnabledDiagnostics.ToDictionary(s => s, s => ReportDiagnostic.Info)); + } + + var compilationWithAnalyzers = compilation + .WithOptions(options) + .WithAnalyzers(ImmutableArray.Create(analyzer)); + + if (getAllDiagnostics) + { + var diags = await compilationWithAnalyzers.GetAllDiagnosticsAsync(); + + Assert.DoesNotContain(diags, d => d.Id == "AD0001"); + + // Filter out non-error diagnostics not produced by our analyzer + // We want to KEEP errors because we might have written bad code. But sometimes we leave warnings in to make the + // test code more convenient + diags = diags.Where(d => d.Severity == DiagnosticSeverity.Error || analyzer.SupportedDiagnostics.Any(s => s.Id.Equals(d.Id))).ToImmutableArray(); + + foreach (var diag in diags) + { + if (diag.Location == Location.None || diag.Location.IsInMetadata) + { + diagnostics.Add(diag); + } + else + { + foreach (var document in projects.SelectMany(p => p.Documents)) + { + var tree = await document.GetSyntaxTreeAsync(); + if (tree == diag.Location.SourceTree) + { + diagnostics.Add(diag); + } + } + } + } + } + else + { + diagnostics.AddRange(await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync()); + } + } + + return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); + } + + protected virtual CompilationOptions ConfigureCompilationOptions(CompilationOptions options) + { + return options.WithOutputKind(OutputKind.DynamicallyLinkedLibrary); + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs new file mode 100644 index 0000000000..51a011f49a --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs @@ -0,0 +1,39 @@ +// 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; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + /// + /// Location where the diagnostic appears, as determined by path, line number, and column number. + /// + public class DiagnosticLocation + { + public DiagnosticLocation(int line, int column) + : this($"{DiagnosticProject.DefaultFilePathPrefix}.cs", line, column) + { + } + + public DiagnosticLocation(string path, int line, int column) + { + if (line < -1) + { + throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1"); + } + + if (column < -1) + { + throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); + } + + Path = path; + Line = line; + Column = column; + } + + public string Path { get; } + public int Line { get; } + public int Column { get; } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs new file mode 100644 index 0000000000..5d195f28ed --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs @@ -0,0 +1,86 @@ +// 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.IO; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.DependencyModel.Resolution; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + public class DiagnosticProject + { + /// + /// File name prefix used to generate Documents instances from source. + /// + public static string DefaultFilePathPrefix = "Test"; + + /// + /// Project name. + /// + public static string TestProjectName = "TestProject"; + + public static Project Create(Assembly testAssembly, string[] sources) + { + var fileNamePrefix = DefaultFilePathPrefix; + + var projectId = ProjectId.CreateNewId(debugName: TestProjectName); + + var solution = new AdhocWorkspace() + .CurrentSolution + .AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp); + + foreach (var defaultCompileLibrary in DependencyContext.Load(testAssembly).CompileLibraries) + { + foreach (var resolveReferencePath in defaultCompileLibrary.ResolveReferencePaths(new AppLocalResolver())) + { + solution = solution.AddMetadataReference(projectId, MetadataReference.CreateFromFile(resolveReferencePath)); + } + } + + for (var i = 0; i < sources.Length; i++) + { + var newFileName = fileNamePrefix; + if (sources.Length > 1) + { + newFileName += i; + } + newFileName += ".cs"; + + var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); + solution = solution.AddDocument(documentId, newFileName, SourceText.From(sources[i])); + } + + return solution.GetProject(projectId); + } + + // Required to resolve compilation assemblies inside unit tests + private class AppLocalResolver : ICompilationAssemblyResolver + { + public bool TryResolveAssemblyPaths(CompilationLibrary library, List assemblies) + { + foreach (var assembly in library.Assemblies) + { + var dll = Path.Combine(Directory.GetCurrentDirectory(), "refs", Path.GetFileName(assembly)); + if (File.Exists(dll)) + { + assemblies.Add(dll); + return true; + } + + dll = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(assembly)); + if (File.Exists(dll)) + { + assemblies.Add(dll); + return true; + } + } + + return false; + } + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs new file mode 100644 index 0000000000..a67eda76c9 --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs @@ -0,0 +1,213 @@ +// 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.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.DependencyModel.Resolution; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + /// + /// Superclass of all Unit Tests for DiagnosticAnalyzers + /// + public abstract class DiagnosticVerifier + { + private readonly ITestOutputHelper _testOutputHelper; + + /// + protected DiagnosticVerifier(): this(null) + { + } + + /// + protected DiagnosticVerifier(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + /// + /// File name prefix used to generate Documents instances from source. + /// + protected static string DefaultFilePathPrefix = "Test"; + /// + /// Project name of + /// + protected static string TestProjectName = "TestProject"; + + protected Solution Solution { get; set; } + + /// + /// Given classes in the form of strings, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document. + /// + /// Classes in the form of strings + /// The analyzer to be run on the sources + /// Additional diagnostics to enable at Info level + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + protected Task GetDiagnosticsAsync(string[] sources, DiagnosticAnalyzer analyzer, string[] additionalEnabledDiagnostics) + { + return GetDiagnosticsAsync(GetDocuments(sources), analyzer, additionalEnabledDiagnostics); + } + + /// + /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. + /// The returned diagnostics are then ordered by location in the source document. + /// + /// The Documents that the analyzer will be run on + /// The analyzer to run on the documents + /// Additional diagnostics to enable at Info level + /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location + protected async Task GetDiagnosticsAsync(Document[] documents, DiagnosticAnalyzer analyzer, string[] additionalEnabledDiagnostics) + { + var projects = new HashSet(); + foreach (var document in documents) + { + projects.Add(document.Project); + } + + var diagnostics = new List(); + foreach (var project in projects) + { + var compilation = await project.GetCompilationAsync(); + + // Enable any additional diagnostics + var options = compilation.Options; + if (additionalEnabledDiagnostics.Length > 0) + { + options = compilation.Options + .WithSpecificDiagnosticOptions( + additionalEnabledDiagnostics.ToDictionary(s => s, s => ReportDiagnostic.Info)); + } + + var compilationWithAnalyzers = compilation + .WithOptions(options) + .WithAnalyzers(ImmutableArray.Create(analyzer)); + + var diags = await compilationWithAnalyzers.GetAllDiagnosticsAsync(); + + foreach (var diag in diags) + { + _testOutputHelper?.WriteLine("Diagnostics: " + diag); + } + + Assert.DoesNotContain(diags, d => d.Id == "AD0001"); + + // Filter out non-error diagnostics not produced by our analyzer + // We want to KEEP errors because we might have written bad code. But sometimes we leave warnings in to make the + // test code more convenient + diags = diags.Where(d => d.Severity == DiagnosticSeverity.Error || analyzer.SupportedDiagnostics.Any(s => s.Id.Equals(d.Id))).ToImmutableArray(); + + foreach (var diag in diags) + { + if (diag.Location == Location.None || diag.Location.IsInMetadata) + { + diagnostics.Add(diag); + } + else + { + foreach (var document in documents) + { + var tree = await document.GetSyntaxTreeAsync(); + if (tree == diag.Location.SourceTree) + { + diagnostics.Add(diag); + } + } + } + } + } + + return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray(); + } + + /// + /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. + /// + /// Classes in the form of strings + /// An array of Documents produced from the sources. + private Document[] GetDocuments(string[] sources) + { + var project = CreateProject(sources); + var documents = project.Documents.ToArray(); + + Debug.Assert(sources.Length == documents.Length); + + return documents; + } + + /// + /// Create a project using the inputted strings as sources. + /// + /// Classes in the form of strings + /// A Project created out of the Documents created from the source strings + protected Project CreateProject(params string[] sources) + { + var fileNamePrefix = DefaultFilePathPrefix; + + var projectId = ProjectId.CreateNewId(debugName: TestProjectName); + + Solution = Solution ?? new AdhocWorkspace().CurrentSolution; + + Solution = Solution.AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp) + .WithProjectCompilationOptions(projectId, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + foreach (var defaultCompileLibrary in DependencyContext.Load(GetType().Assembly).CompileLibraries) + { + foreach (var resolveReferencePath in defaultCompileLibrary.ResolveReferencePaths(new AppLocalResolver())) + { + Solution = Solution.AddMetadataReference(projectId, MetadataReference.CreateFromFile(resolveReferencePath)); + } + } + + var count = 0; + foreach (var source in sources) + { + var newFileName = fileNamePrefix + count; + + _testOutputHelper?.WriteLine("Adding file: " + newFileName + Environment.NewLine + source); + + var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); + Solution = Solution.AddDocument(documentId, newFileName, SourceText.From(source)); + count++; + } + return Solution.GetProject(projectId); + } + + // Required to resolve compilation assemblies inside unit tests + private class AppLocalResolver : ICompilationAssemblyResolver + { + public bool TryResolveAssemblyPaths(CompilationLibrary library, List assemblies) + { + foreach (var assembly in library.Assemblies) + { + var dll = Path.Combine(Directory.GetCurrentDirectory(), "refs", Path.GetFileName(assembly)); + if (File.Exists(dll)) + { + assemblies.Add(dll); + return true; + } + + dll = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(assembly)); + if (File.Exists(dll)) + { + assemblies.Add(dll); + return true; + } + } + + return false; + } + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj new file mode 100644 index 0000000000..0930dc8f96 --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -0,0 +1,22 @@ + + + + Helpers for writing tests for Roslyn analyzers. + netstandard2.0 + $(PackageTags);testing + false + + + + + + + + + + + + + + + diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs new file mode 100644 index 0000000000..f88f68d767 --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs @@ -0,0 +1,51 @@ +// 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.Generic; +using System.IO; + +namespace Microsoft.AspNetCore.Analyzer.Testing +{ + public class TestSource + { + private const string MarkerStart = "/*MM"; + private const string MarkerEnd = "*/"; + + public IDictionary MarkerLocations { get; } + = new Dictionary(StringComparer.Ordinal); + + public DiagnosticLocation DefaultMarkerLocation { get; private set; } + + public string Source { get; private set; } + + public static TestSource Read(string rawSource) + { + var testInput = new TestSource(); + var lines = rawSource.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + 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 markerLocation = new DiagnosticLocation(i + 1, markerStartIndex + 1); + if (testInput.DefaultMarkerLocation == null) + { + testInput.DefaultMarkerLocation = markerLocation; + } + + testInput.MarkerLocations.Add(markerName, markerLocation); + line = line.Substring(0, markerStartIndex) + line.Substring(markerEndIndex + MarkerEnd.Length); + } + + lines[i] = line; + } + + testInput.Source = string.Join(Environment.NewLine, lines); + return testInput; + } + } +} diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/build/Microsoft.AspNetCore.Analyzer.Testing.props b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/build/Microsoft.AspNetCore.Analyzer.Testing.props new file mode 100644 index 0000000000..ea709701d7 --- /dev/null +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/build/Microsoft.AspNetCore.Analyzer.Testing.props @@ -0,0 +1,7 @@ + + + + true + + + \ No newline at end of file From 33609a988c8abadd0b03928646c3e7520287f7d1 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 14 Nov 2018 08:43:07 -0800 Subject: [PATCH 02/14] Prepare repo to build 2.2.1 * Update dependencies to 2.2.0 rtm * Update branding to 2.2.1 * Update package baselines to 2.2.0 * Add a restore source for 2.2.0 RTM --- .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 0930dc8f96..15259c0539 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -5,6 +5,8 @@ netstandard2.0 $(PackageTags);testing false + + true From 3c1bcd4ab402720e3e079772b97fa25a1999a541 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 14 Nov 2018 12:25:46 -0800 Subject: [PATCH 03/14] Add soluition cache for analyzers (#499) --- .../src/DiagnosticProject.cs | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs index 5d195f28ed..db42edf380 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs @@ -1,8 +1,9 @@ -// 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.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; @@ -23,24 +24,35 @@ namespace Microsoft.AspNetCore.Analyzer.Testing /// public static string TestProjectName = "TestProject"; + private static readonly Dictionary _solutionCache = new Dictionary(); + public static Project Create(Assembly testAssembly, string[] sources) { - var fileNamePrefix = DefaultFilePathPrefix; - - var projectId = ProjectId.CreateNewId(debugName: TestProjectName); - - var solution = new AdhocWorkspace() - .CurrentSolution - .AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp); - - foreach (var defaultCompileLibrary in DependencyContext.Load(testAssembly).CompileLibraries) + Solution solution; + lock (_solutionCache) { - foreach (var resolveReferencePath in defaultCompileLibrary.ResolveReferencePaths(new AppLocalResolver())) + if (!_solutionCache.TryGetValue(testAssembly, out solution)) { - solution = solution.AddMetadataReference(projectId, MetadataReference.CreateFromFile(resolveReferencePath)); + var projectId = ProjectId.CreateNewId(debugName: TestProjectName); + solution = new AdhocWorkspace() + .CurrentSolution + .AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp); + + foreach (var defaultCompileLibrary in DependencyContext.Load(testAssembly).CompileLibraries) + { + foreach (var resolveReferencePath in defaultCompileLibrary.ResolveReferencePaths(new AppLocalResolver())) + { + solution = solution.AddMetadataReference(projectId, MetadataReference.CreateFromFile(resolveReferencePath)); + } + } + + _solutionCache.Add(testAssembly, solution); } } + var testProject = solution.ProjectIds.Single(); + var fileNamePrefix = DefaultFilePathPrefix; + for (var i = 0; i < sources.Length; i++) { var newFileName = fileNamePrefix; @@ -50,11 +62,11 @@ namespace Microsoft.AspNetCore.Analyzer.Testing } newFileName += ".cs"; - var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName); + var documentId = DocumentId.CreateNewId(testProject, debugName: newFileName); solution = solution.AddDocument(documentId, newFileName, SourceText.From(sources[i])); } - return solution.GetProject(projectId); + return solution.GetProject(testProject); } // Required to resolve compilation assemblies inside unit tests From e952668572817b91c694605a85b6e80b9011d3ff Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 12 Dec 2018 09:27:33 -0800 Subject: [PATCH 04/14] Merge branch 'merge/release/2.1-to-release/2.2' of github.com:dotnet-maestro-bot/Common into merge/release/2.1-to-release/2.2 --- .../src/DiagnosticVerifier.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs index a67eda76c9..d56178e0e2 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs @@ -195,18 +195,17 @@ namespace Microsoft.AspNetCore.Analyzer.Testing if (File.Exists(dll)) { assemblies.Add(dll); - return true; + continue; } dll = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(assembly)); if (File.Exists(dll)) { assemblies.Add(dll); - return true; } } - return false; + return assemblies.Count > 0; } } } From df645bd25f729551d14ddfc6794f2fe582b5be6d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 7 Jan 2019 15:56:39 -0800 Subject: [PATCH 05/14] Merge branch 'release/2.1' into release/2.2 --- .../test/Internal.AspNetCore.Analyzers.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj index 5795e1e43d..b58886f76d 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj @@ -1,7 +1,7 @@  - $(StandardTestTfms) + netcoreapp2.2;net461 true Analyzers From cf72b68a1c631139f4bfd0a754c162424de0ed86 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Tue, 29 Jan 2019 13:26:53 -0800 Subject: [PATCH 06/14] Use Arcade (#586) Use arcade --- .../src/Internal.AspNetCore.Analyzers.csproj | 1 + .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 2 ++ .../Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj index 1814c4c69f..09a66966e0 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj @@ -7,6 +7,7 @@ $(NoWarn);CS1591 false analyzers/dotnet/cs/ + true diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 15259c0539..988ca150cb 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -7,6 +7,8 @@ false true + true + false diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs index f88f68d767..726204e059 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Analyzer.Testing public static TestSource Read(string rawSource) { var testInput = new TestSource(); - var lines = rawSource.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var lines = rawSource.Split(new[] { "\n", "\r\n" }, StringSplitOptions.None); for (var i = 0; i < lines.Length; i++) { var line = lines[i]; From f9de66f47d9322f9d9e3c1aba696b01e4d351217 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Jan 2019 18:34:54 -0800 Subject: [PATCH 07/14] Cleanup conversion to Arcade (#1014) * Remove obsolete targets, properties, and scripts * Replace IsProductComponent with IsShipping * Undo bad merge to version.props * Update documentation, and put workarounds into a common file * Replace usages of RepositoryRoot with RepoRoot * Remove API baselines * Remove unnecessary restore feeds and split workarounds into two files * Enable PR checks on all branches, and disable autocancel --- .../src/Internal.AspNetCore.Analyzers.csproj | 2 +- .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj index 09a66966e0..d5635e153f 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj @@ -5,9 +5,9 @@ netstandard1.3 $(PackageTags);analyzers $(NoWarn);CS1591 - false analyzers/dotnet/cs/ true + false diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 988ca150cb..8ff629df7f 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -4,7 +4,6 @@ Helpers for writing tests for Roslyn analyzers. netstandard2.0 $(PackageTags);testing - false true true From f87c01b129df61758b9fd09f3c9e1249b8fab09f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 31 Jan 2019 13:20:34 -0800 Subject: [PATCH 08/14] Remove implicit references for non-test projects (#1037) --- .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 8ff629df7f..3416e43e18 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -4,6 +4,8 @@ Helpers for writing tests for Roslyn analyzers. netstandard2.0 $(PackageTags);testing + + false true true @@ -14,6 +16,15 @@ + + From e5ee01f97b834fcd70fedf8f9ec668b1fbfdb973 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 1 Feb 2019 10:33:04 -0800 Subject: [PATCH 09/14] Add code check CI tests, add docs about ReferenceResolution, and other cleanups (#1044) Changes: * Add a step which checks that generated code is up to date * Copy over the documentation on how to work with `` * Fixup a broken reference in the .sln * Fix the casing on Microsoft.Extensions.ValueStopwatch.Sources * Remove some unused references and variables --- .../src/Internal.AspNetCore.Analyzers.csproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj index d5635e153f..a9d809513a 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj @@ -6,6 +6,14 @@ $(PackageTags);analyzers $(NoWarn);CS1591 analyzers/dotnet/cs/ + + false + true + true true false From e44d9d3103ec73b66b68957c971b66859ae0b844 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 22 Feb 2019 12:35:31 -0800 Subject: [PATCH 10/14] Add xml docs to targeting pack (#1149) --- .../src/DiagnosticAnalyzerRunner.cs | 2 +- .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs index df3b01d413..01f3699c09 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Analyzer.Testing /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// - /// The Documents that the analyzer will be run on + /// Projects that the analyzer will be run on /// The analyzer to run on the documents /// Additional diagnostics to enable at Info level /// diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 3416e43e18..9c68e65853 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -4,6 +4,7 @@ Helpers for writing tests for Roslyn analyzers. netstandard2.0 $(PackageTags);testing + true false From 6a577824f87b291242342a98e78fbf1b1c2eaa96 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 12 Jun 2019 22:39:41 -0700 Subject: [PATCH 11/14] Use even more Arcade and other csproj cleanups (#1833) * Use Arcade's convention for setting IsPackable (must be explicitly set) * Use Arcade conventions for using DebugType and eng/Versions.props * Remove dead code * Update restore feeds in daily builds.md * Disable UsingToolNetFrameworkReferenceAssemblies in analyzer tests * Remove usage of TestGroupName (an obsolete KoreBuild setting) * Use IVT as a .csproj attribute --- .../test/Internal.AspNetCore.Analyzers.Tests.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj index 80bcd40647..0a0852d723 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj @@ -3,7 +3,8 @@ netcoreapp3.0;net472 true - Analyzers + + false From a79ca4056f1d3bd5975817e9174618573f55d20e Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 12 Sep 2019 22:34:52 -0700 Subject: [PATCH 12/14] Support netcoreapp3.1 TFM (#2336) * Support netcoreapp3.1 TFM * Unpin SDK for source build * Update to preview1 branding --- .../test/Internal.AspNetCore.Analyzers.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj index 0a0852d723..99dcca9dc1 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/Internal.AspNetCore.Analyzers.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 true false From 16539847c573d9f2596dd93dbd4c289daa85e765 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 12 Dec 2019 13:43:49 -0800 Subject: [PATCH 13/14] Set IsShipping=false for all TestingUtils projects (#2782) --- .../src/Internal.AspNetCore.Analyzers.csproj | 1 - .../src/Microsoft.AspNetCore.Analyzer.Testing.csproj | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj index a9d809513a..2ce18ea5b7 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/Internal.AspNetCore.Analyzers.csproj @@ -15,7 +15,6 @@ true true true - false diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj index 9c68e65853..bea1900716 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Microsoft.AspNetCore.Analyzer.Testing.csproj @@ -10,7 +10,6 @@ true true - false From 5c489400b9e446ebdddbc41b21278b741ada3042 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 26 Feb 2020 10:31:24 -0800 Subject: [PATCH 14/14] Switch file headers to the MIT license --- .../src/PubternalityAnalyzer.cs | 5 +++-- .../src/PubturnalityDescriptors.cs | 5 +++-- .../test/PubternabilityAnalyzerTests.cs | 5 +++-- .../Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs | 5 +++-- .../src/CodeFixRunner.cs | 5 +++-- .../src/DiagnosticAnalyzerRunner.cs | 5 +++-- .../src/DiagnosticLocation.cs | 5 +++-- .../src/DiagnosticProject.cs | 5 +++-- .../src/DiagnosticVerifier.cs | 5 +++-- .../Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs | 5 +++-- 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs index 8a1a3efdee..b66aa38c2e 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubternalityAnalyzer.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Immutable; using Microsoft.CodeAnalysis; diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs index 4b99afd7eb..6064ebaf34 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/src/PubturnalityDescriptors.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis; diff --git a/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs b/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs index 58ffafc0e9..ebcd5fa1e8 100644 --- a/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs +++ b/src/Analyzers/Internal.AspNetCore.Analyzers/test/PubternabilityAnalyzerTests.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Linq; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs index 1d866f9b5a..b79ae064b0 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/Assert.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis; using Xunit.Sdk; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs index c56618774e..3c21e5c3b4 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/CodeFixRunner.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs index 01f3699c09..bfc9406335 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticAnalyzerRunner.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs index 51a011f49a..e5321613f7 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticLocation.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs index db42edf380..013bbf151c 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.IO; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs index d56178e0e2..d0796f40a8 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticVerifier.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; diff --git a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs index 726204e059..ef70152faa 100644 --- a/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs +++ b/src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/TestSource.cs @@ -1,5 +1,6 @@ -// 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. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System; using System.Collections.Generic;