/// <summary> /// Method to merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target. /// This is the first step in attribute binding. /// </summary> /// <remarks> /// This method can generate diagnostics for few cases where we have an invalid target specifier and the parser hasn't generated the necessary diagnostics. /// It should not perform any bind operations as it can lead to an attribute binding cycle. /// </remarks> private ImmutableArray <AttributeSyntax> GetAttributesToBind( OneOrMany <SyntaxList <AttributeListSyntax> > attributeDeclarationSyntaxLists, AttributeLocation symbolPart, DiagnosticBag diagnostics, CSharpCompilation compilation, Binder rootBinderOpt, out ImmutableArray <Binder> binders) { var attributeTarget = (IAttributeTargetSymbol)this; ArrayBuilder <AttributeSyntax> syntaxBuilder = null; ArrayBuilder <Binder> bindersBuilder = null; int attributesToBindCount = 0; for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++) { var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex]; if (attributeDeclarationSyntaxList.Any()) { int prevCount = attributesToBindCount; foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList) { // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation. if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics)) { if (syntaxBuilder == null) { syntaxBuilder = new ArrayBuilder <AttributeSyntax>(); bindersBuilder = new ArrayBuilder <Binder>(); } var attributesToBind = attributeDeclarationSyntax.Attributes; syntaxBuilder.AddRange(attributesToBind); attributesToBindCount += attributesToBind.Count; } } if (attributesToBindCount != prevCount) { Debug.Assert(attributeDeclarationSyntaxList.Node != null); Debug.Assert(bindersBuilder != null); var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree; var binder = rootBinderOpt ?? compilation.GetBinderFactory(syntaxTree).GetBinder((CSharpSyntaxNode)attributeDeclarationSyntaxList.Node); binder = new ContextualAttributeBinder(binder, this); Debug.Assert(!binder.InAttributeArgument, "Possible cycle in attribute binding"); for (int i = 0; i < attributesToBindCount - prevCount; i++) { bindersBuilder.Add(binder); } } } } if (syntaxBuilder != null) { binders = bindersBuilder.ToImmutableAndFree(); return(syntaxBuilder.ToImmutableAndFree()); } else { binders = ImmutableArray <Binder> .Empty; return(ImmutableArray <AttributeSyntax> .Empty); } }
/// <summary> /// Method to merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target. /// This is the first step in attribute binding. /// </summary> /// <remarks> /// This method can generate diagnostics for few cases where we have an invalid target specifier and the parser hasn't generated the necessary diagnostics. /// It should not perform any bind operations as it can lead to an attribute binding cycle. /// </remarks> private ImmutableArray<AttributeSyntax> GetAttributesToBind( OneOrMany<SyntaxList<AttributeListSyntax>> attributeDeclarationSyntaxLists, AttributeLocation symbolPart, DiagnosticBag diagnostics, CSharpCompilation compilation, out ImmutableArray<Binder> binders) { var attributeTarget = (IAttributeTargetSymbol)this; ArrayBuilder<AttributeSyntax> syntaxBuilder = null; ArrayBuilder<Binder> bindersBuilder = null; int attributesToBindCount = 0; for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++) { var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex]; if (attributeDeclarationSyntaxList.Any()) { int prevCount = attributesToBindCount; foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList) { // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation. if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics)) { if (syntaxBuilder == null) { syntaxBuilder = new ArrayBuilder<AttributeSyntax>(); bindersBuilder = new ArrayBuilder<Binder>(); } var attributesToBind = attributeDeclarationSyntax.Attributes; syntaxBuilder.AddRange(attributesToBind); attributesToBindCount += attributesToBind.Count; } } if (attributesToBindCount != prevCount) { Debug.Assert(attributeDeclarationSyntaxList.Node != null); Debug.Assert(bindersBuilder != null); var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree; var binder = compilation.GetBinderFactory(syntaxTree).GetBinder((CSharpSyntaxNode)attributeDeclarationSyntaxList.Node); binder = new ContextualAttributeBinder(binder, this); Debug.Assert(!binder.InAttributeArgument, "Possible cycle in attribute binding"); for (int i = 0; i < attributesToBindCount - prevCount; i++) { bindersBuilder.Add(binder); } } } } if (syntaxBuilder != null) { binders = bindersBuilder.ToImmutableAndFree(); return syntaxBuilder.ToImmutableAndFree(); } else { binders = ImmutableArray<Binder>.Empty; return ImmutableArray<AttributeSyntax>.Empty; } }
private ImmutableArray <AttributeSyntax> GetAttributesToBind( OneOrMany <SyntaxList <AttributeListSyntax> > attributeDeclarationSyntaxLists, AttributeLocation symbolPart, BindingDiagnosticBag diagnostics, CSharpCompilation compilation, Func <AttributeSyntax, bool> attributeMatchesOpt, Binder rootBinderOpt, out ImmutableArray <Binder> binders) { var attributeTarget = (IAttributeTargetSymbol)this; ArrayBuilder <AttributeSyntax> syntaxBuilder = null; ArrayBuilder <Binder> bindersBuilder = null; int attributesToBindCount = 0; for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++) { var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex]; if (attributeDeclarationSyntaxList.Any()) { int prevCount = attributesToBindCount; foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList) { // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation. if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics)) { if (syntaxBuilder == null) { syntaxBuilder = new ArrayBuilder <AttributeSyntax>(); bindersBuilder = new ArrayBuilder <Binder>(); } var attributesToBind = attributeDeclarationSyntax.Attributes; if (attributeMatchesOpt is null) { syntaxBuilder.AddRange(attributesToBind); attributesToBindCount += attributesToBind.Count; } else { foreach (var attribute in attributesToBind) { if (attributeMatchesOpt(attribute)) { syntaxBuilder.Add(attribute); attributesToBindCount++; } } } } } if (attributesToBindCount != prevCount) { Debug.Assert(attributeDeclarationSyntaxList.Node != null); Debug.Assert(bindersBuilder != null); var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree; var binder = rootBinderOpt ?? compilation.GetBinderFactory(syntaxTree).GetBinder(attributeDeclarationSyntaxList.Node); binder = new ContextualAttributeBinder(binder, this); Debug.Assert(!binder.InAttributeArgument || this is MethodSymbol { MethodKind: MethodKind.LambdaMethod }, "Possible cycle in attribute binding");