private static async Task <Document> ChangeToPublicInterfaceImplementationAsync(Document document, ISymbol symbolToChange, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); IEnumerable <ISymbol>?explicitImplementations = GetExplicitImplementations(symbolToChange); if (explicitImplementations == null) { return(document); } await editor.EditAllDeclarationsAsync(symbolToChange, (docEditor, declaration) => { SyntaxNode newDeclaration = declaration; foreach (ISymbol implementedMember in explicitImplementations) { SyntaxNode interfaceTypeNode = docEditor.Generator.TypeExpression(implementedMember.ContainingType); newDeclaration = docEditor.Generator.AsPublicInterfaceImplementation(newDeclaration, interfaceTypeNode); } docEditor.ReplaceNode(declaration, newDeclaration); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private async Task <Document> MakeProtected(Document document, ISymbol symbolToChange, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditAllDeclarationsAsync(symbolToChange, (docEditor, declaration) => { docEditor.SetAccessibility(declaration, Accessibility.Protected); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private static async Task <Document> AddSerializableAttributeToType(Document document, ITypeSymbol type, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditOneDeclarationAsync(type, (docEditor, declaration) => { SyntaxNode serializableAttr = docEditor.Generator.Attribute(docEditor.Generator.TypeExpression(WellKnownTypes.SerializableAttribute(docEditor.SemanticModel.Compilation))); docEditor.AddAttribute(declaration, serializableAttr); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private async Task <Document> MakeContainingTypeSealed(Document document, IMethodSymbol methodSymbol, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditAllDeclarationsAsync(methodSymbol.ContainingType, (docEditor, declaration) => { DeclarationModifiers modifiers = docEditor.Generator.GetModifiers(declaration); docEditor.SetModifiers(declaration, modifiers + DeclarationModifiers.Sealed); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private static async Task <Document> SetAccessibilityAsync(Document document, IMethodSymbol methodSymbol, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); // This would be constructor and can have only one definition. Debug.Assert(methodSymbol.IsConstructor() && methodSymbol.DeclaringSyntaxReferences.HasExactly(1)); await editor.EditOneDeclarationAsync(methodSymbol, (docEditor, declaration) => { Accessibility newAccessibility = methodSymbol.ContainingType.IsSealed ? Accessibility.Private : Accessibility.Protected; docEditor.SetAccessibility(declaration, newAccessibility); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private async Task <Document> AddAccessor(Document document, SyntaxNode parameter, CancellationToken cancellationToken) { SymbolEditor symbolEditor = SymbolEditor.Create(document); SemanticModel model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var parameterSymbol = model.GetDeclaredSymbol(parameter, cancellationToken) as IParameterSymbol; if (parameterSymbol == null) { return(document); } // Make the first character uppercase since we are generating a property. string propName = char.ToUpper(parameterSymbol.Name[0]).ToString() + parameterSymbol.Name.Substring(1); INamedTypeSymbol typeSymbol = parameterSymbol.ContainingType; ISymbol propertySymbol = typeSymbol.GetMembers(propName).Where(m => m.Kind == SymbolKind.Property).FirstOrDefault(); // Add a new property if (propertySymbol == null) { await symbolEditor.EditOneDeclarationAsync(typeSymbol, parameter.GetLocation(), // edit the partial declaration that has this parameter symbol. (editor, typeDeclaration) => { SyntaxNode newProperty = editor.Generator.PropertyDeclaration(propName, editor.Generator.TypeExpression(parameterSymbol.Type), Accessibility.Public, DeclarationModifiers.ReadOnly); newProperty = editor.Generator.WithGetAccessorStatements(newProperty, null); editor.AddMember(typeDeclaration, newProperty); }, cancellationToken).ConfigureAwait(false); } else { await symbolEditor.EditOneDeclarationAsync(propertySymbol, (editor, propertyDeclaration) => { editor.SetGetAccessorStatements(propertyDeclaration, null); editor.SetModifiers(propertyDeclaration, editor.Generator.GetModifiers(propertyDeclaration) - DeclarationModifiers.WriteOnly); }, cancellationToken).ConfigureAwait(false); } return(symbolEditor.GetChangedDocuments().First()); }
private static async Task <Document> ApplyRuleNameMultipleZeroAsync(Document document, INamedTypeSymbol enumType, CancellationToken cancellationToken) { // Diagnostic: Remove all members that have the value zero from '{0}' except for one member that is named 'None'. // Fix: Remove all members that have the value zero except for one member that is named 'None'. SymbolEditor editor = SymbolEditor.Create(document); bool needsNewZeroValuedNoneField = true; ISet <IFieldSymbol> set = EnumsShouldHaveZeroValueAnalyzer.GetZeroValuedFields(enumType).ToSet(); bool makeNextFieldExplicit = false; foreach (IFieldSymbol field in enumType.GetMembers().Where(m => m.Kind == SymbolKind.Field)) { bool isZeroValued = set.Contains(field); bool isZeroValuedNamedNone = isZeroValued && EnumsShouldHaveZeroValueAnalyzer.IsMemberNamedNone(field); if (!isZeroValued || isZeroValuedNamedNone) { if (makeNextFieldExplicit) { await editor.EditOneDeclarationAsync(field, (e, d) => e.ReplaceNode(d, GetExplicitlyAssignedField(field, d, e.Generator)), cancellationToken).ConfigureAwait(false); makeNextFieldExplicit = false; } if (isZeroValuedNamedNone) { needsNewZeroValuedNoneField = false; } } else { await editor.EditOneDeclarationAsync(field, (e, d) => e.RemoveNode(d), cancellationToken).ConfigureAwait(false); // removes the field declaration makeNextFieldExplicit = true; } } if (needsNewZeroValuedNoneField) { await editor.EditOneDeclarationAsync(enumType, (e, d) => e.InsertMembers(d, 0, new[] { e.Generator.EnumMember("None") }), cancellationToken).ConfigureAwait(false); } return(editor.GetChangedDocuments().First()); }
private static async Task <Document> ApplyRuleNameNoZeroValueAsync(Document document, INamedTypeSymbol enumType, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); // remove any non-zero member named 'None' foreach (IFieldSymbol field in enumType.GetMembers().Where(m => m.Kind == SymbolKind.Field)) { if (EnumsShouldHaveZeroValueAnalyzer.IsMemberNamedNone(field)) { await editor.EditOneDeclarationAsync(field, (e, d) => e.RemoveNode(d), cancellationToken).ConfigureAwait(false); } } // insert zero-valued member 'None' to top await editor.EditOneDeclarationAsync(enumType, (e, d) => e.InsertMembers(d, 0, new[] { e.Generator.EnumMember("None") }), cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private async Task <Document> AddDisposeCall(Document document, SyntaxNode declaration, IFieldSymbol fieldSymbol, IMethodSymbol disposeMethod, ITypeSymbol iDisposableType, ISymbol iDisposable_Dispose, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditOneDeclarationAsync(disposeMethod, (docEditor, disposeMethodNode) => { var generator = docEditor.Generator; // handle the case where a local in the Dispose method exists with the same name by generating this (or ClassName) and simplifying it var path = fieldSymbol.IsStatic ? generator.IdentifierName(fieldSymbol.ContainingType.MetadataName) : generator.ThisExpression(); var disposeMethodOfFieldType = fieldSymbol.Type.FindImplementationForInterfaceMember(iDisposable_Dispose) as IMethodSymbol; // If the original interface was implemented implicitly then we can simply invoke through the name of the implementation. // Note that in VB, the name of the method implementing the interface method can be different from the interface method name. SyntaxNode statement; if (disposeMethodOfFieldType.CanBeReferencedByName) { statement = generator.ExpressionStatement( generator.InvocationExpression( generator.MemberAccessExpression( generator.MemberAccessExpression(path, generator.IdentifierName(fieldSymbol.Name)).WithAdditionalAnnotations(Simplifier.Annotation), generator.IdentifierName(disposeMethodOfFieldType.Name)))); } // Otherwise dispatch through the interface else { statement = generator.ExpressionStatement( generator.InvocationExpression( generator.MemberAccessExpression( generator.CastExpression(iDisposableType, generator.MemberAccessExpression(path, generator.IdentifierName(fieldSymbol.Name)).WithAdditionalAnnotations(Simplifier.Annotation)), generator.IdentifierName(DisposableFieldsShouldBeDisposedAnalyzer.Dispose)))); } var body = generator.GetStatements(disposeMethodNode); docEditor.SetStatements(disposeMethodNode, body.Concat(ImmutableArray.Create(statement))); }).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private static async Task <Document> GenerateConstructorAsync(Document document, SyntaxNode node, INamedTypeSymbol typeSymbol, INamedTypeSymbol notImplementedExceptionType, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); await editor.EditOneDeclarationAsync(typeSymbol, node.GetLocation(), (docEditor, declaration) => { SyntaxGenerator generator = docEditor.Generator; SyntaxNode throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(generator.TypeExpression(notImplementedExceptionType))); SyntaxNode ctorDecl = generator.ConstructorDeclaration( typeSymbol.Name, new[] { generator.ParameterDeclaration("serializationInfo", generator.TypeExpression(docEditor.SemanticModel.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationSerializationInfo))), generator.ParameterDeclaration("streamingContext", generator.TypeExpression(docEditor.SemanticModel.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationStreamingContext))) }, typeSymbol.IsSealed ? Accessibility.Private : Accessibility.Protected, statements: new[] { throwStatement }); docEditor.AddMember(declaration, ctorDecl); }, cancellationToken).ConfigureAwait(false); return(editor.GetChangedDocuments().First()); }
private static async Task <Document> MakeProtectedAsync(Document document, ISymbol symbolToChange, bool checkSetter, CancellationToken cancellationToken) { SymbolEditor editor = SymbolEditor.Create(document); ISymbol?getter = null; ISymbol?setter = null; if (symbolToChange.Kind == SymbolKind.Property) { var propertySymbol = (IPropertySymbol)symbolToChange; getter = propertySymbol.GetMethod; setter = propertySymbol.SetMethod; } await editor.EditAllDeclarationsAsync(symbolToChange, (docEditor, declaration) => { docEditor.SetAccessibility(declaration, Accessibility.Protected); }, cancellationToken).ConfigureAwait(false); if (getter != null && getter.DeclaredAccessibility == Accessibility.Private) { await editor.EditAllDeclarationsAsync(getter, (docEditor, declaration) => { docEditor.SetAccessibility(declaration, Accessibility.NotApplicable); }, cancellationToken).ConfigureAwait(false); } if (checkSetter && setter != null && setter.DeclaredAccessibility == Accessibility.Private) { await editor.EditAllDeclarationsAsync(setter, (docEditor, declaration) => { docEditor.SetAccessibility(declaration, Accessibility.NotApplicable); }, cancellationToken).ConfigureAwait(false); } return(editor.GetChangedDocuments().First()); }
private static async Task <Document> FixAsync(CodeFixContext context, CancellationToken cancellationToken) { var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var generator = SyntaxGenerator.GetGenerator(context.Document); SyntaxNode node = root.FindNode(context.Span); Diagnostic diagnostic = context.Diagnostics.First(); switch (diagnostic.Properties[OperatorOverloadsHaveNamedAlternatesAnalyzer.DiagnosticKindText]) { case OperatorOverloadsHaveNamedAlternatesAnalyzer.AddAlternateText: SyntaxNode methodDeclaration = generator.GetDeclaration(node, DeclarationKind.Operator) ?? generator.GetDeclaration(node, DeclarationKind.ConversionOperator); var operatorOverloadSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken); INamedTypeSymbol typeSymbol = operatorOverloadSymbol.ContainingType; // For C# the following `typeDeclarationSyntax` and `typeDeclaration` nodes are identical, but for VB they're different so in // an effort to keep this as language-agnostic as possible, the heavy-handed approach is used. SyntaxNode typeDeclarationSyntax = await typeSymbol.DeclaringSyntaxReferences.First().GetSyntaxAsync(cancellationToken).ConfigureAwait(false); SyntaxNode typeDeclaration = generator.GetDeclaration(typeDeclarationSyntax, typeSymbol.TypeKind == TypeKind.Struct ? DeclarationKind.Struct : DeclarationKind.Class); SyntaxNode addedMember; IEnumerable <SyntaxNode> bodyStatements = generator.DefaultMethodBody(semanticModel.Compilation); if (OperatorOverloadsHaveNamedAlternatesAnalyzer.IsPropertyExpected(operatorOverloadSymbol.Name)) { // add a property addedMember = generator.PropertyDeclaration( name: OperatorOverloadsHaveNamedAlternatesAnalyzer.IsTrueText, type: generator.TypeExpression(SpecialType.System_Boolean), accessibility: Accessibility.Public, modifiers: DeclarationModifiers.ReadOnly, getAccessorStatements: bodyStatements); } else { // add a method ExpectedMethodSignature?expectedSignature = GetExpectedMethodSignature(operatorOverloadSymbol, semanticModel.Compilation); if (expectedSignature == null) { return(context.Document); } if (expectedSignature.Name == "CompareTo" && operatorOverloadSymbol.ContainingType.TypeKind == TypeKind.Class) { var nullCheck = generator.IfStatement( generator.InvocationExpression( generator.IdentifierName("ReferenceEquals"), generator.IdentifierName(expectedSignature.Parameters.First().name), generator.NullLiteralExpression()), new[] { generator.ReturnStatement(generator.LiteralExpression(1)) }); bodyStatements = new[] { nullCheck }.Concat(bodyStatements); } addedMember = generator.MethodDeclaration( name: expectedSignature.Name, parameters: expectedSignature.Parameters.Select(p => generator.ParameterDeclaration(p.name, generator.TypeExpression(p.typeSymbol))), returnType: generator.TypeExpression(expectedSignature.ReturnType), accessibility: Accessibility.Public, modifiers: expectedSignature.IsStatic ? DeclarationModifiers.Static : DeclarationModifiers.None, statements: bodyStatements); } SyntaxNode newTypeDeclaration = generator.AddMembers(typeDeclaration, addedMember); return(context.Document.WithSyntaxRoot(root.ReplaceNode(typeDeclaration, newTypeDeclaration))); case OperatorOverloadsHaveNamedAlternatesAnalyzer.FixVisibilityText: SyntaxNode badVisibilityNode = generator.GetDeclaration(node, DeclarationKind.Method) ?? generator.GetDeclaration(node, DeclarationKind.Property); ISymbol badVisibilitySymbol = semanticModel.GetDeclaredSymbol(badVisibilityNode, cancellationToken); SymbolEditor symbolEditor = SymbolEditor.Create(context.Document); ISymbol newSymbol = await symbolEditor.EditOneDeclarationAsync(badVisibilitySymbol, (documentEditor, syntaxNode) => documentEditor.SetAccessibility(badVisibilityNode, Accessibility.Public), cancellationToken).ConfigureAwait(false); Document newDocument = symbolEditor.GetChangedDocuments().Single(); SyntaxNode newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return(context.Document.WithSyntaxRoot(newRoot)); default: return(context.Document); } }
private static async Task <Document> Fix(CodeFixContext context, SyntaxNode root, SyntaxGenerator generator, SemanticModel semanticModel, CancellationToken cancellationToken) { SyntaxNode node = root.FindNode(context.Span); Diagnostic diagnostic = context.Diagnostics.First(); switch (diagnostic.Properties[OperatorOverloadsHaveNamedAlternatesAnalyzer.DiagnosticKindText]) { case OperatorOverloadsHaveNamedAlternatesAnalyzer.AddAlternateText: SyntaxNode methodDeclaration = generator.GetDeclaration(node, DeclarationKind.Operator) ?? generator.GetDeclaration(node, DeclarationKind.ConversionOperator); var operatorOverloadSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken); INamedTypeSymbol typeSymbol = operatorOverloadSymbol.ContainingType; // For C# the following `typeDeclarationSyntax` and `typeDeclaration` nodes are identical, but for VB they're different so in // an effort to keep this as language-agnostic as possible, the heavy-handed approach is used. SyntaxNode typeDeclarationSyntax = typeSymbol.DeclaringSyntaxReferences.First().GetSyntax(cancellationToken); SyntaxNode typeDeclaration = generator.GetDeclaration(typeDeclarationSyntax, DeclarationKind.Class); SyntaxNode addedMember; ImmutableArray <SyntaxNode> bodyStatements = ImmutableArray.Create( generator.ThrowStatement(generator.ObjectCreationExpression(semanticModel.Compilation.GetTypeByMetadataName("System.NotImplementedException")))); if (OperatorOverloadsHaveNamedAlternatesAnalyzer.IsPropertyExpected(operatorOverloadSymbol.Name)) { // add a property addedMember = generator.PropertyDeclaration( name: OperatorOverloadsHaveNamedAlternatesAnalyzer.IsTrueText, type: generator.TypeExpression(SpecialType.System_Boolean), accessibility: Accessibility.Public, modifiers: DeclarationModifiers.ReadOnly, getAccessorStatements: bodyStatements); } else { // add a method ExpectedMethodSignature expectedSignature = GetExpectedMethodSignature(operatorOverloadSymbol, semanticModel.Compilation); addedMember = generator.MethodDeclaration( name: expectedSignature.Name, parameters: expectedSignature.Parameters.Select(p => generator.ParameterDeclaration(p.Item1, generator.TypeExpression(p.Item2))), returnType: generator.TypeExpression(expectedSignature.ReturnType), accessibility: Accessibility.Public, modifiers: expectedSignature.IsStatic ? DeclarationModifiers.Static : DeclarationModifiers.None, statements: bodyStatements); } SyntaxNode newTypeDeclaration = generator.AddMembers(typeDeclaration, addedMember); return(context.Document.WithSyntaxRoot(root.ReplaceNode(typeDeclaration, newTypeDeclaration))); case OperatorOverloadsHaveNamedAlternatesAnalyzer.FixVisibilityText: SyntaxNode badVisibilityNode = generator.GetDeclaration(node, DeclarationKind.Method) ?? generator.GetDeclaration(node, DeclarationKind.Property); ISymbol badVisibilitySymbol = semanticModel.GetDeclaredSymbol(badVisibilityNode, cancellationToken); SymbolEditor symbolEditor = SymbolEditor.Create(context.Document); ISymbol newSymbol = await symbolEditor.EditOneDeclarationAsync(badVisibilitySymbol, (documentEditor, syntaxNode) => documentEditor.SetAccessibility(badVisibilityNode, Accessibility.Public)); Document newDocument = symbolEditor.GetChangedDocuments().Single(); SyntaxNode newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken); return(context.Document.WithSyntaxRoot(newRoot)); default: return(context.Document); } }