internal override CustomAttributesBag <CSharpAttributeData> GetAttributesBag() { if (lazyCustomAttributesBag == null || !lazyCustomAttributesBag.IsSealed) { bool lazyAttributesStored = false; var sourceMethod = this.ContainingSymbol as SourceMemberMethodSymbol; if ((object)sourceMethod == null || (object)sourceMethod.SourcePartialDefinition == null) { lazyAttributesStored = LoadAndValidateAttributes(OneOrMany.Create(this.MergedAttributeDeclarationSyntaxLists), ref lazyCustomAttributesBag); } else { var typeParameter = (SourceTypeParameterSymbolBase)sourceMethod.SourcePartialDefinition.TypeParameters[this.ordinal]; CustomAttributesBag <CSharpAttributeData> attributesBag = typeParameter.GetAttributesBag(); lazyAttributesStored = Interlocked.CompareExchange(ref lazyCustomAttributesBag, attributesBag, null) == null; } if (lazyAttributesStored) { state.NotePartComplete(CompletionPart.Attributes); } } return(lazyCustomAttributesBag); }
/// <summary> /// Returns a bag of applied custom attributes and data decoded from well-known attributes. Returns null if there are no attributes applied on the symbol. /// </summary> /// <remarks> /// Forces binding and decoding of attributes. /// </remarks> internal virtual CustomAttributesBag <CSharpAttributeData> GetAttributesBag() { if (_lazyCustomAttributesBag == null || !_lazyCustomAttributesBag.IsSealed) { bool lazyAttributesStored = false; var sourceMethod = this.ContainingSymbol as SourceOrdinaryMethodSymbol; if ((object)sourceMethod == null || (object)sourceMethod.SourcePartialDefinition == null) { lazyAttributesStored = LoadAndValidateAttributes( OneOrMany.Create(this.MergedAttributeDeclarationSyntaxLists), ref _lazyCustomAttributesBag, binderOpt: (ContainingSymbol as LocalFunctionSymbol)?.SignatureBinder); } else { var typeParameter = (SourceTypeParameterSymbolBase)sourceMethod.SourcePartialDefinition.TypeParameters[_ordinal]; CustomAttributesBag <CSharpAttributeData> attributesBag = typeParameter.GetAttributesBag(); lazyAttributesStored = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, attributesBag, null) == null; } if (lazyAttributesStored) { _state.NotePartComplete(CompletionPart.Attributes); } } return(_lazyCustomAttributesBag); }
internal override void ForceComplete(SourceLocation locationOpt, CancellationToken cancellationToken) { if (!_state.HasComplete(CompletionPart.Attributes)) { _ = GetAttributes(); // Consider the following items: // 1. It is possible for parallel calls to GetAttributes to exist // 2. GetAttributes will return when the attributes are available, not when the part is noted // as complete. // 3. The thread which actually completes the attributes is the one which must set the CompletionParts.Attributes // value. // 4. This call cannot correctly return until this part is set. // // That is why it is necessary to check this value again. // // Note: #2 above is common practice amongst all of the symbols. // // Note: #3 above is an invariant that has existed in the code for some time. It's not clear if this invariant // is 100% correct. After inspection though it seems likely to be correct as the code is asserting that // SymbolDeclaredEvent is raised before CompletionPart.Attributes is noted as completed. Also this is a common // pattern amongst the GetAttributes implementations. _state.SpinWaitComplete(CompletionPart.Attributes, cancellationToken); } _state.NotePartComplete(CompletionPart.All); }
private AliasSymbol(InContainerBinder binder, NamespaceOrTypeSymbol target, SyntaxToken aliasName, ImmutableArray <Location> locations) { _aliasName = aliasName; _locations = locations; _aliasTarget = target; _binder = binder; _state.NotePartComplete(CompletionPart.AliasTarget); }
protected void LazyMethodChecks() { if (!state.HasComplete(CompletionPart.FinishMethodChecks)) { // TODO: if this lock ever encloses a potential call to Debugger.NotifyOfCrossThreadDependency, // then we should call DebuggerUtilities.CallBeforeAcquiringLock() (see method comment for more // details). object lockObject = MethodChecksLockObject; Debug.Assert(lockObject != null); lock (lockObject) { if (state.NotePartComplete(CompletionPart.StartMethodChecks)) { // By setting StartMethodChecks, we've committed to doing the checks and setting // FinishMethodChecks. So there is no cancellation supported between one and the other. var diagnostics = BindingDiagnosticBag.GetInstance(); try { MethodChecks(diagnostics); AddDeclarationDiagnostics(diagnostics); } finally { state.NotePartComplete(CompletionPart.FinishMethodChecks); diagnostics.Free(); } } else { // Either (1) this thread is in the process of completing the method, // or (2) some other thread has beat us to the punch and completed the method. // We can distinguish the two cases here by checking for the FinishMethodChecks // part to be complete, which would only occur if another thread completed this // method. // // The other case, in which this thread is in the process of completing the method, // requires that we return here even though the checks are not complete. That's because // methods are processed by first populating the return type and parameters by binding // the syntax from source. Those values are visible to the same thread for the purpose // of computing which methods are implemented and overridden. But then those values // may be rewritten (by the same thread) to copy down custom modifiers. In order to // allow the same thread to see the return type and parameters from the syntax (though // they do not yet take on their final values), we return here. // Due to the fact that LazyMethodChecks is potentially reentrant, we must use a // reentrant lock to avoid deadlock and cannot assert that at this point method checks // have completed (state.HasComplete(CompletionPart.FinishMethodChecks)). } } } }
// basesBeingResolved is only used to break circular references. internal NamespaceOrTypeSymbol GetAliasTarget(ConsList <Symbol> basesBeingResolved) { if (!state.HasComplete(CompletionPart.AliasTarget)) { // the target is not yet bound. If it is an ordinary alias, bind the target // symbol. If it is an extern alias then find the target in the list of metadata references. var newDiagnostics = DiagnosticBag.GetInstance(); NamespaceOrTypeSymbol symbol = this.IsExtern ? ResolveExternAliasTarget(newDiagnostics) : ResolveAliasTarget(this.binder, this.aliasTargetName, newDiagnostics, basesBeingResolved); if ((object)Interlocked.CompareExchange(ref this.aliasTarget, symbol, null) == null) { bool won = ImmutableInterlocked.InterlockedInitialize(ref this.aliasTargetDiagnostics, newDiagnostics.ToReadOnlyAndFree()); Debug.Assert(won, "Only one thread can win the alias target CompareExchange"); state.NotePartComplete(CompletionPart.AliasTarget); // we do not clear this.aliasTargetName, as another thread might be about to use it for ResolveAliasTarget(...) } else { newDiagnostics.Free(); // Wait for diagnostics to have been reported if another thread resolves the alias state.SpinWaitComplete(CompletionPart.AliasTarget, default(CancellationToken)); } } return(aliasTarget); }
/// <summary> /// Returns a bag of applied custom attributes and data decoded from well-known attributes. Returns null if there are no attributes applied on the symbol. /// </summary> /// <remarks> /// Forces binding and decoding of attributes. /// </remarks> private CustomAttributesBag <CSharpAttributeData> GetAttributesBag() { if ((_lazyCustomAttributesBag == null || !_lazyCustomAttributesBag.IsSealed) && LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref _lazyCustomAttributesBag)) { DeclaringCompilation.SymbolDeclaredEvent(this); var wasCompletedThisThread = state.NotePartComplete(CompletionPart.Attributes); Debug.Assert(wasCompletedThisThread); } return(_lazyCustomAttributesBag); }
private TypeParameterBounds GetBounds(ConsList <TypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, ContainingSymbol)); if (ReferenceEquals(_lazyBounds, TypeParameterBounds.Unset)) { var diagnostics = DiagnosticBag.GetInstance(); var bounds = ResolveBounds(inProgress, diagnostics); if (ReferenceEquals(Interlocked.CompareExchange(ref _lazyBounds, bounds, TypeParameterBounds.Unset), TypeParameterBounds.Unset)) { //@t-mawind TODO: does this belong elsewhere? CheckAllConstraintTypesNameConcepts(diagnostics); CheckConstraintTypeConstraints(diagnostics); AddDeclarationDiagnostics(diagnostics); _state.NotePartComplete(CompletionPart.TypeParameterConstraints); } diagnostics.Free(); } return(_lazyBounds); }
/// <summary> /// Returns a bag of applied custom attributes and data decoded from well-known attributes. Returns null if there are no attributes applied on the symbol. /// </summary> /// <remarks> /// Forces binding and decoding of attributes. /// </remarks> private CustomAttributesBag <CSharpAttributeData> GetAttributesBag() { var bag = this.lazyCustomAttributesBag; if (bag != null && bag.IsSealed) { return(bag); } if (LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref lazyCustomAttributesBag)) { var completed = state.NotePartComplete(CompletionPart.Attributes); Debug.Assert(completed); } Debug.Assert(lazyCustomAttributesBag.IsSealed); return(this.lazyCustomAttributesBag); }
internal override void ForceComplete(SourceLocation locationOpt, CancellationToken cancellationToken) { while (true) { cancellationToken.ThrowIfCancellationRequested(); var incompletePart = _state.NextIncompletePart; switch (incompletePart) { case CompletionPart.Attributes: GetAttributes(); break; case CompletionPart.StartValidatingReferencedAssemblies: { BindingDiagnosticBag diagnostics = null; if (AnyReferencedAssembliesAreLinked) { diagnostics = BindingDiagnosticBag.GetInstance(); ValidateLinkedAssemblies(diagnostics, cancellationToken); } if (_state.NotePartComplete(CompletionPart.StartValidatingReferencedAssemblies)) { if (diagnostics != null) { _assemblySymbol.AddDeclarationDiagnostics(diagnostics); } _state.NotePartComplete(CompletionPart.FinishValidatingReferencedAssemblies); } if (diagnostics != null) { diagnostics.Free(); } } break; case CompletionPart.FinishValidatingReferencedAssemblies: // some other thread has started validating references (otherwise we would be in the case above) so // we just wait for it to both finish and report the diagnostics. Debug.Assert(_state.HasComplete(CompletionPart.StartValidatingReferencedAssemblies)); _state.SpinWaitComplete(CompletionPart.FinishValidatingReferencedAssemblies, cancellationToken); break; case CompletionPart.MembersCompleted: this.GlobalNamespace.ForceComplete(locationOpt, cancellationToken); if (this.GlobalNamespace.HasComplete(CompletionPart.MembersCompleted)) { _state.NotePartComplete(CompletionPart.MembersCompleted); } else { Debug.Assert(locationOpt != null, "If no location was specified, then the namespace members should be completed"); return; } break; case CompletionPart.None: return; default: // any other values are completion parts intended for other kinds of symbols _state.NotePartComplete(incompletePart); break; } _state.SpinWaitComplete(incompletePart, cancellationToken); } }
public void TestNextCompletionPart() { SymbolCompletionState state = new SymbolCompletionState(); Action reader = () => { while (state.IncompleteParts != 0) { Assert.True(SymbolCompletionState.HasAtMostOneBitSet((int)state.NextIncompletePart)); } }; Action writers = () => { Parallel.For(0, Math.Max(1, Environment.ProcessorCount - 1), t => { Random r = new Random(t); while (state.IncompleteParts != 0) { CompletionPart part = (CompletionPart)(1 << r.Next(8 * sizeof(CompletionPart))); state.NotePartComplete(part); } }); }; for (int i = 0; i < 1000; i++) { Parallel.Invoke(reader, writers); } }