|
// 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.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics
{
public partial class SuppressMessageAttributeTests
{
protected const string TestDiagnosticCategory = "Test";
protected const string TestDiagnosticMessageTemplate = "{0}";
protected class WarningOnCompilationEndedAnalyzer : DiagnosticAnalyzer
{
public const string Id = "CompilationEnded";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterCompilationAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, Location.None, messageArgs: Id));
}
);
}
}
// Produces a warning on the declaration of any symbol whose name starts with a specified prefix
protected class WarningOnNamePrefixDeclarationAnalyzer : DiagnosticAnalyzer
{
public const string Id = "Declaration";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
private readonly string _errorSymbolPrefix;
public WarningOnNamePrefixDeclarationAnalyzer(string errorSymbolPrefix)
{
_errorSymbolPrefix = errorSymbolPrefix;
}
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterSymbolAction(
(context) =>
{
if (context.Symbol.Name.StartsWith(_errorSymbolPrefix, StringComparison.Ordinal))
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Symbol.Locations.First(), messageArgs: context.Symbol.Name));
}
},
SymbolKind.Event,
SymbolKind.Field,
SymbolKind.Method,
SymbolKind.NamedType,
SymbolKind.Namespace,
SymbolKind.Property);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
}
// Produces a warning on the declaration of any named type
protected class WarningOnTypeDeclarationAnalyzer : DiagnosticAnalyzer
{
public const string TypeId = "TypeDeclaration";
private static readonly DiagnosticDescriptor s_rule = GetRule(TypeId);
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterSymbolAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Symbol.Locations.First(), messageArgs: context.Symbol.Name));
},
SymbolKind.NamedType);
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
}
// Produces a warning for the end of every code body and every invocation expression within that code body
protected class WarningOnCodeBodyAnalyzer : DiagnosticAnalyzer
{
public const string Id = "CodeBody";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
private readonly string _language;
public WarningOnCodeBodyAnalyzer(string language)
{
_language = language;
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
public override void Initialize(AnalysisContext analysisContext)
{
if (_language == LanguageNames.CSharp)
{
analysisContext.RegisterCodeBlockStartAction<CSharp.SyntaxKind>(new CSharpCodeBodyAnalyzer().Initialize);
}
else
{
analysisContext.RegisterCodeBlockStartAction<VisualBasic.SyntaxKind>(new BasicCodeBodyAnalyzer().Initialize);
}
}
protected class CSharpCodeBodyAnalyzer
{
public void Initialize(CodeBlockStartAnalysisContext<CSharp.SyntaxKind> analysisContext)
{
analysisContext.RegisterCodeBlockEndAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.OwningSymbol.Locations.First(), messageArgs: context.OwningSymbol.Name + ":end"));
});
analysisContext.RegisterSyntaxNodeAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Node.GetLocation(), messageArgs: context.Node.ToFullString()));
},
CSharp.SyntaxKind.InvocationExpression);
}
}
protected class BasicCodeBodyAnalyzer
{
public void Initialize(CodeBlockStartAnalysisContext<VisualBasic.SyntaxKind> analysisContext)
{
analysisContext.RegisterCodeBlockEndAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.OwningSymbol.Locations.First(), messageArgs: context.OwningSymbol.Name + ":end"));
});
analysisContext.RegisterSyntaxNodeAction(
(context) =>
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Node.GetLocation(), messageArgs: context.Node.ToFullString()));
},
VisualBasic.SyntaxKind.InvocationExpression);
}
}
}
// Produces a warning for each comment trivium in a syntax tree
protected class WarningOnCommentAnalyzer : DiagnosticAnalyzer
{
public const string Id = "Comment";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterSyntaxTreeAction(
(context) =>
{
var comments = context.Tree.GetRoot().DescendantTrivia()
.Where(t =>
t.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
t.IsKind(SyntaxKind.MultiLineCommentTrivia) ||
t.IsKind(VisualBasic.SyntaxKind.CommentTrivia));
foreach (var comment in comments)
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, comment.GetLocation(), messageArgs: comment.ToFullString()));
}
});
}
}
// Produces a warning for each token overlapping the given span in a syntax tree
protected class WarningOnTokenAnalyzer : DiagnosticAnalyzer
{
public const string Id = "Token";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
private readonly IList<TextSpan> _spans;
public WarningOnTokenAnalyzer(IList<TextSpan> spans)
{
_spans = spans;
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterSyntaxTreeAction(
(context) =>
{
foreach (var nodeOrToken in context.Tree.GetRoot().DescendantNodesAndTokens())
{
if (nodeOrToken.IsToken && _spans.Any(s => s.OverlapsWith(nodeOrToken.FullSpan)))
{
context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, nodeOrToken.GetLocation(), messageArgs: nodeOrToken.ToString()));
}
}
});
}
}
// Throws an exception on every AnalyzeSymbol on named types
protected class ThrowExceptionForEachNamedTypeAnalyzer : DiagnosticAnalyzer
{
public const string Id = "ThrowException";
private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
private readonly ExceptionDispatchInfo _exceptionDispatchInfo;
public ThrowExceptionForEachNamedTypeAnalyzer(ExceptionDispatchInfo exceptionDispatchInfo)
{
_exceptionDispatchInfo = exceptionDispatchInfo;
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(s_rule);
}
}
public string AssemblyName { get; private set; }
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterCompilationStartAction(context => AssemblyName = context.Compilation.AssemblyName);
analysisContext.RegisterSymbolAction(
(context) =>
{
_exceptionDispatchInfo.Throw();
},
SymbolKind.NamedType);
}
}
protected class ThrowExceptionFromSupportedDiagnostics : DiagnosticAnalyzer
{
private readonly Exception _exception;
public ThrowExceptionFromSupportedDiagnostics(Exception exception)
{
_exception = exception;
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
ExceptionDispatchInfo.Capture(_exception).Throw();
throw ExceptionUtilities.Unreachable();
}
}
public override void Initialize(AnalysisContext analysisContext)
=> throw ExceptionUtilities.Unreachable();
}
protected static DiagnosticDescriptor GetRule(string id)
{
return new DiagnosticDescriptor(
id,
id,
TestDiagnosticMessageTemplate,
TestDiagnosticCategory,
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
}
}
}
|