Example #1
0
        /// <summary>
        /// Add return default to the end of the method to prevent "not all code paths return a value" error as a result of mutations
        /// </summary>
        private SyntaxNode AddReturnDefault(SyntaxNode currentNode)
        {
            // If it's not a method or the method has no body skip the node
            if (!(currentNode is MethodDeclarationSyntax methodNode) || methodNode.Body == null)
            {
                return(currentNode);
            }

            // If method return type is void skip the node
            if (methodNode.ReturnType is PredefinedTypeSyntax predefinedType && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword))
            {
                return(currentNode);
            }

            TypeSyntax returnType = methodNode.ReturnType;

            // the GenericNameSyntax node can be encapsulated by QualifiedNameSyntax nodes
            var genericReturn = returnType.DescendantNodesAndSelf().OfType <GenericNameSyntax>().FirstOrDefault();

            if (methodNode.Modifiers.Any(x => x.IsKind(SyntaxKind.AsyncKeyword)))
            {
                if (genericReturn != null)
                {
                    // if the method is async and returns a generic task, make the return default return the underlying type
                    returnType = genericReturn.TypeArgumentList.Arguments.First();
                }
                else
                {
                    // if the method is async but returns a non-generic task, don't add the return default
                    return(currentNode);
                }
            }

            var newBody = methodNode.Body.AddStatements(MutantPlacer.AnnotateHelper(SyntaxFactory.ReturnStatement(SyntaxFactory.DefaultExpression(returnType))));

            currentNode = currentNode.ReplaceNode(methodNode.Body, newBody);

            return(currentNode);
        }