private static bool TryChangeType(ITypeSymbol targetType, object argumentValue) { var targetReflectionType = Type.GetType( AttributeArgumentSyntaxExtensions.GetFullName(targetType), false); if (targetReflectionType != null) { try { Convert.ChangeType(argumentValue, targetReflectionType, CultureInfo.InvariantCulture); return(true); } catch (InvalidCastException) { return(false); } catch (FormatException) { return(false); } catch (OverflowException) { return(false); } } else { return(false); } }
private static Type GetTargetReflectionType(ITypeSymbol targetType) { string assembly = ", " + targetType.ContainingAssembly.Identity.ToString(); string typeName = AttributeArgumentSyntaxExtensions.GetQualifiedTypeName(targetType); // First try to get type using assembly-qualified name, and if that fails try to get type // using only the type name qualified by its namespace. // This is a hacky attempt to make it work for types that are forwarded in .NET Core, e.g. // Double which exists in the System.Runtime assembly at design time and in // System.Private.CorLib at runtime, so targetType.ContainingAssembly will denote the wrong // assembly, System.Runtime. See e.g. the following comment // https://github.com/dotnet/roslyn/issues/16211#issuecomment-373084209 var targetReflectionType = Type.GetType(typeName + assembly, false) ?? Type.GetType(typeName, false); return(targetReflectionType); }
internal static bool CanAssignTo(this AttributeArgumentSyntax @this, ITypeSymbol target, SemanticModel model) { //See https://github.com/nunit/nunit/blob/f16d12d6fa9e5c879601ad57b4b24ec805c66054/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs#L396 //for the reasoning behind this implementation. Optional <object> possibleConstantValue = model.GetConstantValue(@this.Expression); object argumentValue = null; if (possibleConstantValue.HasValue) { argumentValue = possibleConstantValue.Value; } TypeInfo sourceTypeInfo = model.GetTypeInfo(@this.Expression); ITypeSymbol argumentType = sourceTypeInfo.Type; if (argumentType == null) { return(target.IsReferenceType || target.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T); } else { var targetType = GetTargetType(target); if (targetType.IsAssignableFrom(argumentType)) { return(true); } else { var canConvert = false; if (targetType.SpecialType == SpecialType.System_Int16 || targetType.SpecialType == SpecialType.System_Byte || targetType.SpecialType == SpecialType.System_Int64 || targetType.SpecialType == SpecialType.System_SByte || targetType.SpecialType == SpecialType.System_Double) { canConvert = argumentType.SpecialType == SpecialType.System_Int32; } else if (targetType.SpecialType == SpecialType.System_Decimal) { canConvert = argumentType.SpecialType == SpecialType.System_Double || argumentType.SpecialType == SpecialType.System_String || argumentType.SpecialType == SpecialType.System_Int32; } else if (targetType.SpecialType == SpecialType.System_DateTime) { canConvert = argumentType.SpecialType == SpecialType.System_String; } if (canConvert) { return(AttributeArgumentSyntaxExtensions.TryChangeType(targetType, argumentValue)); } else if (argumentType.SpecialType == SpecialType.System_String && model.Compilation.GetTypeByMetadataName(typeof(TimeSpan).FullName).IsAssignableFrom(targetType)) { canConvert = TimeSpan.TryParse(argumentValue as string, out _); } return(canConvert); } } }
internal static bool CanAssignTo(this AttributeArgumentSyntax @this, ITypeSymbol target, SemanticModel model) { //See https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs#L363 //for the reasoning behind this implementation. object argumentValue = null; if (@this.Expression is LiteralExpressionSyntax) { argumentValue = (@this.Expression as LiteralExpressionSyntax).Token.Value; } TypeInfo sourceTypeInfo = model.GetTypeInfo(@this.Expression); ITypeSymbol argumentType = sourceTypeInfo.Type; if (sourceTypeInfo.Type == null) { return(target.IsReferenceType || target.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T); } else { var targetType = GetTargetType(target); if (targetType.IsAssignableFrom(argumentType)) { return(true); } else { var canConvert = false; if (targetType.SpecialType == SpecialType.System_Int16 || targetType.SpecialType == SpecialType.System_Byte || targetType.SpecialType == SpecialType.System_SByte || targetType.SpecialType == SpecialType.System_Double) { canConvert = argumentType.SpecialType == SpecialType.System_Int32; } else if (targetType.SpecialType == SpecialType.System_Decimal) { canConvert = argumentType.SpecialType == SpecialType.System_Double || argumentType.SpecialType == SpecialType.System_String || argumentType.SpecialType == SpecialType.System_Int32; } else if (targetType.SpecialType == SpecialType.System_DateTime) { canConvert = argumentType.SpecialType == SpecialType.System_String; } if (canConvert) { return(AttributeArgumentSyntaxExtensions.TryChangeType(targetType, argumentValue)); } else if (argumentType.SpecialType == SpecialType.System_String && model.Compilation.GetTypeByMetadataName(typeof(TimeSpan).FullName).IsAssignableFrom(targetType)) { var outValue = default(TimeSpan); canConvert = TimeSpan.TryParse(argumentValue as string, out outValue); } return(canConvert); } } }