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) --- .../AnalyzerUtilities.cs | 12 +++++++++ .../NetFieldAnalyzer.cs | 30 +++++++++++++++++++--- .../ObsoleteFieldAnalyzer.cs | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) (limited to 'src/SMAPI.ModBuildConfig.Analyzer') 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; + } + } } } diff --git a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs index 895eebf0..7c8b804e 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs @@ -1,6 +1,8 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; @@ -17,6 +19,9 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /// The namespace for Stardew Valley's Netcode types. private const string NetcodeNamespace = "Netcode"; + /// The full name for Stardew Valley's Netcode.NetList type. + private readonly string NetListTypeFullName = "Netcode.NetList"; + /// Maps net fields to their equivalent non-net properties where available. private readonly IDictionary NetFieldWrapperProperties = new Dictionary { @@ -190,10 +195,9 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer return; if (!this.IsNetType(memberType.Type)) return; - bool isConverted = !this.IsNetType(memberType.ConvertedType); // warn: use property wrapper if available - for (ITypeSymbol type = declaringType; type != null; type = type.BaseType) + foreach (ITypeSymbol type in AnalyzerUtilities.GetConcreteTypes(declaringType)) { if (this.NetFieldWrapperProperties.TryGetValue($"{type}::{memberName}", out string suggestedPropertyName)) { @@ -203,7 +207,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer } // warn: implicit conversion - if (isConverted) + if (this.IsInvalidConversion(memberType)) context.ReportDiagnostic(Diagnostic.Create(this.Rules["AvoidImplicitNetFieldCast"], context.Node.GetLocation(), context.Node, memberType.Type.Name, memberType.ConvertedType)); } catch (Exception ex) @@ -212,6 +216,26 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer } } + /// Get whether a net field was converted in an error-prone way. + /// The member access type info. + private bool IsInvalidConversion(TypeInfo typeInfo) + { + // no conversion + if (!this.IsNetType(typeInfo.Type) || this.IsNetType(typeInfo.ConvertedType)) + return false; + + // list conversion to an implemented interface is OK + if (AnalyzerUtilities.GetConcreteTypes(typeInfo.Type).Any(p => p.ToString().StartsWith(this.NetListTypeFullName))) // StartsWith to ignore generics + { + string toType = typeInfo.ConvertedType.ToString(); + if (toType.StartsWith(typeof(IEnumerable<>).Namespace) || toType == typeof(IEnumerable).FullName) + return false; + } + + // avoid any other conversions + return true; + } + /// Get whether a type symbol references a Netcode type. /// The type symbol. private bool IsNetType(ITypeSymbol typeSymbol) diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs index dc21e505..943d0350 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs @@ -79,7 +79,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer return; // suggest replacement - for (ITypeSymbol type = declaringType; type != null; type = type.BaseType) + foreach (ITypeSymbol type in AnalyzerUtilities.GetConcreteTypes(declaringType)) { if (this.ReplacedFields.TryGetValue($"{type}::{memberName}", out string replacement)) { -- cgit