public static bool IsAccessOnNewlyCreatedObject(KnownSymbols knownSymbols, SemanticModel semanticModel, SyntaxNode node, RecursiveState recursiveState1) { bool IsOnNewlyCreatedObject(ExpressionSyntax exp) { if (exp is MemberAccessExpressionSyntax memberAccess1) { return(IsOnNewlyCreatedObject(memberAccess1.Expression)); } if (exp is ElementAccessExpressionSyntax elementAccess1) { return(IsOnNewlyCreatedObject(elementAccess1.Expression)); } return(Utils.IsNewlyCreatedObject(semanticModel, exp, knownSymbols, RecursiveIsNewlyCreatedObjectState.Empty(), recursiveState1)); } if (node.Parent is MemberAccessExpressionSyntax memberAccess) { return(IsOnNewlyCreatedObject(memberAccess)); } if (node is ElementAccessExpressionSyntax elementAccess) { return(IsOnNewlyCreatedObject(elementAccess)); } return(false); }
public static bool ReturnsNewObject(PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState1) { return(!GetNonNewObjectReturnsForPropertyGet(propertyDeclaration, semanticModel, knownSymbols, recursiveState1).Any()); }
public static IEnumerable <ExpressionSyntax> GetNonNewObjectReturnsForMethod( BaseMethodDeclarationSyntax methodDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState1) { var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration); if (!methodSymbol.ReturnsByRef && IsCompleteValueType(methodSymbol.ReturnType)) { yield break; } var returnExpressions = methodDeclaration.Body != null ? methodDeclaration.Body .DescendantNodes() .OfType <ReturnStatementSyntax>() .Select(x => x.Expression) .ToArray() : new[] { methodDeclaration.ExpressionBody.Expression }; foreach (var expression in returnExpressions) { if (!Utils.IsNewlyCreatedObject(semanticModel, expression, knownSymbols, RecursiveIsNewlyCreatedObjectState.Empty(), recursiveState1)) { yield return(expression); } } }
private static bool MethodReturnsNewObject( SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState, IMethodSymbol invokedMethod) { if (invokedMethod.IsInCode() && !invokedMethod.IsAbstract) { var location = invokedMethod.Locations.First(); var locationSourceTree = location.SourceTree; var node = locationSourceTree.GetRoot().FindNode(location.SourceSpan); if (node is BaseMethodDeclarationSyntax methodNode) { if (ReturnsNewObject( methodNode, Utils.GetSemanticModel(semanticModel, methodNode.SyntaxTree), knownSymbols, recursiveState)) { return(true); } } else if (node.Parent.Parent is PropertyDeclarationSyntax propertyDeclaration) { if (ReturnsNewObject( propertyDeclaration, Utils.GetSemanticModel(semanticModel, propertyDeclaration.SyntaxTree), knownSymbols, recursiveState)) { return(true); } } } else { if (GetAllAttributes(invokedMethod) .Any(x => IsReturnsNewObjectAttribute(x.AttributeClass.Name))) { return(true); } if (knownSymbols.KnownReturnsNewObjectMethods.TryGetValue( Utils.GetFullMetaDataName(invokedMethod.ContainingType), out var methods) && methods.AnyMatches(invokedMethod)) { return(true); } } return(false); }
public static IEnumerable <Impurity> GetImpurities( SyntaxNode methodDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState, PurityType purityType = PurityType.Pure, Maybe <PureLambdaConfig> pureLambdaConfig = default) { var impuritiesFinder = new ImpuritiesFinder(semanticModel, purityType, knownSymbols); return(impuritiesFinder.GetImpurities(methodDeclaration, recursiveState, pureLambdaConfig)); }
ChangeAcceptedPurityTypeBasedOnWhetherExpressionRepresentsANewObjectOrParameterBasedExpression( PurityType currentAcceptedPurityType, ExpressionSyntax node, KnownSymbols knownSymbols, SemanticModel semanticModel, RecursiveState recursiveState) { if (Utils.IsNewlyCreatedObject(semanticModel, node, knownSymbols, RecursiveIsNewlyCreatedObjectState.Empty(), recursiveState)) { return(PurityType.PureExceptLocally); } else if (ImpuritiesFinder.IsParameter(semanticModel, node)) { return(PurityType.PureExceptReadLocally); } return(currentAcceptedPurityType); }
public static bool AnyImpurePropertyInitializer(TypeDeclarationSyntax typeDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState, InstanceStaticCombination instanceStaticCombination) { var props = typeDeclaration .Members .OfType <PropertyDeclarationSyntax>() .Where(instanceStaticCombination.Matches) .ToArray(); foreach (var var in props.Select(x => x.Initializer).Where(i => i != null)) { if (Utils.GetImpurities(var, semanticModel, knownSymbols, recursiveState).Any()) { return(true); } } return(false); }
public static bool AnyImpureFieldInitializer( TypeDeclarationSyntax typeDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState, InstanceStaticCombination instanceStaticCombination) { var fields = typeDeclaration.Members .OfType <FieldDeclarationSyntax>() .Where(instanceStaticCombination.Matches) .ToArray(); foreach (var var in fields.SelectMany(x => x.Declaration.Variables)) { if (Utils.GetImpurities(var, semanticModel, knownSymbols, recursiveState).Any()) { return(true); } } return(false); }
public static IEnumerable <ExpressionSyntax> GetNonNewObjectReturnsForPropertyGet( PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState1) { var propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration); if (propertySymbol.GetMethod == null) { yield break; } if (!propertySymbol.ReturnsByRef && IsCompleteValueType(propertySymbol.Type)) { yield break; } List <ExpressionSyntax> returnExpressions; if (propertyDeclaration.AccessorList != null) { var getAccessor = propertyDeclaration.AccessorList.Accessors.FirstOrNoValue(x => x.Keyword.Kind() == SyntaxKind.GetKeyword); if (getAccessor.HasNoValue) { yield break; } var getAccessorValue = getAccessor.GetValue(); returnExpressions = getAccessorValue.ExpressionBody != null ? new List <ExpressionSyntax>() { getAccessorValue.ExpressionBody.Expression } : getAccessor.GetValue() .DescendantNodes() .OfType <ReturnStatementSyntax>() .Select(x => x.Expression) .ToList(); } else if (propertyDeclaration.ExpressionBody != null) { returnExpressions = new List <ExpressionSyntax>() { propertyDeclaration.ExpressionBody.Expression }; } else { yield break; } foreach (var expression in returnExpressions) { if (!Utils.IsNewlyCreatedObject(semanticModel, expression, knownSymbols, RecursiveIsNewlyCreatedObjectState.Empty(), recursiveState1)) { yield return(expression); } } }
public static bool ReturnsNewObject(BaseMethodDeclarationSyntax methodDeclaration, SemanticModel semanticModel, KnownSymbols knownSymbols, RecursiveState recursiveState1) { return(!GetNonNewObjectReturnsForMethod(methodDeclaration, semanticModel, knownSymbols, recursiveState1).Any()); }
public static List <ExpressionSyntax> GetValuesPossiblyInjectedInto(SemanticModel semanticModel, ILocalSymbol variable, SyntaxNode containingBlockNode, KnownSymbols knownSymbols, RecursiveState recursiveState) { var usages = containingBlockNode .DescendantNodes() .OfType <IdentifierNameSyntax>() .Where(x => x.Identifier.Text == variable.Name) .Where(x => semanticModel.GetSymbolInfo(x).Symbol?.Equals(variable) ?? false) .Select(x => x.Parent) .ToList(); List <ExpressionSyntax> result = new List <ExpressionSyntax>(); void HandleMemberAccess(MemberAccessExpressionSyntax usage) { if (usage.Parent is AssignmentExpressionSyntax assignment) { result.Add(assignment.Right); } else if (usage.Parent is InvocationExpressionSyntax invocation) { if (semanticModel.GetSymbolInfo(invocation.Expression).Symbol is IMethodSymbol invokedMethod) { var purityType = ImpuritiesFinder.GetMethodPurityType(semanticModel, knownSymbols, invokedMethod, recursiveState); if (purityType.HasValueAnd(x => x.Equals(PurityType.PureExceptLocally))) { result.AddRange(invocation.ArgumentList.Arguments.Select(x => x.Expression)); } } } else if (usage.Parent is MemberAccessExpressionSyntax memberAccess) { HandleMemberAccess(memberAccess); } } foreach (var usage in usages) { if (usage is MemberAccessExpressionSyntax memberAccess) { HandleMemberAccess(memberAccess); } else if (usage is ElementAccessExpressionSyntax elementAccess) { if (elementAccess.Parent is AssignmentExpressionSyntax assignment) { result.Add(assignment.Right); } } } return(result); }
public static bool IsNewlyCreatedObject(SemanticModel semanticModel, SyntaxNode expression, KnownSymbols knownSymbols, RecursiveIsNewlyCreatedObjectState recursiveState, RecursiveState recursiveState1) { if (expression is LiteralExpressionSyntax) { return(true); } if (expression is TupleExpressionSyntax tuple) { return(tuple.Arguments .Select(x => x.Expression) .All(x => IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState, recursiveState1))); } if (expression is ObjectCreationExpressionSyntax objectCreationExpression) { if (objectCreationExpression .ArgumentList != null) { if (objectCreationExpression .ArgumentList .Arguments.Any(arg => !IsNewlyCreatedObject(semanticModel, arg.Expression, knownSymbols, recursiveState, recursiveState1))) { return(false); } } if (objectCreationExpression.Initializer != null) { if (objectCreationExpression .Initializer .Expressions .OfType <AssignmentExpressionSyntax>() .Any(x => !IsNewlyCreatedObject(semanticModel, x.Right, knownSymbols, recursiveState, recursiveState1))) { return(false); } } return(true); } if (expression is ArrayCreationExpressionSyntax arrayCreationExpression) { if (arrayCreationExpression.Initializer != null) { if (arrayCreationExpression .Initializer .Expressions .Any(x => !IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState, recursiveState1))) { return(false); } } return(true); } if (expression is ImplicitArrayCreationExpressionSyntax arrayCreationExpression1) { if (arrayCreationExpression1.Initializer != null) { if (arrayCreationExpression1 .Initializer .Expressions .Any(x => !IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState, recursiveState1))) { return(false); } } return(true); } if (expression is InitializerExpressionSyntax initSyntax && initSyntax.Kind() == SyntaxKind.ArrayInitializerExpression) { if (initSyntax .Expressions .Any(x => !IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState, recursiveState1))) { return(false); } return(true); } if (expression is InvocationExpressionSyntax invocationExpression) { if (semanticModel.GetSymbolInfo(invocationExpression.Expression).Symbol is IMethodSymbol invokedMethod) { if (MethodReturnsNewObject(semanticModel, knownSymbols, recursiveState1, invokedMethod)) { return(true); } } } if (expression is MemberAccessExpressionSyntax memberAccessExpression) { if (semanticModel.GetSymbolInfo(memberAccessExpression.Name).Symbol is IPropertySymbol propertySymbol && !GetUsage(memberAccessExpression.Name).IsWrite()) { if (MethodReturnsNewObject(semanticModel, knownSymbols, recursiveState1, propertySymbol.GetMethod)) { return(true); } } } if (expression is IdentifierNameSyntax identifier) { var identifierSymbol = semanticModel.GetSymbolInfo(identifier).Symbol; if (identifierSymbol is ILocalSymbol local) { if (!local.IsRef && IsCompleteValueType(local.Type)) { return(true); } if (recursiveState.VariablesUnderTest.Contains(local)) { return(true); } var methodBody = GetBodyOfMethodThatContainsExpression(expression); if (methodBody.HasNoValue) { return(false); } var valuesInjectedIntoObject = GetValuesPossiblyInjectedInto(semanticModel, local, methodBody.GetValue(), knownSymbols, recursiveState1); if (!valuesInjectedIntoObject.All(x => { var typeSymbol = semanticModel.GetTypeInfo(x).Type; if (typeSymbol != null && IsImmutablePureData(typeSymbol)) { return(true); } return(IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState.Add(local), recursiveState1)); })) { return(false); } return(FindValuesAssignedToVariable(semanticModel, local, methodBody.GetValue()).All(x => IsNewlyCreatedObject(semanticModel, x, knownSymbols, recursiveState.Add(local), recursiveState1))); } } if (semanticModel.GetTypeInfo(expression).Type is ITypeSymbol type) { if (IsCompleteValueType(type)) { return(true); } } return(false); }