/// <summary> /// If the given property is a reference type and is not initialized, it should *either* be marked as nullable or /// be initialized to a non-null value. This method will do it's best to initialize the property using a default constructor /// or empty string, and failing that will mark the type as nullable. /// </summary> /// <param name="property">The <see cref="PropertyDeclarationSyntax"/> to update. Must be on a <see cref="SyntaxTree"/>.</param> /// <param name="semanticModel"><see cref="SemanticModel"/> used to perform type analysis.</param> /// <returns>The mutated property declaration, or the original if no mutation was required.</returns> public static PropertyDeclarationSyntax MakeNullableOrInitializeIfReferenceType(this PropertyDeclarationSyntax property, SemanticModel semanticModel) { if (property == null) { throw new ArgumentNullException(nameof(property)); } if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } if (property.Initializer != null || property.ExpressionBody != null) { // No need if already initialized or expression body only return(property); } if (property.Type is NullableTypeSyntax) { // Already nullable return(property); } var typeInfo = semanticModel.GetTypeInfo(property.Type); if (typeInfo.Type?.IsReferenceType ?? false) { if (typeInfo.Type.SpecialType == SpecialType.System_String) { // Initialize to an empty string property = property .WithInitializer(EqualsValueClause(SyntaxHelpers.StringLiteral(""))); } else if (!typeInfo.Type.IsAbstract && typeInfo.Type.GetMembers() .Where(p => p.Kind == SymbolKind.Method && p.Name == ".ctor") .Cast <IMethodSymbol>() .Any(p => p.Parameters.Length == 0 && p.DeclaredAccessibility == Accessibility.Public)) { // Build a default object using the default constructor property = property .WithInitializer(EqualsValueClause(ObjectCreationExpression(property.Type))); } else { // Mark the types as nullable, even if the parameter is required // This will encourage SDK consumers to check for nulls and prevent NREs property = property.MakeNullable(); } } return(property); }
public static StatementSyntax ThrowIfArgumentNull(string parameterName) => IfNull( IdentifierName(parameterName), Block(ThrowStatement( ObjectCreationExpression(WellKnownTypes.System.ArgumentNullException.Name) .AddArgumentListArguments(Argument(SyntaxHelpers.StringLiteral(parameterName))))));
public static ExpressionSyntax ArgumentOrThrowIfNull(string parameterName) => BinaryExpression(SyntaxKind.CoalesceExpression, IdentifierName(parameterName), ThrowExpression( ObjectCreationExpression(WellKnownTypes.System.ArgumentNullException.Name) .AddArgumentListArguments(Argument(SyntaxHelpers.StringLiteral(parameterName)))));