public override TAbstractAnalysisValue VisitAwait(IAwaitOperation operation, object argument)
        {
            var value = base.VisitAwait(operation, argument);
            PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(operation);

            return(HandleInstanceCreation(operation, instanceLocation, value));
        }
        private static bool ShouldAnalyze(
            IAwaitOperation awaitOperation,
            IMethodSymbol configureAwaitMethod,
            IMethodSymbol genericConfigureAwaitMethod,
            INamedTypeSymbol streamType,
            out IMethodSymbol?actualMethod)
        {
            actualMethod = null;

            // The await should have a known operation child, check its kind
            if (!(awaitOperation.Operation is IInvocationOperation invocation))
            {
                return(false);
            }

            IMethodSymbol method = invocation.TargetMethod;

            // Check if the child operation of the await is ConfigureAwait
            // in which case we should analyze the grandchild operation
            if (method.OriginalDefinition.Equals(configureAwaitMethod) ||
                method.OriginalDefinition.Equals(genericConfigureAwaitMethod))
            {
                if (invocation.Instance is IInvocationOperation instanceInvocation)
                {
                    method = instanceInvocation.TargetMethod;
                }
                else
                {
                    return(false);
                }
            }

            // Verify if the current method's type is or inherits from Stream
            return(IsDefinedBy(method, streamType, out actualMethod));
        }
        private static void AnalyzeOperation(OperationAnalysisContext context, ImmutableArray <INamedTypeSymbol> taskTypes)
        {
            IAwaitOperation awaitExpression = context.Operation as IAwaitOperation;

            // Get the type of the expression being awaited and check it's a task type.
            ITypeSymbol typeOfAwaitedExpression = awaitExpression?.Operation?.Type;

            if (typeOfAwaitedExpression != null && taskTypes.Contains(typeOfAwaitedExpression.OriginalDefinition))
            {
                context.ReportDiagnostic(awaitExpression.Operation.Syntax.CreateDiagnostic(Rule));
            }
        }
Beispiel #4
0
        private static void AnalyzeAwait(
            OperationAnalysisContext context,
            ImmutableHashSet <INamedTypeSymbol> configuredTaskTypes,
            IAwaitOperation operation
            )
        {
            IOperation  rhs         = operation.Operation;
            ITypeSymbol awaitedType = rhs.Type.OriginalDefinition;

            if (configuredTaskTypes.Contains(awaitedType))
            {
                return;
            }

            context.ReportDiagnostic(Diagnostic.Create(
                                         Diagnostics.AwaitedTaskNotConfigured,
                                         operation.Syntax.GetLocation()
                                         ));
        }
Beispiel #5
0
        private void AnalyzeCompilationStart(CompilationStartAnalysisContext context)
        {
            // Find the essential type for this analysis
            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIOStream, out INamedTypeSymbol? streamType))
            {
                return;
            }

            // Find the types for the rule message, available since .NET Standard 2.1
            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemReadOnlyMemory1, out INamedTypeSymbol? readOnlyMemoryType))
            {
                return;
            }

            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemMemory1, out INamedTypeSymbol? memoryType))
            {
                return;
            }

            // Find the additional types for this analysis
            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingCancellationToken, out INamedTypeSymbol? cancellationTokenType))
            {
                return;
            }

            INamedTypeSymbol byteType = context.Compilation.GetSpecialType(SpecialType.System_Byte);

            if (byteType == null)
            {
                return;
            }

            INamedTypeSymbol int32Type = context.Compilation.GetSpecialType(SpecialType.System_Int32);

            if (int32Type == null)
            {
                return;
            }

            // Create the arrays with the exact parameter order of the undesired methods
            var undesiredParameters = new[]
            {
                ParameterInfo.GetParameterInfo(byteType, isArray: true, arrayRank: 1), // byte[] buffer
                ParameterInfo.GetParameterInfo(int32Type),                             // int offset
                ParameterInfo.GetParameterInfo(int32Type),                             // int count
            };

            var undesiredParametersWithCancellationToken = new[]
            {
                ParameterInfo.GetParameterInfo(byteType, isArray: true, arrayRank: 1),
                ParameterInfo.GetParameterInfo(int32Type),
                ParameterInfo.GetParameterInfo(int32Type),
                ParameterInfo.GetParameterInfo(cancellationTokenType)
            };

            // Retrieve the ReadAsync/WriteSync methods available in Stream
            IEnumerable <IMethodSymbol> readAsyncMethodGroup  = streamType.GetMembers("ReadAsync").OfType <IMethodSymbol>();
            IEnumerable <IMethodSymbol> writeAsyncMethodGroup = streamType.GetMembers("WriteAsync").OfType <IMethodSymbol>();

            // Retrieve the undesired methods
            IMethodSymbol?undesiredReadAsyncMethod = readAsyncMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(undesiredParameters);

            if (undesiredReadAsyncMethod == null)
            {
                return;
            }

            IMethodSymbol?undesiredWriteAsyncMethod = writeAsyncMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(undesiredParameters);

            if (undesiredWriteAsyncMethod == null)
            {
                return;
            }

            IMethodSymbol?undesiredReadAsyncMethodWithCancellationToken = readAsyncMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(undesiredParametersWithCancellationToken);

            if (undesiredReadAsyncMethodWithCancellationToken == null)
            {
                return;
            }

            IMethodSymbol?undesiredWriteAsyncMethodWithCancellationToken = writeAsyncMethodGroup.GetFirstOrDefaultMemberWithParameterInfos(undesiredParametersWithCancellationToken);

            if (undesiredWriteAsyncMethodWithCancellationToken == null)
            {
                return;
            }

            // Retrieve the preferred methods, which are used for constructing the rule message
            IMethodSymbol?preferredReadAsyncMethod = readAsyncMethodGroup.FirstOrDefault(x =>
                                                                                         x.Parameters.Count() == 2 &&
                                                                                         x.Parameters[0].Type is INamedTypeSymbol type &&
                                                                                         type.ConstructedFrom.Equals(memoryType));

            if (preferredReadAsyncMethod == null)
            {
                return;
            }

            IMethodSymbol?preferredWriteAsyncMethod = writeAsyncMethodGroup.FirstOrDefault(x =>
                                                                                           x.Parameters.Count() == 2 &&
                                                                                           x.Parameters[0].Type is INamedTypeSymbol type &&
                                                                                           type.ConstructedFrom.Equals(readOnlyMemoryType));

            if (preferredWriteAsyncMethod == null)
            {
                return;
            }

            // Retrieve the ConfigureAwait methods that could also be detected:
            // - The undesired WriteAsync methods return a Task
            // - The preferred WriteAsync method returns a ValueTask
            // - The undesired ReadAsync methods return a Task<int>
            // - The preferred ReadAsync method returns a ValueTask<int>
            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask, out INamedTypeSymbol? taskType))
            {
                return;
            }

            if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask1, out INamedTypeSymbol? genericTaskType))
            {
                return;
            }

            IMethodSymbol?configureAwaitMethod = taskType.GetMembers("ConfigureAwait").OfType <IMethodSymbol>().FirstOrDefault();

            if (configureAwaitMethod == null)
            {
                return;
            }

            IMethodSymbol?genericConfigureAwaitMethod = genericTaskType.GetMembers("ConfigureAwait").OfType <IMethodSymbol>().FirstOrDefault();

            if (genericConfigureAwaitMethod == null)
            {
                return;
            }

            context.RegisterOperationAction(context =>
            {
                IAwaitOperation awaitOperation = (IAwaitOperation)context.Operation;

                if (ShouldAnalyze(
                        awaitOperation,
                        configureAwaitMethod,
                        genericConfigureAwaitMethod,
                        streamType,
                        out IInvocationOperation? invocation,
                        out IMethodSymbol? method) &&
                    invocation != null &&
                    method != null)
                {
                    DiagnosticDescriptor rule;
                    string ruleMessageMethod;
                    string ruleMessagePreferredMethod;

                    // Verify if the method is an undesired Async overload
                    if (method.Equals(undesiredReadAsyncMethod) ||
                        method.Equals(undesiredReadAsyncMethodWithCancellationToken))
                    {
                        rule = PreferStreamReadAsyncMemoryOverloadsRule;
                        ruleMessageMethod          = undesiredReadAsyncMethod.Name;
                        ruleMessagePreferredMethod = preferredReadAsyncMethod.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat);
                    }
                    else if (method.Equals(undesiredWriteAsyncMethod) ||
                             method.Equals(undesiredWriteAsyncMethodWithCancellationToken))
                    {
                        rule = PreferStreamWriteAsyncMemoryOverloadsRule;
                        ruleMessageMethod          = undesiredWriteAsyncMethod.Name;
                        ruleMessagePreferredMethod = preferredWriteAsyncMethod.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat);
                    }
                    else
                    {
                        // Prevent use of unassigned variables error
                        return;
                    }
                    context.ReportDiagnostic(invocation.CreateDiagnostic(rule, ruleMessageMethod, ruleMessagePreferredMethod));
                }
            },
                                            OperationKind.Await);
        }
Beispiel #6
0
            public override PointsToAbstractValue VisitAwait(IAwaitOperation operation, object argument)
            {
                var _ = base.VisitAwait(operation, argument);

                return(PointsToAbstractValue.Unknown);
            }
            public override NullAbstractValue VisitAwait(IAwaitOperation operation, object argument)
            {
                var _ = base.VisitAwait(operation, argument);

                return(NullAbstractValue.NotNull);
            }
Beispiel #8
0
 public override IOperation VisitAwait(IAwaitOperation operation, object argument)
 {
     return(new AwaitExpression(Visit(operation.Operation), ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit));
 }
Beispiel #9
0
 public override void VisitAwait(IAwaitOperation operation)
 {
     Assert.Equal(OperationKind.Await, operation.Kind);
     Assert.Same(operation.Operation, operation.Children.Single());
 }
Beispiel #10
0
 public virtual void VisitAwait(IAwaitOperation operation)
 {
     DefaultVisit(operation);
 }
Beispiel #11
0
 public override void VisitAwait([NotNull] IAwaitOperation operation)
 {
     base.VisitAwait(operation);
 }
Beispiel #12
0
 private static AbstractExpression ReadAwait(IAwaitOperation op)
 {
     return(new AwaitExpression {
         Expression = ReadExpression(op.Operation)
     });
 }
Beispiel #13
0
 public override bool VisitAwait([NotNull] IAwaitOperation operation1, [CanBeNull] IOperation argument)
 {
     return(argument is IAwaitOperation operation2 && AreBaseOperationsEqual(operation1, operation2));
 }
Beispiel #14
0
        private void MethodSummary(ImmutableArray <BasicBlock> bb, List <string> sharedFields)
        {
            foreach (BasicBlock b in bb)
            {
                var a = b.GetType();
                var c = b.BranchValue;

                if (b.Operations != null)
                {
                    foreach (IOperation inst in b.Operations)
                    {
                        //Console.WriteLine($"inst.Syntax.ToSring() '{inst.Syntax.ToString()}'");

                        if (inst.Kind.ToString() == "ExpressionStatement")
                        {
                            IExpressionStatementOperation exprInst = (IExpressionStatementOperation)inst;

                            if (exprInst.Operation != null)
                            {
                                //if (exprInst.Operation.Kind.ToString() == Kind = SimpleAssignment)
                                //if (exprInst.Operation.Kind.ToString() == Kind = SimpleAssignment)
                                if (exprInst.Operation.Kind.ToString() == "SimpleAssignment")
                                {
                                    ISimpleAssignmentOperation assignInst = (ISimpleAssignmentOperation)exprInst.Operation;
                                    ProcessSimpleAssignmentOper(assignInst, sharedFields, inst);
                                }
                                else if (exprInst.Operation.Kind.ToString() == "Await")
                                {
                                    IAwaitOperation awaitInst = (IAwaitOperation)exprInst.Operation;

                                    if (awaitInst.Operation.Kind.ToString() == "Invocation")
                                    {
                                        IInvocationOperation invocInst = (IInvocationOperation)awaitInst.Operation;
                                        string leftOperand             = "";
                                        ProcessInvocationOper(invocInst, inst, leftOperand);
                                        isAsync = true;
                                        //conflictUnit.Add(new Tuple<Accesses, string, IOperation>(Accesses.Invocation, "", inst));
                                    }
                                    else if (awaitInst.Operation.Kind.ToString() == "Invalid")
                                    {
                                        ExpressionSyntax localvar = (ExpressionSyntax)awaitInst.Operation.Syntax;
                                        //var v = localvar.Kind().ToString();
                                        if (localvar.Kind().ToString() == "InvocationExpression")
                                        {
                                            InvocationExpressionSyntax invocInst = (InvocationExpressionSyntax)localvar;
                                            string leftOperand = "";
                                            ProcessInvocationExpr(invocInst, inst, leftOperand);
                                            isAsync = true;
                                        }
                                    }
                                    else if (awaitInst.Operation.Kind.ToString() == "IdentifierName")
                                    {
                                        //IdentifierNameSyntax indentInst = (IdentifierNameSyntax)awaitInst.Operation;
                                        isAsync = true;
                                        //rightOperand = indentInst.Identifier.ValueText;
                                        //awaitInvocRel.Add(new Tuple<string, string>(rightOperand, leftOperand));
                                    }
                                    conflictUnit.Add(new Tuple <Accesses, string, IOperation>(Accesses.Await, invocSuffix, inst));
                                }
                                else if (exprInst.Operation.Kind.ToString() == "Invocation")
                                {
                                    IInvocationOperation invocInst = (IInvocationOperation)exprInst.Operation;
                                    string leftOperand             = "";
                                    ProcessInvocationOper(invocInst, inst, leftOperand);
                                    //conflictUnit.Add(new Tuple<Accesses, string, IOperation>(Accesses.Invocation, "", inst));

                                    // invocSyntax = Regex.Replace(invocSyntax, @"(\w.*)(\.Wait\(\))$", "$1");
                                    //invocSyntax = Regex.Replace(invocSyntax, @"(\w.*)(\.)(\w.*)$", "$3");
                                }
                            }
                        }
                        else if (inst.Kind.ToString() == "SimpleAssignment")
                        {
                            ISimpleAssignmentOperation exprInst = (ISimpleAssignmentOperation)inst;
                            ProcessSimpleAssignmentOper(exprInst, sharedFields, inst);
                        }
                    }
                }
            }
        }
            public override Location VisitAwait([NotNull] IAwaitOperation operation, [CanBeNull] object argument)
            {
                var syntax = (AwaitExpressionSyntax)operation.Syntax;

                return(syntax.AwaitKeyword.GetLocation());
            }