/// <summary> /// Bind an XmlNameAttributeSyntax and update the sets of documented parameters and type parameters. /// </summary> /// <remarks> /// Does not respect DocumentationMode, so do not call unless diagnostics are desired. /// </remarks> private static void BindName( XmlNameAttributeSyntax syntax, Binder binder, Symbol memberSymbol, ref HashSet<ParameterSymbol> documentedParameters, ref HashSet<TypeParameterSymbol> documentedTypeParameters, DiagnosticBag diagnostics) { XmlNameAttributeElementKind elementKind = syntax.GetElementKind(); // NOTE: We want the corresponding hash set to be non-null if we saw // any <param>/<typeparam> elements, even if they didn't bind (for // WRN_MissingParamTag and WRN_MissingTypeParamTag). if (elementKind == XmlNameAttributeElementKind.Parameter) { if (documentedParameters == null) { documentedParameters = new HashSet<ParameterSymbol>(); } } else if (elementKind == XmlNameAttributeElementKind.TypeParameter) { if (documentedTypeParameters == null) { documentedTypeParameters = new HashSet<TypeParameterSymbol>(); } } IdentifierNameSyntax identifier = syntax.Identifier; if (identifier.ContainsDiagnostics) { return; } HashSet<DiagnosticInfo> useSiteDiagnostics = null; ImmutableArray<Symbol> referencedSymbols = binder.BindXmlNameAttribute(syntax, ref useSiteDiagnostics); diagnostics.Add(syntax, useSiteDiagnostics); if (referencedSymbols.IsEmpty) { switch (elementKind) { case XmlNameAttributeElementKind.Parameter: diagnostics.Add(ErrorCode.WRN_UnmatchedParamTag, identifier.Location, identifier); break; case XmlNameAttributeElementKind.ParameterReference: diagnostics.Add(ErrorCode.WRN_UnmatchedParamRefTag, identifier.Location, identifier, memberSymbol); break; case XmlNameAttributeElementKind.TypeParameter: diagnostics.Add(ErrorCode.WRN_UnmatchedTypeParamTag, identifier.Location, identifier); break; case XmlNameAttributeElementKind.TypeParameterReference: diagnostics.Add(ErrorCode.WRN_UnmatchedTypeParamRefTag, identifier.Location, identifier, memberSymbol); break; default: Debug.Assert(false, "Unknown element kind " + syntax.GetElementKind()); break; } } else { foreach (Symbol referencedSymbol in referencedSymbols) { if (elementKind == XmlNameAttributeElementKind.Parameter) { Debug.Assert(referencedSymbol.Kind == SymbolKind.Parameter); Debug.Assert(documentedParameters != null); // Restriction preserved from dev11: don't report this for the "value" parameter. // Here, we detect that case by checking the containing symbol - only "value" // parameters are contained by accessors, others are on the corresponding property/event. ParameterSymbol parameter = (ParameterSymbol)referencedSymbol; if (!parameter.ContainingSymbol.IsAccessor() && !documentedParameters.Add(parameter)) { diagnostics.Add(ErrorCode.WRN_DuplicateParamTag, syntax.Location, identifier); } } else if (elementKind == XmlNameAttributeElementKind.TypeParameter) { Debug.Assert(referencedSymbol.Kind == SymbolKind.TypeParameter); Debug.Assert(documentedTypeParameters != null); if (!documentedTypeParameters.Add((TypeParameterSymbol)referencedSymbol)) { diagnostics.Add(ErrorCode.WRN_DuplicateTypeParamTag, syntax.Location, identifier); } } } } }