コード例 #1
0
 public void Elide(IParametersOwnerDeclaration parametersOwnerDeclaration)
 {
     foreach (var awaitExpression in parametersOwnerDeclaration.DescendantsInScope <IAwaitExpression>())
     {
         Elide(awaitExpression);
     }
 }
コード例 #2
0
 static bool HasPreviousUsingDeclaration([NotNull] ITreeNode node, [NotNull] IParametersOwnerDeclaration container)
 => node.SelfAndPathToRoot()
 .TakeWhile(n => n != container)
 .Any(
     n => n.AssertNotNull()
     .LeftSiblings()
     .Any(s => ((s as IDeclarationStatement)?.Declaration as IMultipleLocalVariableDeclaration)?.UsingKeyword != null));
コード例 #3
0
        static void AnalyzeRedundantCapturedContext(
            [NotNull] IParametersOwnerDeclaration container,
            [NotNull] IAwaitExpression awaitExpression,
            bool isLastExpression,
            [NotNull] IHighlightingConsumer consumer)
        {
            var hasRedundantCapturedContext = isLastExpression ||
                                              awaitExpression.Parent is IReturnStatement returnStatement &&
                                              !returnStatement.PathToRoot()
                                              .Skip(1)
                                              .TakeWhile(node => node != container)
                                              .Any(node => node is IUsingStatement || node is ITryStatement) &&
                                              !returnStatement.PathToRoot()
                                              .TakeWhile(node => node != container)
                                              .Any(
                node => node.AssertNotNull()
                .LeftSiblings()
                .Any(s => ((s as IDeclarationStatement)?.Declaration as IMultipleLocalVariableDeclaration)?.UsingKeyword != null));

            if (hasRedundantCapturedContext && awaitExpression.Task.IsConfigureAwaitAvailable())
            {
                consumer.AddHighlighting(
                    new RedundantCapturedContextHighlighting(
                        $"Redundant captured context (add '.{nameof(Task.ConfigureAwait)}(false)')",
                        awaitExpression));
            }
        }
コード例 #4
0
        public static IEnumerable <TNode> DescendantsInScope <TNode>([CanBeNull] this IParametersOwnerDeclaration root) where TNode : class, ICSharpTreeNode
        {
            if (root == null)
            {
                return(Enumerable.Empty <TNode>());
            }

            var expressions = root.Descendants <TNode>().ToEnumerable();

            return(expressions.Where(x => x.GetContainingFunctionLikeDeclarationOrClosure() == root));
        }
コード例 #5
0
        static void TryGetContainerTypeAndAsyncKeyword(
            [NotNull] IParametersOwnerDeclaration container,
            [CanBeNull] out IType type,
            [CanBeNull] out ITokenNode asyncKeyword,
            [CanBeNull] out Action removeAsync,
            [CanBeNull] out IAttributesOwnerDeclaration attributesOwnerDeclaration)
        {
            switch (container)
            {
            case IMethodDeclaration methodDeclaration:
                type         = methodDeclaration.Type;
                asyncKeyword = methodDeclaration.ModifiersList?.Modifiers.FirstOrDefault(
                    node => node?.GetTokenType() == CSharpTokenType.ASYNC_KEYWORD);
                removeAsync = () => methodDeclaration.SetAsync(false);
                attributesOwnerDeclaration =
                    type.IsValueTask() || type.IsGenericValueTask() || methodDeclaration.IsNullableAnnotationsContextEnabled()
                            ? null
                            : methodDeclaration;
                return;

            case ILambdaExpression lambdaExpression:
                type         = lambdaExpression.ReturnType;
                asyncKeyword = lambdaExpression.AsyncKeyword;
                removeAsync  = () => lambdaExpression.SetAsync(false);
                attributesOwnerDeclaration = null;
                return;

            case IAnonymousMethodExpression anonymousMethodExpression:
                type         = anonymousMethodExpression.ReturnType;
                asyncKeyword = anonymousMethodExpression.AsyncKeyword;
                removeAsync  = () => anonymousMethodExpression.SetAsync(false);
                attributesOwnerDeclaration = null;
                return;

            case ILocalFunctionDeclaration localFunctionDeclaration:
                type         = localFunctionDeclaration.Type;
                asyncKeyword = localFunctionDeclaration.ModifiersList?.Modifiers.FirstOrDefault(
                    node => node?.GetTokenType() == CSharpTokenType.ASYNC_KEYWORD);
                removeAsync = () => localFunctionDeclaration.SetAsync(false);
                attributesOwnerDeclaration = null;
                return;

            default:
                type         = null;
                asyncKeyword = null;
                removeAsync  = null;
                attributesOwnerDeclaration = null;
                return;
            }
        }
コード例 #6
0
        public bool CanElide(IParametersOwnerDeclaration element)
        {
            var returnStatements = element.DescendantsInScope <IReturnStatement>().ToArray();
            var returnType       = element.DeclaredParametersOwner?.ReturnType;

            if (returnType == null)
            {
                return(false);
            }

            if (returnType.IsTask() && returnStatements.Any() ||
                returnType.IsGenericTask() && returnStatements.Length > 1)
            {
                return(false);
            }

            var awaitExpressions = element.DescendantsInScope <IAwaitExpression>().ToArray();

            //TODO: think about this, different settings
            if (awaitExpressions.Length != 1)
            {
                return(false);
            }

            var awaitExpression = awaitExpressions.First();

            if (returnStatements.Any() && returnStatements.First() != awaitExpression.GetContainingStatement())
            {
                return(false);
            }

            if (!lastNodeChecker.IsLastNode(awaitExpression))
            {
                return(false);
            }

            var awaitingType = (awaitExpression.Task as IInvocationExpression)?.RemoveConfigureAwait()?.Type();

            if (awaitingType == null)
            {
                return(false);
            }

            if (!awaitingType.Equals(returnType) && !(returnType.IsTask() && awaitingType.IsGenericTask()) && !returnType.IsVoid())
            {
                return(false);
            }

            return(true);
        }
コード例 #7
0
        private static bool isParameter(ICSharpTypeMemberDeclaration decl, string word)
        {
            IParametersOwnerDeclaration methodDecl = decl as IParametersOwnerDeclaration;

            if (methodDecl != null)
            {
                foreach (IRegularParameterDeclaration parm in methodDecl.ParameterDeclarations)
                {
                    if (parm.DeclaredName == word)
                    {
                        return true;
                    }
                }
            }

            return false;
        }
コード例 #8
0
        /// <summary>Builds the parameters.</summary>
        /// <param name="parametersOwner">The method.</param>
        /// <param name="isAbstract">if set to <c>true</c> [is abstract].</param>
        private void BuildParameters(IParametersOwnerDeclaration parametersOwner, bool isAbstract)
        {
            foreach (var parameter in parametersOwner.ParameterDeclarations)
            {
                if (!parameter.Type.IsReferenceType())
                {
                    continue;
                }

                var expectsAssertion  = false;
                var assertionCode     = string.Empty;
                var appliedAttribute  = this.CodeAnnotation.GetAnnotation(parameter);
                var expectedAttribute = CodeAnnotationAttribute.NotNull;

                if (appliedAttribute == CodeAnnotationAttribute.CanBeNull)
                {
                    expectedAttribute = CodeAnnotationAttribute.CanBeNull;
                }
                else if (parameter.DeclaredElement != null && parameter.DeclaredElement.Kind == ParameterKind.OUTPUT)
                {
                    appliedAttribute  = CodeAnnotationAttribute.Undefined;
                    expectedAttribute = CodeAnnotationAttribute.Undefined;
                }
                else
                {
                    if (this.GenerateAssertions)
                    {
                        assertionCode = this.GetCode();
                        if (!string.IsNullOrEmpty(assertionCode))
                        {
                            assertionCode    = string.Format(assertionCode, parameter.DeclaredName).Trim();
                            expectsAssertion = true;
                        }
                    }
                }

                if (isAbstract)
                {
                    expectsAssertion = false;
                }

                var descriptor = new ParameterDescriptor(parameter, expectedAttribute, appliedAttribute, expectsAssertion, assertionCode);
                this.parameters.Add(descriptor);
            }
        }
コード例 #9
0
        public bool CanElide(IParametersOwnerDeclaration element)
        {
            var excludeTestMethods = element.GetSettingsStore().GetValue(AsyncConverterSettingsAccessor.ExcludeTestMethodsFromEliding);

            if (!excludeTestMethods)
            {
                return(true);
            }

            var method = element as IMethodDeclaration;

            if (method == null)
            {
                return(true);
            }

            return(!underTestChecker.IsUnder(method));
        }
コード例 #10
0
        static void AnalyzeRedundantCapturedContext(
            [NotNull] IParametersOwnerDeclaration container,
            [NotNull] IAwaitExpression awaitExpression,
            bool isLastExpression,
            [NotNull] IHighlightingConsumer consumer)
        {
            var hasRedundantCapturedContext = isLastExpression ||
                                              awaitExpression.Parent is IReturnStatement returnStatement &&
                                              !returnStatement.PathToRoot()
                                              .Skip(1)
                                              .TakeWhile(node => node != container)
                                              .Any(node => node is IUsingStatement || node is ITryStatement) &&
                                              !HasPreviousUsingDeclaration(returnStatement, container);

            if (hasRedundantCapturedContext && awaitExpression.Task.IsConfigureAwaitAvailable())
            {
                consumer.AddHighlighting(
                    new RedundantCapturedContextSuggestion(
                        $"Redundant captured context (add '.{nameof(Task.ConfigureAwait)}(false)')",
                        awaitExpression));
            }
        }
コード例 #11
0
        /// <summary>
        /// Checks method comment blocks.
        /// </summary>
        /// <param name="methodDeclaration">
        /// The method <see cref="IDeclaration"/> to check.
        /// </param>
        /// <param name="options">
        /// <see cref="OrderingOptions"/>Current options that we can reference.
        /// </param>
        private void CheckMethodAndIndexerDeclarationDocumentation(IParametersOwnerDeclaration methodDeclaration, DocumentationOptions options)
        {
            Param.Ignore(options);

            if (methodDeclaration == null)
            {
                return;
            }

            bool insertMissingParamTagOption = true;
            bool insertMissingReturnTagOption = true;
            bool removeReturnTagOnVoidElementsOption = true;

            if (options != null)
            {
                insertMissingParamTagOption = options.SA1611ElementParametersMustBeDocumented;
                insertMissingReturnTagOption = options.SA1615ElementReturnValueMustBeDocumented;
                removeReturnTagOnVoidElementsOption = options.SA1617VoidReturnValueMustNotBeDocumented;
            }

            if (insertMissingParamTagOption && !Utils.IsRuleSuppressed(methodDeclaration, StyleCopRules.SA1611))
            {
                if (methodDeclaration.ParameterDeclarations.Count > 0)
                {
                    this.InsertMissingParamElement(methodDeclaration);
                }
            }

            if (methodDeclaration.DeclaredElement == null)
            {
                return;
            }

            DeclaredTypeFromCLRName declaredTypeFromClrName = methodDeclaration.DeclaredElement.ReturnType as DeclaredTypeFromCLRName;

            if (removeReturnTagOnVoidElementsOption && !Utils.IsRuleSuppressed(methodDeclaration, StyleCopRules.SA1617))
            {
                // Remove the <returns> if the return type is void
                if (declaredTypeFromClrName != null && declaredTypeFromClrName.GetClrName().FullName == "System.Void")
                {
                    this.RemoveReturnsElement(methodDeclaration as ITypeMemberDeclaration);
                }
            }

            if (insertMissingReturnTagOption && !Utils.IsRuleSuppressed(methodDeclaration, StyleCopRules.SA1615))
            {
                // Insert the <returns> if the return type is not void and it was missing
                if ((declaredTypeFromClrName != null && declaredTypeFromClrName.GetClrName().FullName != "System.Void") || declaredTypeFromClrName == null)
                {
                    this.InsertReturnsElement(methodDeclaration as ITypeMemberDeclaration, Utils.GetXmlPresentableName(methodDeclaration.DeclaredElement.ReturnType));
                }
            }
        }
コード例 #12
0
        public bool CanElide(IParametersOwnerDeclaration element)
        {
            var multipleLocalVariable = element.Descendants <IMultipleLocalVariableDeclaration>();

            return(multipleLocalVariable.ToEnumerable().All(x => x.UsingKind == UsingDeclarationKind.Regular));
        }
コード例 #13
0
 public bool CanElide(IParametersOwnerDeclaration element) => checkers.All(x => x.CanElide(element));
コード例 #14
0
        static bool AnalyzeRedundantAwait(
            [NotNull] IAwaitExpression awaitExpression,
            bool isLastExpression,
            [NotNull] IParametersOwnerDeclaration container,
            [CanBeNull] IExpressionStatement statementToBeReplacedWithReturnStatement,
            [NotNull] IHighlightingConsumer consumer)
        {
            if (isLastExpression &&
                !IsTestMethodOfOldMsTest(container as IMethodDeclaration) &&
                !GetAllChildrenRecursive(container).OfType <IAwaitExpression>().HasMoreThan(1) &&
                !GetAllChildrenRecursive(container).OfType <IReturnStatement>().HasMoreThan(awaitExpression.Parent is IReturnStatement ? 1 : 0))
            {
                TryGetContainerTypeAndAsyncKeyword(
                    container,
                    out var containerType,
                    out var asyncKeyword,
                    out var removeAsync,
                    out var attributesOwnerDeclaration);

                if (asyncKeyword != null)
                {
                    var awaitExpressionType = awaitExpression.Task?.Type();

                    if (containerType.IsValueTask() && awaitExpressionType.IsValueTask() ||
                        containerType.IsTask() && (awaitExpressionType.IsTask() || awaitExpressionType.IsGenericTask()))
                    {
                        // container is ValueTask, awaitExpression is ValueTask
                        // or
                        // container is Task, awaitExpression is Task or Task<T>

                        AddRedundantAwaitHighlightings(
                            consumer,
                            asyncKeyword,
                            removeAsync,
                            awaitExpression,
                            statementToBeReplacedWithReturnStatement,
                            awaitExpression.Task,
                            attributesOwnerDeclaration);
                        return(true);
                    }

                    if ((containerType.IsGenericValueTask() && awaitExpressionType.IsGenericValueTask() ||
                         containerType.IsGenericTask() && awaitExpressionType.IsGenericTask()) &&
                        containerType.Equals(awaitExpressionType, TypeEqualityComparer.Default))
                    {
                        // container is ValueTask<T>, awaitExpression is ValueTask<T>, container type == awaitExpression type
                        // or
                        // container is Task<T>, awaitExpression is Task<T>, container type == awaitExpression type

                        AddRedundantAwaitHighlightings(
                            consumer,
                            asyncKeyword,
                            removeAsync,
                            awaitExpression,
                            statementToBeReplacedWithReturnStatement,
                            awaitExpression.Task,
                            attributesOwnerDeclaration);
                        return(true);
                    }

                    if (awaitExpression.Task is IInvocationExpression configureAwaitInvocationExpression)
                    {
                        var method = configureAwaitInvocationExpression.InvocationExpressionReference.Resolve().DeclaredElement as IMethod;
                        if (method?.ShortName == nameof(Task.ConfigureAwait))
                        {
                            var methodContainingTypeElement = method.GetContainingType();
                            if (methodContainingTypeElement != null)
                            {
                                var methodContainingType = TypeFactory.CreateType(methodContainingTypeElement);

                                var awaitExpressionWithoutConfigureAwait =
                                    (configureAwaitInvocationExpression.InvokedExpression as IReferenceExpression)?.QualifierExpression;
                                var awaitExpressionTypeWithoutConfigureAwait = awaitExpressionWithoutConfigureAwait?.Type();

                                if (containerType.IsValueTask() &&
                                    methodContainingType.IsValueTask() &&
                                    awaitExpressionTypeWithoutConfigureAwait.IsValueTask() ||
                                    containerType.IsTask() &&
                                    (methodContainingType.IsTask() && awaitExpressionTypeWithoutConfigureAwait.IsTask() ||
                                     methodContainingType.IsGenericTask() && awaitExpressionTypeWithoutConfigureAwait.IsGenericTask()))
                                {
                                    // container is ValueTask, awaitExpression (without "ConfigureAwait") is ValueTask
                                    // or
                                    // container is Task, awaitExpression (without "ConfigureAwait") is Task or Task<T>

                                    AddRedundantAwaitHighlightings(
                                        consumer,
                                        asyncKeyword,
                                        removeAsync,
                                        awaitExpression,
                                        statementToBeReplacedWithReturnStatement,
                                        awaitExpressionWithoutConfigureAwait,
                                        attributesOwnerDeclaration,
                                        configureAwaitInvocationExpression);
                                    return(true);
                                }

                                if ((containerType.IsGenericValueTask() &&
                                     methodContainingType.IsGenericValueTask() &&
                                     awaitExpressionTypeWithoutConfigureAwait.IsGenericValueTask() ||
                                     containerType.IsGenericTask() &&
                                     methodContainingType.IsGenericTask() &&
                                     awaitExpressionTypeWithoutConfigureAwait.IsGenericTask()) &&
                                    containerType.Equals(awaitExpressionTypeWithoutConfigureAwait, TypeEqualityComparer.Default))
                                {
                                    // container is ValueTask<T>, awaitExpression (without "ConfigureAwait") is ValueTask<T>, container type == awaitExpression type (without "ConfigureAwait")
                                    // or
                                    // container is Task<T>, awaitExpression (without "ConfigureAwait") is Task<T>, container type == awaitExpression type (without "ConfigureAwait")

                                    AddRedundantAwaitHighlightings(
                                        consumer,
                                        asyncKeyword,
                                        removeAsync,
                                        awaitExpression,
                                        statementToBeReplacedWithReturnStatement,
                                        awaitExpressionWithoutConfigureAwait,
                                        attributesOwnerDeclaration,
                                        configureAwaitInvocationExpression);
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
コード例 #15
0
        static bool IsLastExpression(
            [NotNull] IParametersOwnerDeclaration container,
            [NotNull] ICSharpExpression expression,
            [CanBeNull] out IExpressionStatement statementToBeReplacedWithReturnStatement)
        {
            var block = null as IBlock;

            switch (container)
            {
            case IMethodDeclaration methodDeclaration:
                if (methodDeclaration.ArrowClause?.Expression == expression)
                {
                    statementToBeReplacedWithReturnStatement = null;
                    return(true);
                }

                block = methodDeclaration.Body;
                break;

            case ILambdaExpression lambdaExpression:
                if (lambdaExpression.BodyExpression == expression)
                {
                    statementToBeReplacedWithReturnStatement = null;
                    return(true);
                }

                block = lambdaExpression.BodyBlock;
                break;

            case IAnonymousMethodExpression anonymousMethodExpression:
                block = anonymousMethodExpression.Body;
                break;

            case ILocalFunctionDeclaration localFunctionDeclaration:
                if (localFunctionDeclaration.ArrowClause?.Expression == expression)
                {
                    statementToBeReplacedWithReturnStatement = null;
                    return(true);
                }

                block = localFunctionDeclaration.Body;
                break;
            }

            var lastStatement = block?.Children <ICSharpStatement>()
                                .LastOrDefault(s => !(s is IDeclarationStatement declarationStatement) || declarationStatement.LocalFunctionDeclaration == null);

            switch (lastStatement)
            {
            case IExpressionStatement expressionStatement when expressionStatement.Expression == expression &&
                !HasPreviousUsingDeclaration(expressionStatement, container):
                statementToBeReplacedWithReturnStatement = expressionStatement;
                return(true);

            case IReturnStatement returnStatement when returnStatement.Value == expression &&
                !HasPreviousUsingDeclaration(returnStatement, container):
                statementToBeReplacedWithReturnStatement = null;
                return(true);

            default:
                statementToBeReplacedWithReturnStatement = null;
                return(false);
            }
        }
コード例 #16
0
    /// <summary>Builds the parameters.</summary>
    /// <param name="parametersOwner">The method.</param>
    /// <param name="isAbstract">if set to <c>true</c> [is abstract].</param>
    private void BuildParameters(IParametersOwnerDeclaration parametersOwner, bool isAbstract)
    {
      foreach (var parameter in parametersOwner.ParameterDeclarations)
      {
        if (!parameter.Type.IsReferenceType())
        {
          continue;
        }

        var expectsAssertion = false;
        var assertionCode = string.Empty;
        var appliedAttribute = this.CodeAnnotation.GetAnnotation(parameter);
        var expectedAttribute = CodeAnnotationAttribute.NotNull;

        if (appliedAttribute == CodeAnnotationAttribute.CanBeNull)
        {
          expectedAttribute = CodeAnnotationAttribute.CanBeNull;
        }
        else if (parameter.DeclaredElement != null && parameter.DeclaredElement.Kind == ParameterKind.OUTPUT)
        {
          appliedAttribute = CodeAnnotationAttribute.Undefined;
          expectedAttribute = CodeAnnotationAttribute.Undefined;
        }
        else
        {
          if (this.GenerateAssertions)
          {
            assertionCode = this.GetCode();
            if (!string.IsNullOrEmpty(assertionCode))
            {
              assertionCode = string.Format(assertionCode, parameter.DeclaredName).Trim();
              expectsAssertion = true;
            }
          }
        }

        if (isAbstract)
        {
          expectsAssertion = false;
        }

        var descriptor = new ParameterDescriptor(parameter, expectedAttribute, appliedAttribute, expectsAssertion, assertionCode);
        this.parameters.Add(descriptor);
      }
    }