/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Test/Utilities/CSharp/UsesIsNullableVisitor.cs
216 строк
8 KB
Jared Parsons
generated move
28 сен 2020, 19:36
28 сен 2020, 19:36
1cca63b
Код
Авторство
О чём код?
// 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.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { /// <summary> /// Returns the set of members that contain reference types with IsNullable set. /// </summary> internal sealed class UsesIsNullableVisitor : CSharpSymbolVisitor<bool> { private readonly ArrayBuilder<Symbol> _builder; private UsesIsNullableVisitor(ArrayBuilder<Symbol> builder) { _builder = builder; } internal static void GetUses(ArrayBuilder<Symbol> builder, Symbol symbol) { var visitor = new UsesIsNullableVisitor(builder); visitor.Visit(symbol); } private void Add(Symbol symbol) => _builder.Add(symbol); public override bool VisitNamespace(NamespaceSymbol symbol) { return VisitList(symbol.GetMembers()); } public override bool VisitNamedType(NamedTypeSymbol symbol) { if (AddIfUsesIsNullable(symbol, symbol.BaseTypeNoUseSiteDiagnostics, inProgress: null) || AddIfUsesIsNullable(symbol, symbol.InterfacesNoUseSiteDiagnostics(), inProgress: null) || AddIfUsesIsNullable(symbol, symbol.TypeParameters, inProgress: null)) { return true; } return VisitList(symbol.GetMembers()); } public override bool VisitMethod(MethodSymbol symbol) { return AddIfUsesIsNullable(symbol, symbol.TypeParameters, inProgress: null) || AddIfUsesIsNullable(symbol, symbol.ReturnTypeWithAnnotations, inProgress: null) || AddIfUsesIsNullable(symbol, symbol.Parameters, inProgress: null); } public override bool VisitProperty(PropertySymbol symbol) { return AddIfUsesIsNullable(symbol, symbol.TypeWithAnnotations, inProgress: null) || AddIfUsesIsNullable(symbol, symbol.Parameters, inProgress: null); } public override bool VisitEvent(EventSymbol symbol) { return AddIfUsesIsNullable(symbol, symbol.TypeWithAnnotations, inProgress: null); } public override bool VisitField(FieldSymbol symbol) { return AddIfUsesIsNullable(symbol, symbol.TypeWithAnnotations, inProgress: null); } private bool VisitList<TSymbol>(ImmutableArray<TSymbol> symbols) where TSymbol : Symbol { bool result = false; foreach (var symbol in symbols) { if (this.Visit(symbol)) { result = true; } } return result; } /// <summary> /// Check the parameters of a method or property, but report that method/property rather than /// the parameter itself. /// </summary> private bool AddIfUsesIsNullable(Symbol symbol, ImmutableArray<ParameterSymbol> parameters, ConsList<TypeParameterSymbol> inProgress) { foreach (var parameter in parameters) { if (UsesIsNullable(parameter.TypeWithAnnotations, inProgress)) { Add(symbol); return true; } } return false; } private bool AddIfUsesIsNullable(Symbol symbol, ImmutableArray<TypeParameterSymbol> typeParameters, ConsList<TypeParameterSymbol> inProgress) { foreach (var type in typeParameters) { if (UsesIsNullable(type, inProgress)) { Add(symbol); return true; } } return false; } private bool AddIfUsesIsNullable(Symbol symbol, ImmutableArray<NamedTypeSymbol> types, ConsList<TypeParameterSymbol> inProgress) { foreach (var type in types) { if (UsesIsNullable(type, inProgress)) { Add(symbol); return true; } } return false; } private bool AddIfUsesIsNullable(Symbol symbol, TypeWithAnnotations type, ConsList<TypeParameterSymbol> inProgress) { if (UsesIsNullable(type, inProgress)) { Add(symbol); return true; } return false; } private bool AddIfUsesIsNullable(Symbol symbol, TypeSymbol type, ConsList<TypeParameterSymbol> inProgress) { if (UsesIsNullable(type, inProgress)) { Add(symbol); return true; } return false; } private bool UsesIsNullable(TypeWithAnnotations type, ConsList<TypeParameterSymbol> inProgress) { if (!type.HasType) { return false; } var typeSymbol = type.Type; return (type.NullableAnnotation != NullableAnnotation.Oblivious && typeSymbol.IsReferenceType && !typeSymbol.IsErrorType()) || UsesIsNullable(typeSymbol, inProgress); } private bool UsesIsNullable(TypeSymbol type, ConsList<TypeParameterSymbol> inProgress) { if (type is null) { return false; } switch (type.TypeKind) { case TypeKind.Class: case TypeKind.Delegate: case TypeKind.Interface: case TypeKind.Struct: case TypeKind.Enum: if (UsesIsNullable(type.ContainingType, inProgress)) { return true; } break; } switch (type.TypeKind) { case TypeKind.Array: return UsesIsNullable(((ArrayTypeSymbol)type).ElementTypeWithAnnotations, inProgress); case TypeKind.Class: case TypeKind.Delegate: case TypeKind.Error: case TypeKind.Interface: case TypeKind.Struct: return UsesIsNullable(((NamedTypeSymbol)type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics, inProgress); case TypeKind.Dynamic: case TypeKind.Enum: return false; case TypeKind.Pointer: return UsesIsNullable(((PointerTypeSymbol)type).PointedAtTypeWithAnnotations, inProgress); case TypeKind.TypeParameter: var typeParameter = (TypeParameterSymbol)type; if (inProgress?.ContainsReference(typeParameter) == true) { return false; } inProgress = inProgress ?? ConsList<TypeParameterSymbol>.Empty; inProgress = inProgress.Prepend(typeParameter); return UsesIsNullable(typeParameter.ConstraintTypesNoUseSiteDiagnostics, inProgress) || typeParameter.ReferenceTypeConstraintIsNullable == true; default: throw ExceptionUtilities.UnexpectedValue(type.TypeKind); } } private bool UsesIsNullable(ImmutableArray<TypeWithAnnotations> types, ConsList<TypeParameterSymbol> inProgress) { return types.Any(t => UsesIsNullable(t, inProgress)); } } }