Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Have @page understand malformed directives. #1506

Merged
merged 1 commit into from
Jul 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions src/Microsoft.AspNetCore.Mvc.Razor.Extensions/PageDirective.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
Expand All @@ -20,13 +21,16 @@ public class PageDirective
builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
});

private PageDirective(string routeTemplate)
private PageDirective(string routeTemplate, IntermediateNode directiveNode)
{
RouteTemplate = routeTemplate;
DirectiveNode = directiveNode;
}

public string RouteTemplate { get; }

public IntermediateNode DirectiveNode { get; }

public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
Expand All @@ -41,25 +45,27 @@ public static bool TryGetPageDirective(DocumentIntermediateNode documentNode, ou
visitor.Visit(documentNode.Children[i]);
}

if (visitor.DirectiveNode == null)
if (visitor.DirectiveTokens == null)
{
pageDirective = null;
return false;
}

var tokens = visitor.DirectiveNode.Tokens.ToList();
var tokens = visitor.DirectiveTokens.ToList();
string routeTemplate = null;
if (tokens.Count > 0)
{
routeTemplate = TrimQuotes(tokens[0].Content);
}

pageDirective = new PageDirective(routeTemplate);
pageDirective = new PageDirective(routeTemplate, visitor.DirectiveNode);
return true;
}

private static string TrimQuotes(string content)
{
// Tokens aren't captured if they're malformed. Therefore, this method will
// always be called with a valid token content.
Debug.Assert(content.Length >= 2);
Debug.Assert(content.StartsWith("\"", StringComparison.Ordinal));
Debug.Assert(content.EndsWith("\"", StringComparison.Ordinal));
Expand All @@ -69,13 +75,25 @@ private static string TrimQuotes(string content)

private class Visitor : IntermediateNodeWalker
{
public DirectiveIntermediateNode DirectiveNode { get; private set; }
public IntermediateNode DirectiveNode { get; private set; }

public IEnumerable<DirectiveTokenIntermediateNode> DirectiveTokens { get; private set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why set this? As opposed to just doing node.DirectiveTokens at the callsite?

Copy link
Member Author

@NTaylorMullen NTaylorMullen Jul 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DirectiveNode is an IntermediateNode because it can be a malformed node or a non-malformed node.


public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Descriptor == Directive)
{
DirectiveNode = node;
DirectiveTokens = node.Tokens;
}
}

public override void VisitMalformedDirective(MalformedDirectiveIntermediateNode node)
{
if (DirectiveTokens == null && node.Descriptor == Directive)
{
DirectiveNode = node;
DirectiveTokens = node.Tokens;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;

Expand All @@ -15,7 +15,7 @@ public class RazorPageDocumentClassifierPass : DocumentClassifierPassBase

protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
return PageDirective.TryGetPageDirective(documentNode, out var directive);
return PageDirective.TryGetPageDirective(documentNode, out var pageDirective);
}

protected override void OnDocumentStructureCreated(
Expand Down Expand Up @@ -49,26 +49,14 @@ protected override void OnDocumentStructureCreated(
private void EnsureValidPageDirective(RazorCodeDocument codeDocument)
{
var document = codeDocument.GetDocumentIntermediateNode();
var visitor = new Visitor();
visitor.VisitDocument(document);
PageDirective.TryGetPageDirective(document, out var pageDirective);

if (visitor.DirectiveNode.IsImported())
{
visitor.DirectiveNode.Diagnostics.Add(
RazorExtensionsDiagnosticFactory.CreatePageDirective_CannotBeImported(visitor.DirectiveNode.Source.Value));
}
}

private class Visitor : IntermediateNodeWalker
{
public DirectiveIntermediateNode DirectiveNode { get; private set; }
Debug.Assert(pageDirective != null);

public override void VisitDirective(DirectiveIntermediateNode node)
if (pageDirective.DirectiveNode.IsImported())
{
if (node.Descriptor == PageDirective.Directive)
{
DirectiveNode = node;
}
pageDirective.DirectiveNode.Diagnostics.Add(
RazorExtensionsDiagnosticFactory.CreatePageDirective_CannotBeImported(pageDirective.DirectiveNode.Source.Value));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class PageDirectiveTest
{
[Fact]
public void TryGetPageDirective_ReturnsTrue_IfPageIsMalformed()
{
// Arrange
var content = "@page \"some-route-template\" Invalid";
var sourceDocument = RazorSourceDocument.Create(content, "file");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);

// Act
var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective);

// Assert
Assert.True(result);
Assert.Equal("some-route-template", pageDirective.RouteTemplate);
Assert.NotNull(pageDirective.DirectiveNode);
}

[Fact]
public void TryGetPageDirective_ReturnsTrue_IfPageIsImported()
{
Expand Down Expand Up @@ -48,7 +67,7 @@ public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective()
}

[Fact]
public void TryGetPageDirective_ReturnsFalse_IfPageDoesStartWithDirective()
public void TryGetPageDirective_ReturnsTrue_IfPageDoesStartWithDirective()
{
// Arrange
var content = "Hello @page";
Expand All @@ -61,8 +80,9 @@ public void TryGetPageDirective_ReturnsFalse_IfPageDoesStartWithDirective()
var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective);

// Assert
Assert.False(result);
Assert.Null(pageDirective);
Assert.True(result);
Assert.Null(pageDirective.RouteTemplate);
Assert.NotNull(pageDirective.DirectiveNode);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// <auto-generated/>
#pragma warning disable 1591
[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))]
[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)]
namespace AspNetCore
{
#line hidden
Expand All @@ -12,7 +12,7 @@ namespace AspNetCore
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
Expand All @@ -35,7 +35,9 @@ private void __RazorDirectiveTokenHelpers__() {
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;
}
}
#pragma warning restore 1591
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Document -
CSharpCode -
IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))]
IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)]
NamespaceDeclaration - - AspNetCore
UsingDirective - - TModel = global::System.Object
UsingDirective - (1:0,1 [12] ) - System
Expand All @@ -10,7 +10,7 @@ Document -
UsingDirective - (102:4,1 [30] ) - Microsoft.AspNetCore.Mvc
UsingDirective - (135:5,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingDirective - (178:6,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> -
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page -
DesignTimeDirective -
DirectiveToken - (231:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel>
DirectiveToken - (294:7,71 [4] ) - Html
Expand Down Expand Up @@ -47,3 +47,7 @@ Document -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
CSharpCode -
IntermediateToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5a9ff8440150c6746e4a8ba63bc633ea84930405"
// <auto-generated/>
#pragma warning disable 1591
[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))]
[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)]
namespace AspNetCore
{
#line hidden
Expand All @@ -12,7 +12,7 @@ namespace AspNetCore
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
Expand All @@ -31,7 +31,9 @@ public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedP
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;
}
}
#pragma warning restore 1591
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Document -
CSharpCode -
IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))]
IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)]
NamespaceDeclaration - - AspNetCore
UsingDirective - (1:0,1 [14] ) - System
UsingDirective - (16:1,1 [34] ) - System.Collections.Generic
Expand All @@ -9,7 +9,7 @@ Document -
UsingDirective - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc
UsingDirective - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingDirective - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> -
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page -
MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync
MalformedDirective - (0:0,0 [6] MalformedPageDirective.cshtml) - page
CSharpCode -
Expand All @@ -30,3 +30,7 @@ Document -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
CSharpCode -
IntermediateToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;