Example #1
0
 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);
Example #3
0
        /// <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);
            }
Example #7
0
        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)
            }
                       )
                   ));
        }
Example #8
0
        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);
        }
Example #9
0
 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 }
         }
     } &&
Example #10
0
 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));
 }
Example #12
0
 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);
        }
Example #16
0
        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));
        }
Example #23
0
        /// <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);
            }
Example #24
0
 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));
Example #26
0
 public static ParenthesizedLambdaExpressionSyntax ParenthesizedLambdaExpression(ParameterListSyntax parameterList, BlockSyntax?block, ExpressionSyntax?expressionBody)
 => ParenthesizedLambdaExpression(default(SyntaxTokenList), parameterList, block, expressionBody);
Example #27
0
        /// <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);
            }
        }
Example #28
0
 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);
Example #29
0
        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);
        }
Example #30
0
 public static bool IsMemberBindingExpressionName([NotNullWhen(true)] this ExpressionSyntax?expression)
 => expression.IsParentKind(SyntaxKind.MemberBindingExpression, out MemberBindingExpressionSyntax? memberBinding) &&
 memberBinding.Name == expression;