Пример #1
0
        public static void UsingBorrowBorrowOrIncrementUsage()
        {
            using var set = PooledSet <int> .Borrow();

            using var meh  = set.IncrementUsage();
            using var meh1 = meh.IncrementUsage();
        }
Пример #2
0
        public static void UsingBorrowAddForeach()
        {
            using var set = PooledSet <int> .Borrow();

            _ = set.Add(1);
            foreach (var i in set)
            {
            }
        }
Пример #3
0
 public static void UsingBorrowAddForeachCallId()
 {
     using (var set = PooledSet <int> .Borrow())
     {
         set.Add(1);
         foreach (var i in set)
         {
             var j = Id(i);
         }
     }
 }
Пример #4
0
        internal static bool TryGetReturnType(ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ITypeSymbol?returnType)
        {
            returnType = null;
            if (classDeclaration.TryFindMethod("ProvideValue", out var convertMethod) &&
                convertMethod.ReturnType is PredefinedTypeSyntax predefinedType &&
                predefinedType.Keyword.ValueText == "object" &&
                convertMethod.ParameterList != null &&
                convertMethod.ParameterList.Parameters.Count == 1)
            {
                using var walker      = ReturnValueWalker.Borrow(convertMethod);
                using var returnTypes = PooledSet <ITypeSymbol> .Borrow();

                returnTypes.UnionWith(walker.ReturnValues.Select(x => semanticModel.GetTypeInfoSafe(x, cancellationToken).Type));
                return(returnTypes.TrySingle <ITypeSymbol>(out returnType));
            }

            return(false);
        }
Пример #5
0
        internal static Result IsAlreadyAssignedWithCreated(ExpressionSyntax disposable, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol assignedSymbol)
        {
            if (!IsPotentiallyAssignableFrom(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            var symbol = semanticModel.GetSymbolSafe(disposable, cancellationToken);

            if (symbol is IPropertySymbol property &&
                IsAssignableFrom(property.Type, semanticModel.Compilation) &&
                property.TryGetSetter(cancellationToken, out var setter) &&
                (setter.ExpressionBody != null || setter.Body != null))
            {
                using (var assignedSymbols = PooledSet <ISymbol> .Borrow())
                {
                    using (var pooledAssigned = AssignmentExecutionWalker.Borrow(setter, Scope.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var assigned in pooledAssigned.Assignments)
                        {
                            if (assigned.Right is IdentifierNameSyntax identifierName &&
                                identifierName.Identifier.ValueText == "value" &&
                                IsPotentiallyAssignableFrom(assigned.Left, semanticModel, cancellationToken) &&
                                semanticModel.GetSymbolSafe(assigned.Left, cancellationToken) is ISymbol candidate &&
                                candidate.IsEitherKind(SymbolKind.Field, SymbolKind.Property))
                            {
                                assignedSymbols.Add(candidate);
                            }
                        }
                    }

                    assignedSymbol = null;
                    var result = Result.No;
                    foreach (var candidate in assignedSymbols)
                    {
                        switch (IsAssignedWithCreated(candidate, disposable, semanticModel, cancellationToken))
                        {
                        case Result.Unknown:
                            if (result == Result.No)
                            {
                                assignedSymbol = candidate;
                                result         = Result.Unknown;
                            }

                            break;

                        case Result.Yes:
                            assignedSymbol = candidate;
                            return(Result.Yes);

                        case Result.AssumeYes:
                            assignedSymbol = candidate;
                            result         = Result.AssumeYes;
                            break;

                        case Result.No:
                        case Result.AssumeNo:
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    return(result);
                }
            }

            if (symbol is IParameterSymbol parameter &&
                disposable.TryFirstAncestor <ArrowExpressionClauseSyntax>(out _))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = assignedValues.CurrentSymbol;
                if (assignedValues.Count == 1 &&
                    disposable.Parent is AssignmentExpressionSyntax assignment)
                {
                    if (assignment.Parent is ParenthesizedExpressionSyntax parenthesizedExpression &&
                        parenthesizedExpression.Parent is BinaryExpressionSyntax binary &&
                        binary.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        // lazy
                        return(Result.No);
                    }
                }

                if (symbol.IsEither <IParameterSymbol, ILocalSymbol>())
                {
                    assignedValues.RemoveAll(x => IsReturnedBefore(x));
                }

                using (var recursive = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAnyCreation(recursive, semanticModel, cancellationToken));
                }
            }

            bool IsReturnedBefore(ExpressionSyntax expression)
            {
                if (expression.TryFirstAncestor(out BlockSyntax block) &&
                    block.Statements.TryFirstOfType(out ReturnStatementSyntax _))
                {
                    if (expression.TryFirstAncestor <ForEachStatementSyntax>(out _) ||
                        expression.TryFirstAncestor <ForStatementSyntax>(out _) ||
                        expression.TryFirstAncestor <WhileStatementSyntax>(out _))
                    {
                        return(true);
                    }

                    return(!block.Contains(disposable) &&
                           block.SharesAncestor(disposable, out MemberDeclarationSyntax _));
                }

                return(false);
            }
        }
Пример #6
0
        internal static bool TryGetConversionTypes(ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol sourceType, out ITypeSymbol targetType)
        {
            sourceType = null;
            targetType = null;
            if (classDeclaration.TryFindMethod("Convert", out var convertMethod) &&
                convertMethod.ReturnType is PredefinedTypeSyntax returnType &&
                returnType.Keyword.ValueText == "object" &&
                convertMethod.ParameterList != null &&
                convertMethod.ParameterList.Parameters.Count == 4 &&
                convertMethod.ParameterList.Parameters.TryFirst(out var valueParameter))
            {
                using (var returnValues = ReturnValueWalker.Borrow(convertMethod))
                {
                    using (var returnTypes = PooledSet <ITypeSymbol> .Borrow())
                    {
                        foreach (var returnValue in returnValues.ReturnValues)
                        {
                            AddReturnType(returnTypes, returnValue);
                        }

                        return(returnTypes.TrySingle(out targetType) &&
                               ConversionWalker.TryGetCommonBase(
                                   convertMethod,
                                   semanticModel.GetDeclaredSymbolSafe(valueParameter, cancellationToken),
                                   semanticModel,
                                   cancellationToken,
                                   out sourceType));
                    }
                }
            }

            return(false);

            void AddReturnType(PooledSet <ITypeSymbol> returnTypes, ExpressionSyntax returnValue)
            {
                switch (returnValue)
                {
                case LiteralExpressionSyntax literal when literal.IsKind(SyntaxKind.NullLiteralExpression):
                    break;

                case ConditionalExpressionSyntax ternary:
                    AddReturnType(returnTypes, ternary.WhenTrue);
                    AddReturnType(returnTypes, ternary.WhenFalse);
                    break;

                case BinaryExpressionSyntax coalesce when coalesce.IsKind(SyntaxKind.CoalesceExpression):
                    AddReturnType(returnTypes, coalesce.Left);

                    AddReturnType(returnTypes, coalesce.Right);
                    break;

                case IdentifierNameSyntax _:
                case MemberAccessExpressionSyntax _:
                    var type = semanticModel.GetTypeInfoSafe(returnValue, cancellationToken).Type;
                    if (type == KnownSymbol.Object &&
                        semanticModel.GetSymbolSafe(returnValue, cancellationToken) is ISymbol symbol &&
                        symbol.IsEither <IFieldSymbol, IPropertySymbol>())
                    {
                        switch (symbol)
                        {
                        case IFieldSymbol field:
                            if (field.Type == KnownSymbol.Object &&
                                field.DeclaredAccessibility == Accessibility.Private &&
                                returnValue.FirstAncestor <TypeDeclarationSyntax>() is TypeDeclarationSyntax typeDeclaration)
                            {
                                using (var walker = AssignmentExecutionWalker.Borrow(typeDeclaration, Scope.Instance, semanticModel, cancellationToken))
                                {
                                    foreach (var assignment in walker.Assignments)
                                    {
                                        if (semanticModel.TryGetSymbol(assignment.Left, cancellationToken, out IFieldSymbol assigned) &&
                                            FieldSymbolComparer.Equals(assigned, field))
                                        {
                                            returnTypes.Add(semanticModel.GetTypeInfoSafe(assignment.Right, cancellationToken).Type);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                returnTypes.Add(field.Type);
                            }

                            return;

                        case IPropertySymbol property:
                            returnTypes.Add(property.Type);
                            return;
                        }
                    }
                    else
                    {
                        returnTypes.Add(type);
                    }

                    break;
Пример #7
0
 public static void UsingBorrow()
 {
     using (PooledSet <int> .Borrow())
     {
     }
 }
        /// <summary>
        /// Walk <paramref name="containing"/> then all documents in project.
        /// </summary>
        /// <param name="containing">The <see cref="Document"/>.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> that cancels the operation.</param>
        /// <returns>The <see cref="CodeStyleResult"/> found.</returns>
        protected async Task <CodeStyleResult> CheckCoreAsync(Document containing, CancellationToken cancellationToken)
        {
            if (containing is null)
            {
                throw new ArgumentNullException(nameof(containing));
            }

            if (await Check(containing).ConfigureAwait(false) is { } containingResult&&
                containingResult != CodeStyleResult.NotFound)
            {
                return(containingResult);
            }

            using var set = PooledSet <Document> .Borrow();

            foreach (var document in Documents())
            {
                if (set.Add(document) &&
                    await Check(document).ConfigureAwait(false) is { } documentResult&&
                    documentResult != CodeStyleResult.NotFound)
                {
                    return(documentResult);
                }
            }

            return(CodeStyleResult.NotFound);

            async Task <CodeStyleResult> Check(Document candidate)
            {
                if (IsExcluded(candidate.FilePath))
                {
                    return(CodeStyleResult.NotFound);
                }

                var tree = await candidate.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                if (tree is null)
                {
                    return(CodeStyleResult.NotFound);
                }

                if (IsExcluded(tree.FilePath))
                {
                    return(CodeStyleResult.NotFound);
                }

                if (tree.TryGetRoot(out var root))
                {
                    this.Visit(root);
                    return(this.result);
                }

                return(CodeStyleResult.NotFound);
            }

            IEnumerable <Document> Documents()
            {
                foreach (var document in containing.Project.Documents)
                {
                    if (Equals(document.Folders, containing.Folders))
                    {
                        yield return(document);
                    }
                }

                foreach (var document in containing.Project.Documents)
                {
                    if (IsIn(document.Folders, containing.Folders))
                    {
                        yield return(document);
                    }
                }

                foreach (var document in containing.Project.Documents)
                {
                    if (document.Folders.TrySingle(out var folder) &&
                        folder == "obj")
                    {
                        continue;
                    }

                    yield return(document);
                }
Пример #9
0
        internal static bool TryGetCommonBase(SyntaxNode node, IParameterSymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol sourceType)
        {
            sourceType = null;
            using (var walker = Borrow(node))
            {
                foreach (var cast in walker.casts)
                {
                    if (IsFor(cast.Expression, symbol, semanticModel, cancellationToken) &&
                        !TryGetCommonBase(sourceType, cast.Type, out sourceType))
                    {
                        return(false);
                    }
                }

                foreach (var cast in walker.asCasts)
                {
                    if (IsFor(cast.Left, symbol, semanticModel, cancellationToken) &&
                        !TryGetCommonBase(sourceType, cast.Right as TypeSyntax, out sourceType))
                    {
                        return(false);
                    }
                }

                foreach (var isCheck in walker.isChecks)
                {
                    if (IsFor(isCheck.Left, symbol, semanticModel, cancellationToken) &&
                        !TryGetCommonBase(sourceType, isCheck.Right as TypeSyntax, out sourceType))
                    {
                        return(false);
                    }
                }

                foreach (var isPattern in walker.isPatterns)
                {
                    if (isPattern.Pattern is DeclarationPatternSyntax declarationPattern &&
                        IsFor(isPattern.Expression, symbol, semanticModel, cancellationToken) &&
                        !TryGetCommonBase(sourceType, declarationPattern.Type, out sourceType))
                    {
                        return(false);
                    }
                }

                foreach (var label in walker.caseLabels)
                {
                    if (label.Pattern is DeclarationPatternSyntax declarationPattern &&
                        IsFor(label.FirstAncestor <SwitchStatementSyntax>().Expression, symbol, semanticModel, cancellationToken) &&
                        !TryGetCommonBase(sourceType, declarationPattern.Type, out sourceType))
                    {
                        return(false);
                    }
                }

                // If we couldn't "guess" a source type we take parameters type
                if (sourceType == null)
                {
                    sourceType = symbol.Type;
                }

                return(true);
            }

            bool IsFor(ExpressionSyntax e, ISymbol s, SemanticModel sm, CancellationToken ct)
            {
                if (e is IdentifierNameSyntax idn &&
                    idn.Identifier.ValueText != symbol.Name)
                {
                    return(false);
                }

                return(ReferenceEquals(sm.GetSymbolSafe(e, ct), s));
            }

            bool TryGetCommonBase(ITypeSymbol?t1, TypeSyntax?ts, out ITypeSymbol result)
            {
                result = null !;
                if (ts == null)
                {
                    return(false);
                }

                var t2 = semanticModel.GetTypeInfoSafe(ts, cancellationToken).Type;

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

                if (ReferenceEquals(t1, t2))
                {
                    result = t1;
                    return(true);
                }

                if (t1 == null ||
                    t1.IsAssignableTo(t2, semanticModel.Compilation))
                {
                    result = t2;
                    return(true);
                }

                if (t2.IsAssignableTo(t1, semanticModel.Compilation))
                {
                    result = t1;
                    return(true);
                }

                using (var set = PooledSet <ITypeSymbol> .Borrow())
                {
                    set.UnionWith(t1.RecursiveBaseTypes());
                    set.IntersectWith(t2.RecursiveBaseTypes());
                    return(set.TryFirst(x => x is INamedTypeSymbol namedType && namedType.IsGenericType, out result) ||
                           set.TryFirst(out result));
                }
            }
        }