public static Pool <CallsWalker> .Pooled GetCallsInContext(IMethodSymbol method, SyntaxNode context, SemanticModel semanticModel, CancellationToken cancellationToken) { var pooled = Pool.GetOrCreate(); pooled.Item.method = method; pooled.Item.semanticModel = semanticModel; pooled.Item.cancellationToken = cancellationToken; Constructor.AddRunBefore(context, pooled.Item.ctors, semanticModel, cancellationToken); var contextCtor = semanticModel.GetDeclaredSymbolSafe( context.FirstAncestorOrSelf <ConstructorDeclarationSyntax>(), cancellationToken); if (contextCtor != null) { pooled.Item.ctors.Add(contextCtor).IgnoreReturnValue(); } pooled.Item.contextType = semanticModel.GetDeclaredSymbolSafe(context.FirstAncestor <TypeDeclarationSyntax>(), cancellationToken); var type = pooled.Item.contextType; while (type != null && type != KnownSymbol.Object) { foreach (var reference in type.DeclaringSyntaxReferences) { pooled.Item.Visit(reference.GetSyntax(cancellationToken)); } type = type.BaseType; } return(pooled); }
internal static bool IsRunBefore(this ConstructorDeclarationSyntax ctor, ConstructorDeclarationSyntax otherDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) { if (ctor == otherDeclaration) { return(false); } var first = semanticModel.GetDeclaredSymbolSafe(ctor, cancellationToken); var other = semanticModel.GetDeclaredSymbolSafe(otherDeclaration, cancellationToken); return(IsRunBefore(first, other, semanticModel, cancellationToken)); }
private static bool AssignedType(ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol memberType) { foreach (var reference in symbol.DeclaringSyntaxReferences) { var node = reference.GetSyntax(cancellationToken); if (AssignmentExecutionWalker.SingleForSymbol( symbol, node.FirstAncestor <TypeDeclarationSyntax>(), Search.TopLevel, semanticModel, cancellationToken, out var assignment) && assignment.Right is IdentifierNameSyntax identifier) { var ctor = assignment.FirstAncestor <ConstructorDeclarationSyntax>(); if (ctor != null && ctor.ParameterList != null && ctor.ParameterList.Parameters.TryFirst( p => p.Identifier.ValueText == identifier.Identifier.ValueText, out var parameter)) { memberType = semanticModel.GetDeclaredSymbolSafe(parameter, cancellationToken)?.Type; return(true); } } } memberType = null; return(false); }
private static void AddCtorsRecursively(ConstructorDeclarationSyntax ctor, HashSet <IMethodSymbol> ctorsRunBefore, SemanticModel semanticModel, CancellationToken cancellationToken) { if (ctor.Initializer != null) { var nestedCtor = semanticModel.GetSymbolSafe(ctor.Initializer, cancellationToken); if (nestedCtor == null) { return; } foreach (var reference in nestedCtor.DeclaringSyntaxReferences) { var runBefore = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); ctorsRunBefore.Add(nestedCtor).IgnoreReturnValue(); AddCtorsRecursively(runBefore, ctorsRunBefore, semanticModel, cancellationToken); } } else { var baseType = semanticModel.GetDeclaredSymbolSafe(ctor, cancellationToken) .ContainingType.BaseType; if (TryGetDefault(baseType, out IMethodSymbol defaultCtor)) { foreach (var reference in defaultCtor.DeclaringSyntaxReferences) { ctorsRunBefore.Add(defaultCtor).IgnoreReturnValue(); var runBefore = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); AddCtorsRecursively(runBefore, ctorsRunBefore, semanticModel, cancellationToken); } } } }
private static bool TryGetAssignedFieldOrProperty(ArgumentSyntax argument, IMethodSymbol method, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol member) { member = null; if (method == null) { return(false); } if (method.TrySingleDeclaration <BaseMethodDeclarationSyntax>(cancellationToken, out var methodDeclaration) && methodDeclaration.TryGetMatchingParameter(argument, out var paremeter)) { var parameterSymbol = semanticModel.GetDeclaredSymbolSafe(paremeter, cancellationToken); if (methodDeclaration.Body.TryGetAssignment(parameterSymbol, semanticModel, cancellationToken, out var assignment)) { member = semanticModel.GetSymbolSafe(assignment.Left, cancellationToken); if (member is IFieldSymbol || member is IPropertySymbol) { return(true); } } if (methodDeclaration is ConstructorDeclarationSyntax ctor && ctor.Initializer is ConstructorInitializerSyntax initializer && initializer.ArgumentList != null && initializer.ArgumentList.Arguments.TrySingle(x => x.Expression is IdentifierNameSyntax identifier && identifier.Identifier.ValueText == paremeter.Identifier.ValueText, out var chainedArgument)) { var chained = semanticModel.GetSymbolSafe(ctor.Initializer, cancellationToken); return(TryGetAssignedFieldOrProperty(chainedArgument, chained, semanticModel, cancellationToken, out member)); } } return(false); }
internal static Pool <ConstructorsWalker> .Pooled Create(TypeDeclarationSyntax context, SemanticModel semanticModel, CancellationToken cancellationToken) { var pooled = Pool.GetOrCreate(); pooled.Item.semanticModel = semanticModel; pooled.Item.cancellationToken = cancellationToken; pooled.Item.Visit(context); pooled.Item.type = semanticModel.GetDeclaredSymbolSafe(context, cancellationToken) as INamedTypeSymbol; if (pooled.Item.type == null) { return(pooled); } foreach (var reference in pooled.Item.type.DeclaringSyntaxReferences) { pooled.Item.Visit(reference.GetSyntax(cancellationToken)); } if (pooled.Item.nonPrivateCtors.Count == 0 && pooled.Item.Default == null) { if (Constructor.TryGetDefault(pooled.Item.type, out IMethodSymbol @default)) { foreach (var reference in @default.DeclaringSyntaxReferences) { pooled.Item.Default = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); pooled.Item.Visit(pooled.Item.Default); } } } return(pooled); }
internal static bool TryGetMatchingParameter(this InvocationExpressionSyntax invocation, ArgumentSyntax argument, SemanticModel semanticModel, CancellationToken cancellationToken, out IParameterSymbol parameter) { parameter = null; if (invocation?.ArgumentList == null) { return(false); } if (semanticModel.GetSymbolSafe(invocation, cancellationToken) is IMethodSymbol method) { foreach (var reference in method.DeclaringSyntaxReferences) { if (reference.GetSyntax(cancellationToken) is MethodDeclarationSyntax methodDeclaration) { if (methodDeclaration.TryGetMatchingParameter(argument, out ParameterSyntax parameterSyntax)) { parameter = semanticModel.GetDeclaredSymbolSafe(parameterSyntax, cancellationToken); return(parameter != null); } } } } return(false); }
private static bool TryGetField(SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken, out IFieldSymbol field) { field = null; var typeDeclaration = node.FirstAncestor <TypeDeclarationSyntax>(); if (typeDeclaration == null) { return(false); } var type = semanticModel.GetDeclaredSymbolSafe(typeDeclaration, cancellationToken); if (type == null) { return(false); } foreach (var member in type.GetMembers()) { if (member is IFieldSymbol candidateField && candidateField.Type == KnownSymbol.CompositeDisposable) { field = candidateField; return(true); } } return(false); }
private static Fix CreateFix(Diagnostic diagnostic, SyntaxNode syntaxRoot, SemanticModel semanticModel, CancellationToken cancellationToken, SyntaxGenerator syntaxGenerator, bool usesUnderscoreNames) { var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText)) { return(default(Fix)); } var assignment = syntaxRoot.FindNode(diagnostic.Location.SourceSpan) .FirstAncestorOrSelf <ExpressionSyntax>(); var typeDeclaration = assignment?.FirstAncestorOrSelf <TypeDeclarationSyntax>(); if (typeDeclaration == null) { return(default(Fix)); } if (!diagnostic.Properties.TryGetValue(WPF1012NotifyWhenPropertyChanges.PropertyNameKey, out string property)) { return(default(Fix)); } var type = semanticModel.GetDeclaredSymbolSafe(typeDeclaration, cancellationToken); if (PropertyChanged.Helpers.PropertyChanged.TryGetInvoker(type, semanticModel, cancellationToken, out IMethodSymbol invoker) && invoker.Parameters[0].Type == KnownSymbol.String) { var onPropertyChanged = syntaxGenerator.OnPropertyChanged(property, useCallerMemberName: false, usedUnderscoreNames: usesUnderscoreNames, invoker: invoker); return(new Fix(assignment, onPropertyChanged, invoker)); } return(default(Fix)); }
internal static ConstructorsWalker Borrow(TypeDeclarationSyntax context, SemanticModel semanticModel, CancellationToken cancellationToken) { var walker = Borrow(() => new ConstructorsWalker()); walker.semanticModel = semanticModel; walker.cancellationToken = cancellationToken; walker.Visit(context); walker.type = semanticModel.GetDeclaredSymbolSafe(context, cancellationToken) as INamedTypeSymbol; if (walker.type == null) { return(walker); } foreach (var reference in walker.type.DeclaringSyntaxReferences) { walker.Visit(reference.GetSyntax(cancellationToken)); } if (walker.nonPrivateCtors.Count == 0 && walker.Default == null) { if (Constructor.TryGetDefault(walker.type, out var @default)) { foreach (var reference in @default.DeclaringSyntaxReferences) { walker.Default = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); walker.Visit(walker.Default); } } } return(walker); }
internal static bool IsEither <T1, T2>(this SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) where T1 : ISymbol where T2 : ISymbol { return(semanticModel.GetSymbolSafe(node, cancellationToken).IsEither <T1, T2>() || semanticModel.GetDeclaredSymbolSafe(node, cancellationToken).IsEither <T1, T2>() || semanticModel.GetTypeInfoSafe(node, cancellationToken).Type.IsEither <T1, T2>()); }
private static bool TryGetMemberSymbol(MemberDeclarationSyntax member, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol symbol) { if (member is FieldDeclarationSyntax field && field.Declaration.Variables.TryGetSingle(out VariableDeclaratorSyntax declarator)) { symbol = semanticModel.GetDeclaredSymbolSafe(declarator, cancellationToken); return(symbol != null); } if (member is PropertyDeclarationSyntax property) { symbol = semanticModel.GetDeclaredSymbolSafe(property, cancellationToken); return(symbol != null); } symbol = null; return(false); }
private static Fix CreateFix(Diagnostic diagnostic, SyntaxNode syntaxRoot, SemanticModel semanticModel, CancellationToken cancellationToken, bool usesUnderscoreNames) { var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing) { return(default(Fix)); } var member = (MemberDeclarationSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); if (member is MethodDeclarationSyntax methodDeclaration) { var method = semanticModel.GetDeclaredSymbolSafe(methodDeclaration, cancellationToken); if (method.Parameters.Length != 1) { return(default(Fix)); } var overridden = method.OverriddenMethod; var baseCall = SyntaxFactory.ParseStatement($"base.{overridden.Name}({method.Parameters[0].Name});") .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker); return(new Fix(baseCall, methodDeclaration)); } if (!TryGetMemberSymbol(member, semanticModel, cancellationToken, out ISymbol memberSymbol)) { return(default(Fix)); } if (Disposable.TryGetDisposeMethod(memberSymbol.ContainingType, Search.TopLevel, out IMethodSymbol disposeMethodSymbol)) { if (disposeMethodSymbol.DeclaredAccessibility == Accessibility.Public && disposeMethodSymbol.Parameters.Length == 0 && disposeMethodSymbol.TryGetSingleDeclaration(cancellationToken, out MethodDeclarationSyntax disposeMethodDeclaration)) { var disposeStatement = CreateDisposeStatement(memberSymbol, semanticModel, cancellationToken, usesUnderscoreNames); return(new Fix(disposeStatement, disposeMethodDeclaration)); } if (disposeMethodSymbol.Parameters.Length == 1 && disposeMethodSymbol.TryGetSingleDeclaration(cancellationToken, out disposeMethodDeclaration)) { var parameterType = semanticModel.GetTypeInfoSafe(disposeMethodDeclaration.ParameterList.Parameters[0]?.Type, cancellationToken).Type; if (parameterType == KnownSymbol.Boolean) { var disposeStatement = CreateDisposeStatement(memberSymbol, semanticModel, cancellationToken, usesUnderscoreNames); return(new Fix(disposeStatement, disposeMethodDeclaration)); } } } return(default(Fix)); }
private static void MakeAutoPropertyNotifyWhenValueChanges(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken) { if (Property.IsMutableAutoProperty(propertyDeclaration, out var getter, out var setter)) { if (getter.Body != null || getter.ContainsSkippedText || setter.Body != null || setter.ContainsSkippedText) { return; } var underscoreFields = CodeStyle.UnderscoreFields(semanticModel); var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); var backingField = editor.AddBackingField(propertyDeclaration, underscoreFields, cancellationToken); var fieldAccess = underscoreFields ? backingField.Name() : $"this.{backingField.Name()}"; var code = StringBuilderPool.Borrow() .AppendLine($"public Type PropertyName") .AppendLine("{") .AppendLine($" get => {fieldAccess};") .AppendLine() .AppendLine(" set") .AppendLine(" {") .AppendLine($" if ({Snippet.EqualityCheck(property.Type, "value", fieldAccess, semanticModel)})") .AppendLine(" {") .AppendLine($" return;") .AppendLine(" }") .AppendLine() .AppendLine($" {fieldAccess} = value;") .AppendLine($" {Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)}") .AppendLine(" }") .AppendLine("}") .Return(); var template = ParseProperty(code); editor.ReplaceNode( getter, x => x.WithExpressionBody(template.Getter().ExpressionBody) .WithTrailingElasticLineFeed() .WithAdditionalAnnotations(Formatter.Annotation)); editor.ReplaceNode( setter, x => x.WithBody(template.Setter().Body) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithAdditionalAnnotations(Formatter.Annotation)); if (propertyDeclaration.Initializer != null) { editor.ReplaceNode( propertyDeclaration, x => x.WithoutInitializer()); } editor.ReplaceNode(propertyDeclaration, x => x.WithAdditionalAnnotations(Formatter.Annotation)); } }
private static IEnumerable <ISymbol> ReadOnlies(ConstructorDeclarationSyntax ctor, SemanticModel semanticModel, CancellationToken cancellationToken) { var isStatic = ctor.Modifiers.Any(SyntaxKind.StaticKeyword); var typeDeclarationSyntax = (TypeDeclarationSyntax)ctor.Parent; foreach (var member in typeDeclarationSyntax.Members) { if (member is FieldDeclarationSyntax fieldDeclaration && fieldDeclaration.Modifiers.Any(SyntaxKind.ReadOnlyKeyword)) { var declaration = fieldDeclaration.Declaration; if (declaration.Variables.TryGetSingle(out var variable)) { var field = (IFieldSymbol)semanticModel.GetDeclaredSymbolSafe(variable, cancellationToken); if (field.IsReadOnly && field.IsStatic == isStatic && variable.Initializer == null) { yield return(field); } } continue; } if (member is PropertyDeclarationSyntax propertyDeclaration && propertyDeclaration.ExpressionBody == null && !propertyDeclaration.TryGetSetAccessorDeclaration(out _) && propertyDeclaration.TryGetGetAccessorDeclaration(out var getter) && getter.Body == null) { var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); if (property.IsReadOnly && property.IsStatic == isStatic && !property.IsAbstract && propertyDeclaration.Initializer == null) { yield return(semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken)); } } } }
private static IEnumerable <string> ReadOnlies(ConstructorDeclarationSyntax ctor, SemanticModel semanticModel, CancellationToken cancellationToken) { var isStatic = semanticModel.GetDeclaredSymbolSafe(ctor, cancellationToken) .IsStatic; var typeDeclarationSyntax = (TypeDeclarationSyntax)ctor.Parent; foreach (var member in typeDeclarationSyntax.Members) { if (member is FieldDeclarationSyntax fieldDeclaration) { var declaration = fieldDeclaration.Declaration; if (declaration.Variables.TryGetSingle(out VariableDeclaratorSyntax variable)) { var field = (IFieldSymbol)semanticModel.GetDeclaredSymbolSafe(variable, cancellationToken); if (field.IsReadOnly && field.IsStatic == isStatic && variable.Initializer == null) { yield return(field.Name); } } continue; } var propertyDeclaration = member as PropertyDeclarationSyntax; if (propertyDeclaration != null && propertyDeclaration.ExpressionBody == null && propertyDeclaration.TryGetGetAccessorDeclaration(out AccessorDeclarationSyntax getter) && getter.Body == null) { var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); if (property.IsReadOnly && property.IsStatic == isStatic && !property.IsAbstract && propertyDeclaration.Initializer == null) { yield return(propertyDeclaration.Identifier.ValueText); } } } }
internal static bool TryGetRegisteredName(ArgumentSyntax callback, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName) { registeredName = null; if (callback == null) { return(false); } var fieldDeclaration = callback.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); var dependencyProperty = semanticModel.GetDeclaredSymbolSafe(fieldDeclaration, cancellationToken) as IFieldSymbol; return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName)); }
internal static bool TryGetDependencyProperty(ObjectCreationExpressionSyntax objectCreation, SemanticModel semanticModel, CancellationToken cancellationToken, out IFieldSymbol dependencyProperty) { dependencyProperty = null; var declarator = objectCreation.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); if (declarator == null) { return(false); } dependencyProperty = semanticModel.GetDeclaredSymbolSafe(declarator, cancellationToken) as IFieldSymbol; return(dependencyProperty != null); }
internal static bool Creates(this ObjectCreationExpressionSyntax creation, ConstructorDeclarationSyntax ctor, Search search, SemanticModel semanticModel, CancellationToken cancellationToken) { var created = semanticModel.GetSymbolSafe(creation, cancellationToken) as IMethodSymbol; var ctorSymbol = semanticModel.GetDeclaredSymbolSafe(ctor, cancellationToken); if (SymbolComparer.Equals(ctorSymbol, created)) { return(true); } return(search == Search.Recursive && IsRunBefore(created, ctorSymbol, semanticModel, cancellationToken)); }
private static bool TryGetAssignedFieldOrProperty(ArgumentSyntax argument, IMethodSymbol method, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol member) { member = null; if (method == null) { return(false); } foreach (var reference in method.DeclaringSyntaxReferences) { var methodDeclaration = reference.GetSyntax(cancellationToken) as BaseMethodDeclarationSyntax; if (methodDeclaration == null) { continue; } if (!methodDeclaration.TryGetMatchingParameter(argument, out ParameterSyntax paremeter)) { continue; } var parameterSymbol = semanticModel.GetDeclaredSymbolSafe(paremeter, cancellationToken); if (methodDeclaration.Body.TryGetAssignment(parameterSymbol, semanticModel, cancellationToken, out AssignmentExpressionSyntax assignment)) { member = semanticModel.GetSymbolSafe(assignment.Left, cancellationToken); if (member is IFieldSymbol || member is IPropertySymbol) { return(true); } } var ctor = reference.GetSyntax(cancellationToken) as ConstructorDeclarationSyntax; if (ctor?.Initializer != null) { foreach (var arg in ctor.Initializer.ArgumentList.Arguments) { var argSymbol = semanticModel.GetSymbolSafe(arg.Expression, cancellationToken); if (parameterSymbol.Equals(argSymbol)) { var chained = semanticModel.GetSymbolSafe(ctor.Initializer, cancellationToken); return(TryGetAssignedFieldOrProperty(arg, chained, semanticModel, cancellationToken, out member)); } } } } return(false); }
internal static bool TryGetRegisteredName(ArgumentSyntax callback, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName) { registeredName = null; var invocation = callback?.FirstAncestorOrSelf <InvocationExpressionSyntax>(); var memberAccess = invocation?.Expression as MemberAccessExpressionSyntax; if (memberAccess == null) { return(false); } var method = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol; if (method == KnownSymbol.DependencyProperty.OverrideMetadata || method == KnownSymbol.DependencyProperty.AddOwner) { var dependencyProperty = semanticModel.GetSymbolSafe(memberAccess.Expression, cancellationToken) as IFieldSymbol; if (dependencyProperty?.Type != KnownSymbol.DependencyProperty) { return(false); } return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName)); } if (method == KnownSymbol.DependencyProperty.Register || method == KnownSymbol.DependencyProperty.RegisterReadOnly || method == KnownSymbol.DependencyProperty.RegisterAttached || method == KnownSymbol.DependencyProperty.RegisterAttachedReadOnly) { var fieldDeclaration = callback.FirstAncestorOrSelf <VariableDeclaratorSyntax>(); if (fieldDeclaration == null) { return(false); } var dependencyProperty = semanticModel.GetDeclaredSymbolSafe(fieldDeclaration, cancellationToken) as IFieldSymbol; if (dependencyProperty == null) { return(false); } return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName)); } return(false); }
internal static void AddRunBefore(SyntaxNode context, HashSet <IMethodSymbol> ctorsRunBefore, SemanticModel semanticModel, CancellationToken cancellationToken) { if (context == null) { return; } var contextCtor = context.FirstAncestorOrSelf <ConstructorDeclarationSyntax>(); if (contextCtor == null) { var type = (INamedTypeSymbol)semanticModel.GetDeclaredSymbolSafe(context.FirstAncestorOrSelf <TypeDeclarationSyntax>(), cancellationToken); if (type == null) { return; } if (type.Constructors.Length != 0) { foreach (var ctor in type.Constructors) { foreach (var reference in ctor.DeclaringSyntaxReferences) { var ctorDeclaration = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); ctorsRunBefore.Add(ctor).IgnoreReturnValue(); AddCtorsRecursively(ctorDeclaration, ctorsRunBefore, semanticModel, cancellationToken); } } } else { if (TryGetDefault(type, out IMethodSymbol ctor)) { foreach (var reference in ctor.DeclaringSyntaxReferences) { var ctorDeclaration = (ConstructorDeclarationSyntax)reference.GetSyntax(cancellationToken); ctorsRunBefore.Add(ctor).IgnoreReturnValue(); AddCtorsRecursively(ctorDeclaration, ctorsRunBefore, semanticModel, cancellationToken); } } } } else { AddCtorsRecursively(contextCtor, ctorsRunBefore, semanticModel, cancellationToken); } }
private static Task <Document> ApplyImplementINotifyPropertyChangedFixAsync( CodeFixContext context, SemanticModel semanticModel, CancellationToken cancellationToken, CompilationUnitSyntax syntaxRoot, TypeDeclarationSyntax typeDeclaration) { var type = semanticModel.GetDeclaredSymbolSafe(typeDeclaration, cancellationToken); var syntaxGenerator = SyntaxGenerator.GetGenerator(context.Document); var updated = typeDeclaration.WithINotifyPropertyChangedInterface(syntaxGenerator, type) .WithPropertyChangedEvent(syntaxGenerator) .WithInvoker(syntaxGenerator, type); var newRoot = syntaxRoot.ReplaceNode(typeDeclaration, updated) .WithUsings(); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }
private static void MakeWithBackingFieldNotify(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken) { var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>(); if (classDeclaration == null) { return; } if (IsSimpleAssignmentOnly(propertyDeclaration, out var setter, out var statement, out var assignment, out _)) { var underscoreFields = CodeStyle.UnderscoreFields(semanticModel); var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); var notifyStatement = SyntaxFactory .ParseStatement(Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)) .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker) .WithSimplifiedNames() .WithAdditionalAnnotations(Formatter.Annotation); if (setter.ExpressionBody != null) { editor.ReplaceNode( setter, (x, _) => { var old = (AccessorDeclarationSyntax)x; return(old.WithBody( SyntaxFactory.Block( SyntaxFactory.ExpressionStatement(assignment), notifyStatement)) .WithExpressionBody(null) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None))); }); editor.FormatNode(propertyDeclaration); } else if (setter.Body != null) { editor.InsertAfter(statement, notifyStatement); editor.FormatNode(propertyDeclaration); } } }
private static Neighbors GetNeighbors(BasePropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) { var typeDeclaration = propertyDeclaration.FirstAncestorOrSelf <TypeDeclarationSyntax>(); if (typeDeclaration == null) { return(default(Neighbors)); } var isBefore = true; BasePropertyDeclarationSyntax before = null; BasePropertyDeclarationSyntax after = null; foreach (var member in typeDeclaration.Members) { var declaration = member as BasePropertyDeclarationSyntax; if (declaration == null || !declaration.IsPropertyOrIndexer()) { continue; } if (declaration == propertyDeclaration) { isBefore = false; continue; } if (isBefore) { before = declaration; } else { after = declaration; break; } } return(new Neighbors((IPropertySymbol)semanticModel.GetDeclaredSymbolSafe(before, cancellationToken), (IPropertySymbol)semanticModel.GetDeclaredSymbolSafe(after, cancellationToken))); }
internal static bool IsSimplePropertyWithBackingField(PropertyDeclarationSyntax property, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!(property.TryGetGetAccessorDeclaration(out AccessorDeclarationSyntax getter) && property.TryGetSetAccessorDeclaration(out AccessorDeclarationSyntax setter))) { return(false); } if (getter.Body?.Statements.Count != 1 || setter.Body?.Statements.Count != 1) { return(false); } var returnStatement = getter.Body.Statements[0] as ReturnStatementSyntax; var assignment = (setter.Body.Statements[0] as ExpressionStatementSyntax)?.Expression as AssignmentExpressionSyntax; if (returnStatement == null || assignment == null) { return(false); } var returnedField = semanticModel.GetSymbolSafe(returnStatement.Expression, cancellationToken) as IFieldSymbol; var assignedField = semanticModel.GetSymbolSafe(assignment.Left, cancellationToken) as IFieldSymbol; if (assignedField == null || returnedField == null) { return(false); } var propertySymbol = semanticModel.GetDeclaredSymbolSafe(property, cancellationToken); return(assignedField.Equals(returnedField) && assignedField.ContainingType == propertySymbol?.ContainingType); }
private static void MakeWithBackingFieldNotifyWhenValueChanges(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken) { var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>(); if (classDeclaration == null) { return; } if (propertyDeclaration.TryGetSetter(out var setter)) { if (setter.ExpressionBody != null && IsSimpleAssignmentOnly(propertyDeclaration, out _, out _, out var assignment, out _)) { var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); var underscoreFields = CodeStyle.UnderscoreFields(semanticModel); var code = StringBuilderPool.Borrow() .AppendLine($"public Type PropertyName") .AppendLine("{") .AppendLine($" get => {assignment.Left};") .AppendLine() .AppendLine(" set") .AppendLine(" {") .AppendLine($" if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})") .AppendLine(" {") .AppendLine($" return;") .AppendLine(" }") .AppendLine() .AppendLine($" {assignment};") .AppendLine($" {Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)}") .AppendLine(" }") .AppendLine("}") .Return(); var template = ParseProperty(code); editor.ReplaceNode( setter, (x, _) => { var old = (AccessorDeclarationSyntax)x; return(old.WithBody(template.Setter().Body) .WithExpressionBody(null) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None))); }); editor.FormatNode(propertyDeclaration); } if (setter.Body?.Statements.Count == 1 && IsSimpleAssignmentOnly(propertyDeclaration, out _, out var statement, out assignment, out _)) { var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); var code = StringBuilderPool.Borrow() .AppendLine($" if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})") .AppendLine(" {") .AppendLine($" return;") .AppendLine(" }") .AppendLine() .Return(); var ifStatement = SyntaxFactory.ParseStatement(code) .WithSimplifiedNames() .WithLeadingElasticLineFeed() .WithTrailingElasticLineFeed() .WithAdditionalAnnotations(Formatter.Annotation); editor.InsertBefore( statement, ifStatement); var underscoreFields = CodeStyle.UnderscoreFields(semanticModel); var notifyStatement = SyntaxFactory .ParseStatement( Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)) .WithSimplifiedNames() .WithLeadingElasticLineFeed() .WithTrailingElasticLineFeed() .WithAdditionalAnnotations(Formatter.Annotation); editor.InsertAfter(statement, notifyStatement); editor.FormatNode(propertyDeclaration); } } }
internal static Result IsMemberDisposed(ISymbol member, TypeDeclarationSyntax context, SemanticModel semanticModel, CancellationToken cancellationToken) { return(IsMemberDisposed(member, semanticModel.GetDeclaredSymbolSafe(context, cancellationToken), semanticModel, cancellationToken)); }
internal static bool TryGetConversionTypes(ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol sourceType, out ITypeSymbol targetType) { sourceType = null; targetType = null; if (classDeclaration.TryFindMethod("Convert", out var convertMethod) && convertMethod.ReturnType is PredefinedTypeSyntax returnType && returnType.Keyword.ValueText == "object" && convertMethod.ParameterList != null && convertMethod.ParameterList.Parameters.Count == 4 && convertMethod.ParameterList.Parameters.TryFirst(out var valueParameter)) { using (var returnValues = ReturnValueWalker.Borrow(convertMethod)) { using (var returnTypes = PooledSet <ITypeSymbol> .Borrow()) { foreach (var returnValue in returnValues.ReturnValues) { AddReturnType(returnTypes, returnValue); } return(returnTypes.TrySingle(out targetType) && ConversionWalker.TryGetCommonBase( convertMethod, semanticModel.GetDeclaredSymbolSafe(valueParameter, cancellationToken), semanticModel, cancellationToken, out sourceType)); } } } return(false); void AddReturnType(PooledSet <ITypeSymbol> returnTypes, ExpressionSyntax returnValue) { switch (returnValue) { case LiteralExpressionSyntax literal when literal.IsKind(SyntaxKind.NullLiteralExpression): break; case ConditionalExpressionSyntax ternary: AddReturnType(returnTypes, ternary.WhenTrue); AddReturnType(returnTypes, ternary.WhenFalse); break; case BinaryExpressionSyntax coalesce when coalesce.IsKind(SyntaxKind.CoalesceExpression): AddReturnType(returnTypes, coalesce.Left); AddReturnType(returnTypes, coalesce.Right); break; case IdentifierNameSyntax _: case MemberAccessExpressionSyntax _: var type = semanticModel.GetTypeInfoSafe(returnValue, cancellationToken).Type; if (type == KnownSymbol.Object && semanticModel.GetSymbolSafe(returnValue, cancellationToken) is ISymbol symbol && symbol.IsEither <IFieldSymbol, IPropertySymbol>()) { switch (symbol) { case IFieldSymbol field: if (field.Type == KnownSymbol.Object && field.DeclaredAccessibility == Accessibility.Private && returnValue.FirstAncestor <TypeDeclarationSyntax>() is TypeDeclarationSyntax typeDeclaration) { using (var walker = AssignmentExecutionWalker.Borrow(typeDeclaration, Scope.Instance, semanticModel, cancellationToken)) { foreach (var assignment in walker.Assignments) { if (semanticModel.TryGetSymbol(assignment.Left, cancellationToken, out IFieldSymbol assigned) && FieldSymbolComparer.Equals(assigned, field)) { returnTypes.Add(semanticModel.GetTypeInfoSafe(assignment.Right, cancellationToken).Type); } } } } else { returnTypes.Add(field.Type); } return; case IPropertySymbol property: returnTypes.Add(property.Type); return; } } else { returnTypes.Add(type); } break;
internal static Result IsArgumentDisposedByReturnValue(ArgumentSyntax argument, SemanticModel semanticModel, CancellationToken cancellationToken, PooledHashSet <SyntaxNode> visited = null) { if (argument?.Parent is ArgumentListSyntax argumentList) { if (argumentList.Parent is InvocationExpressionSyntax invocation && semanticModel.GetSymbolSafe(invocation, cancellationToken) is IMethodSymbol method) { if (method.ContainingType.DeclaringSyntaxReferences.Length == 0) { if (method == KnownSymbol.CompositeDisposable.Add) { return(Result.Yes); } return(method.ReturnsVoid || !IsAssignableTo(method.ReturnType) ? Result.No : Result.AssumeYes); } if (invocation.TryGetMatchingParameter(argument, semanticModel, cancellationToken, out var parameter)) { return(CheckReturnValues(parameter, invocation, semanticModel, cancellationToken, visited)); } return(Result.Unknown); } if (argumentList.Parent is ObjectCreationExpressionSyntax || argumentList.Parent is ConstructorInitializerSyntax) { if (TryGetAssignedFieldOrProperty(argument, semanticModel, cancellationToken, out var member, out var ctor) && member != null) { var initializer = argument.FirstAncestorOrSelf <ConstructorInitializerSyntax>(); if (initializer != null) { if (semanticModel.GetDeclaredSymbolSafe(initializer.Parent, cancellationToken) is IMethodSymbol chainedCtor && chainedCtor.ContainingType != member.ContainingType) { if (TryGetDelRefMethod(chainedCtor.ContainingType, Search.TopLevel, out var disposeMethod)) { return(IsMemberDisposed(member, disposeMethod, semanticModel, cancellationToken) ? Result.Yes : Result.No); } } } return(IsMemberDisposed(member, ctor.ContainingType, semanticModel, cancellationToken)); } if (ctor == null) { return(Result.AssumeYes); } if (ctor.ContainingType.DeclaringSyntaxReferences.Length == 0) { return(IsAssignableTo(ctor.ContainingType) ? Result.AssumeYes : Result.No); } return(Result.No); } } return(Result.Unknown); }