Escape backticks in error messages (#20893)

This commit is contained in:
Dennis 2025-02-19 00:06:47 +01:00 committed by GitHub
parent e082ce247a
commit 0e5c41f799
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 39 additions and 6 deletions

View file

@ -1896,8 +1896,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
const sident = se.toStringz();
if (!sident.length || !Identifier.isValidIdentifier(sident))
{
error(ns.exp.loc, "expected valid identifier for C++ namespace but got `%.*s`",
cast(int)sident.length, sident.ptr);
error(ns.exp.loc, "expected valid identifier for C++ namespace but got `%s`", se.toErrMsg());
return null;
}
else

View file

@ -714,7 +714,10 @@ private void verrorPrint(const(char)* format, va_list ap, ref ErrorInfo info)
writeHighlights(con, tmp);
}
else
{
unescapeBackticks(tmp);
fputs(tmp.peekChars(), stderr);
}
fputc('\n', stderr);
__gshared SourceLoc old_loc;
@ -828,6 +831,7 @@ extern (C++) void halt() @safe
* is D source code, and color syntax highlight it.
* Modify contents of `buf` with highlighted result.
* Many parallels to ddoc.highlightText().
* Double backticks are replaced by a single backtick without coloring.
* Params:
* buf = text containing `...` code to highlight
*/
@ -843,6 +847,13 @@ private void colorSyntaxHighlight(ref OutBuffer buf)
switch (c)
{
case '`':
// A double backtick means it's part of the content, don't color
if (i + 1 < buf.length && buf[i + 1] == '`')
{
buf.remove(i, 1);
continue;
}
if (inBacktick)
{
inBacktick = false;
@ -867,6 +878,27 @@ private void colorSyntaxHighlight(ref OutBuffer buf)
}
}
/// Replace double backticks in `buf` with a single backtick
void unescapeBackticks(ref OutBuffer buf)
{
for (size_t i = 0; i + 1 < buf.length; ++i)
{
if (buf[i] == '`' && buf[i + 1] == '`')
buf.remove(i, 1);
}
}
unittest
{
OutBuffer buf;
buf.writestring("x````");
unescapeBackticks(buf);
assert(buf.extractSlice() == "x``");
buf.writestring("x````");
colorSyntaxHighlight(buf);
assert(buf.extractSlice() == "x``");
}
/**
* Embed these highlighting commands in the text stream.

View file

@ -155,13 +155,15 @@ const(char)* toErrMsg(const Dsymbol d)
*/
private void truncateForError(ref OutBuffer buf, size_t maxLength)
{
// Remove newlines
// Remove newlines, escape backticks ` by doubling them
for (size_t i = 0; i < buf.length; i++)
{
if (buf[i] == '\r')
buf.remove(i, 1);
if (buf[i] == '\n')
buf.peekSlice[i] = ' ';
if (buf[i] == '`')
i = buf.insert(i, "`");
}
// Strip trailing whitespace

View file

@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
fail_compilation/cppmangle.d(11): Error: expected valid identifier for C++ namespace but got ``
fail_compilation/cppmangle.d(15): Error: expected valid identifier for C++ namespace but got `0num`
fail_compilation/cppmangle.d(11): Error: expected valid identifier for C++ namespace but got `""`
fail_compilation/cppmangle.d(15): Error: expected valid identifier for C++ namespace but got `"0num"`
fail_compilation/cppmangle.d(19): Error: compile time string constant (or sequence) expected, not `2`
fail_compilation/cppmangle.d(23): Error: expected valid identifier for C++ namespace but got `invalid@namespace`
fail_compilation/cppmangle.d(23): Error: expected valid identifier for C++ namespace but got `"invalid@namespace"`
---
*/