| File: RequiresUnreferencedCodeAnalyzer.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj (ILLink.RoslynAnalyzer) |
// 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. using System; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using ILLink.RoslynAnalyzer.DataFlow; using ILLink.RoslynAnalyzer.TrimAnalysis; using ILLink.Shared; using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using ILLink.Shared.TypeSystemProxy; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; namespace ILLink.RoslynAnalyzer { [DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed class RequiresUnreferencedCodeAnalyzer : RequiresAnalyzerBase { public const string RequiresUnreferencedCodeAttribute = nameof(RequiresUnreferencedCodeAttribute); public const string FullyQualifiedRequiresUnreferencedCodeAttribute = "System.Diagnostics.CodeAnalysis." + RequiresUnreferencedCodeAttribute; private static readonly DiagnosticDescriptor s_requiresUnreferencedCodeRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCode); private static readonly DiagnosticDescriptor s_requiresUnreferencedCodeAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCodeAttributeMismatch); private static readonly DiagnosticDescriptor s_makeGenericTypeRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.MakeGenericType); private static readonly DiagnosticDescriptor s_makeGenericMethodRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.MakeGenericMethod); private static readonly DiagnosticDescriptor s_requiresUnreferencedCodeOnStaticCtor = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCodeOnStaticConstructor); private static readonly DiagnosticDescriptor s_requiresUnreferencedCodeOnEntryPoint = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.RequiresUnreferencedCodeOnEntryPoint); private static readonly DiagnosticDescriptor s_referenceNotMarkedIsTrimmableRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.ReferenceNotMarkedIsTrimmable); private static readonly DiagnosticDescriptor s_dynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameterRule = DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch, s_requiresUnreferencedCodeOnStaticCtor, s_requiresUnreferencedCodeOnEntryPoint, s_referenceNotMarkedIsTrimmableRule, s_dynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameterRule); private protected override string RequiresAttributeName => RequiresUnreferencedCodeAttribute; internal override string RequiresAttributeFullyQualifiedName => FullyQualifiedRequiresUnreferencedCodeAttribute; private protected override DiagnosticTargets AnalyzerDiagnosticTargets => DiagnosticTargets.MethodOrConstructor | DiagnosticTargets.Class; private protected override DiagnosticDescriptor RequiresDiagnosticRule => s_requiresUnreferencedCodeRule; private protected override DiagnosticId RequiresDiagnosticId => DiagnosticId.RequiresUnreferencedCode; private protected override DiagnosticDescriptor RequiresAttributeMismatch => s_requiresUnreferencedCodeAttributeMismatch; private protected override DiagnosticDescriptor RequiresOnStaticCtor => s_requiresUnreferencedCodeOnStaticCtor; private protected override DiagnosticDescriptor RequiresOnEntryPoint => s_requiresUnreferencedCodeOnEntryPoint; internal override bool IsAnalyzerEnabled(AnalyzerOptions options) => options.IsMSBuildPropertyValueTrue(MSBuildPropertyOptionNames.EnableTrimAnalyzer); private protected override bool IsRequiresCheck(IPropertySymbol propertySymbol, Compilation compilation) { // "IsUnreferencedCodeSupported" is treated as a requires check for testing purposes only, and // is not officially-supported product behavior. var runtimeFeaturesType = compilation.GetTypeByMetadataName("ILLink.RoslynAnalyzer.TestFeatures"); if (runtimeFeaturesType == null) return false; var isDynamicCodeSupportedProperty = runtimeFeaturesType.GetMembers("IsUnreferencedCodeSupported").OfType<IPropertySymbol>().FirstOrDefault(); if (isDynamicCodeSupportedProperty == null) return false; return SymbolEqualityComparer.Default.Equals(propertySymbol, isDynamicCodeSupportedProperty); } protected override bool CreateSpecialIncompatibleMembersDiagnostic( ImmutableArray<ISymbol> specialIncompatibleMembers, ISymbol member, in DiagnosticContext diagnosticContext) { // Some RUC-annotated APIs are intrinsically handled by the trimmer if (member is IMethodSymbol method && Intrinsics.GetIntrinsicIdForMethod(new MethodProxy(method)) != IntrinsicId.None) { return true; } return false; } private protected override ImmutableArray<Action<CompilationAnalysisContext>> ExtraCompilationActions => ImmutableArray.Create<Action<CompilationAnalysisContext>>((context) => { CheckReferencedAssemblies( context, MSBuildPropertyOptionNames.VerifyReferenceTrimCompatibility, "IsTrimmable", s_referenceNotMarkedIsTrimmableRule); }); protected override bool VerifyAttributeArguments(AttributeData attribute) => RequiresUnreferencedCodeUtils.VerifyRequiresUnreferencedCodeAttributeArguments(attribute); protected override string GetMessageFromAttribute(AttributeData? requiresAttribute) => RequiresUnreferencedCodeUtils.GetMessageFromAttribute(requiresAttribute); public override void ProcessGenericInstantiation( ITypeSymbol typeArgument, ITypeParameterSymbol typeParameter, FeatureContext featureContext, TypeNameResolver typeNameResolver, ISymbol owningSymbol, Location location, Action<Diagnostic>? reportDiagnostic) { base.ProcessGenericInstantiation(typeArgument, typeParameter, featureContext, typeNameResolver, owningSymbol, location, reportDiagnostic); var parameterRequirements = typeParameter.GetDynamicallyAccessedMemberTypes(); // Avoid duplicate warnings for new() and DAMT.PublicParameterlessConstructor if (typeParameter.HasConstructorConstraint) parameterRequirements &= ~DynamicallyAccessedMemberTypes.PublicParameterlessConstructor; var genericParameterValue = new GenericParameterValue(typeParameter, parameterRequirements); if (!owningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) && !featureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute) && genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol(typeArgument)!; var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeNameResolver, typeHierarchyType: null); var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(this, featureContext, typeNameResolver, location, reportDiagnostic, reflectionAccessAnalyzer, owningSymbol); requireDynamicallyAccessedMembersAction.Invoke(genericArgumentValue, genericParameterValue); } } } }