Exemplo n.º 1
0
 private static void ReportError(SyntaxNodeAnalysisContext context, ISymbol local,
                                 RefCounterStatus status)
 {
     if (!status.IsSkip)
     {
         if (status.AssignCounter > 1)
         {
             var diagnostic = Diagnostic.Create(RuleRefCounterSkip, local.Locations[0], local.Name,
                                                string.Format("assigned more than once: {0}", status.AssignInfo));
             context.ReportDiagnostic(diagnostic);
         }
         else if (status.RefCounter != 0)
         {
             var diagnostic = Diagnostic.Create(RuleRefCounterError, local.Locations[0], local.Name,
                                                status.RefCounter, status.RefInfo);
             context.ReportDiagnostic(diagnostic);
         }
     }
     else
     {
         var diagnostic = Diagnostic.Create(RuleRefCounterSkip, local.Locations[0], local.Name,
                                            status.SkipReason);
         context.ReportDiagnostic(diagnostic);
     }
 }
Exemplo n.º 2
0
 public static void ProcessReturnStatement(ISymbol local, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken,
                                           RefCounterStatus status)
 {
     using (var walker = ReturnValueWalker.Borrow(block, Search.TopLevel, semanticModel, cancellationToken))
     {
         foreach (var value in walker)
         {
             var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken);
             if (SymbolComparer.Equals(local, returnedSymbol))
             {
                 var  method = block.FirstAncestor <MethodDeclarationSyntax>();
                 var  access = block.FirstAncestor <AccessorDeclarationSyntax>();
                 bool isGet  = false;
                 if (method != null)
                 {
                     isGet = KnownSymbol.IsGetMethodName(method.Identifier.ToString());
                 }
                 else if (access != null)
                 {
                     isGet = true;
                 }
                 if (isGet)
                 {
                     status.RemainRef("return value from get method", value.GetLocation());
                 }
                 else
                 {
                     status.ReleaseReference("return value from non get", value.GetLocation());
                 }
             }
         }
     }
 }
Exemplo n.º 3
0
        private static void HandleMethodParameter(SyntaxNodeAnalysisContext context, ParameterSyntax parameter)
        {
            var paramSympol = context.SemanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

            if (paramSympol != null)
            {
                var isRefCounter = RefCounter.IsRefCounterType(paramSympol.Type);
                if (isRefCounter)
                {
                    var param = context.SemanticModel.GetDeclaredSymbolSafe(parameter, context.CancellationToken);

                    if (param != null)
                    {
                        var method = parameter.FirstAncestorOrSelf <MethodDeclarationSyntax>();
                        var block  = method?.Body;
                        if (block == null)
                        {
                            return;
                        }

                        RefCounterStatus status = new RefCounterStatus();
                        if (method.Identifier.ToString().Equals(KnownSymbol.ReleaseReference))
                        {
                            status.AcquireReference("param of ReleaseReference", method.GetLocation());
                        }
                        ProcessLocalOrParamenterVar(context, param, block, status);
                    }
                }
            }
        }
    public static void ProcessRightOfAssignmentToField(
        ISymbol variable,
        BlockSyntax block,
        SemanticModel semanticModel,
        CancellationToken cancellationToken,
        RefCounterStatus status)
    {
        List <AssignmentExpressionSyntax> rc = new List <AssignmentExpressionSyntax>();

        block?.TryGetAssignment(variable, semanticModel, cancellationToken, rc);
        int      count = 0;
        ISymbol  field = null;
        Location loc   = Location.None;

        foreach (AssignmentExpressionSyntax assignment in rc)
        {
            var classDef    = block.FirstAncestor <ClassDeclarationSyntax>();
            var classSymbol = CSharpExtensions.GetDeclaredSymbol(semanticModel, classDef, cancellationToken);

            if (IsRightOfAssignmentToField(semanticModel, cancellationToken, assignment.Left, out field))
            {
                count++;
                loc = assignment.GetLocation();
                if (!field.ContainingType.Equals(classSymbol))
                {
                    status.Skip("assigned to field/property of other class", loc);
                }

                if (LoopUtils.HasLoopBetween(assignment, block))
                {
                    status.Skip("loop between assignment to field/property and var block", loc);
                }
            }
        }

        if (count == 1)
        {
            status.ReleaseReference("assign to class field/property", loc);

            var methodBlock = block?.FirstAncestorOrSelf <BlockSyntax>();
            if (methodBlock == null)
            {
                return;
            }

            if (RightSideOfAssignmentCount(field, methodBlock, semanticModel, cancellationToken) > 0)
            {
                status.Skip("var assigned to field/property, which is assigned to others", loc);
            }


            ChangeReferenceMethodUtils.ProcessIncDelRefInvocation(field, methodBlock, semanticModel, cancellationToken, status);
            ReturnUtils.ProcessReturnStatement(field, methodBlock, semanticModel, cancellationToken, status);
        }
        else if (count > 1)
        {
            status.Skip("multiple assign to field/property", loc);
        }
    }
Exemplo n.º 5
0
        public static void ProcessIncDelRefInvocation(ISymbol local, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken,
                                                      RefCounterStatus status)
        {
            IncRefInvocationCount(local, block, semanticModel, cancellationToken, status);


            DelRefInvocationCount(local, block, semanticModel, cancellationToken, status);
        }
    public static void ProcessRightSideOfAssignment(ISymbol local, BlockSyntax block, SemanticModel semanticModel,
                                                    CancellationToken cancellationToken,
                                                    RefCounterStatus status)
    {
        ProcessRightOfAssignmentToField(local, block, semanticModel, cancellationToken, status);

        ProcessRightOfAssignmentToLocal(local, block, semanticModel, cancellationToken, status);
    }
Exemplo n.º 7
0
 public static void ProcessVariableInitialization(
     VariableDeclaratorSyntax variable,
     BlockSyntax block,
     SemanticModel semanticModel,
     CancellationToken cancellationToken,
     RefCounterStatus refCounterStatus)
 {
     if (variable.Initializer == null || variable.Initializer.Value == null)
     {
         //refCounterStatus.Skip("not initialized while declare");
     }
     else
     {
         CalcAssignmentValue(variable.Initializer.Value, block, semanticModel, cancellationToken, refCounterStatus);
     }
 }
Exemplo n.º 8
0
        private static void HandleLocalVariable(SyntaxNodeAnalysisContext context, VariableDeclaratorSyntax variable)
        {
            if (context.SemanticModel.GetDeclaredSymbolSafe(variable, context.CancellationToken) is
                ILocalSymbol local)
            {
                var block = variable.FirstAncestorOrSelf <BlockSyntax>();
                if (block == null)
                {
                    return;
                }
                RefCounterStatus status = new RefCounterStatus();

                AssignmentUtils.ProcessVariableInitialization(variable, block, context.SemanticModel, context.CancellationToken, status);

                ProcessLocalOrParamenterVar(context, local, block, status);
            }
        }
Exemplo n.º 9
0
 public static void CalcAssignmentValue(ExpressionSyntax variable, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken,
                                        RefCounterStatus refCounterStatus)
 {
     if (InitializeFromCreation(variable))
     {
         refCounterStatus.IncAssignCounter("initialize from new", variable.GetLocation());
         refCounterStatus.AcquireReference("init from new", variable.GetLocation());
     }
     else if (InitializeFromTypeCastParameter(variable, semanticModel, cancellationToken, out var param))
     {
         refCounterStatus.IncAssignCounter("init cast from param", variable.GetLocation());
         refCounterStatus.RemainRef("init cast from param", variable.GetLocation());
         if (RightOfAssignmentUtils.RightSideOfAssignmentCount(param, block, semanticModel, cancellationToken) > 1)
         {
             refCounterStatus.Skip("cast from param also assigned to others", variable.GetLocation());
         }
     }
     else if (InitializeFromNonGetMethod(variable, semanticModel, cancellationToken))
     {
         refCounterStatus.IncAssignCounter("initialize from non-get method", variable.GetLocation());
         refCounterStatus.AcquireReference("init from non-get method", variable.GetLocation());
     }
     else if (InitializeFromGetMethod(variable, semanticModel, cancellationToken))
     {
         refCounterStatus.IncAssignCounter("initialize from get method", variable.GetLocation());
         refCounterStatus.RemainRef("init from get method", variable.GetLocation());
     }
     else if (InitializeFromProperty(variable, semanticModel, cancellationToken))
     {
         refCounterStatus.IncAssignCounter("initialize from field/property", variable.GetLocation());
         refCounterStatus.RemainRef("init from property", variable.GetLocation());
         // nothing
     }
     else if (InitializeFromElement(variable, semanticModel, cancellationToken))
     {
         refCounterStatus.IncAssignCounter("initialize from element access", variable.GetLocation());
         refCounterStatus.RemainRef("init from element access", variable.GetLocation());
     }
     else // assigned from other local variable, class field, or other expression
     {
         refCounterStatus.IncAssignCounter("initialize from unkown", variable.GetLocation());
         refCounterStatus.Skip("unsupported initialization", variable.GetLocation());
     }
 }
Exemplo n.º 10
0
        private static void ProcessLocalOrParamenterVar(SyntaxNodeAnalysisContext context, ISymbol local,
                                                        BlockSyntax block, RefCounterStatus status)
        {
            RightOfAssignmentUtils.ProcessRightSideOfAssignment(local, block, context.SemanticModel,
                                                                context.CancellationToken, status);

            SystemCollectionUtils.ProcessAddedToCollection(local, block, context.SemanticModel, context.CancellationToken,
                                                           status);
            LeftOfAssignmentUtils.ProcessLeftSideOfAssignment(local, block, context.SemanticModel,
                                                              context.CancellationToken, status);

            ChangeReferenceMethodUtils.ProcessIncDelRefInvocation(local, block, context.SemanticModel, context.CancellationToken,
                                                                  status);

            AssignmentUtils.ProcessOutRefInvocation(local, block, context.SemanticModel, context.CancellationToken, status);

            ReturnUtils.ProcessReturnStatement(local, block, context.SemanticModel, context.CancellationToken, status);

            ReportError(context, local, status);
        }
Exemplo n.º 11
0
    public static void ProcessOutRefInvocation(ISymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status)
    {
        using (var pooledInvocations = InvocationWalker.Borrow(block))
        {
            foreach (var invocation in pooledInvocations.Invocations)
            {
                foreach (ArgumentSyntax arg in invocation.ArgumentList.Arguments)
                {
                    if (arg.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword) || arg.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword))
                    {
                        var     sym       = ModelExtensions.GetSymbolInfo(semanticModel, arg.Expression, cancellationToken);
                        ISymbol argSymbol = sym.Symbol;
                        if (symbol.Equals(argSymbol))
                        {
                            status.RemainRef("init from out/ref call", arg.GetLocation());
                            status.IncAssignCounter("out/ref call parameter", arg.GetLocation());

                            if (LoopUtils.HasLoopBetween(invocation, block))
                            {
                                status.Skip("loop between ref/out call and var block", arg.GetLocation());
                            }
                        }
                    }
                }
            }
        }
    }
Exemplo n.º 12
0
    public static void ProcessAddedToCollection(
        ISymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status)
    {
        int      count = 0;
        Location loc   = Location.None;

        using (var pooledInvocations = InvocationWalker.Borrow(block))
        {
            foreach (var invocation in pooledInvocations.Invocations)
            {
                bool isAddToCollection = false;
                var  method            = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol;
                if (method?.ReceiverType != null)
                {
                    if (!isAddToCollection)
                    {
                        isAddToCollection = (method.ReceiverType.Is(KnownSymbol.IDictionary) || method.ReceiverType.Is(KnownSymbol.ICollection)) &&
                                            method?.Name == "Add";
                    }

                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.QueueOfT) &&
                                            method?.Name == "Enqueue";
                    }

                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.Queue) &&
                                            method?.Name == "Enqueue";
                    }

                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.ListOfT) &&
                                            method?.Name == "Insert";
                    }
                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.IRefCounterContainerOfT) &&
                                            method?.Name == "Add";
                    }

                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.CollectionOfT) &&
                                            method?.Name == "Add";
                    }
                    if (!isAddToCollection)
                    {
                        isAddToCollection = method.ReceiverType.Is(KnownSymbol.LinkedListOfT) &&
                                            (method?.Name == "AddLast" || method?.Name == "AddFirst");
                    }
                }

                if (isAddToCollection)
                {
                    bool isInArg = false;
                    foreach (ArgumentSyntax arg in invocation.ArgumentList.Arguments)
                    {
                        var     sym       = ModelExtensions.GetSymbolInfo(semanticModel, arg.Expression, cancellationToken);
                        ISymbol argSymbol = sym.Symbol;
                        if (symbol.Equals(argSymbol))
                        {
                            isInArg = true;
                        }
                    }

                    if (isInArg)
                    {
                        count++;
                        loc = invocation.GetLocation();
                        if (LoopUtils.HasLoopBetween(invocation, block))
                        {
                            status.Skip("loop between add to collection and var block", invocation.GetLocation());
                        }
                    }
                }
            }
        }

        if (count == 1)
        {
            status.ReleaseReference("added to collection", loc);
        }
    }
Exemplo n.º 13
0
        private static int IncRefInvocationCount(ISymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status)
        {
            int      count = 0;
            Location loc   = Location.None;;

            using (var pooledInvocations = InvocationWalker.Borrow(block))
            {
                foreach (var invocation in pooledInvocations.Invocations)
                {
                    var isFromSymbol = IsInvokeFrom(symbol, semanticModel, cancellationToken, invocation);

                    var method = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol;
                    if (isFromSymbol && method.ReceiverType != null)
                    {
                        if (method.ReceiverType.Is(KnownSymbol.RefCounter) &&
                            method?.Name == KnownSymbol.IncRef)
                        {
                            count++;
                            loc = invocation.GetLocation();
                            if (LoopUtils.HasLoopBetween(invocation, block))
                            {
                                status.Skip("loop between IncRef call and var block", loc);
                            }
                        }
                    }
                }
            }

            if (count > 1)
            {
                status.Skip("more than one IncRef", loc);
            }
            else if (count == 1)
            {
                status.IncRef("call IncRef", loc);
            }

            return(count);
        }
Exemplo n.º 14
0
        public static int DelRefInvocationCount(ISymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status)
        {
            int      count = 0;
            Location loc   = Location.None;;

            using (var pooledInvocations = InvocationWalker.Borrow(block))
            {
                foreach (var invocation in pooledInvocations.Invocations)
                {
                    var isFromSymbol = IsInvokeFrom(symbol, semanticModel, cancellationToken, invocation);
                    var method       = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol;
                    if (isFromSymbol && method?.ReceiverType != null)
                    {
                        if (method.ReceiverType.Is(KnownSymbol.RefCounter) &&
                            method?.Name == KnownSymbol.ReleaseReference)
                        {
                            count++;
                            loc = invocation.GetLocation();
                            if (LoopUtils.HasLoopBetween(invocation, block))
                            {
                                status.Skip("loop between ReleaseReference call and var block", invocation.GetLocation());
                            }
                        }
                    }
                    else
                    {
                        if (method?.Name == KnownSymbol.ReleaseReference)
                        {
                            foreach (ArgumentSyntax arg in invocation.ArgumentList.Arguments)
                            {
                                var     sym       = ModelExtensions.GetSymbolInfo(semanticModel, arg.Expression, cancellationToken);
                                ISymbol argSymbol = sym.Symbol;
                                if (symbol.Equals(argSymbol))
                                {
                                    count++;
                                    loc = invocation.GetLocation();

                                    if (LoopUtils.HasLoopBetween(invocation, block))
                                    {
                                        status.Skip("loop between ReleaseReference call and var block", arg.GetLocation());
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (count > 1)
            {
                status.Skip("more than one ReleaseReference", loc);
            }
            else if (count == 1)
            {
                status.ReleaseReference("call ReleaseReference", loc);
            }

            return(count);
        }
Exemplo n.º 15
0
    public static void ProcessRightOfAssignmentToLocal(ISymbol variable,
                                                       BlockSyntax block, SemanticModel semanticModel,
                                                       CancellationToken cancellationToken, RefCounterStatus status)
    {
        List <AssignmentExpressionSyntax> rc = new List <AssignmentExpressionSyntax>();

        block?.TryGetAssignment(variable, semanticModel, cancellationToken, rc);
        foreach (AssignmentExpressionSyntax assignment in rc)
        {
            var left = semanticModel.GetSymbolSafe(assignment.Left, cancellationToken) ??
                       semanticModel.GetSymbolSafe((assignment.Left as ElementAccessExpressionSyntax)?.Expression, cancellationToken);
            bool fOrP = left is ILocalSymbol || left is IParameterSymbol;
            if (fOrP)
            {
                status.Skip("assigned to other local variables", assignment.GetLocation());
            }
        }
    }
Exemplo n.º 16
0
    public static void ProcessLeftSideOfAssignment(ISymbol variable, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status)
    {
        List <AssignmentExpressionSyntax> rc = new List <AssignmentExpressionSyntax>();

        using (var walker = AssignmentWalker.Borrow(block, Search.TopLevel, semanticModel, cancellationToken))
        {
            foreach (AssignmentExpressionSyntax assignment in walker.Assignments)
            {
                var sym = ModelExtensions.GetSymbolInfo(semanticModel, assignment.Left, cancellationToken);
                if (variable.Equals(sym.Symbol))
                {
                    AssignmentUtils.CalcAssignmentValue(assignment.Right, block, semanticModel, cancellationToken, status);
                }
            }
        }
    }