Skip to content

Commit

Permalink
Merge pull request #1748 from riganti/errormsg-viewmodel-wrong-assembly
Browse files Browse the repository at this point in the history
Better error message for wrong assembly name in directives
  • Loading branch information
exyi committed Feb 8, 2024
2 parents b4aab99 + a2ccff0 commit 53c3da6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
Expand Up @@ -6,6 +6,9 @@
using DotVVM.Framework.Compilation.Binding;
using System.Collections.Immutable;
using DotVVM.Framework.Configuration;
using System.Security.Cryptography;
using System.Diagnostics;
using FastExpressionCompiler;
using DotVVM.Framework.Utils;

namespace DotVVM.Framework.Compilation.ControlTree.Resolved
Expand All @@ -27,7 +30,8 @@ public DirectiveCompilationService(CompiledAssemblyCache compiledAssemblyCache,
{
if (CompileDirectiveExpression(directive, nameSyntax, imports) is not StaticClassIdentifierExpression expression)
{
directive.AddError($"Could not resolve type '{nameSyntax.ToDisplayString()}'.");
var help = GetMissingTypeHelp(nameSyntax, imports);
directive.AddError($"Could not resolve type '{nameSyntax.ToDisplayString()}'.{(help is null ? "" : " " + help)}");
return null;
}
else return new ResolvedTypeDescriptor(expression.Type);
Expand Down Expand Up @@ -86,7 +90,38 @@ public DirectiveCompilationService(CompiledAssemblyCache compiledAssemblyCache,
}
}

private Expression? CompileDirectiveExpression(DothtmlDirectiveNode directive, BindingParserNode expressionSyntax, ImmutableList<NamespaceImport> imports)
private object? CreateDefaultValue(Type? type)
{
if (type != null && type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}

private string? GetMissingTypeHelp(BindingParserNode syntax, ImmutableList<NamespaceImport> imports)
{
try
{
// wrong assembly name:
if (syntax is AssemblyQualifiedNameBindingParserNode assemblyQualifiedName)
{
var noAssemblyResolve = CompileDirectiveExpression(null, assemblyQualifiedName.TypeName, imports);
if (noAssemblyResolve is StaticClassIdentifierExpression expression)
{
return $"Did you mean the '{expression.Type.Assembly.GetName().Name}' assembly? Note that assembly name is optional.";
}
}
return null;
}
catch
{
Debug.Fail("This should not happen");
return null; // just fancy error handling, ignore errors
}
}

private Expression? CompileDirectiveExpression(DothtmlDirectiveNode? directive, BindingParserNode expressionSyntax, ImmutableList<NamespaceImport> imports)
{
TypeRegistry registry;
if (expressionSyntax is TypeOrFunctionReferenceBindingParserNode typeOrFunction)
Expand Down Expand Up @@ -114,7 +149,7 @@ public DirectiveCompilationService(CompiledAssemblyCache compiledAssemblyCache,
}
catch (Exception ex)
{
directive.AddError($"{expressionSyntax.ToDisplayString()} is not a valid type or namespace: {ex.Message}");
directive?.AddError($"{expressionSyntax.ToDisplayString()} is not a valid type or namespace: {ex.Message}");
return null;
}
}
Expand Down
Expand Up @@ -112,5 +112,16 @@ public void ResolvedTree_ViewModel_DirectiveIdentifier_CaseInsensitivity(string
Assert.IsFalse(root.Directives.Any(d => d.Value.Any(dd => dd.DothtmlNode.HasNodeErrors)));
Assert.AreEqual(typeof(string), root.DataContextTypeStack.DataContextType);
}

[TestMethod]
public void ResolvedTree_ViewModel_AssemblyNotFound_Error()
{
var root = ParseSource($"@viewModel DotVVM.Framework.Controls.IGridViewDataSet, DotVVM.Framework");

var directive = root.Directives["viewModel"].Single().DothtmlNode;
Assert.IsTrue(directive.HasNodeErrors);
StringAssert.Contains(directive.NodeErrors.Single(), "'DotVVM.Core'");
}

}
}

0 comments on commit 53c3da6

Please sign in to comment.