public static void UsingBorrowBorrowOrIncrementUsage() { using var set = PooledSet <int> .Borrow(); using var meh = set.IncrementUsage(); using var meh1 = meh.IncrementUsage(); }
public static void UsingBorrowAddForeach() { using var set = PooledSet <int> .Borrow(); _ = set.Add(1); foreach (var i in set) { } }
public static void UsingBorrowAddForeachCallId() { using (var set = PooledSet <int> .Borrow()) { set.Add(1); foreach (var i in set) { var j = Id(i); } } }
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); }
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); } }
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;
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); }
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)); } } }