Skip to content

Commit

Permalink
Helpers that accept StringBuilders now are supplied one.
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinHaedicke committed Apr 30, 2021
1 parent a05cebb commit fdb84e5
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 55 deletions.
11 changes: 3 additions & 8 deletions Compiler/CodeGeneration/SyntaxHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,21 +276,16 @@ internal static ExpressionStatementSyntax AppendFuntionCallResult(string functio
}
else
{
//ExpressionStatementSyntax
ExpressionSyntax expr = SF.InvocationExpression(SF.ParseExpression(functionName))
.AddArgumentListArguments(
parameters.Select(x => SF.Argument(SF.ParseExpression(x))).ToArray()
);
if (doAwait)
{
expr = SF.ParenthesizedExpression(SF.AwaitExpression(expr));
expr = SF.AwaitExpression(expr);
}
expr = ExpressionToString(expr);

return
SbAppend(
SF.Argument(expr),
encoded: encoded
);
return SF.ExpressionStatement(expr);
}
}

Expand Down
79 changes: 64 additions & 15 deletions Compiler/Introspection/RoslynIntrospector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ public RoslynIntrospector(Project project)
foreach (var addedProject in changes.GetAddedProjects())
projectCompilations.Add(addedProject.Id, GetCompilationForProject(addedProject));
foreach (var projectChanges in changes.GetProjectChanges())
{
//Bruteforce way: Just get the new compilation...
//If that does not scale try adding documents to the compilation (incremental update)
projectCompilations[projectChanges.ProjectId] = GetCompilationForProject(projectChanges.NewProject);
//projectCompilations[projectChanges.ProjectId] = GetCompilationForProject(projectChanges.NewProject);
}
solution = project.Solution;
}
else
Expand Down Expand Up @@ -132,12 +134,54 @@ private INamedTypeSymbol FindClassesWithNameAndAttribute(string fullName, string
(y.AttributeClass != null && y.AttributeClass.Name.Equals(attribute)))))
.OrderByDescending(x => x.ContainingNamespace.ToDisplayString())
.FirstOrDefault();
//var y = comp.GetSymbolsWithName(x => x.Equals(name, System.StringComparison.Ordinal))
// .OfType<INamedTypeSymbol>()
// .Where(x => NamespaceUtility.IsPartOf(x.ToDisplayString(), fullName)
// && (x.GetAttributes().Any(y =>
// (y.AttributeClass != null && y.AttributeClass.Name.Equals(attributeFull)) ||
// (y.AttributeClass != null && y.AttributeClass.Name.Equals(attribute)))))
// .OrderByDescending(x => x.ContainingNamespace.ToDisplayString())
// .ToList();

//if (name == "_DyloAttributes")
//{
// var z1 = comp.GetSymbolsWithName(x => x.Equals(name, System.StringComparison.Ordinal)).OfType<INamedTypeSymbol>().ToList();
// var z2 = comp.GetSymbolsWithName(x => x.Equals(name, System.StringComparison.Ordinal)).ToList();
// var z3 = comp.GetSymbolsWithName(x => x.IndexOf("_DyloAttributes", StringComparison.OrdinalIgnoreCase) != -1).ToList();
// var z4 = comp.GetSymbolsWithName(n => true).ToList();
// //StiftungWarentest.Website.ViewsRelaunch.Shared._DyloAttributes
// var z5 = z4.Where(n => n.ContainingNamespace.ToString().StartsWith("StiftungWarentest.Website.ViewsRelaunch", StringComparison.OrdinalIgnoreCase)).ToList();
// Console.WriteLine(z1.Count);
//}

if (template != null)
return template;
}
return null;
}

private IMethodSymbol findHelperMethod(string funtionName, List<ITypeSymbol> parameters)
{
foreach (var comp in projectCompilations.Values)
{
var candidates = comp.GetSymbolsWithName(x => x.Equals(funtionName))
.OfType<IMethodSymbol>()
.Where(x => x.IsStatic &&
// The check for both HelperMethodAttribute and HelperMethodAttributeFull because when loading a asp.net core project
// we the attribute name is HelpermethodAttribute while when loading a .net framework project the attribute name is
// HelperMethodAttribute
x.GetAttributes().Any(y => y.AttributeClass.Name.Equals(StringConstants.HELPERMETHODATTRIBUTEFULL)
|| y.AttributeClass.Name.Equals(StringConstants.HELPERMETHODATTRIBUTE)));
var helperMethod = candidates.FirstOrDefault(x => DoParametersMatch(x, parameters));
if (helperMethod != null)
{
return helperMethod;
}
}
return null;
}


/// <summary>
/// Searches each referenced project for helper methods.
/// These must serve following conditions:
Expand All @@ -149,23 +193,23 @@ private INamedTypeSymbol FindClassesWithNameAndAttribute(string fullName, string
/// <param name="funtionName">Name of the Helper as declared in the handlebars-template</param>
/// <param name="parameters">Types of the Parameters that are passed to the helper method</param>
/// <returns>The MethodSymbol for the called HelperMethod or null if it could not be found</returns>
public IMethodSymbol GetHelperMethod(string funtionName, List<ITypeSymbol> parameters)
public IMethodSymbol GetHelperMethod(string funtionName, List<ITypeSymbol> parameters, out bool acceptsStringBuilder)
{
foreach (var comp in projectCompilations.Values)
//acceptsStringBuilder = false;
//return findHelperMethod(funtionName, parameters);

var sbSymbol = GetStringBuilderTypeSymbol();
parameters.Add(sbSymbol);

IMethodSymbol helperMethod = findHelperMethod(funtionName, parameters);
acceptsStringBuilder = true;
if (helperMethod == null)
{
var candidates = comp.GetSymbolsWithName(x => x.Equals(funtionName))
.OfType<IMethodSymbol>()
.Where(x => x.IsStatic &&
// The check for both HelperMethodAttribute and HelperMethodAttributeFull because when loading a asp.net core project
// we the attribute name is HelpermethodAttribute while when loading a .net framework project the attribute name is
// HelperMethodAttribute
x.GetAttributes().Any(y => y.AttributeClass.Name.Equals(StringConstants.HELPERMETHODATTRIBUTEFULL)
|| y.AttributeClass.Name.Equals(StringConstants.HELPERMETHODATTRIBUTE)));
var helperMethod = candidates.FirstOrDefault(x => DoParametersMatch(x, parameters));
if (helperMethod != null)
return helperMethod;
acceptsStringBuilder = false;
parameters.Remove(sbSymbol);
helperMethod = findHelperMethod(funtionName, parameters);
}
return null;
return helperMethod;
}

private static bool DoParametersMatch(IMethodSymbol methodSymbol, List<ITypeSymbol> parameters)
Expand Down Expand Up @@ -207,5 +251,10 @@ public INamedTypeSymbol GetStringTypeSymbol()
{
return projectCompilations.First().Value.GetSpecialType(SpecialType.System_String);
}

public INamedTypeSymbol GetStringBuilderTypeSymbol()
{
return projectCompilations.First().Value.GetTypeByMetadataName(@"System.Text.StringBuilder");
}
}
}
9 changes: 7 additions & 2 deletions Compiler/Introspection/SymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,16 @@ public static ITypeSymbol GetElementSymbol(this ISymbol symbol)
/// <param name="name"></param>
/// <returns></returns>
public static bool IsString(this ITypeSymbol symbol)
{
{
return (symbol as INamedTypeSymbol).SpecialType.HasFlag(SpecialType.System_String);
}

private static ITypeSymbol FindMemberRec(this ITypeSymbol symbol, string name)
public static bool IsTaskOfString(this ITypeSymbol symbol)
{
return symbol != null && symbol.ToDisplayString().Equals(@"System.Threading.Tasks.Task<string>", StringComparison.Ordinal);
}

private static ITypeSymbol FindMemberRec(this ITypeSymbol symbol, string name)
{
var result = symbol.GetMembers(name).FirstOrDefault();
if (result == null && symbol.BaseType != null)
Expand Down
16 changes: 12 additions & 4 deletions Compiler/Visitors/CodeGenerationVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,23 @@ public void Visit(HelperCall astLeaf)
if (param.TryEvaluate(state, out Context paramContext))
paramContextList.Add(paramContext);
}
var helperMethod = state.Introspector.GetHelperMethod(astLeaf.FunctionName, paramContextList.Select(x => x.Symbol).ToList());

bool acceptsStringBuilder;
var helperMethod = state.Introspector.GetHelperMethod(astLeaf.FunctionName, paramContextList.Select(x => x.Symbol).ToList(), out acceptsStringBuilder);
if (helperMethod != null)
{
state.RegisterUsing(helperMethod.ContainingNamespace.ToDisplayString());
state.PushStatement(
bool returnTypeIsString = helperMethod.ReturnType.IsString() || helperMethod.ReturnType.IsTaskOfString();
var paramList = paramContextList.Select(x => x.FullPath).ToList();
if (acceptsStringBuilder && !returnTypeIsString)
{
paramList.Add("sb");
}
state.PushStatement(
SyntaxHelper.AppendFuntionCallResult(
functionName: string.Concat(helperMethod.ContainingType.Name, ".", helperMethod.Name),
parameters: paramContextList.Select(x => x.FullPath).ToList(),
returnTypeIsString: helperMethod.ReturnType.IsString(),
parameters: paramList,
returnTypeIsString: returnTypeIsString,
encoded: astLeaf.Type == TokenType.Encoded,
doAwait: helperMethod.Name.EndsWith("Async", StringComparison.Ordinal)));
}
Expand Down
46 changes: 23 additions & 23 deletions CompilerVSIX/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="HandlebarsCompiler.Jakob Demler.71222594-41cc-4ba2-b691-ad7c2783a83b" Version="0.4.1" Language="en-US" Publisher="Jakob Demler" />
<DisplayName>HandlebarsCompiler</DisplayName>
<Description xml:space="preserve">Compiles Handlebars Templates into performant and typechecked C# Code</Description>
<MoreInfo>https://github.com/Noxum/CompiledHandlebars</MoreInfo>
<Tags>Handlebars Html Rendering</Tags>
</Metadata>
<Installation>
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Pro" />
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Community" />
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Enterprise" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="File" Path="Microsoft.CodeAnalysis.Workspaces.dll" AssemblyName="Microsoft.CodeAnalysis.Workspaces, Version=2.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="File" Path="microsoft.visualstudio.languageservices.dll" AssemblyName="Microsoft.VisualStudio.LanguageServices, Version=2.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</Assets>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,)" DisplayName="Visual Studio core editor" />
</Prerequisites>
<Metadata>
<Identity Id="HandlebarsCompiler.Jakob Demler.71222594-41cc-4ba2-b691-ad7c2783a83b" Version="0.4.2" Language="en-US" Publisher="Jakob Demler" />
<DisplayName>HandlebarsCompiler</DisplayName>
<Description xml:space="preserve">Compiles Handlebars Templates into performant and typechecked C# Code</Description>
<MoreInfo>https://github.com/Noxum/CompiledHandlebars</MoreInfo>
<Tags>Handlebars Html Rendering</Tags>
</Metadata>
<Installation>
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Pro" />
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Community" />
<InstallationTarget Version="[15.0,17.0)" Id="Microsoft.VisualStudio.Enterprise" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="File" Path="Microsoft.CodeAnalysis.Workspaces.dll" AssemblyName="Microsoft.CodeAnalysis.Workspaces, Version=2.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="File" Path="microsoft.visualstudio.languageservices.dll" AssemblyName="Microsoft.VisualStudio.LanguageServices, Version=2.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</Assets>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,)" DisplayName="Visual Studio core editor" />
</Prerequisites>
</PackageManifest>
2 changes: 1 addition & 1 deletion RuntimeUtils/CompiledHandlebars.RuntimeUtils.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>net45;net46;net462;netstandard2</TargetFrameworks>
<AssemblyName>CompiledHandlebars.RuntimeUtils</AssemblyName>
<RootNamespace>CompiledHandlebars.RuntimeUtils</RootNamespace>
<Version>0.4.1</Version>
<Version>0.4.2</Version>
<Description>RuntimeUtils for the HandlebarsCompiler.</Description>
<Authors>CurrySoftware GmbH</Authors>
<Company>CurrySoftware GmbH</Company>
Expand Down
2 changes: 1 addition & 1 deletion ViewEngine.Core/CompiledHandlebars.ViewEngine.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>netstandard2;net462</TargetFrameworks>
<AssemblyName>CompiledHandlebars.ViewEngine.Core</AssemblyName>
<RootNamespace>CompiledHandlebars.ViewEngine.Core</RootNamespace>
<Version>0.4.1</Version>
<Version>0.4.2</Version>
<Authors>CurrySoftware GmbH</Authors>
<Company>CurrySoftware GmbH</Company>
<Product>HanldebarsCompiler</Product>
Expand Down
2 changes: 1 addition & 1 deletion ViewEngine/CompiledHandlebars.ViewEngine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks>net45;net46;net462</TargetFrameworks>
<AssemblyName>CompiledHandlebars.ViewEngine</AssemblyName>
<RootNamespace>CompiledHandlebars.ViewEngine</RootNamespace>
<Version>0.4.1</Version>
<Version>0.4.2</Version>
<Authors>CurrySoftware GmbH</Authors>
<Company>CurrySoftware GmbH</Company>
<Product>HanldebarsCompiler</Product>
Expand Down

0 comments on commit fdb84e5

Please sign in to comment.