internal static Reset?InferDefaultReset( AttributedMembers attrMembers, DeserializerTypes types, ITypeSymbol declaringType, string propertyName, ImmutableArray <AttributeSyntax> attrs, Location?location, ref ImmutableArray <Diagnostic> diags ) { var ignoredDiags = ImmutableArray <Diagnostic> .Empty; var resetType = Utils.GetTypeConstantWithName(attrMembers, attrs, "ResetType", ref ignoredDiags); var resetMethod = Utils.GetConstantsWithName <string>(attrMembers, attrs, "ResetMethodName", ref ignoredDiags); // if anything _tried_ to set a non-default, don't include any defaults if (!resetType.IsEmpty || !resetMethod.IsEmpty) { return(null); } foreach (var candidate in declaringType.GetMembers("Reset" + propertyName)) { var mtd = candidate as IMethodSymbol; if (mtd == null) { continue; } if (mtd.ReturnType.SpecialType != SpecialType.System_Void) { continue; } bool isStatic, takesContext; var ps = mtd.Parameters; if (mtd.IsStatic) { isStatic = true; if (ps.Length == 0) { takesContext = false; } else if (ps.Length == 1) { takesContext = ps[0].IsInReadContext(types.OurTypes); if (!takesContext && !ps[0].Equals(declaringType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, mtd, ps[0].Type); diags = diags.Add(diag); return(null); } } else { continue; } } else { isStatic = false; takesContext = false; if (ps.Length != 0) { continue; } } return(new Reset(mtd, isStatic, false, false, takesContext)); } return(null); }
private static Reset?GetReset( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol rowType, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var reset = Utils.GetMethodFromAttribute( attrMembers, "ResetType", Diagnostics.ResetTypeSpecifiedMultipleTimes, "ResetMethodName", Diagnostics.ResetMethodNameSpecifiedMultipleTimes, Diagnostics.ResetBothMustBeSet, location, attrs, ref diags ); if (reset == null) { return(null); } var(type, name) = reset.Value; var resetMtd = Utils.GetMethod(type, name, location, ref diags); if (resetMtd == null) { return(null); } var methodReturnType = resetMtd.ReturnType; if (methodReturnType.SpecialType != SpecialType.System_Void) { var diag = Diagnostics.MethodMustReturnVoid(location, resetMtd); diags = diags.Add(diag); return(null); } if (resetMtd.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, resetMtd); diags = diags.Add(diag); return(null); } var accessible = resetMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(location, resetMtd); diags = diags.Add(diag); return(null); } var ps = resetMtd.Parameters; bool isStatic; bool takesRow; bool takesRowByRef; bool takesContext; if (resetMtd.IsStatic) { isStatic = true; // Options: // - zero parameters or // - a single parameter of the row type or // - a single parameter of `in ReadContext` or // - two parameters, the first of the row type (which may be by ref) and the second of `in ReadContext` if (ps.Length == 0) { // zero parameters takesRow = false; takesRowByRef = false; takesContext = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (p0.RefKind == RefKind.In) { // a single parameter of `in ReadContext` if (!p0.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = false; takesRowByRef = false; takesContext = true; } else if (p0.RefKind == RefKind.None) { // a single parameter of the row type if (!p0.IsNormalParameterOfType(compilation, rowType)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = false; takesContext = false; } else { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } } else if (ps.Length == 2) { // two parameters, the first of the row type (which may be by ref) and the second of `in ReadContext` var p0 = ps[0]; if (!p0.RefKind.IsNormalOrByRef()) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } if (!p0.Type.Equals(rowType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (!p1.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = p0.RefKind == RefKind.Ref; takesContext = true; } else { var diag = Diagnostics.BadResetParameters_TooMany(location, resetMtd); diags = diags.Add(diag); return(null); } } else { isStatic = false; // be on the row type... var declaredOn = Utils.NonNull(resetMtd.ContainingType); var conversion = compilation.ClassifyConversion(rowType, declaredOn); var canConvert = conversion.IsImplicit || conversion.IsIdentity; if (!canConvert) { var diag = Diagnostics.BadReset_NotOnRow(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } // Options: // - zero parameters or // - a single `in ReadContext` parameter. if (ps.Length == 0) { takesRow = true; takesRowByRef = false; takesContext = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (!p0.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_InstanceOne(location, resetMtd); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = false; takesContext = true; } else { var diag = Diagnostics.BadResetParameters_TooMany(location, resetMtd); diags = diags.Add(diag); return(null); } } return(new Reset(resetMtd, isStatic, takesRow, takesRowByRef, takesContext)); }