|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if DEBUG
using System.Collections.Immutable;
using ILLink.Shared;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace ILLink.RoslynAnalyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UnsafeMethodMissingRequiresUnsafeAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor s_rule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.UnsafeMethodMissingRequiresUnsafe, diagnosticSeverity: DiagnosticSeverity.Info);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_rule);
public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.RegisterCompilationStartAction(context =>
{
if (!context.Options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.EnableUnsafeAnalyzer))
return;
if (context.Compilation.GetTypeByMetadataName(RequiresUnsafeAnalyzer.FullyQualifiedRequiresUnsafeAttribute) is null)
return;
context.RegisterSymbolAction(
AnalyzeMethod,
SymbolKind.Method);
});
}
private static void AnalyzeMethod(SymbolAnalysisContext context)
{
if (context.Symbol is not IMethodSymbol method)
return;
if (!HasPointerInSignature(method))
return;
if (method.HasAttribute(RequiresUnsafeAnalyzer.RequiresUnsafeAttributeName))
return;
// For property/indexer accessors, check the containing property instead
if (method.AssociatedSymbol is IPropertySymbol property
&& property.HasAttribute(RequiresUnsafeAnalyzer.RequiresUnsafeAttributeName))
return;
foreach (var location in method.Locations)
{
context.ReportDiagnostic(Diagnostic.Create(s_rule, location, method.GetDisplayName()));
}
}
private static bool HasPointerInSignature(IMethodSymbol method)
{
if (IsPointerType(method.ReturnType))
return true;
foreach (var param in method.Parameters)
{
if (IsPointerType(param.Type))
return true;
}
return false;
}
private static bool IsPointerType(ITypeSymbol type) => type is IPointerTypeSymbol or IFunctionPointerTypeSymbol;
}
}
#endif
|