提交 89ce62cb 编写于 作者: K Kevin Halverson

Minor SourceFileResolver fixups...

- Undo some refactoring of CommonCompiler.ReadFileContent
- Remove LoadDirectiveResolver
- Make SourceReferenceResolver.ReadText detect encoding
- Make SourceReferenceResolver.ReadText Dispose its Stream
- Generate Diagnostic if source contains #load and SourceReferenceResolver
  is not specified in ParseOptions
上级 58897417
...@@ -5588,7 +5588,7 @@ internal class CSharpResources { ...@@ -5588,7 +5588,7 @@ internal class CSharpResources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Metadata references not supported.. /// Looks up a localized string similar to Metadata references are not supported..
/// </summary> /// </summary>
internal static string ERR_MetadataReferencesNotSupported { internal static string ERR_MetadataReferencesNotSupported {
get { get {
...@@ -7765,6 +7765,15 @@ internal class CSharpResources { ...@@ -7765,6 +7765,15 @@ internal class CSharpResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Source file references are not supported..
/// </summary>
internal static string ERR_SourceFileReferencesNotSupported {
get {
return ResourceManager.GetString("ERR_SourceFileReferencesNotSupported", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Instance of type &apos;{0}&apos; cannot be used inside an anonymous function, query expression, iterator block or async method. /// Looks up a localized string similar to Instance of type &apos;{0}&apos; cannot be used inside an anonymous function, query expression, iterator block or async method.
/// </summary> /// </summary>
......
...@@ -373,7 +373,7 @@ ...@@ -373,7 +373,7 @@
<value>Metadata file '{0}' could not be found</value> <value>Metadata file '{0}' could not be found</value>
</data> </data>
<data name="ERR_MetadataReferencesNotSupported" xml:space="preserve"> <data name="ERR_MetadataReferencesNotSupported" xml:space="preserve">
<value>Metadata references not supported.</value> <value>Metadata references are not supported.</value>
</data> </data>
<data name="FTL_MetadataCantOpenFile" xml:space="preserve"> <data name="FTL_MetadataCantOpenFile" xml:space="preserve">
<value>Metadata file '{0}' could not be opened -- {1}</value> <value>Metadata file '{0}' could not be opened -- {1}</value>
...@@ -4651,4 +4651,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -4651,4 +4651,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="SyntaxTreeFromLoadNoRemoveReplace" xml:space="preserve"> <data name="SyntaxTreeFromLoadNoRemoveReplace" xml:space="preserve">
<value>SyntaxTree '{0}' resulted from a #load directive and cannot be removed or replaced directly.</value> <value>SyntaxTree '{0}' resulted from a #load directive and cannot be removed or replaced directly.</value>
</data> </data>
<data name="ERR_SourceFileReferencesNotSupported" xml:space="preserve">
<value>Source file references are not supported.</value>
</data>
</root> </root>
\ No newline at end of file
...@@ -187,55 +187,66 @@ public SyntaxAndDeclarationManager AddSyntaxTrees(IEnumerable<SyntaxTree> trees) ...@@ -187,55 +187,66 @@ public SyntaxAndDeclarationManager AddSyntaxTrees(IEnumerable<SyntaxTree> trees)
} }
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
var resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath); string resolvedFilePath = null;
if (resolvedFilePath == null) if (resolver == null)
{ {
diagnostics.Add( diagnostics.Add(
messageProvider.CreateDiagnostic( messageProvider.CreateDiagnostic(
(int)ErrorCode.ERR_NoSourceFile, (int)ErrorCode.ERR_SourceFileReferencesNotSupported,
fileToken.GetLocation(), directive.Location));
path,
CSharpResources.CouldNotFindFile));
} }
else if (!loadedSyntaxTreeMapBuilder.ContainsKey(resolvedFilePath)) else
{ {
try resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath);
if (resolvedFilePath == null)
{ {
var code = resolver.ReadText(resolvedFilePath); diagnostics.Add(
var loadedTree = SyntaxFactory.ParseSyntaxTree( messageProvider.CreateDiagnostic(
code, (int)ErrorCode.ERR_NoSourceFile,
tree.Options, // Use ParseOptions propagated from "external" tree. fileToken.GetLocation(),
resolvedFilePath); path,
CSharpResources.CouldNotFindFile));
}
else if (!loadedSyntaxTreeMapBuilder.ContainsKey(resolvedFilePath))
{
try
{
var code = resolver.ReadText(resolvedFilePath);
var loadedTree = SyntaxFactory.ParseSyntaxTree(
code,
tree.Options, // Use ParseOptions propagated from "external" tree.
resolvedFilePath);
// All #load'ed trees should have unique path information. // All #load'ed trees should have unique path information.
loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree); loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree);
AppendAllSyntaxTrees( AppendAllSyntaxTrees(
treesBuilder, treesBuilder,
loadedTree, loadedTree,
scriptClassName, scriptClassName,
resolver, resolver,
messageProvider, messageProvider,
isSubmission, isSubmission,
ordinalMapBuilder, ordinalMapBuilder,
loadDirectiveMapBuilder, loadDirectiveMapBuilder,
loadedSyntaxTreeMapBuilder, loadedSyntaxTreeMapBuilder,
declMapBuilder, declMapBuilder,
ref declTable); ref declTable);
}
catch (Exception e)
{
diagnostics.Add(
CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath),
fileToken.GetLocation());
}
} }
catch (Exception e) else
{ {
diagnostics.Add( // The path resolved, but we've seen this file before,
CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath), // so don't attempt to load it again.
fileToken.GetLocation()); Debug.Assert(diagnostics.IsEmptyWithoutResolution);
} }
} }
else
{
// The path resolved, but we've seen this file before,
// so don't attempt to load it again.
Debug.Assert(diagnostics.IsEmptyWithoutResolution);
}
if (loadDirectives == null) if (loadDirectives == null)
{ {
......
...@@ -1314,5 +1314,6 @@ internal enum ErrorCode ...@@ -1314,5 +1314,6 @@ internal enum ErrorCode
ERR_DebugEntryPointNotSourceMethodDefinition = 8096, ERR_DebugEntryPointNotSourceMethodDefinition = 8096,
ERR_LoadDirectiveOnlyAllowedInScripts = 8097, ERR_LoadDirectiveOnlyAllowedInScripts = 8097,
ERR_PPLoadFollowsToken = 8098, ERR_PPLoadFollowsToken = 8098,
ERR_SourceFileReferencesNotSupported = 8099,
} }
} }
...@@ -62,6 +62,19 @@ void FileWithErrors() ...@@ -62,6 +62,19 @@ void FileWithErrors()
Diagnostic(ErrorCode.ERR_NameNotInContext, "asdf").WithArguments("asdf").WithLocation(3, 21)); Diagnostic(ErrorCode.ERR_NameNotInContext, "asdf").WithArguments("asdf").WithLocation(3, 21));
} }
[Fact]
void NoSourceReferenceResolver()
{
var code = "#load \"test\"";
var compilation = CreateCompilationWithMscorlib(code, parseOptions: TestOptions.Script);
Assert.Single(compilation.SyntaxTrees);
compilation.GetDiagnostics().Verify(
// (1,1): error CS8099: Source file references not supported
// #load "test"
Diagnostic(ErrorCode.ERR_SourceFileReferencesNotSupported, @"#load ""test""").WithLocation(1, 1));
}
private static CSharpCompilation CreateCompilation(string code, SourceReferenceResolver sourceReferenceResolver = null) private static CSharpCompilation CreateCompilation(string code, SourceReferenceResolver sourceReferenceResolver = null)
{ {
var options = new CSharpCompilationOptions( var options = new CSharpCompilationOptions(
......
...@@ -153,7 +153,14 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic ...@@ -153,7 +153,14 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic
var filePath = file.Path; var filePath = file.Path;
try try
{ {
return ReadFileContentHelper(filePath, encoding, checksumAlgorithm, out normalizedFilePath); // PERF: Using a very small buffer size for the FileStream opens up an optimization within EncodedStringText where
// we read the entire FileStream into a byte array in one shot. For files that are actually smaller than the buffer
// size, FileStream.Read still allocates the internal buffer.
using (var data = PortableShim.FileStream.Create(filePath, PortableShim.FileMode.Open, PortableShim.FileAccess.Read, PortableShim.FileShare.ReadWrite, bufferSize: 1, options: PortableShim.FileOptions.None))
{
normalizedFilePath = (string)PortableShim.FileStream.Name.GetValue(data);
return EncodedStringText.Create(data, encoding, checksumAlgorithm);
}
} }
catch (Exception e) catch (Exception e)
{ {
...@@ -163,18 +170,6 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic ...@@ -163,18 +170,6 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic
} }
} }
internal static SourceText ReadFileContentHelper(string filePath, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, out string normalizedFilePath)
{
// PERF: Using a very small buffer size for the FileStream opens up an optimization within EncodedStringText where
// we read the entire FileStream into a byte array in one shot. For files that are actually smaller than the buffer
// size, FileStream.Read still allocates the internal buffer.
using (var data = PortableShim.FileStream.Create(filePath, PortableShim.FileMode.Open, PortableShim.FileAccess.Read, PortableShim.FileShare.ReadWrite, bufferSize: 1, options: PortableShim.FileOptions.None))
{
normalizedFilePath = (string)PortableShim.FileStream.Name.GetValue(data);
return EncodedStringText.Create(data, encoding, checksumAlgorithm);
}
}
internal static DiagnosticInfo ToFileReadDiagnostics(CommonMessageProvider messageProvider, Exception e, string filePath) internal static DiagnosticInfo ToFileReadDiagnostics(CommonMessageProvider messageProvider, Exception e, string filePath)
{ {
DiagnosticInfo diagnosticInfo; DiagnosticInfo diagnosticInfo;
......
...@@ -30,7 +30,7 @@ internal abstract class CommonSyntaxAndDeclarationManager ...@@ -30,7 +30,7 @@ internal abstract class CommonSyntaxAndDeclarationManager
{ {
this.ExternalSyntaxTrees = externalSyntaxTrees; this.ExternalSyntaxTrees = externalSyntaxTrees;
this.ScriptClassName = scriptClassName ?? ""; this.ScriptClassName = scriptClassName ?? "";
this.Resolver = resolver; // TODO: What if SourceReferenceResolver is null? this.Resolver = resolver;
this.MessageProvider = messageProvider; this.MessageProvider = messageProvider;
this.IsSubmission = isSubmission; this.IsSubmission = isSubmission;
} }
......
...@@ -62,7 +62,10 @@ internal Stream OpenReadChecked(string fullPath) ...@@ -62,7 +62,10 @@ internal Stream OpenReadChecked(string fullPath)
/// <param name="resolvedPath">Path returned by <see cref="ResolveReference(string, string)"/>.</param> /// <param name="resolvedPath">Path returned by <see cref="ResolveReference(string, string)"/>.</param>
public virtual SourceText ReadText(string resolvedPath) public virtual SourceText ReadText(string resolvedPath)
{ {
return SourceText.From(OpenRead(resolvedPath)); using (var stream = OpenRead(resolvedPath))
{
return EncodedStringText.Create(stream);
}
} }
} }
} }
...@@ -51,7 +51,7 @@ public override Compilation CreateSubmission(Script script) ...@@ -51,7 +51,7 @@ public override Compilation CreateSubmission(Script script)
platform: Platform.AnyCpu, platform: Platform.AnyCpu,
warningLevel: 4, warningLevel: 4,
xmlReferenceResolver: null, // don't support XML file references in interactive (permissions & doc comment includes) xmlReferenceResolver: null, // don't support XML file references in interactive (permissions & doc comment includes)
sourceReferenceResolver: LoadDirectiveResolver.Default, sourceReferenceResolver: null,
metadataReferenceResolver: script.Options.ReferenceResolver, metadataReferenceResolver: script.Options.ReferenceResolver,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default
), ),
...@@ -62,25 +62,5 @@ public override Compilation CreateSubmission(Script script) ...@@ -62,25 +62,5 @@ public override Compilation CreateSubmission(Script script)
return compilation; return compilation;
} }
private class LoadDirectiveResolver : SourceFileResolver
{
public static new LoadDirectiveResolver Default { get; } = new LoadDirectiveResolver();
private LoadDirectiveResolver()
: base(ImmutableArray<string>.Empty, baseDirectory: null)
{
}
public override SourceText ReadText(string resolvedPath)
{
string unused;
return CommonCompiler.ReadFileContentHelper(
resolvedPath,
encoding: null,
checksumAlgorithm: SourceHashAlgorithm.Sha1, // TODO: Should we be fetching the checksum algorithm from somewhere?
normalizedFilePath: out unused);
}
}
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册