public void Elide(IParametersOwnerDeclaration parametersOwnerDeclaration) { foreach (var awaitExpression in parametersOwnerDeclaration.DescendantsInScope <IAwaitExpression>()) { Elide(awaitExpression); } }
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));
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)); } }
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)); }
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; } }
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); }
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; }
/// <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); } }
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)); }
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)); } }
/// <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)); } } }
public bool CanElide(IParametersOwnerDeclaration element) { var multipleLocalVariable = element.Descendants <IMultipleLocalVariableDeclaration>(); return(multipleLocalVariable.ToEnumerable().All(x => x.UsingKind == UsingDeclarationKind.Regular)); }
public bool CanElide(IParametersOwnerDeclaration element) => checkers.All(x => x.CanElide(element));
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); }
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); } }