提交 3b806a9e 编写于 作者: N nmgafter

Implement queue-based analysis engine (part 2) - C# only (changeset 1216332)

上级 dd277876
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Instrumentation;
using Microsoft.CodeAnalysis.Text;
......@@ -107,6 +108,11 @@ internal Conversions Conversions
/// </summary>
private EntryPoint lazyEntryPoint;
/// <summary>
/// The set of trees for which a <see cref="CompilationEvent.CompilationCompleted"/> has been added to the queue.
/// </summary>
private HashSet<SyntaxTree> lazyCompilationUnitCompletedTrees;
public override string Language
{
get
......@@ -288,8 +294,9 @@ internal string Feature(string p)
Type hostObjectType,
bool isSubmission,
ReferenceManager referenceManager,
bool reuseReferenceManager)
: base(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap)
bool reuseReferenceManager,
AsyncQueue<CompilationEvent> eventQueue = null)
: base(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap, eventQueue)
{
using (Logger.LogBlock(FunctionId.CSharp_Compilation_Create, message: assemblyName))
{
......@@ -334,6 +341,7 @@ internal string Feature(string p)
}
Debug.Assert((object)this.lazyAssemblySymbol == null);
if (EventQueue != null) EventQueue.Enqueue(new CompilationEvent.CompilationStarted(this));
}
}
......@@ -500,6 +508,28 @@ internal CSharpCompilation WithPreviousSubmission(CSharpCompilation newPreviousS
reuseReferenceManager: true);
}
/// <summary>
/// Returns a new compilation with a given event queue.
/// </summary>
internal CSharpCompilation WithEventQueue(AsyncQueue<CompilationEvent> eventQueue)
{
return new CSharpCompilation(
this.AssemblyName,
this.options,
this.ExternalReferences,
this.SyntaxTrees,
this.syntaxTreeOrdinalMap,
this.rootNamespaces,
this.declarationTable,
this.previousSubmission,
this.SubmissionReturnType,
this.HostObjectType,
this.IsSubmission,
this.referenceManager,
reuseReferenceManager: true,
eventQueue: eventQueue);
}
#endregion
#region Submission
......@@ -1700,24 +1730,73 @@ private AliasSymbol CreateGlobalNamespaceAlias()
return AliasSymbol.CreateGlobalNamespaceAlias(this.GlobalNamespace, new InContainerBinder(this.GlobalNamespace, new BuckStopsHereBinder(this)));
}
internal void ReportUnusedImports(DiagnosticBag diagnostics, CancellationToken cancellationToken, SyntaxTree filterTree = null)
void CompleteTree(SyntaxTree tree)
{
if (this.lazyImportInfos == null) return;
bool completedCompilationUnit = false;
bool completedCompilation = false;
foreach (ImportInfo info in this.lazyImportInfos)
if (lazyCompilationUnitCompletedTrees == null) Interlocked.CompareExchange(ref lazyCompilationUnitCompletedTrees, new HashSet<SyntaxTree>(), null);
lock (lazyCompilationUnitCompletedTrees)
{
cancellationToken.ThrowIfCancellationRequested();
if (lazyCompilationUnitCompletedTrees.Add(tree))
{
completedCompilationUnit = true;
if (lazyCompilationUnitCompletedTrees.Count == SyntaxTrees.Length)
{
completedCompilation = true;
}
}
}
SyntaxTree infoTree = info.Tree;
if (filterTree == null || filterTree == infoTree)
if (completedCompilationUnit)
{
EventQueue.Enqueue(new CompilationEvent.CompilationUnitCompleted(this, null, tree));
}
if (completedCompilation)
{
EventQueue.Enqueue(new CompilationEvent.CompilationCompleted(this));
EventQueue.Complete(); // signal the end of compilation events
}
}
internal void ReportUnusedImports(DiagnosticBag diagnostics, CancellationToken cancellationToken, SyntaxTree filterTree = null)
{
if (this.lazyImportInfos != null)
{
foreach (ImportInfo info in this.lazyImportInfos)
{
TextSpan infoSpan = info.Span;
if (!this.IsImportDirectiveUsed(infoTree, infoSpan.Start))
cancellationToken.ThrowIfCancellationRequested();
SyntaxTree infoTree = info.Tree;
if (filterTree == null || filterTree == infoTree)
{
ErrorCode code = info.Kind == SyntaxKind.ExternAliasDirective
? ErrorCode.INF_UnusedExternAlias
: ErrorCode.INF_UnusedUsingDirective;
diagnostics.Add(code, infoTree.GetLocation(infoSpan));
TextSpan infoSpan = info.Span;
if (!this.IsImportDirectiveUsed(infoTree, infoSpan.Start))
{
ErrorCode code = info.Kind == SyntaxKind.ExternAliasDirective
? ErrorCode.INF_UnusedExternAlias
: ErrorCode.INF_UnusedUsingDirective;
diagnostics.Add(code, infoTree.GetLocation(infoSpan));
}
}
}
}
// By definition, a tree is complete when all of its compiler diagnostics have been reported.
// Since unused imports are the last thing we compute and report, a tree is complete when
// the unused imports have been reported.
if (EventQueue != null)
{
if (filterTree != null)
{
CompleteTree(filterTree);
}
else
{
foreach (var tree in SyntaxTrees)
{
CompleteTree(tree);
}
}
}
......@@ -2982,5 +3061,10 @@ private bool IsMemberMissing(int member)
{
return lazyMakeMemberMissingMap != null && lazyMakeMemberMissingMap.ContainsKey(member);
}
internal void SymbolDeclaredEvent(Symbol symbol)
{
if (EventQueue != null) EventQueue.Enqueue(new CompilationEvent.SymbolDeclared(this, symbol));
}
}
}
......@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -674,6 +675,15 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
if (methodSymbol.IsAbstract)
{
// TODO: ensure that we only send a single event for each method
if (methodSymbol.DeclaringSyntaxReferences.Length != 0)
{
compilation.SymbolDeclaredEvent(methodSymbol);
}
else
{
// what about source symbols with no declaration? How does that happen?
}
return;
}
......@@ -779,7 +789,15 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
DiagnosticsPass.IssueDiagnostics(compilation, body, diagsForCurrentMethod, methodSymbol);
}
BoundBlock flowAnalyzedBody = (body == null) ? null : FlowAnalysisPass.Rewrite(methodSymbol, body, diagsForCurrentMethod);
BoundBlock flowAnalyzedBody = null;
if (body == null)
{
compilation.SymbolDeclaredEvent(methodSymbol);
}
else
{
flowAnalyzedBody = FlowAnalysisPass.Rewrite(methodSymbol, body, diagsForCurrentMethod);
}
bool hasErrors = hasDeclarationErrors || diagsForCurrentMethod.HasAnyErrors() || processedInitializers.HasErrors;
......
......@@ -5,6 +5,8 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Diagnostics;
using System;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -19,7 +21,10 @@ internal class FlowAnalysisPass
/// <param name="block">the method's body</param>
/// <param name="diagnostics">the receiver of the reported diagnostics</param>
/// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns>
public static BoundBlock Rewrite(MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics)
public static BoundBlock Rewrite(
MethodSymbol method,
BoundBlock block,
DiagnosticBag diagnostics)
{
var compilation = method.DeclaringCompilation;
......@@ -90,10 +95,29 @@ internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbo
}
}
private static bool Analyze(CSharpCompilation compilation, MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics)
private static bool Analyze(
CSharpCompilation compilation,
MethodSymbol method,
BoundBlock block,
DiagnosticBag diagnostics)
{
var result = ControlFlowPass.Analyze(compilation, method, block, diagnostics);
DataFlowPass.Analyze(compilation, method, block, diagnostics);
if (compilation.EventQueue != null)
{
var lazySemanticModel = new Lazy<SemanticModel>(() =>
{
var syntax = block.Syntax;
var semanticModel = (CSharpSemanticModel)compilation.GetSemanticModel(syntax.SyntaxTree);
var memberModel = semanticModel.GetMemberModel(syntax);
if (memberModel != null)
{
memberModel.AddBoundTreeForStandaloneSyntax(syntax, block);
}
return semanticModel;
});
compilation.EventQueue.Enqueue(new CompilationEvent.SymbolDeclared(compilation, method, lazySemanticModel));
}
DisposeCheckerPass.Analyze(compilation, method, block, diagnostics);
return result;
}
......
......@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -177,7 +178,9 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
if ((lazyCustomAttributesBag == null || !lazyCustomAttributesBag.IsSealed) &&
LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref lazyCustomAttributesBag))
{
state.NotePartComplete(CompletionPart.Attributes);
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
DeclaringCompilation.SymbolDeclaredEvent(this);
}
return lazyCustomAttributesBag;
......
......@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -172,7 +173,9 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
if (LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref lazyCustomAttributesBag))
{
state.NotePartComplete(CompletionPart.Attributes);
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
DeclaringCompilation.SymbolDeclaredEvent(this);
}
Debug.Assert(lazyCustomAttributesBag.IsSealed);
......
......@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -161,6 +162,11 @@ internal sealed class SourceMemberMethodSymbol : SourceMethodSymbol
this.constraintClauseBinder = null;
}
if (bodyOpt == null)
{
DeclaringCompilation.SymbolDeclaredEvent(this);
}
}
public override bool ReturnsVoid
......
......@@ -441,7 +441,8 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
var mergedAttributes = ((SourceAssemblySymbol)this.ContainingAssembly).GetAttributeDeclarations();
if (LoadAndValidateAttributes(OneOrMany.Create(mergedAttributes), ref lazyCustomAttributesBag))
{
state.NotePartComplete(CompletionPart.Attributes);
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
}
}
......
......@@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -401,7 +402,9 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
if (LoadAndValidateAttributes(OneOrMany.Create(this.GetAttributeDeclarations()), ref lazyCustomAttributesBag))
{
state.NotePartComplete(CompletionPart.Attributes);
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
DeclaringCompilation.SymbolDeclaredEvent(this);
}
Debug.Assert(lazyCustomAttributesBag.IsSealed);
......
......@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Collections.Generic;
......@@ -853,7 +854,9 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
if (LoadAndValidateAttributes(OneOrMany.Create(this.CSharpSyntaxNode.AttributeLists), ref lazyCustomAttributesBag))
{
state.NotePartComplete(CompletionPart.Attributes);
var completed = state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(completed);
DeclaringCompilation.SymbolDeclaredEvent(this);
}
Debug.Assert(lazyCustomAttributesBag.IsSealed);
......
......@@ -76,6 +76,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyAttributes.cs" />
<Compile Include="Diagnostics\CompilationEventTests.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.AllInOne.cs" />
<Compile Include="Diagnostics\DiagnosticAnalyzerTests.cs" />
<Compile Include="Diagnostics\GetDiagnosticsTests.cs" />
......
// 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.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class CompilationEventTests : CompilingTestBase
{
internal static void VerifyEvents(AsyncQueue<CompilationEvent> queue, params string[] expectedEvents)
{
var expected = new HashSet<string>();
foreach (var s in expectedEvents) expected.Add(s);
var actual = ArrayBuilder<CompilationEvent>.GetInstance();
while (queue.Count != 0 || !queue.IsCompleted)
{
var te = queue.DequeueAsync();
Assert.True(te.IsCompleted);
actual.Add(te.Result);
}
bool unexpected = false;
foreach (var a in actual)
{
var eventString = a.ToString();
if (!expected.Remove(eventString))
{
if (!unexpected)
{
Console.WriteLine("UNEXPECTED EVENTS:");
unexpected = true;
}
Console.WriteLine(eventString);
}
}
if (expected.Count != 0)
{
Console.WriteLine("MISSING EVENTS:");
}
foreach (var e in expected)
{
Console.WriteLine(e);
}
if (unexpected || expected.Count != 0)
{
bool first = true;
Console.WriteLine("ACTUAL EVENTS:");
foreach (var e in actual)
{
if (!first)
{
Console.WriteLine(",");
}
first = false;
Console.Write("\"" + e.ToString() + "\"");
}
Console.WriteLine();
Assert.True(false);
}
}
[Fact]
public void TestQueuedSymbols()
{
var source =
@"namespace N
{
partial class C<T1>
{
partial void M(int x1);
internal int P { get; private set; }
int F = 12;
void N<T2>(int y = 12) { F = F + 1; }
}
partial class C<T1>
{
partial void M(int x2) {}
}
}";
var q = new AsyncQueue<CompilationEvent>();
CreateCompilationWithMscorlib45(source)
.WithEventQueue(q)
.VerifyDiagnostics() // force diagnostics twice
.VerifyDiagnostics();
VerifyEvents(q,
"CompilationStarted",
"SymbolDeclared(C N.C<T1> @ : (2,2)-(8,3))",
"SymbolDeclared(M N.C<T1>.M(int) @ : (4,4)-(4,27))",
"SymbolDeclared(P N.C<T1>.P @ : (5,4)-(5,40))",
"SymbolDeclared(F N.C<T1>.F @ : (6,8)-(6,14))",
"SymbolDeclared(M N.C<T1>.M(int) @ : (11,4)-(11,29))",
"SymbolDeclared(get_P N.C<T1>.P.get @ : (5,21)-(5,25))",
"SymbolDeclared(set_P N.C<T1>.P.set @ : (5,26)-(5,38))",
"SymbolDeclared(N N.C<T1>.N<T2>(int) @ : (7,4)-(7,41))",
"CompilationUnitCompleted()",
"CompilationCompleted"
);
}
}
}
......@@ -163,6 +163,7 @@
<Compile Include="Diagnostic\SourceLocation.cs" />
<Compile Include="Diagnostic\XmlLocation.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerDriver.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationEvent.cs" />
<Compile Include="DiagnosticAnalyzer\AsyncQueue.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticAnalyzerAttribute.cs" />
<Compile Include="DiagnosticAnalyzer\ICodeBlockEndedAnalyzer.cs" />
......
......@@ -12,6 +12,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Instrumentation;
using Microsoft.CodeAnalysis.Text;
......@@ -46,13 +47,15 @@ public abstract partial class Compilation
Type submissionReturnType,
Type hostObjectType,
bool isSubmission,
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap)
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
AsyncQueue<CompilationEvent> eventQueue)
{
Debug.Assert(!references.IsDefault);
this.AssemblyName = name;
this.ExternalReferences = references;
this.syntaxTreeOrdinalMap = syntaxTreeOrdinalMap;
this.EventQueue = eventQueue;
if (isSubmission)
{
......@@ -439,6 +442,11 @@ public bool ContainsSyntaxTree(SyntaxTree syntaxTree)
protected abstract bool CommonContainsSyntaxTree(SyntaxTree syntaxTree);
/// <summary>
/// The event queue that this compilation was created with.
/// </summary>
internal readonly AsyncQueue<CompilationEvent> EventQueue;
#endregion
#region References
......
......@@ -7,6 +7,7 @@
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Diagnostics
......@@ -17,11 +18,11 @@ namespace Microsoft.CodeAnalysis.Diagnostics
/// <typeparam name="TElement">The type of values kept by the queue.</typeparam>
public sealed class AsyncQueue<TElement>
{
private object syncObject = new object();
private Queue<TElement> data = new Queue<TElement>();
private Queue<TaskCompletionSource<TElement>> waiters = new Queue<TaskCompletionSource<TElement>>();
private readonly object syncObject = new object();
private readonly Queue<TElement> data = new Queue<TElement>();
private readonly Queue<TaskCompletionSource<TElement>> waiters = new Queue<TaskCompletionSource<TElement>>();
private bool completed = false;
private TaskCompletionSource<bool> whenCompleted = new TaskCompletionSource<bool>();
private readonly TaskCompletionSource<bool> whenCompleted = new TaskCompletionSource<bool>();
private Exception thrown = null;
/// <summary>
......@@ -31,7 +32,10 @@ public int Count
{
get
{
return data.Count;
lock(syncObject)
{
return data.Count;
}
}
}
......@@ -49,21 +53,32 @@ public AsyncQueue()
public void Enqueue(TElement value)
{
TaskCompletionSource<TElement> waiter;
lock (syncObject)
lock(syncObject)
{
if (completed) throw new InvalidOperationException("Add after Complete");
if (thrown != null) return;
if (waiters.Count == 0)
if (completed)
{
throw new InvalidOperationException("Enqueue after Complete");
}
else if (thrown != null)
{
return;
}
else if (waiters.Count == 0)
{
data.Enqueue(value);
return;
}
waiter = waiters.Dequeue();
Debug.Assert(data.Count == 0);
else
{
Debug.Assert(data.Count == 0);
waiter = waiters.Dequeue();
}
}
waiter.SetResult(value);
Task.Run(() =>
{
waiter.SetResult(value);
});
}
/// <summary>
......@@ -77,19 +92,31 @@ public void SetException(Exception exception)
ImmutableArray<TaskCompletionSource<TElement>> waitersArray;
lock (syncObject)
{
if (completed) throw new InvalidOperationException("Thrown after Completed");
if (thrown != null) throw new InvalidOperationException("Thrown after Thrown");
thrown = exception;
data.Clear();
waitersArray = waiters.AsImmutable(); // TODO: move allocation out of the lock
waiters.Clear();
if (completed)
{
throw new InvalidOperationException("Thrown after Completed");
}
else if (thrown != null)
{
throw new InvalidOperationException("Thrown after Thrown");
}
else
{
thrown = exception;
data.Clear();
waitersArray = waiters.AsImmutable();
waiters.Clear();
}
}
whenCompleted.SetException(exception);
foreach (var tcs in waitersArray)
Task.Run(() =>
{
tcs.SetException(exception);
}
whenCompleted.SetException(exception);
foreach (var tcs in waitersArray)
{
tcs.SetException(exception);
}
});
}
/// <summary>
......@@ -99,7 +126,10 @@ public bool IsCompleted
{
get
{
return completed;
lock(syncObject)
{
return completed;
}
}
}
......@@ -109,27 +139,43 @@ public bool IsCompleted
public void Complete()
{
ImmutableArray<TaskCompletionSource<TElement>> waitersArray;
lock (syncObject)
lock(syncObject)
{
if (thrown != null) throw new InvalidOperationException("Done after Thrown");
waitersArray = waiters.AsImmutable();
waiters.Clear();
completed = true;
if (completed)
{
throw new InvalidOperationException("Completed after Completed");
}
else if (thrown != null)
{
throw new InvalidOperationException("Completed after Thrown");
}
else
{
waitersArray = waiters.AsImmutable();
waiters.Clear();
completed = true;
}
}
foreach (var tcs in waitersArray)
Task.Run(() =>
{
tcs.SetCanceled();
}
whenCompleted.SetResult(true);
whenCompleted.SetResult(true);
foreach (var tcs in waitersArray)
{
tcs.SetCanceled();
}
});
}
/// <summary>
/// Gets a task that transitions to a completed state when <see cref="Complete"/> is called.
/// </summary>
public Task<bool> WhenCompleted
public Task WhenCompleted
{
get { return whenCompleted.Task; }
get
{
return whenCompleted.Task;
}
}
/// <summary>
......@@ -141,20 +187,25 @@ public Task<bool> WhenCompleted
/// </summary>
public Task<TElement> DequeueAsync()
{
lock (syncObject)
lock(syncObject)
{
if (thrown != null)
{
throw thrown;
var waiter = new TaskCompletionSource<TElement>();
waiter.SetException(thrown);
return waiter.Task;
}
else if (data.Count != 0)
{
Debug.Assert(waiters.Count == 0);
return Task.FromResult(data.Dequeue());
var datum = data.Dequeue();
return Task.FromResult(datum);
}
else if (completed)
{
throw new TaskCanceledException();
var waiter = new TaskCompletionSource<TElement>();
waiter.SetCanceled();
return waiter.Task;
}
else
{
......@@ -167,7 +218,7 @@ public Task<TElement> DequeueAsync()
public override string ToString()
{
return "AsyncQueue<" + typeof(TElement).Name + ">:" + (this.IsCompleted ? "Completed" : data.Count.ToString());
return "AsyncQueue<" + typeof(TElement).Name + ">:" + (IsCompleted ? "Completed" : Count.ToString());
}
}
}
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Diagnostics
{
public abstract class CompilationEvent
{
protected CompilationEvent(Compilation compilation)
{
this.Compilation = compilation;
}
public Compilation Compilation { get; private set; }
/// <summary>
/// Flush any cached data in this <see cref="CompilationEvent"/> to minimize space usage (at the possible expense of time later).
/// The principal effect of this is to free cached information on events that have a <see cref="SemanticModel"/>.
/// </summary>
public virtual void FlushCache() { }
/// <summary>
/// The first event placed into a compilation's event queue.
/// </summary>
public class CompilationStarted : CompilationEvent
{
public CompilationStarted(Compilation compilation) : base(compilation) { }
public override string ToString()
{
return "CompilationStarted";
}
}
/// <summary>
/// The last event placed into a compilation's event queue.
/// </summary>
public class CompilationCompleted : CompilationEvent
{
public CompilationCompleted(Compilation compilation) : base(compilation) { }
public override string ToString()
{
return "CompilationCompleted";
}
}
/// <summary>
/// An event for each declaration in the program (namespace, type, method, field, parameter, etc).
/// Note that some symbols may have multiple declarations (namespaces, partial types) and may therefore
/// have multiple events.
/// </summary>
public class SymbolDeclared : CompilationEvent
{
public SymbolDeclared(Compilation compilation, ISymbol symbol) : base(compilation)
{
this.Symbol = symbol;
}
public SymbolDeclared(Compilation compilation, ISymbol symbol, Lazy<SemanticModel> lazySemanticModel) : this(compilation, symbol)
{
this.lazySemanticModel = lazySemanticModel;
}
public ISymbol Symbol { get; private set; }
// At most one of these should be non-null.
private Lazy<SemanticModel> lazySemanticModel;
private SemanticModel semanticModel;
private WeakReference<SemanticModel> weakModel = null;
public SemanticModel SemanticModel(SyntaxReference reference)
{
lock (this)
{
var semanticModel = this.semanticModel;
if (semanticModel == null && this.lazySemanticModel != null)
{
this.semanticModel = semanticModel = this.lazySemanticModel.Value;
this.lazySemanticModel = null;
}
if (semanticModel == null && this.weakModel != null)
{
this.weakModel.TryGetTarget(out semanticModel);
}
if (semanticModel == null || semanticModel.SyntaxTree != reference.SyntaxTree)
{
semanticModel = Compilation.GetSemanticModel(reference.SyntaxTree);
this.weakModel = new WeakReference<SemanticModel>(semanticModel);
}
return semanticModel;
}
}
override public void FlushCache()
{
lock (this)
{
var semanticModel = this.semanticModel;
this.lazySemanticModel = null;
if (semanticModel == null) return;
this.weakModel = new WeakReference<SemanticModel>(semanticModel);
this.semanticModel = null;
}
}
public override string ToString()
{
var refs = Symbol.DeclaringSyntaxReferences;
var loc = refs.Length != 0 ? " @ " + refs[0].GetLocation().GetLineSpan() : null;
return "SymbolDeclared(" + this.Symbol.Name + " " + this.Symbol + loc + ")";
}
}
public class CompilationUnitCompleted : CompilationEvent
{
public CompilationUnitCompleted(Compilation compilation, SemanticModel semanticModel, SyntaxTree compilationUnit) : base(compilation)
{
this.SemanticModel = semanticModel;
this.CompilationUnit = compilationUnit;
}
private SemanticModel semanticModel;
private WeakReference<SemanticModel> weakModel = null;
public SemanticModel SemanticModel
{
get
{
var semanticModel = this.semanticModel;
var weakModel = this.weakModel;
if (semanticModel == null && weakModel == null || !weakModel.TryGetTarget(out semanticModel))
{
semanticModel = Compilation.GetSemanticModel(CompilationUnit);
this.weakModel = new WeakReference<SemanticModel>(semanticModel);
}
return semanticModel;
}
private set
{
this.semanticModel = value;
}
}
override public void FlushCache()
{
var semanticModel = this.semanticModel;
if (semanticModel == null) return;
this.weakModel = new WeakReference<SemanticModel>(semanticModel);
this.semanticModel = null;
}
public SyntaxTree CompilationUnit { get; private set; }
public override string ToString()
{
return "CompilationUnitCompleted(" + CompilationUnit.FilePath + ")";
}
}
}
}
using System;
// 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.Threading;
......
using System;
// 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.Threading;
......
using System;
// 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.Threading;
......
using System;
// 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.Threading;
......
using System;
// 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.Threading;
......
using System;
// 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.Collections.Immutable;
using System.Threading;
......
using System;
// 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.Collections.Immutable;
using System.Threading;
......
using System;
// 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.Threading;
......
......@@ -7,6 +7,7 @@ Imports System.Runtime.InteropServices
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.CodeGen
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.Instrumentation
Imports Microsoft.CodeAnalysis.InternalUtilities
......@@ -369,9 +370,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
hostObjectType As Type,
isSubmission As Boolean,
referenceManager As ReferenceManager,
reuseReferenceManager As Boolean
reuseReferenceManager As Boolean,
Optional eventQueue As AsyncQueue(Of CompilationEvent) = Nothing
)
MyBase.New(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap)
MyBase.New(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap, eventQueue)
Using Logger.LogBlock(FunctionId.VisualBasic_Compilation_Create, message:=assemblyName)
Debug.Assert(rootNamespaces IsNot Nothing)
......@@ -406,6 +408,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Debug.Assert(m_lazyAssemblySymbol Is Nothing)
If Me.EventQueue IsNot Nothing Then
Me.EventQueue.Enqueue(New CompilationEvent.CompilationStarted(Me))
End If
End Using
End Sub
......@@ -427,7 +432,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.HostObjectType,
Me.IsSubmission,
m_referenceManager,
reuseReferenceManager:=True)
reuseReferenceManager:=True,
eventQueue:=Nothing) ' no event queue when cloning
End Function
Private Function UpdateSyntaxTrees(
......@@ -603,6 +609,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
reuseReferenceManager:=True)
End Function
''' <summary>
''' Returns a new compilation with a given event queue.
''' </summary>
Friend Shadows Function WithEventQueue(eventQueue As AsyncQueue(Of CompilationEvent)) As VisualBasicCompilation
Return New VisualBasicCompilation(
Me.AssemblyName,
Me.Options,
Me.ExternalReferences,
m_syntaxTrees,
Me.syntaxTreeOrdinalMap,
m_rootNamespaces,
m_embeddedTrees,
m_declarationTable,
m_previousSubmission,
Me.SubmissionReturnType,
Me.HostObjectType,
Me.IsSubmission,
m_referenceManager,
reuseReferenceManager:=True,
eventQueue:=eventQueue)
End Function
#End Region
#Region "Submission"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册