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

Commit fb451b5

Browse files
committed
Added SourceLocation to inherited chunks \ tag helpers
Updated CompilationResult to support compilation failures from multiple files. Fixes #2321
1 parent f878ca5 commit fb451b5

File tree

19 files changed

+553
-134
lines changed

19 files changed

+553
-134
lines changed

src/Microsoft.AspNet.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,33 @@ private static Dictionary<Type, IChunkMerger> GetMergerMappings(CodeTree codeTre
126126

127127
private static CodeTree ParseViewFile(RazorTemplateEngine engine,
128128
IFileInfo fileInfo,
129-
string viewStartPath)
129+
string globalImportPath)
130130
{
131131
using (var stream = fileInfo.CreateReadStream())
132132
{
133133
using (var streamReader = new StreamReader(stream))
134134
{
135-
var parseResults = engine.ParseTemplate(streamReader, viewStartPath);
135+
var parseResults = engine.ParseTemplate(streamReader, globalImportPath);
136136
var className = ParserHelpers.SanitizeClassName(fileInfo.Name);
137137
var language = engine.Host.CodeLanguage;
138138
var codeGenerator = language.CreateCodeGenerator(className,
139139
engine.Host.DefaultNamespace,
140-
viewStartPath,
140+
globalImportPath,
141141
engine.Host);
142142
codeGenerator.Visit(parseResults);
143143

144-
return codeGenerator.Context.CodeTreeBuilder.CodeTree;
144+
// Rewrite the location of inherited chunks so they point to the global import file.
145+
var codeTree = codeGenerator.Context.CodeTreeBuilder.CodeTree;
146+
foreach (var chunk in codeTree.Chunks)
147+
{
148+
chunk.Start = new SourceLocation(
149+
globalImportPath,
150+
chunk.Start.AbsoluteIndex,
151+
chunk.Start.LineIndex,
152+
chunk.Start.CharacterIndex);
153+
}
154+
155+
return codeTree;
145156
}
146157
}
147158
}

src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
7676
{
7777
var descriptor = new TagHelperDirectiveDescriptor(
7878
addTagHelperChunk.LookupText,
79-
SourceLocation.Undefined,
79+
chunk.Start,
8080
TagHelperDirectiveType.AddTagHelper);
8181

8282
descriptors.Add(descriptor);
@@ -89,7 +89,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
8989
{
9090
var descriptor = new TagHelperDirectiveDescriptor(
9191
removeTagHelperChunk.LookupText,
92-
SourceLocation.Undefined,
92+
chunk.Start,
9393
TagHelperDirectiveType.RemoveTagHelper);
9494

9595
descriptors.Add(descriptor);
@@ -102,7 +102,7 @@ private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDe
102102
{
103103
var descriptor = new TagHelperDirectiveDescriptor(
104104
tagHelperPrefixDirectiveChunk.Prefix,
105-
SourceLocation.Undefined,
105+
chunk.Start,
106106
TagHelperDirectiveType.TagHelperPrefix);
107107

108108
descriptors.Add(descriptor);

src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilationFailedException.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,24 @@ public class CompilationFailedException : Exception, ICompilationException
1717
/// <summary>
1818
/// Instantiates a new instance of <see cref="CompilationFailedException"/>.
1919
/// </summary>
20-
/// <param name="compilationFailure">The <see cref="ICompilationFailure"/> instance containing
20+
/// <param name="compilationFailures"><see cref="ICompilationFailure"/>s containing
2121
/// details of the compilation failure.</param>
2222
public CompilationFailedException(
23-
[NotNull] ICompilationFailure compilationFailure)
24-
: base(FormatMessage(compilationFailure))
23+
[NotNull] IEnumerable<ICompilationFailure> compilationFailures)
24+
: base(FormatMessage(compilationFailures))
2525
{
26-
CompilationFailures = new[] { compilationFailure };
26+
CompilationFailures = compilationFailures;
2727
}
2828

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

32-
private static string FormatMessage(ICompilationFailure compilationFailure)
32+
private static string FormatMessage(IEnumerable<ICompilationFailure> compilationFailures)
3333
{
3434
return Resources.CompilationFailed + Environment.NewLine +
3535
string.Join(
3636
Environment.NewLine,
37-
compilationFailure.Messages.Select(message => message.FormattedMessage));
37+
compilationFailures.SelectMany(f => f.Messages).Select(message => message.FormattedMessage));
3838
}
3939
}
4040
}

src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilationResult.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using Microsoft.Framework.Runtime;
5+
using System.Collections.Generic;
6+
using System.IO;
67
using Microsoft.Framework.Internal;
8+
using Microsoft.Framework.Runtime;
79

810
namespace Microsoft.AspNet.Mvc.Razor.Compilation
911
{
@@ -31,10 +33,11 @@ protected CompilationResult()
3133
public string CompiledContent { get; protected set; }
3234

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

3942
/// <summary>
4043
/// Gets the <see cref="CompilationResult"/>.
@@ -43,9 +46,9 @@ protected CompilationResult()
4346
/// <exception cref="CompilationFailedException">Thrown if compilation failed.</exception>
4447
public CompilationResult EnsureSuccessful()
4548
{
46-
if (CompilationFailure != null)
49+
if (CompilationFailures != null)
4750
{
48-
throw new CompilationFailedException(CompilationFailure);
51+
throw new CompilationFailedException(CompilationFailures);
4952
}
5053

5154
return this;
@@ -54,14 +57,14 @@ public CompilationResult EnsureSuccessful()
5457
/// <summary>
5558
/// Creates a <see cref="CompilationResult"/> for a failed compilation.
5659
/// </summary>
57-
/// <param name="compilationFailure">The <see cref="ICompilationFailure"/> produced from parsing or
60+
/// <param name="compilationFailures"><see cref="ICompilationFailure"/>s produced from parsing or
5861
/// compiling the Razor file.</param>
5962
/// <returns>A <see cref="CompilationResult"/> instance for a failed compilation.</returns>
60-
public static CompilationResult Failed([NotNull] ICompilationFailure compilationFailure)
63+
public static CompilationResult Failed([NotNull] IEnumerable<ICompilationFailure> compilationFailures)
6164
{
6265
return new CompilationResult
6366
{
64-
CompilationFailure = compilationFailure
67+
CompilationFailures = compilationFailures
6568
};
6669
}
6770

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Collections.Generic;
46
using System.IO;
57
using System.Linq;
68
using Microsoft.AspNet.FileProviders;
79
using Microsoft.AspNet.Razor;
810
using Microsoft.Framework.Internal;
11+
using Microsoft.Framework.OptionsModel;
912

1013
namespace Microsoft.AspNet.Mvc.Razor.Compilation
1114
{
@@ -16,12 +19,15 @@ public class RazorCompilationService : IRazorCompilationService
1619
{
1720
private readonly ICompilationService _compilationService;
1821
private readonly IMvcRazorHost _razorHost;
22+
private readonly IFileProvider _fileProvider;
1923

2024
public RazorCompilationService(ICompilationService compilationService,
21-
IMvcRazorHost razorHost)
25+
IMvcRazorHost razorHost,
26+
IOptions<RazorViewEngineOptions> viewEngineOptions)
2227
{
2328
_compilationService = compilationService;
2429
_razorHost = razorHost;
30+
_fileProvider = viewEngineOptions.Options.FileProvider;
2531
}
2632

2733
/// <inheritdoc />
@@ -30,39 +36,61 @@ public CompilationResult Compile([NotNull] RelativeFileInfo file)
3036
GeneratorResults results;
3137
using (var inputStream = file.FileInfo.CreateReadStream())
3238
{
33-
results = _razorHost.GenerateCode(
34-
file.RelativePath, inputStream);
39+
results = _razorHost.GenerateCode(file.RelativePath, inputStream);
3540
}
3641

3742
if (!results.Success)
3843
{
39-
var messages = results.ParserErrors
40-
.Select(parseError => new RazorCompilationMessage(parseError, file.RelativePath));
41-
var failure = new RazorCompilationFailure(
42-
file.RelativePath,
43-
ReadFileContentsSafely(file.FileInfo),
44-
messages);
45-
46-
return CompilationResult.Failed(failure);
44+
return GetCompilationFailedResult(file, results.ParserErrors);
4745
}
4846

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

52-
private static string ReadFileContentsSafely(IFileInfo fileInfo)
50+
// Internal for unit testing
51+
internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable<RazorError> errors)
5352
{
54-
try
53+
// If a SourceLocation does not specify a file path, assume it is produced
54+
// from parsing the current file.
55+
var messageGroups = errors
56+
.GroupBy(razorError =>
57+
razorError.Location.FilePath ?? file.RelativePath,
58+
StringComparer.Ordinal);
59+
60+
var failures = new List<RazorCompilationFailure>();
61+
foreach (var group in messageGroups)
5562
{
56-
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
57-
{
58-
return reader.ReadToEnd();
59-
}
63+
var filePath = group.Key;
64+
var fileContent = ReadFileContentsSafely(filePath);
65+
var compilationFailure = new RazorCompilationFailure(
66+
filePath,
67+
fileContent,
68+
group.Select(parserError => new RazorCompilationMessage(parserError, filePath)));
69+
failures.Add(compilationFailure);
6070
}
61-
catch
71+
72+
return CompilationResult.Failed(failures);
73+
}
74+
75+
private string ReadFileContentsSafely(string relativePath)
76+
{
77+
var fileInfo = _fileProvider.GetFileInfo(relativePath);
78+
if (fileInfo.Exists)
6279
{
63-
// Ignore any failures
64-
return null;
80+
try
81+
{
82+
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
83+
{
84+
return reader.ReadToEnd();
85+
}
86+
}
87+
catch
88+
{
89+
// Ignore any failures
90+
}
6591
}
92+
93+
return null;
6694
}
6795
}
6896
}

0 commit comments

Comments
 (0)