提交 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 {
}
/// <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>
internal static string ERR_MetadataReferencesNotSupported {
get {
......@@ -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>
/// 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>
......
......@@ -373,7 +373,7 @@
<value>Metadata file '{0}' could not be found</value>
</data>
<data name="ERR_MetadataReferencesNotSupported" xml:space="preserve">
<value>Metadata references not supported.</value>
<value>Metadata references are not supported.</value>
</data>
<data name="FTL_MetadataCantOpenFile" xml:space="preserve">
<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
<data name="SyntaxTreeFromLoadNoRemoveReplace" xml:space="preserve">
<value>SyntaxTree '{0}' resulted from a #load directive and cannot be removed or replaced directly.</value>
</data>
<data name="ERR_SourceFileReferencesNotSupported" xml:space="preserve">
<value>Source file references are not supported.</value>
</data>
</root>
\ No newline at end of file
......@@ -187,55 +187,66 @@ public SyntaxAndDeclarationManager AddSyntaxTrees(IEnumerable<SyntaxTree> trees)
}
var diagnostics = DiagnosticBag.GetInstance();
var resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath);
if (resolvedFilePath == null)
string resolvedFilePath = null;
if (resolver == null)
{
diagnostics.Add(
messageProvider.CreateDiagnostic(
(int)ErrorCode.ERR_NoSourceFile,
fileToken.GetLocation(),
path,
CSharpResources.CouldNotFindFile));
(int)ErrorCode.ERR_SourceFileReferencesNotSupported,
directive.Location));
}
else if (!loadedSyntaxTreeMapBuilder.ContainsKey(resolvedFilePath))
else
{
try
resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath);
if (resolvedFilePath == null)
{
var code = resolver.ReadText(resolvedFilePath);
var loadedTree = SyntaxFactory.ParseSyntaxTree(
code,
tree.Options, // Use ParseOptions propagated from "external" tree.
resolvedFilePath);
diagnostics.Add(
messageProvider.CreateDiagnostic(
(int)ErrorCode.ERR_NoSourceFile,
fileToken.GetLocation(),
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.
loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree);
// All #load'ed trees should have unique path information.
loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree);
AppendAllSyntaxTrees(
treesBuilder,
loadedTree,
scriptClassName,
resolver,
messageProvider,
isSubmission,
ordinalMapBuilder,
loadDirectiveMapBuilder,
loadedSyntaxTreeMapBuilder,
declMapBuilder,
ref declTable);
AppendAllSyntaxTrees(
treesBuilder,
loadedTree,
scriptClassName,
resolver,
messageProvider,
isSubmission,
ordinalMapBuilder,
loadDirectiveMapBuilder,
loadedSyntaxTreeMapBuilder,
declMapBuilder,
ref declTable);
}
catch (Exception e)
{
diagnostics.Add(
CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath),
fileToken.GetLocation());
}
}
catch (Exception e)
else
{
diagnostics.Add(
CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath),
fileToken.GetLocation());
// The path resolved, but we've seen this file before,
// so don't attempt to load it again.
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)
{
......
......@@ -1314,5 +1314,6 @@ internal enum ErrorCode
ERR_DebugEntryPointNotSourceMethodDefinition = 8096,
ERR_LoadDirectiveOnlyAllowedInScripts = 8097,
ERR_PPLoadFollowsToken = 8098,
ERR_SourceFileReferencesNotSupported = 8099,
}
}
......@@ -62,6 +62,19 @@ void FileWithErrors()
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)
{
var options = new CSharpCompilationOptions(
......
......@@ -153,7 +153,14 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic
var filePath = file.Path;
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)
{
......@@ -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)
{
DiagnosticInfo diagnosticInfo;
......
......@@ -30,7 +30,7 @@ internal abstract class CommonSyntaxAndDeclarationManager
{
this.ExternalSyntaxTrees = externalSyntaxTrees;
this.ScriptClassName = scriptClassName ?? "";
this.Resolver = resolver; // TODO: What if SourceReferenceResolver is null?
this.Resolver = resolver;
this.MessageProvider = messageProvider;
this.IsSubmission = isSubmission;
}
......
......@@ -62,7 +62,10 @@ internal Stream OpenReadChecked(string fullPath)
/// <param name="resolvedPath">Path returned by <see cref="ResolveReference(string, string)"/>.</param>
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)
platform: Platform.AnyCpu,
warningLevel: 4,
xmlReferenceResolver: null, // don't support XML file references in interactive (permissions & doc comment includes)
sourceReferenceResolver: LoadDirectiveResolver.Default,
sourceReferenceResolver: null,
metadataReferenceResolver: script.Options.ReferenceResolver,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default
),
......@@ -62,25 +62,5 @@ public override Compilation CreateSubmission(Script script)
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.
先完成此消息的编辑!
想要评论请 注册