summaryrefslogtreecommitdiff
path: root/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs')
-rw-r--r--src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs
new file mode 100644
index 00000000..68b5001e
--- /dev/null
+++ b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs
@@ -0,0 +1,93 @@
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace StardewModdingAPI.ModBuildConfig.Analyzer
+{
+ /// <summary>Provides generic utilities for SMAPI's Roslyn analyzers.</summary>
+ internal static class AnalyzerUtilities
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Get the metadata for an explicit cast or 'x as y' expression.</summary>
+ /// <param name="node">The member access expression.</param>
+ /// <param name="semanticModel">provides methods for asking semantic questions about syntax nodes.</param>
+ /// <param name="fromExpression">The expression whose value is being converted.</param>
+ /// <param name="fromType">The type being converted from.</param>
+ /// <param name="toType">The type being converted to.</param>
+ /// <returns>Returns true if the node is a matched expression, else false.</returns>
+ public static bool TryGetCastOrAsInfo(SyntaxNode node, SemanticModel semanticModel, out ExpressionSyntax fromExpression, out TypeInfo fromType, out TypeInfo toType)
+ {
+ // (type)x
+ if (node is CastExpressionSyntax cast)
+ {
+ fromExpression = cast.Expression;
+ fromType = semanticModel.GetTypeInfo(fromExpression);
+ toType = semanticModel.GetTypeInfo(cast.Type);
+ return true;
+ }
+
+ // x as y
+ if (node is BinaryExpressionSyntax binary && binary.Kind() == SyntaxKind.AsExpression)
+ {
+ fromExpression = binary.Left;
+ fromType = semanticModel.GetTypeInfo(fromExpression);
+ toType = semanticModel.GetTypeInfo(binary.Right);
+ return true;
+ }
+
+ // invalid
+ fromExpression = null;
+ fromType = default(TypeInfo);
+ toType = default(TypeInfo);
+ return false;
+ }
+
+ /// <summary>Get the metadata for a member access expression.</summary>
+ /// <param name="node">The member access expression.</param>
+ /// <param name="semanticModel">provides methods for asking semantic questions about syntax nodes.</param>
+ /// <param name="declaringType">The object type which has the member.</param>
+ /// <param name="memberType">The type of the accessed member.</param>
+ /// <param name="memberName">The name of the accessed member.</param>
+ /// <returns>Returns true if the node is a member access expression, else false.</returns>
+ public static bool TryGetMemberInfo(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;
+ }
+
+ /// <summary>Get the class types in a type's inheritance chain, including itself.</summary>
+ /// <param name="type">The initial type.</param>
+ public static IEnumerable<ITypeSymbol> GetConcreteTypes(ITypeSymbol type)
+ {
+ while (type != null)
+ {
+ yield return type;
+ type = type.BaseType;
+ }
+ }
+ }
+}