From 0bac8b180b0d436e50091b27c72ce15c6bef46cd Mon Sep 17 00:00:00 2001 From: Liviu Uba Date: Sat, 18 Feb 2023 15:49:13 +0200 Subject: [PATCH] feat(roslyn): extensibility - make GetMetadataReferencesForExpression virtual. - publish resolved identifiers for descendant classes --- .../Activities/CsExpressionValidator.cs | 7 +++++-- src/UiPath.Workflow/Activities/ExpressionContainer.cs | 5 +++++ .../Activities/RoslynExpressionValidator.cs | 10 ++++++---- .../Activities/VbExpressionValidator.cs | 8 ++++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/UiPath.Workflow/Activities/CsExpressionValidator.cs b/src/UiPath.Workflow/Activities/CsExpressionValidator.cs index 0e1b27f9..8edab133 100644 --- a/src/UiPath.Workflow/Activities/CsExpressionValidator.cs +++ b/src/UiPath.Workflow/Activities/CsExpressionValidator.cs @@ -100,8 +100,11 @@ protected override void UpdateCompilationUnit(ExpressionContainer expressionCont } } - protected override string CreateValidationCode(string types, string names, string code) => - $"public static Expression> CreateExpression() => ({names}) => {code};"; + protected override string CreateValidationCode(string types, string names, ExpressionContainer expressionContainer) + { + var code = expressionContainer.ExpressionToValidate.Code; + return $"public static Expression> CreateExpression() => ({names}) => {code};"; + } protected override SyntaxTree GetSyntaxTreeForExpression(ExpressionContainer expressionContainer) => CSharpSyntaxTree.ParseText(expressionContainer.ExpressionToValidate.Code, s_csScriptParseOptions); diff --git a/src/UiPath.Workflow/Activities/ExpressionContainer.cs b/src/UiPath.Workflow/Activities/ExpressionContainer.cs index 536d4094..7fb34479 100644 --- a/src/UiPath.Workflow/Activities/ExpressionContainer.cs +++ b/src/UiPath.Workflow/Activities/ExpressionContainer.cs @@ -44,4 +44,9 @@ public class ExpressionContainer /// Diagnostics reported by validating the expression. /// public IEnumerable Diagnostics { get; set; } + + /// + /// populated before CreateValidationCode step + /// + public (string Name, Type Type)[] ResolvedIdentifiers { get; set; } } diff --git a/src/UiPath.Workflow/Activities/RoslynExpressionValidator.cs b/src/UiPath.Workflow/Activities/RoslynExpressionValidator.cs index ca34a3b2..68f7630a 100644 --- a/src/UiPath.Workflow/Activities/RoslynExpressionValidator.cs +++ b/src/UiPath.Workflow/Activities/RoslynExpressionValidator.cs @@ -90,7 +90,7 @@ public void AddRequiredAssembly(Assembly assembly) /// /// expression container /// MetadataReference objects for all required assemblies - protected IEnumerable GetMetadataReferencesForExpression(ExpressionContainer expressionContainer) => + protected virtual IEnumerable GetMetadataReferencesForExpression(ExpressionContainer expressionContainer) => expressionContainer.RequiredAssemblies.Select(asm => TryGetMetadataReference(asm)).Where(mr => mr is not null); /// @@ -107,7 +107,7 @@ protected IEnumerable GetMetadataReferencesForExpression(Expr /// list of parameter names in comma-separated string /// expression code /// expression wrapped in a method or function that returns a LambdaExpression - protected abstract string CreateValidationCode(string types, string names, string code); + protected abstract string CreateValidationCode(string types, string names, ExpressionContainer expressionContainer); /// /// Updates the object for the expression. @@ -180,7 +180,7 @@ public virtual IEnumerable Validate(Activity currentAc var diagnostics = expressionContainer .CompilationUnit .GetDiagnostics() - .Where(d=> d.Severity == DiagnosticSeverity.Error) + .Where(d => d.Severity == DiagnosticSeverity.Error) .Select(diagnostic => new TextExpressionCompilerError { @@ -269,6 +269,8 @@ private void PrepValidation(ExpressionContainer expressionContainer) .Where(var => var.Type != null) .ToArray(); + expressionContainer.ResolvedIdentifiers = resolvedIdentifiers; + var names = string.Join(Comma, resolvedIdentifiers.Select(var => var.Name)); var types = string.Join(Comma, resolvedIdentifiers @@ -276,7 +278,7 @@ private void PrepValidation(ExpressionContainer expressionContainer) .Concat(new[] { expressionContainer.ResultType }) .Select(GetTypeName)); - var lambdaFuncCode = CreateValidationCode(types, names, expressionContainer.ExpressionToValidate.Code); + var lambdaFuncCode = CreateValidationCode(types, names, expressionContainer); var sourceText = SourceText.From(lambdaFuncCode); var newSyntaxTree = syntaxTree.WithChangedText(sourceText); expressionContainer.CompilationUnit = expressionContainer.CompilationUnit.ReplaceSyntaxTree(syntaxTree, newSyntaxTree); diff --git a/src/UiPath.Workflow/Activities/VbExpressionValidator.cs b/src/UiPath.Workflow/Activities/VbExpressionValidator.cs index a6e1b836..0017e887 100644 --- a/src/UiPath.Workflow/Activities/VbExpressionValidator.cs +++ b/src/UiPath.Workflow/Activities/VbExpressionValidator.cs @@ -95,8 +95,12 @@ protected override void UpdateCompilationUnit(ExpressionContainer expressionCont } } - protected override string CreateValidationCode(string types, string names, string code) => - $"Public Shared Function CreateExpression() As Expression(Of Func(Of {types}))\nReturn Function({names}) ({code})\nEnd Function"; + protected override string CreateValidationCode(string types, string names, ExpressionContainer expressionContainer) + { + var code = expressionContainer.ExpressionToValidate.Code; + return + $"Public Shared Function CreateExpression() As Expression(Of Func(Of {types}))\nReturn Function({names}) ({code})\nEnd Function"; + } protected override SyntaxTree GetSyntaxTreeForExpression(ExpressionContainer expressionContainer) => VisualBasicSyntaxTree.ParseText("? " + expressionContainer.ExpressionToValidate.Code, s_vbScriptParseOptions);