예제 #1
0
        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);
            });
        }
예제 #2
0
        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);
            });
        }
예제 #3
0
        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);
        }
예제 #5
0
        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&lt;T&gt;, 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&lt;T&gt;, 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);
                }
            }
        }