I'm going to break this up into separate steps ... the current patch combines too many things: changing MatchNoDocsQuery.toString, adding a reason to it, changing it to return its own Weight instead of rewriting to BQ, changing BQ to rewrite to it when there are no clauses.
I'll start by fixing MatchNoDocsQuery.toString() to simply return "MatchNoDocsQuery". But even that small change is not easy: it is something of a break in our normal policy for a Query.toString in that today queries try to have a .toString which when sent back through a query parser would parse back to an equivalent query instance. E.g., a PhraseQuery instance's toString would be "foo bar", which most query parsers would parse back into an equivalent query.
The Python world handles this situation nicely, by having two separate functions: repr makes a string which when eval'd (parsed and executed by Python) turns back into the same object, whereas str makes a pretty thing that humans can understand. But Lucene has no such separation ... and our Query.toString is more like repr now.
Is anyone besides me worried about this? Do we have other queries that return a "human but not query-parser consumable" string?