提交 bb03a8e7 编写于 作者: K Kevin Halverson

Implement #load "semantics" for CSharpCompilations...

上级 6c5767b2
......@@ -230,6 +230,8 @@
<Compile Include="Compilation\AttributeSemanticModel.cs" />
<Compile Include="Compilation\AwaitExpressionInfo.cs" />
<Compile Include="Compilation\BuiltInOperators.cs" />
<Compile Include="Compilation\SyntaxAndDeclarationManager.cs" />
<Compile Include="Compilation\SyntaxAndDeclarationManager.LazyState.cs" />
<Compile Include="Compilation\CSharpCompilerDiagnosticAnalyzer.cs" />
<Compile Include="Compilation\CSharpCompilation.cs" />
<Compile Include="Compilation\CSharpCompilationReference.cs" />
......
......@@ -351,6 +351,12 @@ internal static bool HasReferenceDirectives(this SyntaxTree tree)
return csharpTree != null && csharpTree.HasReferenceDirectives;
}
internal static bool HasReferenceOrLoadDirectives(this SyntaxTree tree)
{
var csharpTree = tree as CSharpSyntaxTree;
return csharpTree != null && csharpTree.HasReferenceOrLoadDirectives;
}
internal static bool IsAnyPreprocessorSymbolDefined(this SyntaxTree tree, ImmutableArray<string> conditionalSymbols)
{
var csharpTree = tree as CSharpSyntaxTree;
......
......@@ -61,6 +61,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot have a previousSubmission when not a submission..
/// </summary>
internal static string CannotHavePreviousSubmission {
get {
return ResourceManager.GetString("CannotHavePreviousSubmission", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Can&apos;t reference compilation of type &apos;{0}&apos; from {1} compilation..
/// </summary>
......@@ -88,6 +97,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Could not find file..
/// </summary>
internal static string CouldNotFindFile {
get {
return ResourceManager.GetString("CouldNotFindFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to element is expected.
/// </summary>
......@@ -9692,6 +9710,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to SyntaxTree &apos;{0}&apos; resulted from a #load directive and cannot be removed or replaced directly..
/// </summary>
internal static string SyntaxTreeFromLoadNoRemoveReplace {
get {
return ResourceManager.GetString("SyntaxTreeFromLoadNoRemoveReplace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SyntaxTree &apos;{0}&apos; not found to remove.
/// </summary>
......@@ -9764,24 +9791,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to trees[{0}].
/// </summary>
internal static string Trees0 {
get {
return ResourceManager.GetString("Trees0", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to trees[{0}] must have root node with SyntaxKind.CompilationUnit..
/// </summary>
internal static string TreesMustHaveRootNode {
get {
return ResourceManager.GetString("TreesMustHaveRootNode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type argument cannot be null.
/// </summary>
......
......@@ -4161,15 +4161,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="CantReferenceCompilationOf" xml:space="preserve">
<value>Can't reference compilation of type '{0}' from {1} compilation.</value>
</data>
<data name="TreesMustHaveRootNode" xml:space="preserve">
<value>trees[{0}] must have root node with SyntaxKind.CompilationUnit.</value>
</data>
<data name="SyntaxTreeAlreadyPresent" xml:space="preserve">
<value>Syntax tree already present</value>
</data>
<data name="Trees0" xml:space="preserve">
<value>trees[{0}]</value>
</data>
<data name="SubmissionCanOnlyInclude" xml:space="preserve">
<value>Submission can only include script code.</value>
</data>
......@@ -4647,4 +4641,14 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_PPLoadFollowsToken" xml:space="preserve">
<value>Cannot use #load after first token in file</value>
</data>
<data name="CouldNotFindFile" xml:space="preserve">
<value>Could not find file.</value>
<comment>File path referenced in source (#load) could not be resolved.</comment>
</data>
<data name="CannotHavePreviousSubmission" xml:space="preserve">
<value>Cannot have a previousSubmission when not a submission.</value>
</data>
<data name="SyntaxTreeFromLoadNoRemoveReplace" xml:space="preserve">
<value>SyntaxTree '{0}' resulted from a #load directive and cannot be removed or replaced directly.</value>
</data>
</root>
\ No newline at end of file
// Copyright (c) Microsoft. 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.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class SyntaxAndDeclarationManager : CommonSyntaxAndDeclarationManager
{
internal sealed class State
{
internal readonly ImmutableArray<SyntaxTree> SyntaxTrees; // In ordinal order.
internal readonly ImmutableDictionary<SyntaxTree, int> OrdinalMap; // Inverse of syntaxTrees array (i.e. maps tree to index)
internal readonly ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> LoadDirectiveMap;
internal readonly ImmutableDictionary<string, SyntaxTree> LoadedSyntaxTreeMap;
internal readonly ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> RootNamespaces;
internal readonly DeclarationTable DeclarationTable;
internal State(
ImmutableArray<SyntaxTree> syntaxTrees,
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> loadDirectiveMap,
ImmutableDictionary<string, SyntaxTree> loadedSyntaxTreeMap,
ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> rootNamespaces,
DeclarationTable declarationTable)
{
Debug.Assert(syntaxTrees.All(tree => syntaxTrees[syntaxTreeOrdinalMap[tree]] == tree));
Debug.Assert(syntaxTrees.SetEquals(rootNamespaces.Keys.AsImmutable(), EqualityComparer<SyntaxTree>.Default));
this.SyntaxTrees = syntaxTrees;
this.OrdinalMap = syntaxTreeOrdinalMap;
this.LoadDirectiveMap = loadDirectiveMap;
this.LoadedSyntaxTreeMap = loadedSyntaxTreeMap;
this.RootNamespaces = rootNamespaces;
this.DeclarationTable = declarationTable;
}
}
}
}
......@@ -110,6 +110,22 @@ internal bool HasReferenceDirectives
}
}
internal bool HasReferenceOrLoadDirectives
{
get
{
Debug.Assert(this.HasCompilationUnitRoot);
if (Options.Kind == SourceCodeKind.Interactive || Options.Kind == SourceCodeKind.Script)
{
var compilationUnitRoot = this.GetCompilationUnitRoot();
return compilationUnitRoot.GetReferenceDirectives().Count > 0 || compilationUnitRoot.GetLoadDirectives().Count > 0;
}
return false;
}
}
#region Preprocessor Symbols
private bool _hasDirectives;
private InternalSyntax.DirectiveStack _directives;
......
......@@ -26,7 +26,7 @@ internal IList<ReferenceDirectiveTriviaSyntax> GetReferenceDirectives(Func<Refer
}
/// <summary>
/// Returns #r directives specified in the compilation.
/// Returns #load directives specified in the compilation.
/// </summary>
public IList<LoadDirectiveTriviaSyntax> GetLoadDirectives()
{
......
......@@ -68,6 +68,7 @@
<Compile Include="Compilation\GetSemanticInfoTests.cs" />
<Compile Include="Compilation\GetUnusedImportDirectivesTests.cs" />
<Compile Include="Compilation\IndexedProperties_BindingTests.cs" />
<Compile Include="Compilation\LoadDirectiveTests.cs" />
<Compile Include="Compilation\QueryClauseInfoTests.cs" />
<Compile Include="Compilation\ReferenceManagerTests.cs" />
<Compile Include="Compilation\SemanticModelAPITests.cs" />
......
// Copyright (c) Microsoft. 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 System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class LoadDirectiveTests : CSharpTestBase
{
[Fact]
void EmptyFile()
{
var code = "#load \"\"";
var compilation = CreateCompilation(code);
Assert.Single(compilation.SyntaxTrees);
compilation.GetDiagnostics().Verify(
// error CS1504: Source file '' could not be opened -- Could not find file.
Diagnostic(ErrorCode.ERR_NoSourceFile, "\"\"").WithArguments("", CSharpResources.CouldNotFindFile).WithLocation(1, 7));
}
[Fact]
void MissingFile()
{
var code = "#load \"missing\"";
var compilation = CreateCompilation(code);
Assert.Single(compilation.SyntaxTrees);
compilation.GetDiagnostics().Verify(
// error CS1504: Source file 'missing' could not be opened -- Could not find file.
Diagnostic(ErrorCode.ERR_NoSourceFile, "\"missing\"").WithArguments("missing", CSharpResources.CouldNotFindFile).WithLocation(1, 7));
}
[Fact]
void FileWithErrors()
{
var code = "#load \"a.csx\"";
var resolver = CreateResolver(
Script("a.csx", @"
#load ""b.csx""
asdf();"));
var compilation = CreateCompilation(code, resolver);
Assert.Equal(2, compilation.SyntaxTrees.Length);
compilation.GetParseDiagnostics().Verify(
// a.csx(2,27): error CS1504: Source file 'b.csx' could not be opened -- Could not find file.
// #load "b.csx";
Diagnostic(ErrorCode.ERR_NoSourceFile, @"""b.csx""").WithArguments("b.csx", "Could not find file.").WithLocation(2, 27));
compilation.GetDiagnostics().Verify(
// a.csx(2,27): error CS1504: Source file 'b.csx' could not be opened -- Could not find file.
// #load "b.csx";
Diagnostic(ErrorCode.ERR_NoSourceFile, @"""b.csx""").WithArguments("b.csx", "Could not find file.").WithLocation(2, 27),
// a.csx(3,21): error CS0103: The name 'asdf' does not exist in the current context
// asdf();
Diagnostic(ErrorCode.ERR_NameNotInContext, "asdf").WithArguments("asdf").WithLocation(3, 21));
}
private static CSharpCompilation CreateCompilation(string code, SourceReferenceResolver sourceReferenceResolver = null)
{
var options = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
sourceReferenceResolver: sourceReferenceResolver ?? TestSourceReferenceResolver.Default);
var parseOptions = new CSharpParseOptions(kind: SourceCodeKind.Interactive);
return CreateCompilationWithMscorlib(code, options: options, parseOptions: parseOptions);
}
private static SourceReferenceResolver CreateResolver(params KeyValuePair<string, string>[] scripts)
{
var sources = new Dictionary<string, string>();
foreach (var script in scripts)
{
sources.Add(script.Key, script.Value);
}
return new TestSourceReferenceResolver(sources);
}
private static KeyValuePair<string, string> Script(string path, string source)
{
return new KeyValuePair<string, string>(path, source);
}
private class TestSourceReferenceResolver : SourceReferenceResolver
{
private readonly IDictionary<string, string> _sources;
public static TestSourceReferenceResolver Default { get; } = new TestSourceReferenceResolver();
public TestSourceReferenceResolver(IDictionary<string, string> sources = null)
{
_sources = sources;
}
public override string NormalizePath(string path, string baseFilePath)
{
return path;
}
public override string ResolveReference(string path, string baseFilePath)
{
return ((_sources != null) && _sources.ContainsKey(path)) ? path : null;
}
public override Stream OpenRead(string resolvedPath)
{
if (_sources != null)
{
return new MemoryStream(Encoding.UTF8.GetBytes(_sources[resolvedPath]));
}
else
{
throw new IOException();
}
}
public override bool Equals(object other)
{
return this.Equals(other);
}
public override int GetHashCode()
{
return this.GetHashCode();
}
}
}
}
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
......
......@@ -135,6 +135,8 @@
<Compile Include="CommandLine\ErrorLogger.WellKnownStrings.cs" />
<Compile Include="CommandLine\TouchedFileLogger.cs" />
<Compile Include="Compilation.EmitStreamProvider.cs" />
<Compile Include="Compilation\LoadDirective.cs" />
<Compile Include="Compilation\CommonSyntaxAndDeclarationManager.cs" />
<Compile Include="Compilation\SymbolFilter.cs" />
<Compile Include="CompilerPathUtilities.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisResult.cs" />
......
......@@ -150,40 +150,46 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic
/// <returns>File content or null on failure.</returns>
internal SourceText ReadFileContent(CommandLineSourceFile file, IList<DiagnosticInfo> diagnostics, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, out string normalizedFilePath)
{
var filePath = file.Path;
try
{
// 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(file.Path, 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);
}
return ReadFileContentHelper(filePath, encoding, checksumAlgorithm, out normalizedFilePath);
}
catch (Exception e)
{
diagnostics.Add(ToFileReadDiagnostics(e, file));
diagnostics.Add(ToFileReadDiagnostics(this.MessageProvider, e, filePath));
normalizedFilePath = null;
return null;
}
}
private DiagnosticInfo ToFileReadDiagnostics(Exception e, CommandLineSourceFile file)
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;
if (e is FileNotFoundException || e.GetType().Name == "DirectoryNotFoundException")
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_FileNotFound, file.Path);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_FileNotFound, filePath);
}
else if (e is InvalidDataException)
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_BinaryFile, file.Path);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_BinaryFile, filePath);
}
else
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_NoSourceFile, file.Path, e.Message);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_NoSourceFile, filePath, e.Message);
}
return diagnosticInfo;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis
{
internal abstract class CommonSyntaxAndDeclarationManager
{
internal readonly ImmutableArray<SyntaxTree> ExternalSyntaxTrees;
internal readonly string ScriptClassName;
internal readonly SourceReferenceResolver Resolver;
internal readonly CommonMessageProvider MessageProvider;
internal readonly bool IsSubmission;
private ImmutableDictionary<SyntaxTree, ImmutableArray<Diagnostic>> _syntaxTreeLoadDirectiveMap;
// This ImmutableDictionary will use default (case-sensitive) comparison
// for its keys. It is the responsibility of the SourceReferenceResolver
// to normalize the paths it resolves in a way that is appropriate for the
// platforms that the host supports.
private ImmutableDictionary<string, SyntaxTree> _resolvedFilePathSyntaxTreeMap;
public CommonSyntaxAndDeclarationManager(
ImmutableArray<SyntaxTree> externalSyntaxTrees,
string scriptClassName,
SourceReferenceResolver resolver,
CommonMessageProvider messageProvider,
bool isSubmission)
{
this.ExternalSyntaxTrees = externalSyntaxTrees;
this.ScriptClassName = scriptClassName ?? "";
this.Resolver = resolver; // TODO: What if SourceReferenceResolver is null?
this.MessageProvider = messageProvider;
this.IsSubmission = isSubmission;
}
}
}
......@@ -32,9 +32,6 @@ namespace Microsoft.CodeAnalysis
/// </summary>
public abstract partial class Compilation
{
// Inverse of syntaxTrees array (i.e. maps tree to index)
internal readonly ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap;
/// <summary>
/// Returns true if this is a case sensitive compilation, false otherwise. Case sensitivity
/// affects compilation features such as name lookup as well as choosing what names to emit
......@@ -58,17 +55,17 @@ public abstract partial class Compilation
internal Compilation(
string name,
ImmutableArray<MetadataReference> references,
IReadOnlyDictionary<string, string> features,
Type submissionReturnType,
Type hostObjectType,
bool isSubmission,
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
AsyncQueue<CompilationEvent> eventQueue)
{
Debug.Assert(!references.IsDefault);
Debug.Assert(features != null);
this.AssemblyName = name;
this.ExternalReferences = references;
this.syntaxTreeOrdinalMap = syntaxTreeOrdinalMap;
this.EventQueue = eventQueue;
if (isSubmission)
......@@ -82,10 +79,10 @@ public abstract partial class Compilation
_lazySubmissionSlotIndex = SubmissionSlotIndexNotApplicable;
}
_features = SyntaxTreeCommonFeatures(syntaxTreeOrdinalMap.Keys);
_features = features;
}
private IReadOnlyDictionary<string, string> SyntaxTreeCommonFeatures(IEnumerable<SyntaxTree> trees)
protected static IReadOnlyDictionary<string, string> SyntaxTreeCommonFeatures(IEnumerable<SyntaxTree> trees)
{
IReadOnlyDictionary<string, string> set = null;
......@@ -2137,14 +2134,10 @@ internal int CompareSyntaxTreeOrdering(SyntaxTree tree1, SyntaxTree tree2)
Debug.Assert(this.ContainsSyntaxTree(tree1));
Debug.Assert(this.ContainsSyntaxTree(tree2));
return this.syntaxTreeOrdinalMap[tree1] - this.syntaxTreeOrdinalMap[tree2];
return this.GetSyntaxTreeOrdinal(tree1) - this.GetSyntaxTreeOrdinal(tree2);
}
internal int GetSyntaxTreeOrdinal(SyntaxTree tree)
{
Debug.Assert(this.ContainsSyntaxTree(tree));
return this.syntaxTreeOrdinalMap[tree];
}
internal abstract int GetSyntaxTreeOrdinal(SyntaxTree tree);
/// <summary>
/// Compare two source locations, using their containing trees, and then by Span.First within a tree.
......
// Copyright (c) Microsoft. 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.Immutable;
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal struct LoadDirective : IEquatable<LoadDirective>
{
public readonly string ResolvedPath;
public readonly ImmutableArray<Diagnostic> Diagnostics;
public LoadDirective(string resolvedPath, ImmutableArray<Diagnostic> diagnostics)
{
Debug.Assert((resolvedPath != null) || !diagnostics.IsEmpty);
Debug.Assert(!diagnostics.IsDefault);
Debug.Assert(diagnostics.IsEmpty || diagnostics.All(d => d.Severity == DiagnosticSeverity.Error));
ResolvedPath = resolvedPath;
Diagnostics = diagnostics;
}
public bool Equals(LoadDirective other)
{
return this.ResolvedPath == other.ResolvedPath &&
this.Diagnostics.SequenceEqual(other.Diagnostics);
}
public override bool Equals(object obj)
{
return obj is LoadDirective && Equals((LoadDirective)obj);
}
public override int GetHashCode()
{
return Hash.Combine(this.Diagnostics.GetHashCode(), this.ResolvedPath.GetHashCode());
}
}
}
// Copyright (c) Microsoft. 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 Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis
{
......@@ -53,5 +55,14 @@ internal Stream OpenReadChecked(string fullPath)
return stream;
}
/// <summary>
/// Reads the contents of <paramref name="resolvedPath"/> and returns a <see cref="SourceText"/>.
/// </summary>
/// <param name="resolvedPath">Path returned by <see cref="ResolveReference(string, string)"/>.</param>
public virtual SourceText ReadText(string resolvedPath)
{
return SourceText.From(OpenRead(resolvedPath));
}
}
}
......@@ -48,4 +48,5 @@ static Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzerExtensions.WithAnaly
static Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.GetAnalyzerActionCountsAsync(this Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers compilationWithAnalyzers, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.ActionCounts>
static Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.GetAnalyzerExecutionTime(this Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers compilationWithAnalyzers, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer) -> System.TimeSpan
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> TNode
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation, bool elasticTrivia) -> TNode
\ No newline at end of file
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation, bool elasticTrivia) -> TNode
virtual Microsoft.CodeAnalysis.SourceReferenceResolver.ReadText(string resolvedPath) -> Microsoft.CodeAnalysis.Text.SourceText
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
......@@ -17,6 +18,13 @@ private PooledDictionary(ObjectPool<PooledDictionary<K, V>> pool)
_pool = pool;
}
public ImmutableDictionary<K, V> ToImmutableDictionaryAndFree()
{
var result = this.ToImmutableDictionary();
this.Free();
return result;
}
public void Free()
{
this.Clear();
......
......@@ -80,6 +80,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' </summary>
Private ReadOnly _syntaxTrees As ImmutableArray(Of SyntaxTree)
Private ReadOnly _syntaxTreeOrdinalMap As ImmutableDictionary(Of SyntaxTree, Integer)
''' <summary>
''' The syntax trees of this compilation plus all 'hidden' trees
''' added to the compilation by compiler, e.g. Vb Core Runtime.
......@@ -411,7 +413,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
reuseReferenceManager As Boolean,
Optional eventQueue As AsyncQueue(Of CompilationEvent) = Nothing
)
MyBase.New(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap, eventQueue)
MyBase.New(assemblyName, references, SyntaxTreeCommonFeatures(syntaxTrees), submissionReturnType, hostObjectType, isSubmission, eventQueue)
Debug.Assert(rootNamespaces IsNot Nothing)
Debug.Assert(declarationTable IsNot Nothing)
......@@ -421,6 +423,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_options = options
_syntaxTrees = syntaxTrees
_syntaxTreeOrdinalMap = syntaxTreeOrdinalMap
_rootNamespaces = rootNamespaces
_embeddedTrees = embeddedTrees
_declarationTable = declarationTable
......@@ -486,7 +489,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -538,7 +541,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -579,7 +582,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
ValidateReferences(Of VisualBasicCompilationReference)(newReferences),
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
embeddedTrees,
declTable,
......@@ -632,7 +635,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
newOptions,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
declMap,
embeddedTrees,
declTable,
......@@ -660,7 +663,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -681,7 +684,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -845,7 +848,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim referenceDirectivesChanged = False
Dim oldTreeCount = _syntaxTrees.Length
Dim ordinalMap = Me.syntaxTreeOrdinalMap
Dim ordinalMap = _syntaxTreeOrdinalMap
Dim declMap = _rootNamespaces
Dim declTable = _declarationTable
Dim i = 0
......@@ -1020,7 +1023,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
RemoveSyntaxTreeFromDeclarationMapAndTable(vbOldTree, declMap, declTable, referenceDirectivesChanged)
AddSyntaxTreeToDeclarationMapAndTable(vbNewTree, _options, Me.IsSubmission, declMap, declTable, referenceDirectivesChanged)
Dim ordinalMap = Me.syntaxTreeOrdinalMap
Dim ordinalMap = _syntaxTreeOrdinalMap
Debug.Assert(ordinalMap.ContainsKey(oldTree)) ' Checked by RemoveSyntaxTreeFromDeclarationMapAndTable
Dim oldOrdinal = ordinalMap(oldTree)
......@@ -1159,6 +1162,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return LexicalSortKey.Compare(first, second, Me)
End Function
Friend Overrides Function GetSyntaxTreeOrdinal(tree As SyntaxTree) As Integer
Debug.Assert(Me.ContainsSyntaxTree(tree))
Return _syntaxTreeOrdinalMap(tree)
End Function
#End Region
#Region "References"
......
......@@ -420,8 +420,8 @@ public void AsyncExecuteFile_ScriptFileWithBuildErrors()
Host.ExecuteFileAsync(file.Path).Wait();
var errorOut = ReadErrorOutputToEnd().Trim();
Assert.True(errorOut.StartsWith(file.Path + "(1,2):", StringComparison.Ordinal), "Error output should start with file name, line and column");
Assert.True(errorOut.Contains("CS1024"), "Error output should include error CS1024");
Assert.True(errorOut.StartsWith(file.Path + "(1,7):", StringComparison.Ordinal), "Error output should start with file name, line and column");
Assert.True(errorOut.Contains("CS7010"), "Error output should include error CS7010");
}
/// <summary>
......
// Copyright (c) Microsoft. 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.Immutable;
using System.Globalization;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Scripting.CSharp
{
......@@ -44,12 +46,12 @@ public override Compilation CreateSubmission(Script script)
scriptClassName: submissionTypeName,
usings: script.Options.Namespaces,
optimizationLevel: OptimizationLevel.Debug, // TODO
checkOverflow: false, // TODO
allowUnsafe: true, // TODO
checkOverflow: false, // TODO
allowUnsafe: true, // TODO
platform: Platform.AnyCpu,
warningLevel: 4,
xmlReferenceResolver: null, // don't support XML file references in interactive (permissions & doc comment includes)
sourceReferenceResolver: SourceFileResolver.Default, // TODO
sourceReferenceResolver: LoadDirectiveResolver.Default,
metadataReferenceResolver: script.Options.ReferenceResolver,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default
),
......@@ -60,5 +62,25 @@ 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);
}
}
}
}
......@@ -54,11 +54,6 @@
<Compile Include="CSharpObjectFormatter.cs" />
<Compile Include="CSharpScript.cs" />
<Compile Include="CSharpScriptCompiler.cs" />
<Compile Include="CSharpScriptingResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>CSharpScriptingResources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<InternalsVisibleToTest Include="Roslyn.Compilers.CSharp.Emit.UnitTests" />
......@@ -67,12 +62,6 @@
<InternalsVisibleToTest Include="Microsoft.CodeAnalysis.Scripting.UnitTests" />
<InternalsVisibleToTest Include="Microsoft.CodeAnalysis.Scripting.CSharp.UnitTests" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="CSharpScriptingResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>CSharpScriptingResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
......
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.CodeAnalysis.Scripting.CSharp {
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpScriptingResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal CSharpScriptingResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CodeAnalysis.Scripting.CSharp.CSharpScriptingResources", typeof(CSharpScriptingResources).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
......@@ -24,7 +24,7 @@ public abstract class Script
private ScriptBuilder _lazyBuilder;
private Compilation _lazyCompilation;
internal Script(ScriptCompiler compiler, string code, ScriptOptions options, Type globalsType, ScriptBuilder builder, Script previous)
{
Compiler = compiler;
......@@ -116,7 +116,7 @@ internal ScriptBuilder Builder
/// <param name="globalsType">The type that defines members that can be accessed by the script.</param>
public Script WithGlobalsType(Type globalsType) => this.WithGlobalsTypeInternal(globalsType);
internal abstract Script WithGlobalsTypeInternal(Type globalsType);
/// <summary>
/// Continues the script with given code snippet.
/// </summary>
......@@ -215,14 +215,14 @@ internal ImmutableArray<MetadataReference> GetReferencesForCompilation()
references = references.Add(corLib);
if (this.GlobalsType != null)
{
{
var globalsTypeAssembly = MetadataReference.CreateFromAssemblyInternal(this.GlobalsType.GetTypeInfo().Assembly);
references = references.Add(globalsTypeAssembly);
}
return references;
}
}
}
}
public sealed class Script<T> : Script
{
......@@ -248,19 +248,19 @@ public new Script<T> WithCode(string code)
if (code == null)
{
code = "";
}
}
return (code == this.Code) ?
this :
new Script<T>(this.Compiler, code, this.Options, this.GlobalsType, this.LazyBuilder, this.Previous);
}
}
public new Script<T> WithGlobalsType(Type globalsType)
{
{
return (globalsType == this.GlobalsType) ?
this :
new Script<T>(this.Compiler, this.Code, this.Options, globalsType, this.LazyBuilder, this.Previous);
}
}
internal override Script WithOptionsInternal(ScriptOptions options) => WithOptions(options);
internal override Script WithCodeInternal(string code) => WithCode(code);
......@@ -268,10 +268,10 @@ public new Script<T> WithGlobalsType(Type globalsType)
/// <exception cref="CompilationErrorException">Compilation has errors.</exception>
internal override void CommonBuild(CancellationToken cancellationToken)
{
{
GetPrecedingExecutors(cancellationToken);
GetExecutor(cancellationToken);
}
}
internal override Func<object[], Task> CommonGetExecutor(CancellationToken cancellationToken)
=> GetExecutor(cancellationToken);
......@@ -304,7 +304,7 @@ internal override void CommonBuild(CancellationToken cancellationToken)
var preceding = TryGetPrecedingExecutors(null, cancellationToken);
Debug.Assert(!preceding.IsDefault);
InterlockedOperations.Initialize(ref _lazyPrecedingExecutors, preceding);
}
}
return _lazyPrecedingExecutors;
}
......@@ -314,32 +314,32 @@ internal override void CommonBuild(CancellationToken cancellationToken)
{
Script script = Previous;
if (script == lastExecutedScriptInChainOpt)
{
{
return ImmutableArray<Func<object[], Task>>.Empty;
}
}
var scriptsReversed = ArrayBuilder<Script>.GetInstance();
while (script != null && script != lastExecutedScriptInChainOpt)
{
{
scriptsReversed.Add(script);
script = script.Previous;
}
}
if (lastExecutedScriptInChainOpt != null && script != lastExecutedScriptInChainOpt)
{
{
scriptsReversed.Free();
return default(ImmutableArray<Func<object[], Task>>);
}
}
var executors = ArrayBuilder<Func<object[], Task>>.GetInstance(scriptsReversed.Count);
// We need to build executors in the order in which they are chained,
// so that assemblies created for the submissions are loaded in the correct order.
for (int i = scriptsReversed.Count - 1; i >= 0; i--)
{
{
executors.Add(scriptsReversed[i].CommonGetExecutor(cancellationToken));
}
}
return executors.ToImmutableAndFree();
}
......@@ -379,7 +379,7 @@ public new Task<ScriptState<T>> RunAsync(object globals = null, CancellationToke
var currentExecutor = GetExecutor(cancellationToken);
return RunSubmissionsAsync(executionState, precedingExecutors, currentExecutor, cancellationToken);
}
}
/// <summary>
/// Creates a delegate that will run this script from the beginning when invoked.
......@@ -388,7 +388,7 @@ public new Task<ScriptState<T>> RunAsync(object globals = null, CancellationToke
/// The delegate doesn't hold on this script or its compilation.
/// </remarks>
public ScriptRunner<T> CreateDelegate(CancellationToken cancellationToken = default(CancellationToken))
{
{
var precedingExecutors = GetPrecedingExecutors(cancellationToken);
var currentExecutor = GetExecutor(cancellationToken);
var globalsType = GlobalsType;
......@@ -411,26 +411,26 @@ public ScriptRunner<T> CreateDelegate(CancellationToken cancellationToken = defa
/// <exception cref="ArgumentNullException"><paramref name="previousState"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="previousState"/> is not a previous execution state of this script.</exception>
public new Task<ScriptState<T>> ContinueAsync(ScriptState previousState, CancellationToken cancellationToken = default(CancellationToken))
{
{
// The following validation and executor contruction may throw;
// do so synchronously so that the exception is not wrapped in the task.
if (previousState == null)
{
{
throw new ArgumentNullException(nameof(previousState));
}
}
if (previousState.Script == this)
{
{
// this state is already the output of running this script.
return Task.FromResult((ScriptState<T>)previousState);
}
}
var precedingExecutors = TryGetPrecedingExecutors(previousState.Script, cancellationToken);
if (precedingExecutors.IsDefault)
{
{
throw new ArgumentException(ScriptingResources.StartingStateIncompatible, nameof(previousState));
}
}
var currentExecutor = GetExecutor(cancellationToken);
ScriptExecutionState newExecutionState = previousState.ExecutionState.FreezeAndClone();
......@@ -447,22 +447,22 @@ private async Task<ScriptState<T>> RunSubmissionsAsync(ScriptExecutionState exec
private static void ValidateGlobals(object globals, Type globalsType)
{
if (globalsType != null)
{
{
if (globals == null)
{
{
throw new ArgumentException(ScriptingResources.ScriptRequiresGlobalVariables, nameof(globals));
}
}
var runtimeType = globals.GetType().GetTypeInfo();
var globalsTypeInfo = globalsType.GetTypeInfo();
if (!globalsTypeInfo.IsAssignableFrom(runtimeType))
{
{
throw new ArgumentException(string.Format(ScriptingResources.GlobalsNotAssignable, runtimeType, globalsTypeInfo), nameof(globals));
}
}
}
else if (globals != null)
{
{
throw new ArgumentException(ScriptingResources.GlobalVariablesWithoutGlobalType, nameof(globals));
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册