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) --- .../NetFieldAnalyzer.cs | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs') 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) -- cgit