private static void AnalyzeTypeArguments( SyntaxNodeAnalysisContext ctx, AnnotationsContext annotationsContext, ImmutabilityContext immutabilityContext, SimpleNameSyntax syntax ) { if (syntax.IsFromDocComment()) { // ignore things in doccomments such as crefs return; } SymbolInfo info = ctx.SemanticModel.GetSymbolInfo(syntax, ctx.CancellationToken); // Ignore anything that cannot have type arguments/parameters if (!GetTypeParamsAndArgs(info.Symbol, out var typeParameters, out var typeArguments)) { return; } int i = 0; var paramArgPairs = typeParameters.Zip(typeArguments, (p, a) => (p, a, i++)); foreach (var(parameter, argument, position) in paramArgPairs) { // TODO: this should eventually use information from ImmutableTypeInfo // however the current information about immutable type parameters // includes [Immutable] filling for what will instead be the upcoming // [OnlyIf] (e.g. it would be broken for IEnumerable<>) if (!annotationsContext.Objects.Immutable.IsDefined(parameter)) { continue; } if (!immutabilityContext.IsImmutable( new ImmutabilityQuery( ImmutableTypeKind.Total, argument ), // If the syntax is a GenericName (has explicit type arguments) then the error should be on the argument // Otherwise, it should be on the identifier itself getLocation: () => syntax is GenericNameSyntax genericSyntax ? genericSyntax.TypeArgumentList.Arguments[position].GetLocation() : syntax.Identifier.GetLocation(), out Diagnostic diagnostic )) { // TODO: not necessarily a good diagnostic for this use-case ctx.ReportDiagnostic(diagnostic); } } }