Skip to content

Commit

Permalink
treat IEnumerable<string,object> as dynamic parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
mgravell committed Nov 15, 2023
1 parent 65cb7d5 commit 8fbb01c
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/Dapper.AOT.Analyzers/CodeAnalysis/DapperAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ internal static Location SharedParseArgsAndFlags(in ParseState ctx, IInvocationO
flags |= OperationFlags.DoNotGenerate;
reportDiagnostic?.Invoke(Diagnostic.Create(Diagnostics.GenericTypeParameter, argLocation, paramType!.ToDisplayString()));
}
else if (IsMissingOrObjectOrDynamic(paramType) || IsDynamicParameters(paramType))
else if (IsMissingOrObjectOrDynamic(paramType) || IsDynamicParameters(paramType, out _))
{
flags |= OperationFlags.DoNotGenerate;
reportDiagnostic?.Invoke(Diagnostic.Create(Diagnostics.UntypedParameter, argLocation));
Expand Down
88 changes: 58 additions & 30 deletions src/Dapper.AOT.Analyzers/Internal/Inspection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,42 @@ public static bool IsDapperAttribute(AttributeData attrib)

public static bool IsMissingOrObjectOrDynamic(ITypeSymbol? type) => type is null || type.SpecialType == SpecialType.System_Object || type.TypeKind == TypeKind.Dynamic;

internal static bool IsDynamicParameters(ITypeSymbol? type)
internal static bool IsDynamicParameters(ITypeSymbol? type, out bool needsConstruction)
{
needsConstruction = false;
if (type is null || type.SpecialType != SpecialType.None) return false;
if (IsBasicDapperType(type, Types.DynamicParameters)
|| IsNestedSqlMapperType(type, Types.IDynamicParameters, TypeKind.Interface)) return true;
foreach (var i in type.AllInterfaces)
{
if (IsNestedSqlMapperType(i, Types.IDynamicParameters, TypeKind.Interface)) return true;
}

// Dapper also treats anything IEnumerable<string,object[?]> as dynamic parameters
if (type.ImplementsIEnumerable(out var found) && found is INamedTypeSymbol { Arity: 1 } iet
&& iet.TypeArguments[0] is INamedTypeSymbol
{
Name: "KeyValuePair", Arity: 2, ContainingType: null,
ContainingNamespace:
{
Name: "Generic",
ContainingNamespace:
{
Name: "Collections",
ContainingNamespace:
{
Name: "System",
ContainingNamespace.IsGlobalNamespace: true
}
}
}
} kvp
&& kvp.TypeArguments[0].SpecialType == SpecialType.System_String
&& kvp.TypeArguments[1].SpecialType == SpecialType.System_Object)
{
needsConstruction = true;
return true;
}
return false;
}

Expand Down Expand Up @@ -419,7 +446,7 @@ public readonly struct ElementMember
/// Order of member in constructor parameter list (starts from 0).
/// </summary>
public int? ConstructorParameterOrder { get; }

/// <summary>
/// Order of member in factory method parameter list (starts from 0).
/// </summary>
Expand Down Expand Up @@ -452,10 +479,10 @@ public ElementMember(
{
_dbValue = dbValue;
_flags = flags;

Member = member;
Kind = kind;

ConstructorParameterOrder = constructorParameterOrder;
FactoryMethodParameterOrder = factoryMethodParameterOrder;
}
Expand Down Expand Up @@ -493,7 +520,7 @@ public enum ConstructorResult
FailMultipleExplicit,
FailMultipleImplicit
}

public enum FactoryMethodResult
{
// note that implicit isn't a thing here
Expand All @@ -513,12 +540,12 @@ internal static FactoryMethodResult ChooseFactoryMethod(ITypeSymbol? typeSymbol,
{
return FactoryMethodResult.NoneFound;
}

var staticMethods = typeSymbol
.GetMethods(method =>
.GetMethods(method =>
method.IsStatic &&
SymbolEqualityComparer.Default.Equals(method.ReturnType, typeSymbol) &&
method.DeclaredAccessibility == Accessibility.Public
method.DeclaredAccessibility == Accessibility.Public
)
?.ToArray();
if (staticMethods?.Length == 0)
Expand All @@ -541,7 +568,7 @@ internal static FactoryMethodResult ChooseFactoryMethod(ITypeSymbol? typeSymbol,

return factoryMethod is null ? FactoryMethodResult.NoneFound : FactoryMethodResult.SuccessSingleExplicit;
}

/// <summary>
/// Builds a collection of type constructors, which are NOT:
/// a) parameterless
Expand Down Expand Up @@ -613,7 +640,8 @@ internal static ConstructorResult ChooseConstructor(ITypeSymbol? typeSymbol, out
ContainingNamespace:
{
Name: "Runtime",
ContainingNamespace: {
ContainingNamespace:
{
Name: "System",
ContainingNamespace.IsGlobalNamespace: true
}
Expand All @@ -630,7 +658,7 @@ internal static ConstructorResult ChooseConstructor(ITypeSymbol? typeSymbol, out
// ruled out by signature
continue;
}

if (constructor is not null)
{
return ConstructorResult.FailMultipleImplicit;
Expand Down Expand Up @@ -704,7 +732,7 @@ internal static ImmutableArray<ElementMember> GetMembers(bool forParameters, ITy
int? constructorParameterOrder = constructorParameters?.TryGetValue(member.Name, out var constructorParameter) == true
? constructorParameter.Order
: null;

int? factoryMethodParamOrder = factoryMethodParameters?.TryGetValue(member.Name, out var factoryMethodParam) == true
? factoryMethodParam.Order
: null;
Expand Down Expand Up @@ -1018,12 +1046,12 @@ public static bool TryGetConstantValueWithSyntax<T>(IOperation val, out T? value
case StringSyntaxKind.ConcatenatedString:
case StringSyntaxKind.InterpolatedString:
case StringSyntaxKind.FormatString:
{
value = default!;
syntax = null;
syntaxKind = stringSyntaxKind;
return false;
}
{
value = default!;
syntax = null;
syntaxKind = stringSyntaxKind;
return false;
}
}
}

Expand Down Expand Up @@ -1096,25 +1124,25 @@ internal static bool IsCommand(INamedTypeSymbol type)
while (type.SpecialType != SpecialType.System_Object)
{
if (type is
{
Name: nameof(DbCommand),
ContainingType: null,
Arity: 0,
IsGenericType: false,
ContainingNamespace:
{
Name: "Common",
Name: nameof(DbCommand),
ContainingType: null,
Arity: 0,
IsGenericType: false,
ContainingNamespace:
{
Name: "Data",
Name: "Common",
ContainingNamespace:
{
Name: "System",
ContainingNamespace.IsGlobalNamespace: true,
Name: "Data",
ContainingNamespace:
{
Name: "System",
ContainingNamespace.IsGlobalNamespace: true,
}
}
}
}
})
})
{
return true;
}
Expand Down
12 changes: 6 additions & 6 deletions src/Dapper.AOT.Analyzers/Internal/Roslyn/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,17 @@ public static bool ImplementsIReadOnlyList(this ITypeSymbol? typeSymbol, out ITy
private static bool ImplementsInterface(
this ITypeSymbol? typeSymbol,
SpecialType interfaceType,
out ITypeSymbol? searchedInterface,
out ITypeSymbol? found,
bool searchFromStart = true)
{
if (typeSymbol is null)
{
searchedInterface = null;
found = null;
return false;
}
if (typeSymbol.SpecialType == interfaceType || typeSymbol.OriginalDefinition?.SpecialType == interfaceType)
{
searchedInterface = typeSymbol;
found = typeSymbol;
return true;
}

Expand All @@ -231,7 +231,7 @@ private static bool ImplementsInterface(
if (currentSymbol.SpecialType == interfaceType
|| currentSymbol.OriginalDefinition?.SpecialType == interfaceType)
{
searchedInterface = currentSymbol;
found = currentSymbol;
return true;
}
}
Expand All @@ -245,13 +245,13 @@ private static bool ImplementsInterface(
if (currentSymbol.SpecialType == interfaceType
|| currentSymbol.OriginalDefinition?.SpecialType == interfaceType)
{
searchedInterface = currentSymbol;
found = currentSymbol;
return true;
}
}
}

searchedInterface = null;
found = null;
return false;
}
}
4 changes: 1 addition & 3 deletions test/Dapper.AOT.Test/Interceptors/Techempower.input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using System.Threading.Tasks;
using System.Linq;

[module: DapperAot]
[module:DapperAot]

var connectionString = new SqlConnectionStringBuilder
{
Expand All @@ -32,7 +32,6 @@ public BenchRunner(string connectionString, DbProviderFactory dbProviderFactory)
_connectionString = connectionString;
}

[DapperAot]
public void Create()
{
using var conn = _dbProviderFactory.CreateConnection();
Expand All @@ -50,7 +49,6 @@ static IEnumerable<World> Invent(int count)
}
}

[DapperAot(false)] // dictionary usage isn't going to work today
public async Task<World[]> LoadMultipleUpdatesRows(int count)
{
count = Clamp(count, 1, 500);
Expand Down
8 changes: 4 additions & 4 deletions test/Dapper.AOT.Test/Interceptors/Techempower.output.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ namespace Dapper.AOT // interceptors must be in a known namespace
{
file static class DapperGeneratedInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 41, 20)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 40, 20)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 41, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 42, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 43, 14)]
internal static int Execute0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Execute, Text
Expand All @@ -17,7 +17,7 @@ internal static int Execute0(this global::System.Data.IDbConnection cnn, string

}

[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 44, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 43, 14)]
internal static int Execute1(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Execute, HasParameters, Text, KnownParameters
Expand All @@ -31,7 +31,7 @@ internal static int Execute1(this global::System.Data.IDbConnection cnn, string

}

[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 95, 19)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 93, 19)]
internal static global::System.Threading.Tasks.Task<global::World> QueryFirstOrDefaultAsync2(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Query, Async, TypedResult, HasParameters, SingleRow, Text, BindResultsByName, KnownParameters
Expand Down
8 changes: 4 additions & 4 deletions test/Dapper.AOT.Test/Interceptors/Techempower.output.netfx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ namespace Dapper.AOT // interceptors must be in a known namespace
{
file static class DapperGeneratedInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 41, 20)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 40, 20)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 41, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 42, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 43, 14)]
internal static int Execute0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Execute, Text
Expand All @@ -17,7 +17,7 @@ internal static int Execute0(this global::System.Data.IDbConnection cnn, string

}

[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 44, 14)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 43, 14)]
internal static int Execute1(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Execute, HasParameters, Text, KnownParameters
Expand All @@ -31,7 +31,7 @@ internal static int Execute1(this global::System.Data.IDbConnection cnn, string

}

[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 95, 19)]
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\Techempower.input.cs", 93, 19)]
internal static global::System.Threading.Tasks.Task<global::World> QueryFirstOrDefaultAsync2(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType)
{
// Query, Async, TypedResult, HasParameters, SingleRow, Text, BindResultsByName, KnownParameters
Expand Down

0 comments on commit 8fbb01c

Please sign in to comment.