public override void Initialize(AnalysisContext analysisContext) { analysisContext.RegisterCompilationStartAction( (context) => { var eventHandler = WellKnownTypes.EventHandler(context.Compilation); if (eventHandler == null) { return; } var genericEventHandler = WellKnownTypes.GenericEventHandler(context.Compilation); if (genericEventHandler == null) { return; } var eventArgs = WellKnownTypes.EventArgs(context.Compilation); if (eventArgs == null) { return; } var comSourceInterfacesAttribute = WellKnownTypes.ComSourceInterfaceAttribute(context.Compilation); if (comSourceInterfacesAttribute == null) { return; } context.RegisterSymbolAction(GetAnalyzer(context.Compilation, eventHandler, genericEventHandler, eventArgs, comSourceInterfacesAttribute).AnalyzeSymbol, SymbolKind.Event); }); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( (context) => { INamedTypeSymbol eventHandler = WellKnownTypes.EventHandler(context.Compilation); if (eventHandler == null) { return; } INamedTypeSymbol genericEventHandler = WellKnownTypes.GenericEventHandler(context.Compilation); if (genericEventHandler == null) { return; } INamedTypeSymbol eventArgs = WellKnownTypes.EventArgs(context.Compilation); if (eventArgs == null) { return; } INamedTypeSymbol comSourceInterfacesAttribute = WellKnownTypes.ComSourceInterfaceAttribute(context.Compilation); if (comSourceInterfacesAttribute == null) { return; } context.RegisterSymbolAction(GetAnalyzer(context.Compilation, eventHandler, genericEventHandler, eventArgs, comSourceInterfacesAttribute).AnalyzeSymbol, SymbolKind.Event); }); }
public ICompilationEndedAnalyzer OnCompilationStarted(Compilation compilation, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var eventHandler = WellKnownTypes.EventHandler(compilation); if (eventHandler == null) { return(null); } var genericEventHandler = WellKnownTypes.GenericEventHandler(compilation); if (genericEventHandler == null) { return(null); } var eventArgs = WellKnownTypes.EventArgs(compilation); if (eventArgs == null) { return(null); } var comSourceInterfacesAttribute = WellKnownTypes.ComSourceInterfaceAttribute(compilation); if (comSourceInterfacesAttribute == null) { return(null); } return(GetAnalyzer(compilation, eventHandler, genericEventHandler, eventArgs, comSourceInterfacesAttribute)); }
private static bool IsEventArgs(ITypeSymbol type, Compilation compilation) { if (type.DerivesFrom(WellKnownTypes.EventArgs(compilation))) { return(true); } if (type.IsValueType) { return(type.Name.EndsWith("EventArgs", StringComparison.Ordinal)); } return(false); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( (context) => { INamedTypeSymbol eventArgs = WellKnownTypes.EventArgs(context.Compilation); if (eventArgs == null) { return; } // Only analyze compilations that have a generic event handler defined. if (WellKnownTypes.GenericEventHandler(context.Compilation) == null) { return; }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( (context) => { INamedTypeSymbol eventArgs = WellKnownTypes.EventArgs(context.Compilation); if (eventArgs == null) { return; } // Only analyze compilations that have a generic event handler defined. if (WellKnownTypes.GenericEventHandler(context.Compilation) == null) { return; } bool IsDelegateTypeWithInvokeMethod(INamedTypeSymbol namedType) => namedType.TypeKind == TypeKind.Delegate && namedType.DelegateInvokeMethod != null; bool IsEventArgsParameter(IParameterSymbol parameter) { var type = parameter.Type; if (IsAssignableTo(context.Compilation, type, eventArgs)) { return(true); } // FxCop compat: Struct with name ending with "EventArgs" are allowed. if (type.IsValueType) { return(type.Name.EndsWith("EventArgs", StringComparison.Ordinal)); } return(false); } bool IsValidNonGenericEventHandler(IMethodSymbol delegateInvokeMethod) { Debug.Assert(delegateInvokeMethod != null); return(delegateInvokeMethod.ReturnsVoid && delegateInvokeMethod.Parameters.Length == 2 && delegateInvokeMethod.Parameters[0].Type.SpecialType == SpecialType.System_Object && IsEventArgsParameter(delegateInvokeMethod.Parameters[1])); } context.RegisterSymbolAction(symbolContext => { // Note all the descriptors/rules for this analyzer have the same ID and category and hence // will always have identical configured visibility. var namedType = (INamedTypeSymbol)symbolContext.Symbol; if (namedType.MatchesConfiguredVisibility(symbolContext.Options, RuleForDelegates, symbolContext.CancellationToken) && IsDelegateTypeWithInvokeMethod(namedType) && IsValidNonGenericEventHandler(namedType.DelegateInvokeMethod)) { // CA1003: Remove '{0}' and replace its usage with a generic EventHandler, for e.g. EventHandler<T>, where T is a valid EventArgs symbolContext.ReportDiagnostic(namedType.CreateDiagnostic(RuleForDelegates, namedType.Name)); } }, SymbolKind.NamedType); INamedTypeSymbol comSourceInterfacesAttribute = WellKnownTypes.ComSourceInterfaceAttribute(context.Compilation); bool ContainingTypeHasComSourceInterfacesAttribute(IEventSymbol eventSymbol) => comSourceInterfacesAttribute != null && eventSymbol.ContainingType.GetAttributes().Any(a => Equals(a.AttributeClass, comSourceInterfacesAttribute)); context.RegisterSymbolAction(symbolContext => { // NOTE: Legacy FxCop reports CA1009 for delegate type that handles a public or protected event and does not have the correct signature, return type, or parameter names. // which recommends fixing the signature to use a valid non-generic event handler. // We do not report CA1009, but instead report CA1003 and recommend using a generic event handler. // Note all the descriptors/rules for this analyzer have the same ID and category and hence // will always have identical configured visibility. var eventSymbol = (IEventSymbol)symbolContext.Symbol; if (eventSymbol.MatchesConfiguredVisibility(symbolContext.Options, RuleForEvents, symbolContext.CancellationToken) && !eventSymbol.IsOverride && !eventSymbol.IsImplementationOfAnyInterfaceMember() && !ContainingTypeHasComSourceInterfacesAttribute(eventSymbol) && eventSymbol.Type is INamedTypeSymbol eventType && IsDelegateTypeWithInvokeMethod(eventType)) { if (eventType.IsImplicitlyDeclared) { // CA1003: Change the event '{0}' to use a generic EventHandler by defining the event type explicitly, for e.g. Event MyEvent As EventHandler(Of MyEventArgs). symbolContext.ReportDiagnostic(eventSymbol.CreateDiagnostic(RuleForEvents2, eventSymbol.Name)); } else if (!IsValidNonGenericEventHandler(eventType.DelegateInvokeMethod)) { // CA1003: Change the event '{0}' to replace the type '{1}' with a generic EventHandler, for e.g. EventHandler<T>, where T is a valid EventArgs symbolContext.ReportDiagnostic(eventSymbol.CreateDiagnostic(RuleForEvents, eventSymbol.Name, eventType.ToDisplayString())); } } }, SymbolKind.Event); }); }
private static void AnalyzeCompilationStart(CompilationStartAnalysisContext context) { var baseTypeSuffixMapBuilder = ImmutableDictionary.CreateBuilder <INamedTypeSymbol, SuffixInfo>(); var interfaceTypeSuffixMapBuilder = ImmutableDictionary.CreateBuilder <INamedTypeSymbol, SuffixInfo>(); foreach (var tuple in s_baseTypesAndTheirSuffix) { var wellKnownNamedType = context.Compilation.GetTypeByMetadataName(tuple.Item1); if (wellKnownNamedType != null && wellKnownNamedType.OriginalDefinition != null) { // If the type is interface if (wellKnownNamedType.OriginalDefinition.TypeKind == TypeKind.Interface) { interfaceTypeSuffixMapBuilder.Add(wellKnownNamedType.OriginalDefinition, SuffixInfo.Create(tuple.Item2, tuple.Item3)); } else { baseTypeSuffixMapBuilder.Add(wellKnownNamedType.OriginalDefinition, SuffixInfo.Create(tuple.Item2, tuple.Item3)); } } } if (baseTypeSuffixMapBuilder.Count > 0 || interfaceTypeSuffixMapBuilder.Count > 0) { var baseTypeSuffixMap = baseTypeSuffixMapBuilder.ToImmutable(); var interfaceTypeSuffixMap = interfaceTypeSuffixMapBuilder.ToImmutable(); context.RegisterSymbolAction((saContext) => { var namedTypeSymbol = (INamedTypeSymbol)saContext.Symbol; if (!namedTypeSymbol.MatchesConfiguredVisibility(saContext.Options, DefaultRule, saContext.CancellationToken)) { Debug.Assert(!namedTypeSymbol.MatchesConfiguredVisibility(saContext.Options, SpecialCollectionRule, saContext.CancellationToken)); return; } Debug.Assert(namedTypeSymbol.MatchesConfiguredVisibility(saContext.Options, SpecialCollectionRule, saContext.CancellationToken)); var baseType = namedTypeSymbol.GetBaseTypes().FirstOrDefault(bt => baseTypeSuffixMap.ContainsKey(bt.OriginalDefinition)); if (baseType != null) { var suffixInfo = baseTypeSuffixMap[baseType.OriginalDefinition]; // SpecialCollectionRule - Rename 'LastInFirstOut<T>' to end in either 'Collection' or 'Stack'. // DefaultRule - Rename 'MyStringObjectHashtable' to end in 'Dictionary'. var rule = suffixInfo.CanSuffixBeCollection ? SpecialCollectionRule : DefaultRule; if ((suffixInfo.CanSuffixBeCollection && !namedTypeSymbol.Name.EndsWith("Collection", StringComparison.Ordinal) && !namedTypeSymbol.Name.EndsWith(suffixInfo.Suffix, StringComparison.Ordinal)) || (!suffixInfo.CanSuffixBeCollection && !namedTypeSymbol.Name.EndsWith(suffixInfo.Suffix, StringComparison.Ordinal))) { saContext.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(rule, namedTypeSymbol.ToDisplayString(), suffixInfo.Suffix)); } return; } var implementedInterface = namedTypeSymbol.AllInterfaces.FirstOrDefault(i => interfaceTypeSuffixMap.ContainsKey(i.OriginalDefinition)); if (implementedInterface != null) { var suffixInfo = interfaceTypeSuffixMap[implementedInterface.OriginalDefinition]; if (!namedTypeSymbol.Name.EndsWith(suffixInfo.Suffix, StringComparison.Ordinal)) { saContext.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(DefaultRule, namedTypeSymbol.ToDisplayString(), suffixInfo.Suffix)); } } } , SymbolKind.NamedType); var eventArgsType = WellKnownTypes.EventArgs(context.Compilation); if (eventArgsType != null) { context.RegisterSymbolAction((saContext) => { const string eventHandlerString = "EventHandler"; var eventSymbol = (IEventSymbol)saContext.Symbol; if (!eventSymbol.Type.Name.EndsWith(eventHandlerString, StringComparison.Ordinal) && eventSymbol.Type.IsInSource() && eventSymbol.Type.TypeKind == TypeKind.Delegate && ((INamedTypeSymbol)eventSymbol.Type).DelegateInvokeMethod?.HasEventHandlerSignature(eventArgsType) == true) { saContext.ReportDiagnostic(eventSymbol.CreateDiagnostic(DefaultRule, eventSymbol.Type.Name, eventHandlerString)); } }, SymbolKind.Event); } } }