private static bool IsSystemConsoleInvocation( SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocationSyntax) { // Get the method member access (Console.WriteLine or Console.Error.WriteLine) if (!(invocationSyntax.Expression is MemberAccessExpressionSyntax memberAccessSyntax)) { return(false); } // Get the semantic model for the invoked method if (!(context.SemanticModel.GetSymbolInfo(memberAccessSyntax).Symbol is IMethodSymbol methodSymbol)) { return(false); } // Check if contained within System.Console if (KnownSymbols.IsSystemConsole(methodSymbol.ContainingType)) { return(true); } // In case with Console.Error.WriteLine that wouldn't work, we need to check parent member access too if (!(memberAccessSyntax.Expression is MemberAccessExpressionSyntax parentMemberAccessSyntax)) { return(false); } // Get the semantic model for the parent member if (!(context.SemanticModel.GetSymbolInfo(parentMemberAccessSyntax).Symbol is IPropertySymbol propertySymbol)) { return(false); } // Check if contained within System.Console if (KnownSymbols.IsSystemConsole(propertySymbol.ContainingType)) { return(true); } return(false); }
private static bool IsSystemConsoleInvocation( SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocationSyntax) { if (invocationSyntax.Expression is MemberAccessExpressionSyntax memberAccessSyntax && context.SemanticModel.GetSymbolInfo(memberAccessSyntax).Symbol is IMethodSymbol methodSymbol) { // Direct call to System.Console (e.g. System.Console.WriteLine()) if (KnownSymbols.IsSystemConsole(methodSymbol.ContainingType)) { return(true); } // Indirect call to System.Console (e.g. System.Console.Error.WriteLine()) if (memberAccessSyntax.Expression is MemberAccessExpressionSyntax parentMemberAccessSyntax && context.SemanticModel.GetSymbolInfo(parentMemberAccessSyntax).Symbol is IPropertySymbol propertySymbol) { return(KnownSymbols.IsSystemConsole(propertySymbol.ContainingType)); } } return(false); }
private static void CheckCommandParameterProperties( SymbolAnalysisContext context, IReadOnlyList <IPropertySymbol> properties) { var parameters = properties .Select(p => { var attribute = p .GetAttributes() .First(a => KnownSymbols.IsCommandParameterAttribute(a.AttributeClass)); var order = attribute .ConstructorArguments .Select(a => a.Value) .FirstOrDefault() as int?; var name = attribute .NamedArguments .Where(a => a.Key == "Name") .Select(a => a.Value.Value) .FirstOrDefault() as string; var converter = attribute .NamedArguments .Where(a => a.Key == "Converter") .Select(a => a.Value.Value) .Cast <ITypeSymbol?>() .FirstOrDefault(); var validators = attribute .NamedArguments .Where(a => a.Key == "Validators") .SelectMany(a => a.Value.Values) .Select(c => c.Value) .Cast <ITypeSymbol>() .ToArray(); return(new { Property = p, Order = order, Name = name, Converter = converter, Validators = validators }); }) .ToArray(); // Duplicate order var duplicateOrderParameters = parameters .Where(p => p.Order != null) .GroupBy(p => p.Order) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var parameter in duplicateOrderParameters) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0021, parameter.Property.Locations.First() )); } // Duplicate name var duplicateNameParameters = parameters .Where(p => !string.IsNullOrWhiteSpace(p.Name)) .GroupBy(p => p.Name, StringComparer.OrdinalIgnoreCase) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var parameter in duplicateNameParameters) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0022, parameter.Property.Locations.First() )); } // Multiple non-scalar var nonScalarParameters = parameters .Where(p => !IsScalarType(p.Property.Type)) .ToArray(); if (nonScalarParameters.Length > 1) { foreach (var parameter in nonScalarParameters) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0023, parameter.Property.Locations.First() )); } } // Non-last non-scalar var nonLastNonScalarParameter = parameters .OrderByDescending(a => a.Order) .Skip(1) .LastOrDefault(p => !IsScalarType(p.Property.Type)); if (nonLastNonScalarParameter != null) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0024, nonLastNonScalarParameter.Property.Locations.First() )); } // Invalid converter var invalidConverterParameters = parameters .Where(p => p.Converter != null && !p.Converter.AllInterfaces.Any(KnownSymbols.IsArgumentValueConverterInterface)) .ToArray(); foreach (var parameter in invalidConverterParameters) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0025, parameter.Property.Locations.First() )); } // Invalid validators var invalidValidatorsParameters = parameters .Where(p => !p.Validators.All(v => v.AllInterfaces.Any(KnownSymbols.IsArgumentValueValidatorInterface))) .ToArray(); foreach (var parameter in invalidValidatorsParameters) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0026, parameter.Property.Locations.First() )); } }
private static bool IsScalarType(ITypeSymbol typeSymbol) => KnownSymbols.IsSystemString(typeSymbol) || !typeSymbol.AllInterfaces.Select(i => i.ConstructedFrom) .Any(KnownSymbols.IsSystemCollectionsGenericIEnumerable);
private static void CheckCommandOptionProperties( SymbolAnalysisContext context, IReadOnlyList <IPropertySymbol> properties) { var options = properties .Select(p => { var attribute = p .GetAttributes() .First(a => KnownSymbols.IsCommandOptionAttribute(a.AttributeClass)); var name = attribute .ConstructorArguments .Where(a => KnownSymbols.IsSystemString(a.Type)) .Select(a => a.Value) .FirstOrDefault() as string; var shortName = attribute .ConstructorArguments .Where(a => KnownSymbols.IsSystemChar(a.Type)) .Select(a => a.Value) .FirstOrDefault() as char?; var envVarName = attribute .NamedArguments .Where(a => a.Key == "EnvironmentVariableName") .Select(a => a.Value.Value) .FirstOrDefault() as string; var converter = attribute .NamedArguments .Where(a => a.Key == "Converter") .Select(a => a.Value.Value) .Cast <ITypeSymbol>() .FirstOrDefault(); var validators = attribute .NamedArguments .Where(a => a.Key == "Validators") .SelectMany(a => a.Value.Values) .Select(c => c.Value) .Cast <ITypeSymbol>() .ToArray(); return(new { Property = p, Name = name, ShortName = shortName, EnvironmentVariableName = envVarName, Converter = converter, Validators = validators }); }) .ToArray(); // No name var noNameOptions = options .Where(o => string.IsNullOrWhiteSpace(o.Name) && o.ShortName == null) .ToArray(); foreach (var option in noNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0041, option.Property.Locations.First() )); } // Too short name var invalidNameLengthOptions = options .Where(o => !string.IsNullOrWhiteSpace(o.Name) && o.Name.Length <= 1) .ToArray(); foreach (var option in invalidNameLengthOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0042, option.Property.Locations.First() )); } // Duplicate name var duplicateNameOptions = options .Where(p => !string.IsNullOrWhiteSpace(p.Name)) .GroupBy(p => p.Name, StringComparer.OrdinalIgnoreCase) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0043, option.Property.Locations.First() )); } // Duplicate name var duplicateShortNameOptions = options .Where(p => p.ShortName != null) .GroupBy(p => p.ShortName) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateShortNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0044, option.Property.Locations.First() )); } // Duplicate environment variable name var duplicateEnvironmentVariableNameOptions = options .Where(p => !string.IsNullOrWhiteSpace(p.EnvironmentVariableName)) .GroupBy(p => p.EnvironmentVariableName, StringComparer.Ordinal) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateEnvironmentVariableNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0045, option.Property.Locations.First() )); } // Invalid converter var invalidConverterOptions = options .Where(o => o.Converter != null && !o.Converter.AllInterfaces.Any(KnownSymbols.IsArgumentValueConverterInterface)) .ToArray(); foreach (var option in invalidConverterOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0046, option.Property.Locations.First() )); } // Invalid validators var invalidValidatorsOptions = options .Where(o => !o.Validators.All(v => v.AllInterfaces.Any(KnownSymbols.IsArgumentValueValidatorInterface))) .ToArray(); foreach (var option in invalidValidatorsOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0047, option.Property.Locations.First() )); } // Non-letter first character in name var nonLetterFirstCharacterInNameOptions = options .Where(o => !string.IsNullOrWhiteSpace(o.Name) && !char.IsLetter(o.Name[0])) .ToArray(); foreach (var option in nonLetterFirstCharacterInNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0048, option.Property.Locations.First() )); } // Non-letter short name var nonLetterShortNameOptions = options .Where(o => o.ShortName != null && !char.IsLetter(o.ShortName.Value)) .ToArray(); foreach (var option in nonLetterShortNameOptions) { context.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.CliFx0049, option.Property.Locations.First() )); } }
private static void CheckCommandOptionProperties( SymbolAnalysisContext context, IReadOnlyList <IPropertySymbol> properties) { var options = properties .Select(p => { var attribute = p .GetAttributes() .First(a => KnownSymbols.IsCommandOptionAttribute(a.AttributeClass)); var name = attribute .ConstructorArguments .Where(a => KnownSymbols.IsSystemString(a.Type)) .Select(a => a.Value) .FirstOrDefault() as string; var shortName = attribute .ConstructorArguments .Where(a => KnownSymbols.IsSystemChar(a.Type)) .Select(a => a.Value) .FirstOrDefault() as char?; var envVarName = attribute .NamedArguments .Where(a => a.Key == "EnvironmentVariableName") .Select(a => a.Value.Value) .FirstOrDefault() as string; return(new { Property = p, Name = name, ShortName = shortName, EnvironmentVariableName = envVarName }); }) .ToArray(); // No name var noNameOptions = options .Where(o => string.IsNullOrWhiteSpace(o.Name) && o.ShortName == null) .ToArray(); foreach (var option in noNameOptions) { context.ReportDiagnostic( Diagnostic.Create(DiagnosticDescriptors.CliFx0041, option.Property.Locations.First())); } // Too short name var invalidNameLengthOptions = options .Where(o => !string.IsNullOrWhiteSpace(o.Name) && o.Name.Length <= 1) .ToArray(); foreach (var option in invalidNameLengthOptions) { context.ReportDiagnostic( Diagnostic.Create(DiagnosticDescriptors.CliFx0042, option.Property.Locations.First())); } // Duplicate name var duplicateNameOptions = options .Where(p => !string.IsNullOrWhiteSpace(p.Name)) .GroupBy(p => p.Name, StringComparer.OrdinalIgnoreCase) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateNameOptions) { context.ReportDiagnostic( Diagnostic.Create(DiagnosticDescriptors.CliFx0043, option.Property.Locations.First())); } // Duplicate name var duplicateShortNameOptions = options .Where(p => p.ShortName != null) .GroupBy(p => p.ShortName) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateShortNameOptions) { context.ReportDiagnostic( Diagnostic.Create(DiagnosticDescriptors.CliFx0044, option.Property.Locations.First())); } // Duplicate environment variable name var duplicateEnvironmentVariableNameOptions = options .Where(p => !string.IsNullOrWhiteSpace(p.EnvironmentVariableName)) .GroupBy(p => p.EnvironmentVariableName, StringComparer.Ordinal) .Where(g => g.Count() > 1) .SelectMany(g => g.AsEnumerable()) .ToArray(); foreach (var option in duplicateEnvironmentVariableNameOptions) { context.ReportDiagnostic( Diagnostic.Create(DiagnosticDescriptors.CliFx0045, option.Property.Locations.First())); } }