public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.RegisterCompilationStartAction(
                compilationStartAnalysisContext =>
            {
                Compilation compilation = compilationStartAnalysisContext.Compilation;

                INamedTypeSymbol[] nativeResourceTypes = new[]
                {
                    WellKnownTypes.IntPtr(compilation),
                    WellKnownTypes.UIntPtr(compilation),
                    WellKnownTypes.HandleRef(compilation)
                };

                compilationStartAnalysisContext.RegisterOperationAction(
                    operationAnalysisContext =>
                {
                    var assignment = (IAssignmentExpression)operationAnalysisContext.Operation;

                    IOperation target = assignment.Target;
                    if (target == null)
                    {
                        // This can happen if the left-hand side is an undefined symbol.
                        return;
                    }

                    if (target.Kind != OperationKind.FieldReferenceExpression)
                    {
                        return;
                    }

                    var fieldReference = (IFieldReferenceExpression)target;
                    var field          = fieldReference.Member as IFieldSymbol;
                    if (field == null || field.Kind != SymbolKind.Field || field.IsStatic)
                    {
                        return;
                    }

                    if (!nativeResourceTypes.Contains(field.Type))
                    {
                        return;
                    }

                    INamedTypeSymbol containingType = field.ContainingType;
                    if (containingType == null || containingType.IsValueType)
                    {
                        return;
                    }

                    if (!containingType.AllInterfaces.Contains(WellKnownTypes.IDisposable(compilation)))
                    {
                        return;
                    }

                    if (containingType.HasFinalizer())
                    {
                        return;
                    }

                    if (assignment.Value == null || assignment.Value.Kind != OperationKind.InvocationExpression)
                    {
                        return;
                    }

                    var invocation = (IInvocationExpression)assignment.Value;
                    if (invocation == null)
                    {
                        return;
                    }

                    IMethodSymbol method = invocation.TargetMethod;

                    // TODO: What about COM?
                    if (method.GetDllImportData() == null)
                    {
                        return;
                    }

                    operationAnalysisContext.ReportDiagnostic(containingType.CreateDiagnostic(Rule));
                },
                    OperationKind.AssignmentExpression);
            });
        }
        private async Task <Document> ImplementIDisposable(Document document, SyntaxNode declaration, CancellationToken cancellationToken)
        {
            DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            var generator = editor.Generator;
            var model     = editor.SemanticModel;

            // Add the interface to the baselist.
            var interfaceType = generator.TypeExpression(WellKnownTypes.IDisposable(model.Compilation));

            editor.AddInterfaceType(declaration, interfaceType);

            // Find a Dispose method. If one exists make that implement IDisposable, else generate a new method.
            var typeSymbol    = model.GetDeclaredSymbol(declaration) as INamedTypeSymbol;
            var disposeMethod = (typeSymbol?.GetMembers("Dispose"))?.OfType <IMethodSymbol>()?.Where(m => m.Parameters.Length == 0).FirstOrDefault();

            if (disposeMethod != null && disposeMethod.DeclaringSyntaxReferences.Length == 1)
            {
                var memberPartNode = await disposeMethod.DeclaringSyntaxReferences.Single().GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

                memberPartNode = generator.GetDeclaration(memberPartNode);
                editor.ReplaceNode(memberPartNode, generator.AsPublicInterfaceImplementation(memberPartNode, interfaceType));
            }
            else
            {
                var throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(WellKnownTypes.NotImplementedException(model.Compilation)));
                var member         = generator.MethodDeclaration(TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer.Dispose, statements: new[] { throwStatement });
                member = generator.AsPublicInterfaceImplementation(member, interfaceType);
                editor.AddMember(declaration, member);
            }

            return(editor.GetChangedDocument());
        }
Пример #3
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(csaContext =>
            {
                #region "Get All the WellKnown Types and Members"
                var iformatProviderType = csaContext.Compilation.GetTypeByMetadataName("System.IFormatProvider");
                var cultureInfoType     = csaContext.Compilation.GetTypeByMetadataName("System.Globalization.CultureInfo");
                if (iformatProviderType == null || cultureInfoType == null)
                {
                    return;
                }

                var objectType          = csaContext.Compilation.GetSpecialType(SpecialType.System_Object);
                var stringType          = csaContext.Compilation.GetSpecialType(SpecialType.System_String);
                var stringFormatMembers = stringType?.GetMembers("Format").OfType <IMethodSymbol>();

                var stringFormatMemberWithStringAndObjectParameter = stringFormatMembers.GetSingleOrDefaultMemberWithParameterInfos(
                    GetParameterInfo(stringType),
                    GetParameterInfo(objectType));
                var stringFormatMemberWithStringObjectAndObjectParameter = stringFormatMembers.GetSingleOrDefaultMemberWithParameterInfos(
                    GetParameterInfo(stringType),
                    GetParameterInfo(objectType),
                    GetParameterInfo(objectType));
                var stringFormatMemberWithStringObjectObjectAndObjectParameter = stringFormatMembers.GetSingleOrDefaultMemberWithParameterInfos(
                    GetParameterInfo(stringType),
                    GetParameterInfo(objectType),
                    GetParameterInfo(objectType),
                    GetParameterInfo(objectType));
                var stringFormatMemberWithStringAndParamsObjectParameter = stringFormatMembers.GetSingleOrDefaultMemberWithParameterInfos(
                    GetParameterInfo(stringType),
                    GetParameterInfo(objectType, isArray: true, arrayRank: 1, isParams: true));
                var stringFormatMemberWithIFormatProviderStringAndParamsObjectParameter = stringFormatMembers.GetSingleOrDefaultMemberWithParameterInfos(
                    GetParameterInfo(iformatProviderType),
                    GetParameterInfo(stringType),
                    GetParameterInfo(objectType, isArray: true, arrayRank: 1, isParams: true));

                var currentCultureProperty     = cultureInfoType?.GetMembers("CurrentCulture").OfType <IPropertySymbol>().SingleOrDefault();
                var invariantCultureProperty   = cultureInfoType?.GetMembers("InvariantCulture").OfType <IPropertySymbol>().SingleOrDefault();
                var currentUICultureProperty   = cultureInfoType?.GetMembers("CurrentUICulture").OfType <IPropertySymbol>().SingleOrDefault();
                var installedUICultureProperty = cultureInfoType?.GetMembers("InstalledUICulture").OfType <IPropertySymbol>().SingleOrDefault();

                var threadType = csaContext.Compilation.GetTypeByMetadataName("System.Threading.Thread");
                var currentThreadCurrentUICultureProperty = threadType?.GetMembers("CurrentUICulture").OfType <IPropertySymbol>().SingleOrDefault();

                var activatorType       = csaContext.Compilation.GetTypeByMetadataName("System.Activator");
                var resourceManagerType = csaContext.Compilation.GetTypeByMetadataName("System.Resources.ResourceManager");

                var computerInfoType = csaContext.Compilation.GetTypeByMetadataName("Microsoft.VisualBasic.Devices.ComputerInfo");
                var installedUICulturePropertyOfComputerInfoType = computerInfoType?.GetMembers("InstalledUICulture").OfType <IPropertySymbol>().SingleOrDefault();

                var obsoleteAttributeType = WellKnownTypes.ObsoleteAttribute(csaContext.Compilation);
                #endregion

                csaContext.RegisterOperationActionInternal(oaContext =>
                {
                    var invocationExpression = (IInvocationExpression)oaContext.Operation;
                    var targetMethod         = invocationExpression.TargetMethod;

                    #region "Exceptions"
                    if (targetMethod.IsGenericMethod || targetMethod.ContainingType == null || targetMethod.ContainingType.IsErrorType() ||
                        (targetMethod.ContainingType != null &&
                         (activatorType != null && activatorType.Equals(targetMethod.ContainingType)) ||
                         (resourceManagerType != null && resourceManagerType.Equals(targetMethod.ContainingType))))
                    {
                        return;
                    }
                    #endregion

                    #region "IFormatProviderAlternateStringRule Only"
                    if (stringType != null && cultureInfoType != null &&
                        (targetMethod.Equals(stringFormatMemberWithStringAndObjectParameter) ||
                         targetMethod.Equals(stringFormatMemberWithStringObjectAndObjectParameter) ||
                         targetMethod.Equals(stringFormatMemberWithStringObjectObjectAndObjectParameter) ||
                         targetMethod.Equals(stringFormatMemberWithStringAndParamsObjectParameter)))
                    {
                        // Sample message for IFormatProviderAlternateStringRule: Because the behavior of string.Format(string, object) could vary based on the current user's locale settings,
                        // replace this call in IFormatProviderStringTest.M() with a call to string.Format(IFormatProvider, string, params object[]).
                        oaContext.ReportDiagnostic(
                            invocationExpression.Syntax.CreateDiagnostic(
                                IFormatProviderAlternateStringRule,
                                targetMethod.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                oaContext.ContainingSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                stringFormatMemberWithIFormatProviderStringAndParamsObjectParameter.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));

                        return;
                    }
                    #endregion

                    #region "IFormatProviderAlternateStringRule & IFormatProviderAlternateRule"

                    IEnumerable <IMethodSymbol> methodsWithSameNameAsTargetMethod = targetMethod.ContainingType.GetMembers(targetMethod.Name).OfType <IMethodSymbol>().WhereMethodDoesNotContainAttribute(obsoleteAttributeType).ToList();
                    if (methodsWithSameNameAsTargetMethod.Count() > 1)
                    {
                        var correctOverloads = methodsWithSameNameAsTargetMethod.GetMethodOverloadsWithDesiredParameterAtLeadingOrTrailing(targetMethod, iformatProviderType).ToList();

                        // If there are two matching overloads, one with CultureInfo as the first parameter and one with CultureInfo as the last parameter,
                        // report the diagnostic on the overload with CultureInfo as the last parameter, to match the behavior of FxCop.
                        var correctOverload = correctOverloads.FirstOrDefault(overload => overload.Parameters.Last().Type.Equals(iformatProviderType)) ?? correctOverloads.FirstOrDefault();

                        // Sample message for IFormatProviderAlternateRule: Because the behavior of Convert.ToInt64(string) could vary based on the current user's locale settings,
                        // replace this call in IFormatProviderStringTest.TestMethod() with a call to Convert.ToInt64(string, IFormatProvider).
                        if (correctOverload != null)
                        {
                            oaContext.ReportDiagnostic(
                                invocationExpression.Syntax.CreateDiagnostic(
                                    targetMethod.ReturnType.Equals(stringType) ?
                                    IFormatProviderAlternateStringRule :
                                    IFormatProviderAlternateRule,
                                    targetMethod.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    oaContext.ContainingSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    correctOverload.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));
                        }
                    }
                    #endregion

                    #region "UICultureStringRule & UICultureRule"
                    IEnumerable <int> IformatProviderParameterIndices = GetIndexesOfParameterType(targetMethod, iformatProviderType);
                    foreach (var index in IformatProviderParameterIndices)
                    {
                        var argument = invocationExpression.ArgumentsInParameterOrder[index];
                        if (argument != null && currentUICultureProperty != null &&
                            installedUICultureProperty != null && currentThreadCurrentUICultureProperty != null)
                        {
                            var semanticModel = oaContext.Compilation.GetSemanticModel(argument.Syntax.SyntaxTree);
                            var symbol        = semanticModel.GetSymbolInfo(argument.Syntax).Symbol;

                            if (symbol != null &&
                                (symbol.Equals(currentUICultureProperty) ||
                                 symbol.Equals(installedUICultureProperty) ||
                                 symbol.Equals(currentThreadCurrentUICultureProperty) ||
                                 (installedUICulturePropertyOfComputerInfoType != null && symbol.Equals(installedUICulturePropertyOfComputerInfoType))))
                            {
                                // Sample message
                                // 1. UICultureStringRule - 'TestClass.TestMethod()' passes 'Thread.CurrentUICulture' as the 'IFormatProvider' parameter to 'TestClass.CalleeMethod(string, IFormatProvider)'.
                                // This property returns a culture that is inappropriate for formatting methods.
                                // 2. UICultureRule -'TestClass.TestMethod()' passes 'CultureInfo.CurrentUICulture' as the 'IFormatProvider' parameter to 'TestClass.Callee(IFormatProvider, string)'.
                                // This property returns a culture that is inappropriate for formatting methods.

                                oaContext.ReportDiagnostic(
                                    invocationExpression.Syntax.CreateDiagnostic(
                                        targetMethod.ReturnType.Equals(stringType) ?
                                        UICultureStringRule :
                                        UICultureRule,
                                        oaContext.ContainingSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                        symbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                        targetMethod.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));
                            }
                        }
                    }
                    #endregion
                }, OperationKind.InvocationExpression);
            });
        }