private void HandleGenericNameSyntax(SyntaxNodeAnalysisContext context) { GenericNameSyntax genericNameSyntax = context.Node as GenericNameSyntax; if (genericNameSyntax == null) { return; } if (genericNameSyntax.Identifier.IsMissing || genericNameSyntax.Identifier.Text != "Nullable") { return; } // This covers the specific forms in an XML comment which cannot be simplified if (genericNameSyntax.Parent is NameMemberCrefSyntax) { // cref="Nullable{T}" return; } else if (genericNameSyntax.Parent is QualifiedCrefSyntax) { // cref="Nullable{T}.Value" return; } else if (genericNameSyntax.Parent is QualifiedNameSyntax && genericNameSyntax.Parent.Parent is QualifiedCrefSyntax) { // cref="System.Nullable{T}.Value" return; } // The shorthand syntax is not available in using directives (covers standard, alias, and static) if (genericNameSyntax.FirstAncestorOrSelf <UsingDirectiveSyntax>() != null) { return; } // This covers special cases of static and instance member access through the type name. It also covers most // special cases for the `nameof` expression. if (genericNameSyntax.Parent is MemberAccessExpressionSyntax) { return; } // This covers the special case of `nameof(Nullable<int>)` if (genericNameSyntax.Parent is ArgumentSyntax) { return; } SemanticModel semanticModel = context.SemanticModel; INamedTypeSymbol symbol = semanticModel.GetSymbolInfo(genericNameSyntax, context.CancellationToken).Symbol as INamedTypeSymbol; if (symbol?.OriginalDefinition?.SpecialType != SpecialType.System_Nullable_T) { return; } if (symbol.IsUnboundGenericType) { // There is never a shorthand syntax for the open generic Nullable<> return; } SyntaxNode locationNode = genericNameSyntax; if (genericNameSyntax.Parent is QualifiedNameSyntax) { locationNode = genericNameSyntax.Parent; } // Use shorthand for nullable types context.ReportDiagnostic(Diagnostic.Create(Descriptor, locationNode.GetLocation())); }