Skip to content

Commit

Permalink
Expression delegate is generated with incorrect number of arguments (…
Browse files Browse the repository at this point in the history
…STUD-72165) (#340)
  • Loading branch information
gpanaitescu authored Oct 14, 2024
1 parent f4baf86 commit 41bcbd6
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 22 deletions.
30 changes: 30 additions & 0 deletions src/Test/TestCases.Workflows/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,20 @@ public void VBRoslynValidator_ValidatesMoreThan16Arguments()
result.Errors.ShouldBeEmpty();
}

[Fact]
public void VBRoslynValidator_ValidatesMoreThan16Arguments_WithGenericReturnType()
{
var sequence = new Sequence();
for (int i = 0; i < 16; i++)
{
sequence.Variables.Add(new Variable<string>($"variable{i}"));
}
var testActivity = new VisualBasicValue<Dictionary<string, InArgument<string>>>(@"new System.Collections.Generic.Dictionary(Of System.String, System.Activities.InArgument(Of System.String)) From { { ""0"", variable0 },{ ""1"", variable1 },{ ""2"", variable2 },{ ""3"", variable3 }, { ""4"", variable4 },{ ""5"", variable5 },{ ""6"", variable6 },{ ""7"", variable7 }, { ""8"", variable8 },{ ""9"", variable9 },{ ""10"", variable10 },{ ""11"", variable11 }, { ""12"", variable12 },{ ""13"", variable13 },{ ""14"", variable14 }, { ""15"", variable15 } }");
sequence.Activities.Add(testActivity);
var result = ActivityValidationServices.Validate(sequence, _useValidator);
result.Errors.ShouldBeEmpty();
}

[Fact]
public void CSRoslynValidator_ValidatesMoreThan16Arguments()
{
Expand All @@ -426,6 +440,22 @@ public void CSRoslynValidator_ValidatesMoreThan16Arguments()
var result = ActivityValidationServices.Validate(sequence, _useValidator);
result.Errors.ShouldBeEmpty();
}

[Fact]
public void CSRoslynValidator_ValidatesMoreThan16Arguments_WithGenericReturnType()
{
var sequence = new Sequence();
for (int i = 0; i < 20; i++)
{
sequence.Variables.Add(new Variable<string>($"variable{i}"));
}
var testActivity = new CSharpValue<Dictionary<string, InArgument<string>>>((@"new System.Collections.Generic.Dictionary<System.String, System.Activities.InArgument<System.String>>() { { ""0"", variable0 },{ ""1"", variable1 },{ ""2"", variable2 },{ ""3"", variable3 }, { ""4"", variable4 },{ ""5"", variable5 },{ ""6"", variable6 },{ ""7"", variable7 }, { ""8"", variable8 },{ ""9"", variable9 },{ ""10"", variable10 },{ ""11"", variable11 }, { ""12"", variable12 },{ ""13"", variable13 },{ ""14"", variable14 }, { ""15"", variable15 } }"));

sequence.Activities.Add(testActivity);
var result = ActivityValidationServices.Validate(sequence, _useValidator);
result.Errors.ShouldBeEmpty();
}

[Fact]
public void VB_Multithreaded_NoError()
{
Expand Down
7 changes: 3 additions & 4 deletions src/UiPath.Workflow/Activities/Utils/CSharpCompilerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,13 @@ public override string CreateExpressionCode(string types, string names, string c
return $"{myDelegate} \n public static Expression<{name}<{types}>> CreateExpression() => ({names}) => {code};";
}

public override (string, string) DefineDelegate(string types)
protected override (string, string) DefineDelegateCommon(int argumentsCount)
{
var crtValue = Interlocked.Add(ref crt, 1);
var arrayType = types.Split(",");

var part1 = new StringBuilder();
var part2 = new StringBuilder();

for (var i = 0; i < arrayType.Length - 1; i++)
for (var i = 0; i < argumentsCount; i++)
{
part1.Append($"in T{i}, ");
part2.Append($" T{i} arg{i},");
Expand Down
10 changes: 9 additions & 1 deletion src/UiPath.Workflow/Activities/Utils/CompilerHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.Linq;

namespace System.Activities
{
Expand All @@ -21,7 +22,14 @@ public abstract class CompilerHelper

public abstract int IdentifierKind { get; }

public abstract (string, string) DefineDelegate(string types);
[Obsolete("DefineDelegate(string types) is deprecated, please use DefineDelegate(IEnumerable<string> types) instead.")]
public (string, string) DefineDelegate(string types)
=> DefineDelegateCommon(types.Split(",").Length - 1);

public (string, string) DefineDelegate(IEnumerable<string> types)
=> DefineDelegateCommon(types.Count() - 1);

protected abstract (string, string) DefineDelegateCommon(int argumentsCount);

public abstract Compilation DefaultCompilationUnit { get; }

Expand Down
6 changes: 2 additions & 4 deletions src/UiPath.Workflow/Activities/Utils/VBCompilerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,13 @@ public override string CreateExpressionCode(string types, string names, string c
return $"{myDelegate} \n Public Shared Function CreateExpression() As Expression(Of {name}(Of {types}))\nReturn Function({names}) ({code})\nEnd Function";
}

public override (string, string) DefineDelegate(string types)
protected override (string, string) DefineDelegateCommon(int argumentsCount)
{
var crtValue = Interlocked.Add(ref crt, 1);

var arrayType = types.Split(",");
var part1 = new StringBuilder();
var part2 = new StringBuilder();

for (var i = 0; i < arrayType.Length - 1; i++)
for (var i = 0; i < argumentsCount; i++)
{
part1.Append($" In T{i},");
part2.Append($" ByVal arg as T{i},");
Expand Down
11 changes: 6 additions & 5 deletions src/UiPath.Workflow/Validation/CSharpExpressionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CSharp.Activities;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static System.Activities.CompilerHelper;

Expand Down Expand Up @@ -53,14 +54,14 @@ protected override Compilation GetCompilation(IReadOnlyCollection<Assembly> asse
return CompilerHelper.DefaultCompilationUnit.WithOptions(options.WithUsings(namespaces)).WithReferences(metadataReferences);
}

protected override string CreateValueCode(string types, string names, string code, string activityId, int index)
protected override string CreateValueCode(IEnumerable<string> types, string names, string code, string activityId, int index)
{
var arrayType = types.Split(",");
if (arrayType.Length <= 16) // .net defines Func<TResult>...Funct<T1,...T16,TResult)
return string.Format(_valueValidationTemplate, types, index, names, code, activityId, _expressionEnder);
var serializedArgumentTypes = string.Join(Comma, types);
if (types.Count() <= 16) // .net defines Func<TResult>...Funct<T1,...T16,TResult)
return string.Format(_valueValidationTemplate, serializedArgumentTypes, index, names, code, activityId, _expressionEnder);

var (myDelegate, name) = CompilerHelper.DefineDelegate(types);
return string.Format(_delegateValueValidationTemplate, myDelegate, name, types, index, names, code, activityId, _expressionEnder);
return string.Format(_delegateValueValidationTemplate, myDelegate, name, serializedArgumentTypes, index, names, code, activityId, _expressionEnder);
}

protected override string CreateReferenceCode(string types, string names, string code, string activityId, string returnType, int index)
Expand Down
7 changes: 5 additions & 2 deletions src/UiPath.Workflow/Validation/RoslynExpressionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,15 @@ protected IEnumerable<MetadataReference> GetMetadataReferencesForExpression(IRea
/// <returns>expression wrapped in a method or function that returns a LambdaExpression</returns>
protected string CreateValidationCode(IEnumerable<string> types, string returnType, string names, string code, bool isLocation, string activityId, int index)
{
var typesWithReturnType = types.ToList();
typesWithReturnType.Add(returnType);

return isLocation
? CreateReferenceCode(string.Join(CompilerHelper.Comma, types), names, code, activityId, returnType, index)
: CreateValueCode(string.Join(CompilerHelper.Comma, types.Concat(new[] { returnType })), names, code, activityId, index);
: CreateValueCode(typesWithReturnType, names, code, activityId, index);
}

protected abstract string CreateValueCode(string types, string names, string code, string activityId, int index);
protected abstract string CreateValueCode(IEnumerable<string> types, string names, string code, string activityId, int index);

protected abstract string CreateReferenceCode(string types, string names, string code, string activityId, string returnType, int index);

Expand Down
12 changes: 6 additions & 6 deletions src/UiPath.Workflow/Validation/VBExpressionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.VisualBasic.Activities;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static System.Activities.CompilerHelper;

Expand Down Expand Up @@ -61,15 +62,14 @@ protected override SyntaxTree GetSyntaxTreeForValidation(string expressionText)

protected override string GetTypeName(Type type) => CompilerHelper.GetTypeName(type);


protected override string CreateValueCode(string types, string names, string code, string activityId, int index)
protected override string CreateValueCode(IEnumerable<string> types, string names, string code, string activityId, int index)
{
var arrayType = types.Split(",");
if (arrayType.Length <= 16) // .net defines Func<TResult>...Funct<T1,...T16,TResult)
return string.Format(_valueValidationTemplate, index, types, names, code, activityId, _expressionEnder);
var serializedArgumentTypes = string.Join(Comma, types);
if (types.Count() <= 16) // .net defines Func<TResult>...Funct<T1,...T16,TResult)
return string.Format(_valueValidationTemplate, index, serializedArgumentTypes, names, code, activityId, _expressionEnder);

var (myDelegate, name) = CompilerHelper.DefineDelegate(types);
return string.Format(_delegateValueValidationTemplate, myDelegate, index, name, types, names, code, activityId, _expressionEnder);
return string.Format(_delegateValueValidationTemplate, myDelegate, index, name, serializedArgumentTypes, names, code, activityId, _expressionEnder);
}

protected override string CreateReferenceCode(string types, string names, string code, string activityId, string returnType, int index)
Expand Down

0 comments on commit 41bcbd6

Please sign in to comment.