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

Commit

Permalink
Added SourceLocation to inherited chunks \ tag helpers
Browse files Browse the repository at this point in the history
Updated CompilationResult to support compilation failures from multiple
files.

Fixes #2321
  • Loading branch information
pranavkm committed Apr 17, 2015
1 parent f878ca5 commit fb451b5
Show file tree
Hide file tree
Showing 19 changed files with 553 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,33 @@ private static Dictionary<Type, IChunkMerger> GetMergerMappings(CodeTree codeTre

private static CodeTree ParseViewFile(RazorTemplateEngine engine,
IFileInfo fileInfo,
string viewStartPath)
string globalImportPath)
{
using (var stream = fileInfo.CreateReadStream())
{
using (var streamReader = new StreamReader(stream))
{
var parseResults = engine.ParseTemplate(streamReader, viewStartPath);
var parseResults = engine.ParseTemplate(streamReader, globalImportPath);
var className = ParserHelpers.SanitizeClassName(fileInfo.Name);
var language = engine.Host.CodeLanguage;
var codeGenerator = language.CreateCodeGenerator(className,
engine.Host.DefaultNamespace,
viewStartPath,
globalImportPath,
engine.Host);
codeGenerator.Visit(parseResults);

return codeGenerator.Context.CodeTreeBuilder.CodeTree;
// Rewrite the location of inherited chunks so they point to the global import file.
var codeTree = codeGenerator.Context.CodeTreeBuilder.CodeTree;
foreach (var chunk in codeTree.Chunks)
{
chunk.Start = new SourceLocation(
globalImportPath,
chunk.Start.AbsoluteIndex,
chunk.Start.LineIndex,
chunk.Start.CharacterIndex);
}

return codeTree;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
{
var descriptor = new TagHelperDirectiveDescriptor(
addTagHelperChunk.LookupText,
SourceLocation.Undefined,
chunk.Start,
TagHelperDirectiveType.AddTagHelper);

descriptors.Add(descriptor);
Expand All @@ -89,7 +89,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
{
var descriptor = new TagHelperDirectiveDescriptor(
removeTagHelperChunk.LookupText,
SourceLocation.Undefined,
chunk.Start,
TagHelperDirectiveType.RemoveTagHelper);

descriptors.Add(descriptor);
Expand All @@ -102,7 +102,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
{
var descriptor = new TagHelperDirectiveDescriptor(
tagHelperPrefixDirectiveChunk.Prefix,
SourceLocation.Undefined,
chunk.Start,
TagHelperDirectiveType.TagHelperPrefix);

descriptors.Add(descriptor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@ public class CompilationFailedException : Exception, ICompilationException
/// <summary>
/// Instantiates a new instance of <see cref="CompilationFailedException"/>.
/// </summary>
/// <param name="compilationFailure">The <see cref="ICompilationFailure"/> instance containing
/// <param name="compilationFailures"><see cref="ICompilationFailure"/>s containing
/// details of the compilation failure.</param>
public CompilationFailedException(
[NotNull] ICompilationFailure compilationFailure)
: base(FormatMessage(compilationFailure))
[NotNull] IEnumerable<ICompilationFailure> compilationFailures)
: base(FormatMessage(compilationFailures))
{
CompilationFailures = new[] { compilationFailure };
CompilationFailures = compilationFailures;
}

/// <inheritdoc />
public IEnumerable<ICompilationFailure> CompilationFailures { get; }

private static string FormatMessage(ICompilationFailure compilationFailure)
private static string FormatMessage(IEnumerable<ICompilationFailure> compilationFailures)
{
return Resources.CompilationFailed + Environment.NewLine +
string.Join(
Environment.NewLine,
compilationFailure.Messages.Select(message => message.FormattedMessage));
compilationFailures.SelectMany(f => f.Messages).Select(message => message.FormattedMessage));
}
}
}
21 changes: 12 additions & 9 deletions src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Framework.Runtime;
using System.Collections.Generic;
using System.IO;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Runtime;

namespace Microsoft.AspNet.Mvc.Razor.Compilation
{
Expand Down Expand Up @@ -31,10 +33,11 @@ protected CompilationResult()
public string CompiledContent { get; protected set; }

/// <summary>
/// Gets the <see cref="ICompilationFailure"/> produced from parsing or compiling the Razor file.
/// Gets the <see cref="ICompilationFailure"/>s produced from parsing or compiling the Razor file.
/// </summary>
/// <remarks>This property is <c>null</c> when compilation succeeded.</remarks>
public ICompilationFailure CompilationFailure { get; private set; }
/// <remarks>This property is <c>null</c> when compilation succeeded. An empty sequence
/// indicates a failed compilation.</remarks>
public IEnumerable<ICompilationFailure> CompilationFailures { get; private set; }

/// <summary>
/// Gets the <see cref="CompilationResult"/>.
Expand All @@ -43,9 +46,9 @@ protected CompilationResult()
/// <exception cref="CompilationFailedException">Thrown if compilation failed.</exception>
public CompilationResult EnsureSuccessful()
{
if (CompilationFailure != null)
if (CompilationFailures != null)
{
throw new CompilationFailedException(CompilationFailure);
throw new CompilationFailedException(CompilationFailures);
}

return this;
Expand All @@ -54,14 +57,14 @@ public CompilationResult EnsureSuccessful()
/// <summary>
/// Creates a <see cref="CompilationResult"/> for a failed compilation.
/// </summary>
/// <param name="compilationFailure">The <see cref="ICompilationFailure"/> produced from parsing or
/// <param name="compilationFailures"><see cref="ICompilationFailure"/>s produced from parsing or
/// compiling the Razor file.</param>
/// <returns>A <see cref="CompilationResult"/> instance for a failed compilation.</returns>
public static CompilationResult Failed([NotNull] ICompilationFailure compilationFailure)
public static CompilationResult Failed([NotNull] IEnumerable<ICompilationFailure> compilationFailures)
{
return new CompilationResult
{
CompilationFailure = compilationFailure
CompilationFailures = compilationFailures
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Razor;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;

namespace Microsoft.AspNet.Mvc.Razor.Compilation
{
Expand All @@ -16,12 +19,15 @@ public class RazorCompilationService : IRazorCompilationService
{
private readonly ICompilationService _compilationService;
private readonly IMvcRazorHost _razorHost;
private readonly IFileProvider _fileProvider;

public RazorCompilationService(ICompilationService compilationService,
IMvcRazorHost razorHost)
IMvcRazorHost razorHost,
IOptions<RazorViewEngineOptions> viewEngineOptions)
{
_compilationService = compilationService;
_razorHost = razorHost;
_fileProvider = viewEngineOptions.Options.FileProvider;
}

/// <inheritdoc />
Expand All @@ -30,39 +36,61 @@ public CompilationResult Compile([NotNull] RelativeFileInfo file)
GeneratorResults results;
using (var inputStream = file.FileInfo.CreateReadStream())
{
results = _razorHost.GenerateCode(
file.RelativePath, inputStream);
results = _razorHost.GenerateCode(file.RelativePath, inputStream);
}

if (!results.Success)
{
var messages = results.ParserErrors
.Select(parseError => new RazorCompilationMessage(parseError, file.RelativePath));
var failure = new RazorCompilationFailure(
file.RelativePath,
ReadFileContentsSafely(file.FileInfo),
messages);

return CompilationResult.Failed(failure);
return GetCompilationFailedResult(file, results.ParserErrors);
}

return _compilationService.Compile(file, results.GeneratedCode);
}

private static string ReadFileContentsSafely(IFileInfo fileInfo)
// Internal for unit testing
internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable<RazorError> errors)
{
try
// If a SourceLocation does not specify a file path, assume it is produced
// from parsing the current file.
var messageGroups = errors
.GroupBy(razorError =>
razorError.Location.FilePath ?? file.RelativePath,
StringComparer.Ordinal);

var failures = new List<RazorCompilationFailure>();
foreach (var group in messageGroups)
{
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
{
return reader.ReadToEnd();
}
var filePath = group.Key;
var fileContent = ReadFileContentsSafely(filePath);
var compilationFailure = new RazorCompilationFailure(
filePath,
fileContent,
group.Select(parserError => new RazorCompilationMessage(parserError, filePath)));
failures.Add(compilationFailure);
}
catch

return CompilationResult.Failed(failures);
}

private string ReadFileContentsSafely(string relativePath)
{
var fileInfo = _fileProvider.GetFileInfo(relativePath);
if (fileInfo.Exists)
{
// Ignore any failures
return null;
try
{
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
{
return reader.ReadToEnd();
}
}
catch
{
// Ignore any failures
}
}

return null;
}
}
}
Loading

0 comments on commit fb451b5

Please sign in to comment.