public override void VisitComponent(ComponentIntermediateNode node) { for (var i = 0; i < node.Children.Count; i++) { // Note that we don't handle ChildContent cases here. Those have their own pass for diagnostics. if (node.Children[i] is ComponentAttributeIntermediateNode attribute && attribute.AttributeName != null) { if (_attributes.TryGetValue(attribute.AttributeName, out var other)) { // As a special case we want to point it out explicitly where a directive or other construct // has emitted an attribute that causes a conflict. We're already looking at the lowered version // of this construct, so it's easy to detect. We just need the original name to report the issue. // // Example: `bind-Value` will set `Value` and `ValueChanged`. var originalAttributeName = attribute.Annotations[ComponentMetadata.Common.OriginalAttributeName] as string ?? other.node.Annotations[ComponentMetadata.Common.OriginalAttributeName] as string; if (originalAttributeName != null) { other.node.Diagnostics.Add(ComponentDiagnosticFactory.Create_DuplicateComponentParameterDirective( other.name, originalAttributeName, other.node.Source ?? node.Source)); } else { // This is a conflict in the code the user wrote. other.node.Diagnostics.Add(ComponentDiagnosticFactory.Create_DuplicateComponentParameter( other.name, other.node.Source ?? node.Source)); } } // Replace the attribute we were previously tracking. Then if you have three, the two on the left will have // diagnostics. _attributes[attribute.AttributeName] = (attribute.AttributeName, attribute); } } _attributes.Clear(); base.VisitComponent(node); }