public static void ForWhenLocal() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace N { public class C { public C() { var i = 0; i = 1; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); Assert.AreEqual(true, semanticModel.TryGetSymbol(syntaxTree.FindVariableDeclaration("i"), CancellationToken.None, out ILocalSymbol local)); using (var walker = IdentifierNameWalker.For(local, semanticModel, CancellationToken.None)) { CollectionAssert.AreEqual(new[] { "i" }, walker.IdentifierNames.Select(x => x.Identifier.ValueText)); Assert.AreEqual(true, walker.TryFind("i", out var match)); Assert.AreEqual("i", match.Identifier.ValueText); Assert.AreEqual(false, walker.TryFind("missing", out _)); } }
public static void TryFindWhenProperty() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace N { public class C { public int P { get; } public void M() { var p = this.P; } } }"); var node = syntaxTree.FindMethodDeclaration("M"); using (var walker = IdentifierNameWalker.Borrow(node)) { CollectionAssert.AreEqual(new[] { "var", "P" }, walker.IdentifierNames.Select(x => x.Identifier.ValueText)); Assert.AreEqual(true, walker.TryFind("P", out var match)); Assert.AreEqual("P", match.Identifier.ValueText); Assert.AreEqual(false, walker.TryFind("missing", out _)); } }
private static bool UsesValueAndMember(IfStatementSyntax ifStatement, SemanticModel semanticModel, CancellationToken cancellationToken, IParameterSymbol value, ISymbol member) { var usesValue = false; var usesMember = false; using (var pooledIdentifierNames = IdentifierNameWalker.Create(ifStatement.Condition)) { foreach (var identifierName in pooledIdentifierNames.Item.IdentifierNames) { var symbol = semanticModel.GetSymbolSafe(identifierName, cancellationToken); if (symbol == null) { continue; } if (symbol.Equals(value)) { usesValue = true; } if (symbol.Equals(member)) { usesMember = true; } } } return(usesMember && usesValue); }
public static void TryFindLast() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace N { public class C { public C(int i) { i = 1; i = 2; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var symbol = semanticModel.GetDeclaredSymbolSafe(syntaxTree.FindParameter("int i"), CancellationToken.None); var node = syntaxTree.FindTypeDeclaration("C"); Assert.AreEqual(true, IdentifierNameWalker.TryFindLast(node, symbol, semanticModel, CancellationToken.None, out var match)); Assert.AreEqual("i = 2", match.Parent.ToString()); using (var walker = IdentifierNameWalker.Borrow(node)) { Assert.AreEqual(true, walker.TryFindLast(symbol, semanticModel, CancellationToken.None, out match)); Assert.AreEqual("i = 2", match.Parent.ToString()); } }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken) .ConfigureAwait(false); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing) { continue; } var ctor = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <ConstructorDeclarationSyntax>(); var invocation = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <InvocationExpressionSyntax>(); if (ctor != null && invocation != null && invocation.Expression is MemberAccessExpressionSyntax memberAccess) { var condition = memberAccess.Expression; var symbol = semanticModel.GetSymbolSafe(condition, context.CancellationToken); if (symbol is IParameterSymbol parameter) { using (var pooled = IdentifierNameWalker.Create(ctor)) { foreach (var name in pooled.Item.IdentifierNames) { if (name.Identifier.ValueText == parameter.Name) { if (!condition.Contains(name)) { return; } } } } if (ctor.ParameterList.Parameters.TryGetFirst(p => p.Identifier.ValueText == parameter.Name, out ParameterSyntax parameterSyntax)) { context.RegisterCodeFix( CodeAction.Create( "Inject negated.", cancellationToken => ApplyInjectNegatedFixAsync(cancellationToken, context, parameterSyntax, invocation), nameof(InjectNegatedCodeFix)), diagnostic); continue; } } } } }
private static bool IsInitializedWith(PropertyDeclarationSyntax x, PropertyDeclarationSyntax y) { if (y.Modifiers.Any(SyntaxKind.StaticKeyword) && x.Initializer is { Value : { } value } initializer&& !(value is LiteralExpressionSyntax)) { using var walker = IdentifierNameWalker.Borrow(initializer); foreach (var identifierName in walker.IdentifierNames) { if (y.Identifier.ValueText == identifierName.Identifier.ValueText) { return(true); } } } return(false); }
private static bool IsInitializedWith(FieldDeclarationSyntax x, FieldDeclarationSyntax y) { if (y.Modifiers.Any(SyntaxKind.ConstKeyword, SyntaxKind.StaticKeyword) && x.Declaration.Variables.TryLast(out var variable) && variable.Initializer is { Value : { } value } initializer&& !(value is LiteralExpressionSyntax)) { using (var walker = IdentifierNameWalker.Borrow(initializer)) { foreach (var identifierName in walker.IdentifierNames) { if (y.Declaration.TryFindVariable(identifierName.Identifier.ValueText, out _)) { return(true); } } } } return(false); }
public static void TryFindWhenParameter() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace N { public class C { public C(int i) { i = 1; } } }"); var node = syntaxTree.FindTypeDeclaration("C"); using var walker = IdentifierNameWalker.Borrow(node); CollectionAssert.AreEqual(new[] { "i" }, walker.IdentifierNames.Select(x => x.Identifier.ValueText)); Assert.AreEqual(true, walker.TryFind("i", out var match)); Assert.AreEqual("i", match.Identifier.ValueText); Assert.AreEqual(false, walker.TryFind("missing", out _)); }
public static void ForWhenParameter() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace N { public class C { public C(int i) { i = 1; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, Settings.Default.MetadataReferences); var semanticModel = compilation.GetSemanticModel(syntaxTree); Assert.AreEqual(true, semanticModel.TryGetSymbol(syntaxTree.FindParameter("i"), CancellationToken.None, out var parameter)); using var walker = IdentifierNameWalker.For(parameter, semanticModel, CancellationToken.None); CollectionAssert.AreEqual(new[] { "i" }, walker.IdentifierNames.Select(x => x.Identifier.ValueText)); Assert.AreEqual(true, walker.TryFind("i", out var match)); Assert.AreEqual("i", match.Identifier.ValueText); Assert.AreEqual(false, walker.TryFind("missing", out _)); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken) .ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing) { continue; } var assignment = syntaxRoot.FindNode(diagnostic.Location.SourceSpan) .FirstAncestorOrSelf <AssignmentExpressionSyntax>(); if (assignment == null || assignment.Left == null || assignment.Right == null) { continue; } if (assignment.Right is ParenthesizedLambdaExpressionSyntax lambda && lambda.Body != null) { using (var pooled = IdentifierNameWalker.Create(lambda.Body)) { var usesArg = false; foreach (var name in pooled.Item.IdentifierNames) { if (name.Identifier.ValueText == lambda.ParameterList.Parameters[0] .Identifier.ValueText) { return; } if (name.Identifier.ValueText == lambda.ParameterList.Parameters[1] .Identifier.ValueText) { usesArg = true; } } context.RegisterCodeFix( CodeAction.Create( "Observe.Event", cancellationToken => ApplyObserveEventLamdaFixAsync( cancellationToken, context, assignment, usesArg), nameof(EventSubscriptionToObserveFix)), diagnostic); } } if (assignment.Right is MemberAccessExpressionSyntax memberAccess) { var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); if (semanticModel.GetSymbolSafe(memberAccess, context.CancellationToken) is IMethodSymbol method && method.DeclaredAccessibility == Accessibility.Private && method.DeclaringSyntaxReferences.Length == 1) { var methodDeclaration = (MethodDeclarationSyntax)method.DeclaringSyntaxReferences[0].GetSyntax(context.CancellationToken); context.RegisterCodeFix( CodeAction.Create( "Observe.Event", cancellationToken => ApplyObserveEventMethodFixAsync(cancellationToken, context, assignment, methodDeclaration), nameof(EventSubscriptionToObserveFix)), diagnostic); } } } }
private static async Task <Document> ApplyObserveEventMethodFixAsync( CancellationToken cancellationToken, CodeFixContext context, AssignmentExpressionSyntax assignment, MethodDeclarationSyntax methodDeclaration) { var usesArg = false; if (methodDeclaration.ParameterList.Parameters.Any()) { using (var pooled = IdentifierNameWalker.Create((SyntaxNode)methodDeclaration.Body ?? methodDeclaration.ExpressionBody)) { foreach (var name in pooled.Item.IdentifierNames) { if (name.Identifier.ValueText == methodDeclaration.ParameterList.Parameters[0].Identifier.ValueText) { if (methodDeclaration.ParameterList.Parameters.Count == 1) { usesArg = true; continue; } return(context.Document); } if (methodDeclaration.ParameterList.Parameters.Count == 2 && name.Identifier.ValueText == methodDeclaration.ParameterList.Parameters[1] .Identifier.ValueText) { usesArg = true; } } } } var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken) .ConfigureAwait(false); var eventSymbol = (IEventSymbol)editor.SemanticModel.GetSymbolSafe(assignment.Left, cancellationToken); var observeSubscribe = GetObservableFromEventString(eventSymbol) .Replace("HANDLERTYPE", eventSymbol.Type.ToDisplayString()) .Replace("ARGTYPE", ArgType(eventSymbol)) .Replace("LEFT", assignment.Left.ToString()) .Replace("LAMBDA", Lambda(methodDeclaration, usesArg)); editor.ReplaceNode( assignment, SyntaxFactory.ParseExpression(observeSubscribe) .WithLeadingTrivia(assignment.GetLeadingTrivia()) .WithAdditionalAnnotations(Simplifier.Annotation)); if (methodDeclaration.ParameterList.Parameters.Count == 2) { editor.RemoveNode(methodDeclaration.ParameterList.Parameters[0]); } if (!usesArg && methodDeclaration.ParameterList.Parameters.Any()) { editor.RemoveNode(methodDeclaration.ParameterList.Parameters.Last()); } return(editor.GetChangedDocument()); }
private static void HandleAssignment(SyntaxNodeAnalysisContext context) { var assignment = (AssignmentExpressionSyntax)context.Node; if (assignment?.IsMissing != false || assignment.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() != null || assignment.FirstAncestorOrSelf <InitializerExpressionSyntax>() != null) { return; } var block = assignment.FirstAncestorOrSelf <BlockSyntax>(); if (block == null) { return; } var typeDeclaration = assignment.FirstAncestorOrSelf <TypeDeclarationSyntax>(); var typeSymbol = context.SemanticModel.GetDeclaredSymbolSafe(typeDeclaration, context.CancellationToken); if (!typeSymbol.Is(KnownSymbol.INotifyPropertyChanged)) { return; } var field = context.SemanticModel.GetSymbolSafe(assignment.Left, context.CancellationToken) as IFieldSymbol; if (field == null || !typeSymbol.Equals(field.ContainingType)) { return; } foreach (var member in typeDeclaration.Members) { var propertyDeclaration = member as PropertyDeclarationSyntax; if (propertyDeclaration == null) { continue; } var property = context.SemanticModel.GetDeclaredSymbolSafe(propertyDeclaration, context.CancellationToken); var getter = Getter(propertyDeclaration); if (getter == null || property == null || property.DeclaredAccessibility != Accessibility.Public) { continue; } using (var pooled = IdentifierNameWalker.Create(getter)) { foreach (var identifierName in pooled.Item.IdentifierNames) { var component = context.SemanticModel.GetSymbolSafe(identifierName, context.CancellationToken); var componentField = component as IFieldSymbol; if (componentField == null) { var propertySymbol = component as IPropertySymbol; if (propertySymbol == null) { continue; } if (!Property.TryGetBackingField(propertySymbol, context.SemanticModel, context.CancellationToken, out componentField)) { continue; } } if (!field.Equals(componentField)) { continue; } if (PropertyChanged.InvokesPropertyChangedFor(assignment, property, context.SemanticModel, context.CancellationToken) == PropertyChanged.InvokesPropertyChanged.No) { var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>(PropertyNameKey, property.Name), }); context.ReportDiagnostic(Diagnostic.Create(Descriptor, assignment.GetLocation(), properties, property.Name)); } } } } }