using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace StardewModdingAPI.ModBuildConfig.Analyzer { /// Provides generic utilities for SMAPI's Roslyn analyzers. internal static class AnalyzerUtilities { /********* ** Public methods *********/ /// Get the metadata for a member access expression. /// The member access expression. /// provides methods for asking semantic questions about syntax nodes. /// The object type which has the member. /// The type of the accessed member. /// The name of the accessed member. /// Returns true if the node is a member access expression, else false. public static bool GetMemberInfo(SyntaxNode node, SemanticModel semanticModel, out ITypeSymbol declaringType, out TypeInfo memberType, out string memberName) { // simple access if (node is MemberAccessExpressionSyntax memberAccess) { declaringType = semanticModel.GetTypeInfo(memberAccess.Expression).Type; memberType = semanticModel.GetTypeInfo(node); memberName = memberAccess.Name.Identifier.Text; return true; } // conditional access if (node is ConditionalAccessExpressionSyntax conditionalAccess && conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax conditionalBinding) { declaringType = semanticModel.GetTypeInfo(conditionalAccess.Expression).Type; memberType = semanticModel.GetTypeInfo(node); memberName = conditionalBinding.Name.Identifier.Text; return true; } // invalid declaringType = null; memberType = default(TypeInfo); memberName = null; return false; } /// Get the class types in a type's inheritance chain, including itself. /// The initial type. public static IEnumerable GetConcreteTypes(ITypeSymbol type) { while (type != null) { yield return type; type = type.BaseType; } } } }