internal static MethodDeclarationSyntax BuildOverridableMethod(IMethodSymbol methodSymbol,
                                                                       string indentation = DefaultIndentation)
        {
            var methodName = methodSymbol.Name;
            var returnType = methodSymbol.ReturnType.SimplifyTypeName();

            var returnsByRef         = methodSymbol.ReturnsByRef;
            var returnsByRefReadonly = methodSymbol.ReturnsByRefReadonly;

            // Build method declaration
            var returnTypeIdentifier = IdentifierName(returnType.ToIdentifier());
            var methodIdentifier     = Identifier(methodName);
            var methodDecl           = !returnsByRefReadonly
            ? returnsByRef
               ? MethodDeclaration(
                RefType(returnTypeIdentifier)
                .WithRefKeyword(
                    SyntaxKind.RefKeyword.BuildToken(
                        Array.Empty <SyntaxTrivia>(), new[] { Space })), methodIdentifier)
               : MethodDeclaration(returnTypeIdentifier, methodIdentifier)
            : MethodDeclaration(
                RefType(returnTypeIdentifier)
                .WithRefKeyword(
                    SyntaxKind.RefKeyword.BuildToken(Array.Empty <SyntaxTrivia>(), new[] { Space }))
                .WithReadOnlyKeyword(
                    SyntaxKind.ReadOnlyKeyword.BuildToken(Array.Empty <SyntaxTrivia>(), new[] { Space })),
                methodIdentifier);

            var methodModifiers =
                methodSymbol.GetAccessModifiersWithOverride(indentation);

            methodDecl = methodDecl.WithModifiers(methodModifiers);

            // Add type parameters if present
            if (methodSymbol.IsGenericMethod)
            {
                var typeParameters = methodSymbol.TypeParameters;
                if (typeParameters.Length > 0)
                {
                    var typeParameterList =
                        BuildGeneric(typeParameters, genericName => TypeParameter(Identifier(genericName)));
                    var genericParametersSyntax = TypeParameterList(SeparatedList <TypeParameterSyntax>(typeParameterList));
                    methodDecl = methodDecl.WithTypeParameterList(genericParametersSyntax);
                }
            }

            // Build method parameters if present
            var parameters          = methodSymbol.Parameters;
            var parameterListSyntax = parameters.Length > 0
            ? ParameterList(SeparatedList <ParameterSyntax>(GetParameterNodes(parameters)))
            : ParameterList();

            parameterListSyntax = parameterListSyntax
                                  .WithCloseParenToken(SyntaxKind.CloseParenToken.BuildToken(
                                                           Array.Empty <SyntaxTrivia>(), new[] { LineFeed }));
            methodDecl = methodDecl.WithParameterList(parameterListSyntax);

            // Build method body
            var invocationExpr =
                methodSymbol.BuildBaseInvocationExpr(methodSymbol.BuildBaseExpr(indentation), methodName);

            if (parameters.Length > 0)
            {
                var argumentNodes = GetArgumentNodes(parameters);
                invocationExpr =
                    invocationExpr.WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>(argumentNodes)));
            }

            var singleStatement =
                GetOverridableStmt(methodSymbol, indentation, invocationExpr, returnsByRefReadonly, returnsByRef);
            var block = Block(SingletonList(singleStatement));
            var reducedIndentation = " ".Repeat(indentation.Length / 2);

            block = block.WithOpenBraceToken(
                SyntaxKind.OpenBraceToken.BuildToken(new[] { Whitespace(reducedIndentation) },
                                                     new[] { LineFeed }));
            block = block.WithCloseBraceToken(
                SyntaxKind.CloseBraceToken.BuildToken(new[] { Whitespace(reducedIndentation) }, new[] { LineFeed }));

            methodDecl = methodDecl.WithBody(block);

            return(methodDecl);
        }