From c2cb76b79919261c4d7eab107c5cb77ec6c6a81c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 14 Apr 2018 17:53:58 -0400 Subject: rewrite analyzers to match more cases, use readable warning IDs (#471) --- .../AnalyzerUtilities.cs | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs (limited to 'src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs') diff --git a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs new file mode 100644 index 00000000..77e7812f --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs @@ -0,0 +1,46 @@ +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; + } + } +} -- cgit From 6d8cf614a24ab69baffa89c351b9a22776741442 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 14 Apr 2018 19:51:50 -0400 Subject: don't warn for NetList conversion to implemented interface (#471) --- src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs') diff --git a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs index 77e7812f..e0c0cd63 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -42,5 +43,16 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer 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; + } + } } } -- cgit From 6be4d5abe03932a7f6a638816c2206388dc18983 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 28 Apr 2018 16:07:41 -0400 Subject: detect conversions due to explicit casts or 'x as y' expressions (#471) --- .../AnalyzerUtilities.cs | 37 +++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs') diff --git a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs index e0c0cd63..68b5001e 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/AnalyzerUtilities.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace StardewModdingAPI.ModBuildConfig.Analyzer @@ -10,6 +11,40 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /********* ** Public methods *********/ + /// Get the metadata for an explicit cast or 'x as y' expression. + /// The member access expression. + /// provides methods for asking semantic questions about syntax nodes. + /// The expression whose value is being converted. + /// The type being converted from. + /// The type being converted to. + /// Returns true if the node is a matched expression, else false. + 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; + } + /// Get the metadata for a member access expression. /// The member access expression. /// provides methods for asking semantic questions about syntax nodes. @@ -17,7 +52,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /// 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) + public static bool TryGetMemberInfo(SyntaxNode node, SemanticModel semanticModel, out ITypeSymbol declaringType, out TypeInfo memberType, out string memberName) { // simple access if (node is MemberAccessExpressionSyntax memberAccess) -- cgit