public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) { var ctor = this.semanticModel.GetDeclaredSymbolSafe(node, this.cancellationToken); if (SymbolComparer.Equals(this.type, ctor.ContainingType)) { if (ctor.DeclaredAccessibility != Accessibility.Private) { this.nonPrivateCtors.Add(node); } if (ctor.Parameters.Length == 0) { this.Default = node; } } base.VisitConstructorDeclaration(node); }
public override void VisitArgument(ArgumentSyntax node) { if (this.visitedLocations.Add(node) && (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword) || node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword))) { var invocation = node.FirstAncestorOrSelf <InvocationExpressionSyntax>(); var argSymbol = this.semanticModel.GetSymbolSafe(node.Expression, this.cancellationToken); if (invocation != null && (SymbolComparer.Equals(this.CurrentSymbol, argSymbol) || this.refParameters.Contains(argSymbol as IParameterSymbol))) { var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (method != null && method.DeclaringSyntaxReferences.Length > 0) { foreach (var reference in method.DeclaringSyntaxReferences) { var methodDeclaration = reference.GetSyntax(this.cancellationToken) as MethodDeclarationSyntax; if (methodDeclaration.TryGetMatchingParameter(node, out var parameterSyntax)) { var parameterSymbol = this.semanticModel.GetDeclaredSymbolSafe(parameterSyntax, this.cancellationToken); if (parameterSymbol != null) { if (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword)) { this.refParameters.Add(parameterSymbol).IgnoreReturnValue(); } if (node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword)) { this.values.Add(node.Expression); } } } } } } } base.VisitArgument(node); }
internal static bool IsDisposing(InvocationExpressionSyntax invocation, ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken) { var method = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol; if (method == null || method.Parameters.Length != 0 || method != KnownSymbol.IDisposable.Dispose) { return(false); } if (TryGetDisposedRootMember(invocation, semanticModel, cancellationToken, out ExpressionSyntax disposed)) { if (SymbolComparer.Equals(member, semanticModel.GetSymbolSafe(disposed, cancellationToken))) { return(true); } } return(false); }
internal Result IsMemberDisposed(ISymbol member) { foreach (var invocation in this.invocations) { if (TryGetDisposedRootMember(invocation, this.SemanticModel, this.CancellationToken, out ExpressionSyntax disposed) && SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(disposed, this.CancellationToken))) { return(Result.Yes); } } foreach (var name in this.identifiers) { if (SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(name, this.CancellationToken))) { return(Result.Maybe); } } return(Result.No); }
private bool TryHandlePropertyGet(ExpressionSyntax propertyGet) { if (propertyGet == null) { return(false); } var property = this.semanticModel.GetSymbolSafe(propertyGet, this.cancellationToken) as IPropertySymbol; var getter = property?.GetMethod; if (getter == null) { return(false); } if (getter.DeclaringSyntaxReferences.Length == 0) { return(true); } foreach (var reference in getter.DeclaringSyntaxReferences) { base.Visit(reference.GetSyntax(this.cancellationToken)); } for (var i = this.values.Count - 1; i >= 0; i--) { var symbol = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken); if (this.search == Search.Recursive && SymbolComparer.Equals(symbol, property)) { this.values.RemoveAt(i); } } this.values.PurgeDuplicates(); return(true); }
private bool TryHandleInvocation(InvocationExpressionSyntax invocation) { if (invocation == null) { return(false); } var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (method == null || method.DeclaringSyntaxReferences.Length == 0) { return(true); } foreach (var reference in method.DeclaringSyntaxReferences) { base.Visit(reference.GetSyntax(this.cancellationToken)); } for (var i = this.values.Count - 1; i >= 0; i--) { var symbol = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken); if (this.search == Search.Recursive && SymbolComparer.Equals(symbol, method)) { this.values.RemoveAt(i); continue; } if (invocation.TryGetArgumentValue(symbol as IParameterSymbol, this.cancellationToken, out ExpressionSyntax arg)) { this.values[i] = arg; } } this.values.PurgeDuplicates(); return(true); }
internal static bool FirstForSymbol(ISymbol symbol, SyntaxNode scope, Search search, SemanticModel semanticModel, CancellationToken cancellationToken, out AssignmentExpressionSyntax assignment) { assignment = null; if (symbol == null || scope == null) { return(false); } using (var pooledAssignments = Create(scope, search, semanticModel, cancellationToken)) { foreach (var candidate in pooledAssignments.Item.Assignments) { var assignedSymbol = semanticModel.GetSymbolSafe(candidate.Left, cancellationToken); if (SymbolComparer.Equals(symbol, assignedSymbol)) { assignment = candidate; return(true); } } } return(false); }
public override void VisitInvocationExpression(InvocationExpressionSyntax node) { if (this.semanticModel.GetSymbolSafe(node, this.cancellationToken) is IMethodSymbol method) { base.VisitInvocationExpression(node); if (this.context is ElementAccessExpressionSyntax && node.Expression is MemberAccessExpressionSyntax memberAccess && method.Name == "Add" && SymbolComparer.Equals(this.CurrentSymbol, this.semanticModel.GetSymbolSafe(memberAccess.Expression, this.cancellationToken))) { if (method.ContainingType.Is(KnownSymbol.IDictionary) && node.ArgumentList?.Arguments.Count == 2) { this.values.Add(node.ArgumentList.Arguments[1].Expression); } else if (node.ArgumentList?.Arguments.Count == 1) { this.values.Add(node.ArgumentList.Arguments[0].Expression); } } this.HandleInvoke(method, node.ArgumentList); } }
private void HandleAssignedValue(SyntaxNode assignee, ExpressionSyntax value) { if (value == null) { return; } if (assignee is VariableDeclaratorSyntax declarator && declarator.Identifier.ValueText != this.CurrentSymbol.Name) { return; } if (this.CurrentSymbol.IsEither <ILocalSymbol, IParameterSymbol>() && assignee is MemberAccessExpressionSyntax) { return; } if (this.context is ElementAccessExpressionSyntax) { switch (value) { case ArrayCreationExpressionSyntax arrayCreation: { if (arrayCreation.Initializer == null) { return; } foreach (var item in arrayCreation.Initializer.Expressions) { this.values.Add(item); } } break; case ObjectCreationExpressionSyntax objectCreation: { if (objectCreation.Initializer == null) { return; } foreach (var item in objectCreation.Initializer.Expressions) { if (item is InitializerExpressionSyntax kvp) { if (kvp.Expressions.Count == 2) { this.values.Add(kvp.Expressions[1]); } } else if (item is AssignmentExpressionSyntax assignment) { this.values.Add(assignment.Right); } else { this.values.Add(item); } } } break; case InitializerExpressionSyntax initializer: { foreach (var item in initializer.Expressions) { this.values.Add(item); } } break; default: return; } return; } var assignedSymbol = this.semanticModel.GetSymbolSafe(assignee, this.cancellationToken) ?? this.semanticModel.GetDeclaredSymbolSafe(assignee, this.cancellationToken); if (assignedSymbol == null) { return; } if (this.CurrentSymbol.IsEither <IFieldSymbol, IPropertySymbol>() && assignedSymbol is IPropertySymbol property && !SymbolComparer.Equals(this.CurrentSymbol, property) && Property.AssignsSymbolInSetter(property, this.CurrentSymbol, this.semanticModel, this.cancellationToken)) { var before = this.values.Count; foreach (var reference in property.DeclaringSyntaxReferences) { var declaration = (PropertyDeclarationSyntax)reference.GetSyntax(this.cancellationToken); if (declaration.TryGetSetter(out var setter)) { this.Visit(setter); } } for (var i = before; i < this.values.Count; i++) { var parameter = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken) as IParameterSymbol; if (Equals(parameter?.ContainingSymbol, property.SetMethod)) { this.values[i] = value; } } }
private static bool IsReturned(ILocalSymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var pooled = ReturnValueWalker.Create(block, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var value in pooled.Item) { var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (SymbolComparer.Equals(symbol, returnedSymbol)) { return(true); } if (value is ObjectCreationExpressionSyntax objectCreation) { if (objectCreation.ArgumentList != null) { foreach (var argument in objectCreation.ArgumentList.Arguments) { var arg = semanticModel.GetSymbolSafe(argument.Expression, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } if (objectCreation.Initializer != null) { foreach (var argument in objectCreation.Initializer.Expressions) { var arg = semanticModel.GetSymbolSafe(argument, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } } if (value is InvocationExpressionSyntax invocation) { if (returnedSymbol == KnownSymbol.RxDisposable.Create && invocation.ArgumentList != null && invocation.ArgumentList.Arguments.TryGetSingle(out ArgumentSyntax argument)) { var body = (argument.Expression as ParenthesizedLambdaExpressionSyntax)?.Body; using (var pooledInvocations = InvocationWalker.Create(body)) { foreach (var candidate in pooledInvocations.Item.Invocations) { if (Disposable.IsDisposing(candidate, symbol, semanticModel, cancellationToken)) { return(true); } } } } } } } return(false); }
private static bool IsMatch(ISymbol symbol, ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken) { switch (expression) { case ConditionalExpressionSyntax conditional: return(IsMatch(symbol, conditional.WhenTrue, semanticModel, cancellationToken) || IsMatch(symbol, conditional.WhenFalse, semanticModel, cancellationToken)); case BinaryExpressionSyntax binary when binary.IsKind(SyntaxKind.CoalesceExpression): return(IsMatch(symbol, binary.Left, semanticModel, cancellationToken) || IsMatch(symbol, binary.Right, semanticModel, cancellationToken)); case BinaryExpressionSyntax binary when binary.IsKind(SyntaxKind.AsExpression): return(IsMatch(symbol, binary.Left, semanticModel, cancellationToken)); case CastExpressionSyntax cast: return(IsMatch(symbol, cast.Expression, semanticModel, cancellationToken)); case ObjectCreationExpressionSyntax objectCreation when objectCreation.ArgumentList != null && objectCreation.ArgumentList.Arguments.TryFirst(x => SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(x.Expression, cancellationToken)), out ArgumentSyntax _): return(true); default: if (symbol.IsEither <ILocalSymbol, IParameterSymbol>()) { return(expression is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == symbol.Name && SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(expression, cancellationToken))); } return(SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(expression, cancellationToken))); } }
internal void HandleInvoke(IMethodSymbol method, ArgumentListSyntax argumentList) { if (method != null && (method.Parameters.TryFirst(x => x.RefKind != RefKind.None, out _) || this.CurrentSymbol.ContainingType.Is(method.ContainingType))) { if (TryGetWalker(out var walker)) { foreach (var value in walker.values) { this.values.Add(GetArgumentValue(value)); } foreach (var outValue in walker.outValues) { this.values.Add(GetArgumentValue(outValue)); } } } bool TryGetWalker(out AssignedValueWalker result) { result = null; if (TryGetKey(out var key)) { if (this.memberWalkers.TryGetValue(key, out result)) { return(false); } if (method.TrySingleDeclaration(this.cancellationToken, out var declaration)) { result = Borrow(() => new AssignedValueWalker()); this.memberWalkers.Add(key, result); result.CurrentSymbol = this.CurrentSymbol; result.semanticModel = this.semanticModel; result.cancellationToken = this.cancellationToken; result.context = this.context.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() != null ? this.context : declaration; result.memberWalkers.Parent = this.memberWalkers; if (argumentList != null) { foreach (var argument in argumentList.Arguments) { if (argument.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword) && TryGetMatchingParameter(argument, out var parameter)) { result.refParameters.Add(parameter); } else if (argument.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword) && TryGetMatchingParameter(argument, out parameter)) { result.outParameters.Add(parameter); } } } result.Visit(declaration); } } return(result != null); bool TryGetMatchingParameter(ArgumentSyntax argument, out IParameterSymbol parameter) { parameter = null; if (this.semanticModel.GetSymbolSafe(argument.Expression, this.cancellationToken) is ISymbol symbol) { if (SymbolComparer.Equals(this.CurrentSymbol, symbol) || this.refParameters.Contains(symbol as IParameterSymbol) || this.outParameters.Contains(symbol as IParameterSymbol)) { return(method.TryGetMatchingParameter(argument, out parameter)); } } return(false); } bool TryGetKey(out SyntaxNode node) { if (argumentList != null) { node = argumentList; return(true); } return(method.TrySingleDeclaration(this.cancellationToken, out node)); } } ExpressionSyntax GetArgumentValue(ExpressionSyntax value) { if (value is IdentifierNameSyntax identifierName && method.Parameters.TryFirst(x => x.Name == identifierName.Identifier.ValueText, out var parameter)) { if (argumentList.TryGetMatchingArgument(parameter, out var argument)) { return(argument.Expression); } if (parameter.HasExplicitDefaultValue && parameter.TrySingleDeclaration(this.cancellationToken, out var parameterDeclaration)) { return(parameterDeclaration.Default?.Value); } } return(value); } }