// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.NetCore.Analyzers.Runtime; namespace Microsoft.NetCore.CSharp.Analyzers.Runtime { /// <summary> /// CA2020: Detects Behavioral Changes introduced by new Numeric IntPtr UIntPtr feature /// </summary> [DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed class CSharpPreventNumericIntPtrUIntPtrBehavioralChanges : PreventNumericIntPtrUIntPtrBehavioralChanges { private const string IntPtr = nameof(IntPtr); private const string UIntPtr = nameof(UIntPtr); protected override bool IsWithinCheckedContext(IOperation operation) { var parent = operation.Parent?.Syntax; while (parent != null) { switch (parent) { case CheckedExpressionSyntax expression: return expression.IsKind(SyntaxKind.CheckedExpression); case CheckedStatementSyntax statement: return statement.IsKind(SyntaxKind.CheckedStatement); case MethodDeclarationSyntax: return false; } parent = parent.Parent; } return false; } protected override bool IsAliasUsed(ISymbol? symbol) { if (symbol != null) { foreach (SyntaxReference reference in symbol.DeclaringSyntaxReferences) { SyntaxNode definition = reference.GetSyntax(); while (definition is VariableDeclaratorSyntax) { definition = definition.Parent!; } var type = GetType(definition); if (IdentifierNameIsIntPtrOrUIntPtr(type)) { return false; } } } return true; } private static bool IdentifierNameIsIntPtrOrUIntPtr(ExpressionSyntax? syntax) => syntax is IdentifierNameSyntax identifierName && identifierName.Identifier.Text is IntPtr or UIntPtr; protected override bool IsAliasUsed(SyntaxNode syntax) { if (syntax is CastExpressionSyntax castSyntax) { if (IdentifierNameIsIntPtrOrUIntPtr(castSyntax.Expression) || IdentifierNameIsIntPtrOrUIntPtr(castSyntax.Type)) { return false; } } return true; } private static TypeSyntax? GetType(SyntaxNode syntax) => syntax switch { VariableDeclarationSyntax fieldDeclaration => fieldDeclaration.Type, ParameterSyntax parameter => parameter.Type, CastExpressionSyntax cast => cast.Type, _ => null, }; } } |