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()); }
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); }); }