public static bool IsRightSideOfQualifiedName([NotNullWhen(true)] this ExpressionSyntax?expression) => expression.IsParentKind(SyntaxKind.QualifiedName, out QualifiedNameSyntax? qualifiedName) && qualifiedName.Right == expression;
private static WhenClauseSyntax?AsWhenClause(ExpressionSyntax?expression) => expression is null ? null : WhenClause(expression);
/// <summary> /// Check if <paramref name="candidate"/> is a check for equality. /// Operators == and != /// Equals, ReferenceEquals. /// </summary> /// <param name="candidate">The <see cref="InvocationExpressionSyntax"/>.</param> /// <param name="semanticModel">The <see cref="SemanticModel"/>. If null only the name is checked.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that cancels the operation.</param> /// <param name="left">The left value.</param> /// <param name="right">The right value.</param> /// <returns>True if <paramref name="candidate"/> is a check for equality.</returns> public static bool IsObjectEquals(InvocationExpressionSyntax candidate, SemanticModel?semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?left, [NotNullWhen(true)] out ExpressionSyntax?right) { if (candidate is null) { throw new ArgumentNullException(nameof(candidate)); } if (candidate.ArgumentList is { Arguments : { Count : 2 } arguments } &&
private static bool TryFindNodeAtSource(Diagnostic diagnostic, SyntaxNode root, [NotNullWhen(true)] out ExpressionSyntax?target, [NotNullWhen(true)] out Func <ExpressionSyntax, CancellationToken, ExpressionSyntax>?transform) { transform = null; target = null; var syntaxNode = (ExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan); if (syntaxNode.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() != null) { // We don't support converting anonymous delegates to async. return(false); } SimpleNameSyntax?FindStaticWaitInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) { var name = ((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Name; return(name?.Identifier.ValueText switch { nameof(Task.WaitAny) => name, nameof(Task.WaitAll) => name, _ => null, });
internal static bool DisposedByReturnValue(ArgumentSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?creation) { if (candidate.TryFirstAncestor(out TypeDeclarationSyntax? containingTypeDeclaration) && semanticModel.TryGetNamedType(containingTypeDeclaration, cancellationToken, out var containingType)) { using var recursion = Recursion.Borrow(containingType, semanticModel, cancellationToken); if (recursion.Target(candidate) is { } target) { return(DisposedByReturnValue(target, recursion, out creation)); } } creation = null; return(false); }
internal static bool TryGetSyntax(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, SignatureHelpTriggerReason triggerReason, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?identifier, out SyntaxToken openBrace) { if (CommonSignatureHelpUtilities.TryGetSyntax(root, position, syntaxFacts, triggerReason, IsTriggerToken, IsArgumentListToken, cancellationToken, out ArrayTypeSyntax arrayTypeSyntax)) { identifier = arrayTypeSyntax.ElementType; openBrace = arrayTypeSyntax.RankSpecifiers.First().OpenBracketToken; return(true); } identifier = null; openBrace = default; return(false); }
protected FieldDeclarationSyntax ResolveStaticGlobal(ITypeInfo type, string name, ExpressionSyntax?initializer = null, bool @private = true) { VariableDeclaratorSyntax declarator = VariableDeclarator ( identifier: Identifier(name) ); if (initializer is not null) { declarator = declarator.WithInitializer ( initializer: EqualsValueClause ( initializer ) ); } return(FieldDeclaration ( declaration: VariableDeclaration ( type: ResolveType(type), variables: SingletonSeparatedList(declarator) ) ) .WithModifiers ( TokenList ( new SyntaxToken[] { Token(@private ? SyntaxKind.PrivateKeyword : SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword) } ) )); }
internal static bool TryGetAssignedValue(this FieldOrProperty fieldOrProperty, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?value) { value = null; if (fieldOrProperty.Symbol is IFieldSymbol field) { return(field.TryGetAssignedValue(cancellationToken, out value)); } if (fieldOrProperty.Symbol is IPropertySymbol property) { if (property.TrySingleDeclaration(cancellationToken, out PropertyDeclarationSyntax? declaration)) { if (declaration.Initializer != null) { value = declaration.Initializer.Value; } else if (declaration.ExpressionBody != null) { value = declaration.ExpressionBody.Expression; } return(value != null); } } return(false); }
private static bool TryGetCreatedType(IMethodSymbol createInstance, InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out ITypeSymbol?createdType, [NotNullWhen(true)] out ExpressionSyntax?typeSource) { if (createInstance.IsGenericMethod && invocation.Expression is MemberAccessExpressionSyntax { Name : GenericNameSyntax { TypeArgumentList : { Arguments : { Count : 1 } typeArguments } } } &&
internal static bool TryFindSingleMutation(AccessorDeclarationSyntax setter, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?backing) { backing = null; using (var mutations = MutationWalker.Borrow(setter, SearchScope.Member, semanticModel, cancellationToken)) { if (mutations.All().TrySingle(x => x.IsEither(SyntaxKind.SimpleAssignmentExpression, SyntaxKind.Argument), out var mutation)) { return(mutation switch { AssignmentExpressionSyntax assignment => IsMutation(assignment, semanticModel, cancellationToken, out _, out backing), ArgumentSyntax { Parent : ArgumentListSyntax { Parent : InvocationExpressionSyntax invocation } } => IsMutation(invocation, semanticModel, cancellationToken, out _, out backing),
internal static bool TryGetSingle(SyntaxNode node, [NotNullWhen(true)] out ExpressionSyntax?returnValue) { using var walker = Borrow(node); return(walker.returnValues.TrySingle(out returnValue)); }
internal static bool TryFindSingleMutation(PropertyDeclarationSyntax property, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?backing) { backing = null; return(property.TryGetSetter(out var setter) && TryFindSingleMutation(setter, semanticModel, cancellationToken, out backing)); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic?diagnostic = context.Diagnostics.First(); SyntaxNode?root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var syntaxNode = (ExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); CSharpUtils.ContainingFunctionData container = CSharpUtils.GetContainingFunction(syntaxNode); if (container.BlockOrExpression is null) { return; } SemanticModel?semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); ISymbol?enclosingSymbol = semanticModel.GetEnclosingSymbol(diagnostic.Location.SourceSpan.Start, context.CancellationToken); if (enclosingSymbol is null) { return; } bool convertToAsync = !container.IsAsync && Utils.HasAsyncCompatibleReturnType(enclosingSymbol as IMethodSymbol); if (convertToAsync) { // We don't support this yet, and we don't want to take the sync method path in this case. // The user will have to fix this themselves. return; } Regex lookupKey = (container.IsAsync || convertToAsync) ? CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread : CommonInterest.FileNamePatternForMethodsThatAssertMainThread; string[] options = diagnostic.Properties[lookupKey.ToString()].Split('\n'); if (options.Length > 0) { // For any symbol lookups, we want to consider the position of the very first statement in the block. int positionForLookup = container.BlockOrExpression.GetLocation().SourceSpan.Start + 1; Lazy <ISymbol> cancellationTokenSymbol = new Lazy <ISymbol>(() => Utils.FindCancellationToken(semanticModel, positionForLookup, context.CancellationToken).FirstOrDefault()); foreach (var option in options) { // We're looking for methods that either require no parameters, // or (if we have one to give) that have just one parameter that is a CancellationToken. IMethodSymbol?proposedMethod = Utils.FindMethodGroup(semanticModel, option) .FirstOrDefault(m => !m.Parameters.Any(p => !p.HasExplicitDefaultValue) || (cancellationTokenSymbol.Value is object && m.Parameters.Length == 1 && Utils.IsCancellationTokenParameter(m.Parameters[0]))); if (proposedMethod is null) { // We can't find it, so don't offer to use it. continue; } if (proposedMethod.IsStatic) { OfferFix(option); } else { foreach (Tuple <bool, ISymbol>?candidate in Utils.FindInstanceOf(proposedMethod.ContainingType, semanticModel, positionForLookup, context.CancellationToken)) { if (candidate.Item1) { OfferFix($"{candidate.Item2.Name}.{proposedMethod.Name}"); } else { OfferFix($"{candidate.Item2.ContainingNamespace}.{candidate.Item2.ContainingType.Name}.{candidate.Item2.Name}.{proposedMethod.Name}"); } } } void OfferFix(string fullyQualifiedMethod) { context.RegisterCodeFix(CodeAction.Create($"Add call to {fullyQualifiedMethod}", ct => Fix(fullyQualifiedMethod, proposedMethod, cancellationTokenSymbol), fullyQualifiedMethod), context.Diagnostics); } } } Task <Document> Fix(string fullyQualifiedMethod, IMethodSymbol methodSymbol, Lazy <ISymbol> cancellationTokenSymbol) { int typeAndMethodDelimiterIndex = fullyQualifiedMethod.LastIndexOf('.'); IdentifierNameSyntax methodName = SyntaxFactory.IdentifierName(fullyQualifiedMethod.Substring(typeAndMethodDelimiterIndex + 1)); ExpressionSyntax invokedMethod = CSharpUtils.MemberAccess(fullyQualifiedMethod.Substring(0, typeAndMethodDelimiterIndex).Split('.'), methodName); InvocationExpressionSyntax?invocationExpression = SyntaxFactory.InvocationExpression(invokedMethod); IParameterSymbol? cancellationTokenParameter = methodSymbol.Parameters.FirstOrDefault(Utils.IsCancellationTokenParameter); if (cancellationTokenParameter is object && cancellationTokenSymbol.Value is object) { ArgumentSyntax?arg = SyntaxFactory.Argument(SyntaxFactory.IdentifierName(cancellationTokenSymbol.Value.Name)); if (methodSymbol.Parameters.IndexOf(cancellationTokenParameter) > 0) { arg = arg.WithNameColon(SyntaxFactory.NameColon(SyntaxFactory.IdentifierName(cancellationTokenParameter.Name))); } invocationExpression = invocationExpression.AddArgumentListArguments(arg); } ExpressionSyntax? awaitExpression = container.IsAsync ? SyntaxFactory.AwaitExpression(invocationExpression) : null; ExpressionStatementSyntax?addedStatement = SyntaxFactory.ExpressionStatement(awaitExpression ?? invocationExpression) .WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation); var initialBlockSyntax = container.BlockOrExpression as BlockSyntax; if (initialBlockSyntax is null) { initialBlockSyntax = SyntaxFactory.Block(SyntaxFactory.ReturnStatement((ExpressionSyntax)container.BlockOrExpression)) .WithAdditionalAnnotations(Formatter.Annotation); } BlockSyntax?newBlock = initialBlockSyntax.WithStatements(initialBlockSyntax.Statements.Insert(0, addedStatement)); return(Task.FromResult(context.Document.WithSyntaxRoot(root.ReplaceNode(container.BlockOrExpression, newBlock)))); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); ExpressionSyntax?syntaxNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) as ExpressionSyntax; if (syntaxNode is null) { continue; } var container = Utils.GetContainingFunction(syntaxNode); if (container.BlockOrExpression == null) { return; } if (!container.IsAsync) { if (!(container.Function is MethodDeclarationSyntax || container.Function is AnonymousFunctionExpressionSyntax)) { // We don't support converting whatever this is into an async method. return; } } var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var enclosingSymbol = semanticModel.GetEnclosingSymbol(diagnostic.Location.SourceSpan.Start, context.CancellationToken); if (enclosingSymbol == null) { return; } var hasReturnValue = ((enclosingSymbol as IMethodSymbol)?.ReturnType as INamedTypeSymbol)?.IsGenericType ?? false; var options = await CommonFixes.ReadMethodsAsync(context, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread, context.CancellationToken); int positionForLookup = diagnostic.Location.SourceSpan.Start; ISymbol cancellationTokenSymbol = Utils.FindCancellationToken(semanticModel, positionForLookup, context.CancellationToken).FirstOrDefault(); foreach (var option in options) { // We're looking for methods that either require no parameters, // or (if we have one to give) that have just one parameter that is a CancellationToken. var proposedMethod = Utils.FindMethodGroup(semanticModel, option) .FirstOrDefault(m => !m.Parameters.Any(p => !p.HasExplicitDefaultValue) || (cancellationTokenSymbol != null && m.Parameters.Length == 1 && Utils.IsCancellationTokenParameter(m.Parameters[0]))); if (proposedMethod == null) { // We can't find it, so don't offer to use it. continue; } if (proposedMethod.IsStatic) { OfferFix(option.ToString()); } else { foreach (var candidate in Utils.FindInstanceOf(proposedMethod.ContainingType, semanticModel, positionForLookup, context.CancellationToken)) { if (candidate.Item1) { OfferFix($"{candidate.Item2.Name}.{proposedMethod.Name}"); } else { OfferFix($"{candidate.Item2.ContainingNamespace}.{candidate.Item2.ContainingType.Name}.{candidate.Item2.Name}.{proposedMethod.Name}"); } } } void OfferFix(string fullyQualifiedMethod) { context.RegisterCodeFix(CodeAction.Create($"Use 'await {fullyQualifiedMethod}'", ct => Fix(fullyQualifiedMethod, proposedMethod, hasReturnValue, ct), fullyQualifiedMethod), context.Diagnostics); } } async Task <Solution> Fix(string fullyQualifiedMethod, IMethodSymbol methodSymbol, bool hasReturnValue, CancellationToken cancellationToken) { var assertionStatementToRemove = syntaxNode !.FirstAncestorOrSelf <StatementSyntax>(); int typeAndMethodDelimiterIndex = fullyQualifiedMethod.LastIndexOf('.'); IdentifierNameSyntax methodName = SyntaxFactory.IdentifierName(fullyQualifiedMethod.Substring(typeAndMethodDelimiterIndex + 1)); ExpressionSyntax invokedMethod = Utils.MemberAccess(fullyQualifiedMethod.Substring(0, typeAndMethodDelimiterIndex).Split('.'), methodName) .WithAdditionalAnnotations(Simplifier.Annotation); var invocationExpression = SyntaxFactory.InvocationExpression(invokedMethod); var cancellationTokenParameter = methodSymbol.Parameters.FirstOrDefault(Utils.IsCancellationTokenParameter); if (cancellationTokenParameter != null && cancellationTokenSymbol != null) { var arg = SyntaxFactory.Argument(SyntaxFactory.IdentifierName(cancellationTokenSymbol.Name)); if (methodSymbol.Parameters.IndexOf(cancellationTokenParameter) > 0) { arg = arg.WithNameColon(SyntaxFactory.NameColon(SyntaxFactory.IdentifierName(cancellationTokenParameter.Name))); } invocationExpression = invocationExpression.AddArgumentListArguments(arg); } ExpressionSyntax awaitExpression = SyntaxFactory.AwaitExpression(invocationExpression); var addedStatement = SyntaxFactory.ExpressionStatement(awaitExpression) .WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation); var methodAnnotation = new SyntaxAnnotation(); CSharpSyntaxNode methodSyntax = container.Function.ReplaceNode(assertionStatementToRemove, addedStatement) .WithAdditionalAnnotations(methodAnnotation); Document newDocument = context.Document.WithSyntaxRoot(root.ReplaceNode(container.Function, methodSyntax)); var newSyntaxRoot = await newDocument.GetSyntaxRootAsync(cancellationToken); methodSyntax = (CSharpSyntaxNode)newSyntaxRoot.GetAnnotatedNodes(methodAnnotation).Single(); if (!container.IsAsync) { switch (methodSyntax) { case AnonymousFunctionExpressionSyntax anonFunc: semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken); methodSyntax = FixUtils.MakeMethodAsync(anonFunc, hasReturnValue, semanticModel, cancellationToken); newDocument = newDocument.WithSyntaxRoot(newSyntaxRoot.ReplaceNode(anonFunc, methodSyntax)); break; case MethodDeclarationSyntax methodDecl: (newDocument, methodSyntax) = await FixUtils.MakeMethodAsync(methodDecl, newDocument, cancellationToken); break; } } return(newDocument.Project.Solution); } } }
private static bool TryFindNodeAtSource(Diagnostic diagnostic, SyntaxNode root, [NotNullWhen(true)] out ExpressionSyntax?target, [NotNullWhen(true)] out Func <ExpressionSyntax, CancellationToken, ExpressionSyntax>?transform) { transform = null; target = null; var syntaxNode = (ExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan); if (syntaxNode.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() != null) { // We don't support converting anonymous delegates to async. return(false); } ExpressionSyntax?FindTwoLevelDeepIdentifierInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) => ((((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression; ExpressionSyntax?FindOneLevelDeepIdentifierInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) => ((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression; ExpressionSyntax?FindParentMemberAccess(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) => (from as MemberAccessExpressionSyntax)?.Expression; var parentInvocation = syntaxNode.FirstAncestorOrSelf <InvocationExpressionSyntax>(); var parentMemberAccess = syntaxNode.FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); if (FindTwoLevelDeepIdentifierInvocation(parentInvocation) != null) { // This method will not return null for the provided 'target' argument transform = NullableHelpers.AsNonNullReturnUnchecked <ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindTwoLevelDeepIdentifierInvocation); target = parentInvocation; } else if (FindOneLevelDeepIdentifierInvocation(parentInvocation) != null) { // This method will not return null for the provided 'target' argument transform = NullableHelpers.AsNonNullReturnUnchecked <ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindOneLevelDeepIdentifierInvocation); target = parentInvocation; } else if (FindParentMemberAccess(parentMemberAccess) != null) { // This method will not return null for the provided 'target' argument transform = NullableHelpers.AsNonNullReturnUnchecked <ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindParentMemberAccess); target = parentMemberAccess; } else { return(false); } return(true); }
protected static InvocationExpressionSyntax?GetConstraintExpression(string constraintString, ExpressionSyntax?expected) { if (expected == null) { return(null); } return(SyntaxFactory.InvocationExpression( SyntaxFactory.ParseExpression(constraintString), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(expected))))); }
internal static bool TryGetSyntax(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, SignatureHelpTriggerReason triggerReason, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?identifier, out SyntaxToken openBrace) { if (CommonSignatureHelpUtilities.TryGetSyntax(root, position, syntaxFacts, triggerReason, IsTriggerToken, IsArgumentListToken, cancellationToken, out ElementAccessExpressionSyntax elementAccessExpression)) { identifier = elementAccessExpression.Expression; openBrace = elementAccessExpression.ArgumentList.OpenBracketToken; return(true); } identifier = null; openBrace = default; return(false); }
/// <summary> /// [[(Type)] target | [(Type)] this | Namespace.Type].Member /// </summary> protected internal MemberAccessExpressionSyntax MemberAccess(ExpressionSyntax?target, IMemberInfo member, ITypeInfo?castTargetTo = null) => SimpleMemberAccess ( AmendTarget(target, member, castTargetTo), member.Name );
internal static bool TryGetSyntax(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, SignatureHelpTriggerReason triggerReason, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?identifier, out SyntaxToken openBrace) { if (CommonSignatureHelpUtilities.TryGetSyntax(root, position, syntaxFacts, triggerReason, IsTriggerToken, IsArgumentListToken, cancellationToken, out ElementBindingExpressionSyntax elementBindingExpression)) { // Find the first conditional access expression that starts left of our open bracket var conditionalAccess = elementBindingExpression.FirstAncestorOrSelf <ConditionalAccessExpressionSyntax, ElementBindingExpressionSyntax>( (c, elementBindingExpression) => c.SpanStart < elementBindingExpression.SpanStart, elementBindingExpression) !; identifier = conditionalAccess.Expression; openBrace = elementBindingExpression.ArgumentList.OpenBracketToken; return(true); } identifier = null; openBrace = default; return(false); }
/// <summary> /// [[(Type)] target | [(Type)] this | Namespace.Type].Method[...](...) /// </summary> protected internal MemberAccessExpressionSyntax MethodAccess(ExpressionSyntax?target, IMethodInfo method, ITypeInfo?castTargetTo = null) => SimpleMemberAccess ( AmendTarget(target, method, castTargetTo), method is not IGenericMethodInfo genericMethod
public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxToken asyncKeyword, ParameterSyntax parameter, SyntaxToken arrowToken, BlockSyntax?block, ExpressionSyntax?expressionBody) => SimpleLambdaExpression(attributeLists: default, TokenList(asyncKeyword), parameter, arrowToken, block, expressionBody);
private static MemberAccessExpressionSyntax?Merge(ExpressionSyntax?outerExpression, ExpressionSyntax?innerExpression) { if (outerExpression == null || innerExpression == null) { return(null); } // if the inner name is simple (i.e. just 'X') we can trivially form the final member // access by joining the two names together. if (innerExpression is SimpleNameSyntax innerName) { return(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, outerExpression, innerName)); } if (innerExpression is not MemberAccessExpressionSyntax innerMemberAccess) { return(null); } // otherwise, attempt to decompose the inner expression, joining that with the outer until we get // the result. return(Merge(Merge(outerExpression, innerMemberAccess.Expression), innerMemberAccess.Name)); }
/// <summary> /// Check if <paramref name="candidate"/> is a null check. /// </summary> /// <param name="candidate">The <see cref="ExpressionSyntax"/>.</param> /// <param name="semanticModel">The <see cref="SemanticModel"/>. If null only the name is checked.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that cancels the operation.</param> /// <param name="value">The null checked value.</param> /// <returns>True if <paramref name="candidate"/> is a null check.</returns> public static bool IsNullCheck(ExpressionSyntax candidate, SemanticModel?semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?value) { if (Equality.IsEqualsCheck(candidate, semanticModel, cancellationToken, out var left, out var right) && IsNullAndExpression(left, right, out value)) { #pragma warning disable CS8762 // Parameter must have a non-null value when exiting in some condition. return(true); #pragma warning restore CS8762 // Parameter must have a non-null value when exiting in some condition. } switch (candidate) { case IsPatternExpressionSyntax { Expression: { } expression, Pattern : ConstantPatternSyntax { Expression : { } constant } } when constant.IsKind(SyntaxKind.NullLiteralExpression) : value = expression; return(true); case BinaryExpressionSyntax node when node.IsKind(SyntaxKind.CoalesceExpression): value = node.Left; return(true); default: value = null; return(false); }
public static ParenthesizedLambdaExpressionSyntax ParenthesizedLambdaExpression(SyntaxToken asyncKeyword, ParameterListSyntax parameterList, SyntaxToken arrowToken, BlockSyntax?block, ExpressionSyntax?expressionBody) => ParenthesizedLambdaExpression(TokenList(asyncKeyword), parameterList, arrowToken, block, expressionBody);
private static bool DisposedByReturnValue(ExpressionSyntax candidate, Recursion recursion, [NotNullWhen(true)] out ExpressionSyntax?creation) { switch (candidate) { case { Parent: ArgumentSyntax argument } when recursion.Target(argument) is { } target: return(DisposedByReturnValue(target, recursion, out creation));
public static ParenthesizedLambdaExpressionSyntax ParenthesizedLambdaExpression(ParameterListSyntax parameterList, BlockSyntax?block, ExpressionSyntax?expressionBody) => ParenthesizedLambdaExpression(default(SyntaxTokenList), parameterList, block, expressionBody);
/// <summary> /// Check if <paramref name="candidate"/> is a check for equality. /// Operators == and != /// Equals, ReferenceEquals. /// </summary> /// <param name="candidate">The <see cref="ExpressionSyntax"/>.</param> /// <param name="semanticModel">The <see cref="SemanticModel"/>. If null only the name is checked.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that cancels the operation.</param> /// <param name="left">The left value.</param> /// <param name="right">The right value.</param> /// <returns>True if <paramref name="candidate"/> is a check for equality.</returns> public static bool IsEqualsCheck(ExpressionSyntax candidate, SemanticModel?semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?left, [NotNullWhen(true)] out ExpressionSyntax?right) { if (candidate is null) { throw new ArgumentNullException(nameof(candidate)); } switch (candidate) { case InvocationExpressionSyntax invocation when IsObjectEquals(invocation, semanticModel, cancellationToken, out left, out right) || IsObjectReferenceEquals(invocation, semanticModel, cancellationToken, out left, out right) || IsNullableEquals(invocation, semanticModel, cancellationToken, out left, out right) || IsRuntimeHelpersEquals(invocation, semanticModel, cancellationToken, out left, out right) || IsStringEquals(invocation, semanticModel, cancellationToken, out left, out right, out _) || IsInstanceEquals(invocation, semanticModel, cancellationToken, out left, out right) || (semanticModel != null && IsEqualityComparerEquals(invocation, semanticModel, cancellationToken, out _, out left, out right)): return(true); case ConditionalAccessExpressionSyntax conditionalAccess when conditionalAccess.WhenNotNull is InvocationExpressionSyntax invocation && IsInstanceEquals(invocation, semanticModel, cancellationToken, out left, out right): return(true); case BinaryExpressionSyntax node when IsInstanceEquals(node, semanticModel, cancellationToken, out left, out right) || IsOperatorEquals(node, out left, out right) || IsOperatorNotEquals(node, out left, out right): return(true); default: left = null; right = null; return(false); } }
public static ParenthesizedLambdaExpressionSyntax ParenthesizedLambdaExpression(SyntaxTokenList modifiers, ParameterListSyntax parameterList, SyntaxToken arrowToken, BlockSyntax?block, ExpressionSyntax?expressionBody) => SyntaxFactory.ParenthesizedLambdaExpression(attributeLists: default, modifiers, returnType: null, parameterList, arrowToken, block, expressionBody);
private static bool TryGetArgs(InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out IMethodSymbol?target, [NotNullWhen(true)] out ExpressionSyntax?member, out ArgumentAndValue <ITypeSymbol> attributeType, out ArgumentSyntax?inheritsArg) { if ((invocation.TryGetTarget(KnownSymbol.Attribute.IsDefined, context.SemanticModel, context.CancellationToken, out target) || invocation.TryGetTarget(KnownSymbol.CustomAttributeExtensions.IsDefined, context.SemanticModel, context.CancellationToken, out target)) && target.TryFindParameter("attributeType", out var attributeTypeParameter) && invocation.TryFindArgument(attributeTypeParameter, out var attributeTypeArg) && attributeTypeArg.Expression is TypeOfExpressionSyntax typeOf && context.SemanticModel.TryGetType(typeOf.Type, context.CancellationToken, out var typeSymbol)) { attributeType = new ArgumentAndValue <ITypeSymbol>(attributeTypeArg, typeSymbol); if (!target.TryFindParameter("inherit", out var inheritParameter) || !invocation.TryFindArgument(inheritParameter, out inheritsArg)) { inheritsArg = null; } if (target.IsExtensionMethod && invocation.Expression is MemberAccessExpressionSyntax memberAccess) { member = memberAccess.Expression; return(true); } if (target.TryFindParameter("element", out var elementParameter) && invocation.TryFindArgument(elementParameter, out var elementArg)) { member = elementArg.Expression; return(true); } } member = null; attributeType = default; inheritsArg = null; return(false); }
public static bool IsMemberBindingExpressionName([NotNullWhen(true)] this ExpressionSyntax?expression) => expression.IsParentKind(SyntaxKind.MemberBindingExpression, out MemberBindingExpressionSyntax? memberBinding) && memberBinding.Name == expression;