# Buggy code
def _solve_undetermined_coefficients(eq, func, order, match):
    r"""
    Helper function for the method of undetermined coefficients.

    See the
    :py:meth:`~sympy.solvers.ode.ode_nth_linear_constant_coeff_undetermined_coefficients`
    docstring for more information on this method.

    The parameter ``match`` should be a dictionary that has the following
    keys:

    ``list``
      A list of solutions to the homogeneous equation, such as the list
      returned by
      ``ode_nth_linear_constant_coeff_homogeneous(returns='list')``.

    ``sol``
      The general solution, such as the solution returned by
      ``ode_nth_linear_constant_coeff_homogeneous(returns='sol')``.

    ``trialset``
      The set of trial functions as returned by
      ``_undetermined_coefficients_match()['trialset']``.

    """
    x = func.args[0]
    f = func.func
    r = match
    coeffs = numbered_symbols("a", cls=Dummy)
    coefflist = []
    gensols = r["list"]
    gsol = r["sol"]
    trialset = r["trialset"]
    notneedset = set([])
    # XXX: This global collectterms hack should be removed.
    global collectterms
    if len(gensols) != order:
        raise NotImplementedError(
            "Cannot find "
            + str(order)
            + " solutions to the homogeneous equation necessary to apply"
            + " undetermined coefficients to "
            + str(eq)
            + " (number of terms != order)"
        )
    usedsin = set([])
    mult = 0  # The multiplicity of the root
    getmult = True
    for i, reroot, imroot in collectterms:
        if getmult:
            mult = i + 1
            getmult = False
        if i == 0:
            getmult = True
        if imroot:
            # Alternate between sin and cos
            if (i, reroot) in usedsin:
                check = x**i * exp(reroot * x) * cos(imroot * x)
            else:
                check = x**i * exp(reroot * x) * sin(abs(imroot) * x)
                usedsin.add((i, reroot))
        else:
            check = x**i * exp(reroot * x)

        if check in trialset:
            # If an element of the trial function is already part of the
            # homogeneous solution, we need to multiply by sufficient x to
            # make it linearly independent.  We also don't need to bother
            # checking for the coefficients on those elements, since we
            # already know it will be 0.
            while True:
                if check * x**mult in trialset:
                    mult += 1
                else:
                    break
            trialset.add(check * x**mult)
            notneedset.add(check)

    newtrialset = trialset - notneedset

    trialfunc = 0
    for i in newtrialset:
        c = next(coeffs)
        coefflist.append(c)
        trialfunc += c * i

    eqs = sub_func_doit(eq, f(x), trialfunc)

    coeffsdict = dict(list(zip(trialset, [0] * (len(trialset) + 1))))

    eqs = _mexpand(eqs)

    for i in Add.make_args(eqs):
        s = separatevars(i, dict=True, symbols=[x])
        coeffsdict[s[x]] += s["coeff"]

    coeffvals = solve(list(coeffsdict.values()), coefflist)

    if not coeffvals:
        raise NotImplementedError(
            "Could not solve `%s` using the "
            "method of undetermined coefficients "
            "(unable to solve for coefficients)." % eq
        )

    psol = trialfunc.subs(coeffvals)

    return Eq(f(x), gsol.rhs + psol)


# Traceback (NotImplementedError)
dsolve(f(x).diff(x, x) + f(x) - x*sin(x - 2), f(x), hint='nth_linear_constant_coeff_undetermined_coefficients')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "sympy/solvers/ode.py", line 457, in dsolve
match=hints[hint]), func, hints['order'], hint)
File "sympy/solvers/ode.py", line 2370, in ode_nth_linear_constant_coeff_undetermined_coefficients
return _solve_undetermined_coefficients(eq, func, order, match)
File "sympy/solvers/ode.py", line 2460, in _solve_undetermined_coefficients
" method of undetermined coefficients (unable to solve for coefficients).")
NotImplementedError: Could not solve -x*sin(-2 + x) + D(f(x), x, x) + f(x) using the  method of undetermined coefficients (unable to solve for coefficients).

# Fixed code
def _solve_undetermined_coefficients(eq, func, order, match):
    r"""
    Helper function for the method of undetermined coefficients.

    See the
    :py:meth:`~sympy.solvers.ode.ode_nth_linear_constant_coeff_undetermined_coefficients`
    docstring for more information on this method.

    The parameter ``match`` should be a dictionary that has the following
    keys:

    ``list``
      A list of solutions to the homogeneous equation, such as the list
      returned by
      ``ode_nth_linear_constant_coeff_homogeneous(returns='list')``.

    ``sol``
      The general solution, such as the solution returned by
      ``ode_nth_linear_constant_coeff_homogeneous(returns='sol')``.

    ``trialset``
      The set of trial functions as returned by
      ``_undetermined_coefficients_match()['trialset']``.

    """
    x = func.args[0]
    f = func.func
    r = match
    coeffs = numbered_symbols("a", cls=Dummy)
    coefflist = []
    gensols = r["list"]
    gsol = r["sol"]
    trialset = r["trialset"]
    if len(gensols) != order:
        raise NotImplementedError(
            "Cannot find "
            + str(order)
            + " solutions to the homogeneous equation necessary to apply"
            + " undetermined coefficients to "
            + str(eq)
            + " (number of terms != order)"
        )

    trialfunc = 0
    for i in trialset:
        c = next(coeffs)
        coefflist.append(c)
        trialfunc += c * i

    eqs = sub_func_doit(eq, f(x), trialfunc)

    coeffsdict = dict(list(zip(trialset, [0] * (len(trialset) + 1))))

    eqs = _mexpand(eqs)

    for i in Add.make_args(eqs):
        s = separatevars(i, dict=True, symbols=[x])
        if coeffsdict.get(s[x]):
            coeffsdict[s[x]] += s["coeff"]
        else:
            coeffsdict[s[x]] = s["coeff"]

    coeffvals = solve(list(coeffsdict.values()), coefflist)

    if not coeffvals:
        raise NotImplementedError(
            "Could not solve `%s` using the "
            "method of undetermined coefficients "
            "(unable to solve for coefficients)." % eq
        )

    psol = trialfunc.subs(coeffvals)

    return Eq(f(x), gsol.rhs + psol)