private static void AnalyzeMemberRule(SymbolAnalysisContext context) { ISymbol symbol = context.Symbol; if (!ShouldAnalyze(context, MemberRule)) { return; } if (!IsKeyword(symbol.Name, out string matchingKeyword)) { return; } // IsAbstract returns true for both abstract class members and interface members. if (symbol.IsVirtual || symbol.IsAbstract) { context.ReportDiagnostic( symbol.CreateDiagnostic( MemberRule, symbol.FormatMemberName(), matchingKeyword)); } }
private void AnalyzeMemberRule(SymbolAnalysisContext context) { ISymbol symbol = context.Symbol; if (symbol.GetResultantVisibility() != SymbolVisibility.Public) { return; } if (!IsKeyword(symbol.Name, out string matchingKeyword)) { return; } // IsAbstract returns true for both abstract class members and interface members. if (symbol.IsVirtual || symbol.IsAbstract) { context.ReportDiagnostic( symbol.CreateDiagnostic( MemberRule, symbol.FormatMemberName(), matchingKeyword)); } }
private void AnalyzeMemberRule(SymbolAnalysisContext context) { ISymbol symbol = context.Symbol; if (!symbol.MatchesConfiguredVisibility(context.Options, MemberRule, context.CancellationToken)) { return; } if (!IsKeyword(symbol.Name, out string matchingKeyword)) { return; } // IsAbstract returns true for both abstract class members and interface members. if (symbol.IsVirtual || symbol.IsAbstract) { context.ReportDiagnostic( symbol.CreateDiagnostic( MemberRule, symbol.FormatMemberName(), matchingKeyword)); } }
public void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; if (namedTypeSymbol.TypeKind is TypeKind.Delegate or TypeKind.Interface) { return; } var implementsISerializable = namedTypeSymbol.AllInterfaces.Contains(_iserializableTypeSymbol); var isSerializable = IsSerializable(namedTypeSymbol); // If the type is public and implements ISerializable if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Public && implementsISerializable) { if (!isSerializable) { // CA2237 : Mark serializable types with the SerializableAttribute if (namedTypeSymbol.BaseType.SpecialType == SpecialType.System_Object || IsSerializable(namedTypeSymbol.BaseType)) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2237, namedTypeSymbol.Name)); } } else { // Look for a serialization constructor. // A serialization constructor takes two params of type SerializationInfo and StreamingContext. IMethodSymbol serializationCtor = namedTypeSymbol.Constructors .FirstOrDefault(c => c.IsSerializationConstructor(_serializationInfoTypeSymbol, _streamingContextTypeSymbol)); // There is no serialization ctor - issue a diagnostic. if (serializationCtor == null) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2229Default, namedTypeSymbol.Name)); } else { // Check the accessibility // The serialization ctor should be protected if the class is unsealed and private if the class is sealed. if (namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Private) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229Sealed, namedTypeSymbol.Name)); } if (!namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Protected) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229Unsealed, namedTypeSymbol.Name)); } } } } // If this is type is marked Serializable and doesn't implement ISerializable, check its fields' types as well if (isSerializable && !implementsISerializable) { foreach (ISymbol member in namedTypeSymbol.GetMembers()) { // Only process field members if (member is not IFieldSymbol field) { continue; } // Only process instance fields if (field.IsStatic) { continue; } // Only process non-serializable fields if (IsSerializable(field.Type)) { continue; } // We bail out from reporting CA2235 in netstandard assemblies for types in metadata // due to missing support: https://github.com/dotnet/roslyn-analyzers/issues/1775#issuecomment-519686818 if (_isNetStandardAssembly && field.Type.Locations.All(l => !l.IsInSource)) { continue; } // Check for [NonSerialized] if (field.GetAttributes().Any(x => x.AttributeClass.Equals(_nonSerializedAttributeTypeSymbol))) { continue; } // Handle compiler-generated fields (without source declaration) that have an associated symbol in code. // For example, auto-property backing fields. ISymbol targetSymbol = field.IsImplicitlyDeclared && field.AssociatedSymbol != null ? field.AssociatedSymbol : field; context.ReportDiagnostic( targetSymbol.CreateDiagnostic( RuleCA2235, targetSymbol.Name, namedTypeSymbol.Name, field.Type)); } } }
public void AnalyzeCodeBlock(SyntaxNode codeBlock, ISymbol ownerSymbol, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) { if (IsEmptyFinalizer(codeBlock, semanticModel)) { addDiagnostic(ownerSymbol.CreateDiagnostic(Rule)); } }
public override void Initialize(AnalysisContext analysisContext) { // TODO: Consider making this analyzer thread-safe. //analysisContext.EnableConcurrentExecution(); // Don't report in generated code since that's not actionable. analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction(compilationContext => { // Since property/event accessors cannot be marked static themselves and the associated symbol (property/event) // has to be marked static, we want to report the diagnostic once on the property/event. So we make a note // of the associated symbols on which we've reported diagnostics for this compilation so that we don't duplicate // those. var reportedAssociatedSymbols = new HashSet <ISymbol>(); // For candidate methods that are not externally visible, we only report a diagnostic if they are actually invoked via a method call in the compilation. // This prevents us from incorrectly flagging methods that are only invoked via delegate invocations: https://github.com/dotnet/roslyn-analyzers/issues/1511 // and also reduces noise by not flagging dead code. var internalCandidates = new HashSet <IMethodSymbol>(); var invokedInternalMethods = new HashSet <IMethodSymbol>(); compilationContext.RegisterOperationBlockStartAction(blockStartContext => { var methodSymbol = blockStartContext.OwningSymbol as IMethodSymbol; if (methodSymbol == null || !ShouldAnalyze(methodSymbol, blockStartContext.Compilation)) { return; } bool isInstanceReferenced = false; blockStartContext.RegisterOperationAction(operationContext => { isInstanceReferenced = true; }, OperationKind.InstanceReference); blockStartContext.RegisterOperationBlockEndAction(blockEndContext => { if (!isInstanceReferenced) { ISymbol reportingSymbol = methodSymbol; var isAccessor = methodSymbol.IsPropertyAccessor() || methodSymbol.IsEventAccessor(); if (isAccessor) { // If we've already reported on this associated symbol (i.e property/event) then don't report again. if (reportedAssociatedSymbols.Contains(methodSymbol.AssociatedSymbol)) { return; } reportingSymbol = methodSymbol.AssociatedSymbol; reportedAssociatedSymbols.Add(reportingSymbol); } if (isAccessor || methodSymbol.IsExternallyVisible()) { blockEndContext.ReportDiagnostic(reportingSymbol.CreateDiagnostic(Rule, reportingSymbol.Name)); } else { internalCandidates.Add(methodSymbol); } } }); }); compilationContext.RegisterOperationAction(operationContext => { var invocation = (IInvocationOperation)operationContext.Operation; if (!invocation.TargetMethod.IsExternallyVisible()) { invokedInternalMethods.Add(invocation.TargetMethod); } }, OperationKind.Invocation); compilationContext.RegisterCompilationEndAction(compilationEndContext => { foreach (var candidate in internalCandidates) { if (invokedInternalMethods.Contains(candidate)) { compilationEndContext.ReportDiagnostic(candidate.CreateDiagnostic(Rule, candidate.Name)); } } }); }); }
public void AnalyzeSymbol(SymbolAnalysisContext context) { var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; if (namedTypeSymbol.TypeKind == TypeKind.Delegate || namedTypeSymbol.TypeKind == TypeKind.Interface) { return; } var implementsISerializable = namedTypeSymbol.AllInterfaces.Contains(_iserializableTypeSymbol); var isSerializable = IsSerializable(namedTypeSymbol); // If the type is public and implements ISerializable if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Public && implementsISerializable) { if (!isSerializable) { // CA2237 : Mark serializable types with the SerializableAttribute if (namedTypeSymbol.BaseType.SpecialType == SpecialType.System_Object || IsSerializable(namedTypeSymbol.BaseType)) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2237, namedTypeSymbol.Name)); } } else { // Look for a serialization constructor. // A serialization constructor takes two params of type SerializationInfo and StreamingContext. IMethodSymbol serializationCtor = namedTypeSymbol.Constructors .FirstOrDefault( c => c.Parameters.Length == 2 && c.Parameters[0].Type.Equals(_serializationInfoTypeSymbol) && c.Parameters[1].Type.Equals(_streamingContextTypeSymbol)); // There is no serialization ctor - issue a diagnostic. if (serializationCtor == null) { context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(RuleCA2229, string.Format(MicrosoftNetCoreAnalyzersResources.ImplementSerializationConstructorsMessageCreateMagicConstructor, namedTypeSymbol.Name))); } else { // Check the accessibility // The serialization ctor should be protected if the class is unsealed and private if the class is sealed. if (namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Private) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229, string.Format( MicrosoftNetCoreAnalyzersResources.ImplementSerializationConstructorsMessageMakeSealedMagicConstructorPrivate, namedTypeSymbol.Name))); } if (!namedTypeSymbol.IsSealed && serializationCtor.DeclaredAccessibility != Accessibility.Protected) { context.ReportDiagnostic(serializationCtor.CreateDiagnostic(RuleCA2229, string.Format( MicrosoftNetCoreAnalyzersResources.ImplementSerializationConstructorsMessageMakeUnsealedMagicConstructorFamily, namedTypeSymbol.Name))); } } } } // If this is type is marked Serializable and doesn't implement ISerializable, check its fields' types as well if (isSerializable && !implementsISerializable) { foreach (ISymbol member in namedTypeSymbol.GetMembers()) { // Only process field members if (!(member is IFieldSymbol field)) { continue; } // Only process instance fields if (field.IsStatic) { continue; } // Only process non-serializable fields if (IsSerializable(field.Type)) { continue; } // Check for [NonSerialized] if (field.GetAttributes().Any(x => x.AttributeClass.Equals(_nonSerializedAttributeTypeSymbol))) { continue; } // Handle compiler-generated fields (without source declaration) that have an associated symbol in code. // For example, auto-property backing fields. ISymbol targetSymbol = field.IsImplicitlyDeclared && field.AssociatedSymbol != null ? field.AssociatedSymbol : field; context.ReportDiagnostic( targetSymbol.CreateDiagnostic( RuleCA2235, targetSymbol.Name, namedTypeSymbol.Name, field.Type)); } } }
public void AnalyzeSymbol(ISymbol symbol, Compilation compilation, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var methodSymbol = (IMethodSymbol)symbol; if (methodSymbol == null) { return; } var dllImportData = methodSymbol.GetDllImportData(); if (dllImportData == null) { return; } var dllAttribute = methodSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(this.dllImportType)); var defaultLocation = dllAttribute == null?methodSymbol.Locations.FirstOrDefault() : GetAttributeLocation(dllAttribute); // CA1401 - PInvoke methods should not be visible if (methodSymbol.DeclaredAccessibility == Accessibility.Public || methodSymbol.DeclaredAccessibility == Accessibility.Protected) { addDiagnostic(symbol.CreateDiagnostic(RuleCA1401, methodSymbol.Name)); } // CA2101 - Specify marshalling for PInvoke string arguments if (dllImportData.BestFitMapping != false) { bool appliedCA2101ToMethod = false; foreach (var parameter in methodSymbol.Parameters) { if (parameter.Type.SpecialType == SpecialType.System_String || parameter.Type.Equals(this.stringBuilderType)) { var marshalAsAttribute = parameter.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(this.marshalAsType)); var charSet = marshalAsAttribute == null ? dllImportData.CharacterSet : MarshalingToCharSet(GetParameterMarshaling(marshalAsAttribute)); // only unicode marshaling is considered safe if (charSet != CharSet.Unicode) { if (marshalAsAttribute != null) { // track the diagnostic on the [MarshalAs] attribute var marshalAsLocation = GetAttributeLocation(marshalAsAttribute); addDiagnostic(marshalAsLocation.CreateDiagnostic(RuleCA2101)); } else if (!appliedCA2101ToMethod) { // track the diagnostic on the [DllImport] attribute appliedCA2101ToMethod = true; addDiagnostic(defaultLocation.CreateDiagnostic(RuleCA2101)); } } } } // only unicode marshaling is considered safe, but only check this if we haven't already flagged the attribute if (!appliedCA2101ToMethod && dllImportData.CharacterSet != CharSet.Unicode && (methodSymbol.ReturnType.SpecialType == SpecialType.System_String || methodSymbol.ReturnType.Equals(this.stringBuilderType))) { addDiagnostic(defaultLocation.CreateDiagnostic(RuleCA2101)); } } }
public void AnalyzeSymbol(ISymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var methodSymbol = (IMethodSymbol)symbol; if (methodSymbol == null) { return; } var dllImportData = methodSymbol.GetDllImportData(); if (dllImportData == null) { return; } var dllAttribute = methodSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(this.dllImportType)); var defaultLocation = dllAttribute == null ? methodSymbol.Locations.FirstOrDefault() : GetAttributeLocation(dllAttribute); // CA1401 - PInvoke methods should not be visible if (methodSymbol.DeclaredAccessibility == Accessibility.Public || methodSymbol.DeclaredAccessibility == Accessibility.Protected) { addDiagnostic(symbol.CreateDiagnostic(RuleCA1401, methodSymbol.Name)); } // CA2101 - Specify marshalling for PInvoke string arguments if (dllImportData.BestFitMapping != false) { bool appliedCA2101ToMethod = false; foreach (var parameter in methodSymbol.Parameters) { if (parameter.Type.SpecialType == SpecialType.System_String || parameter.Type.Equals(this.stringBuilderType)) { var marshalAsAttribute = parameter.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(this.marshalAsType)); var charSet = marshalAsAttribute == null ? dllImportData.CharacterSet : MarshalingToCharSet(GetParameterMarshaling(marshalAsAttribute)); // only unicode marshaling is considered safe if (charSet != CharSet.Unicode) { if (marshalAsAttribute != null) { // track the diagnostic on the [MarshalAs] attribute var marshalAsLocation = GetAttributeLocation(marshalAsAttribute); addDiagnostic(marshalAsLocation.CreateDiagnostic(RuleCA2101)); } else if (!appliedCA2101ToMethod) { // track the diagnostic on the [DllImport] attribute appliedCA2101ToMethod = true; addDiagnostic(defaultLocation.CreateDiagnostic(RuleCA2101)); } } } } // only unicode marshaling is considered safe, but only check this if we haven't already flagged the attribute if (!appliedCA2101ToMethod && dllImportData.CharacterSet != CharSet.Unicode && (methodSymbol.ReturnType.SpecialType == SpecialType.System_String || methodSymbol.ReturnType.Equals(this.stringBuilderType))) { addDiagnostic(defaultLocation.CreateDiagnostic(RuleCA2101)); } } }