From dd5089060e8a57078e771bde1c02b15ab0d28281 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Wed, 11 Jul 2018 06:38:05 +0200 Subject: [PATCH] Generate expressive diagnostic messages --- changelog/error-pretty.dd | 21 +++++++++++++++ src/dmd/cli.d | 3 +++ src/dmd/errors.d | 30 ++++++++++++++++++++++ src/dmd/globals.d | 1 + src/dmd/mars.d | 4 +++ test/fail_compilation/fail_pretty_errors.d | 15 +++++++++++ 6 files changed, 74 insertions(+) create mode 100644 changelog/error-pretty.dd create mode 100644 test/fail_compilation/fail_pretty_errors.d diff --git a/changelog/error-pretty.dd b/changelog/error-pretty.dd new file mode 100644 index 000000000000..3fe7c21a662c --- /dev/null +++ b/changelog/error-pretty.dd @@ -0,0 +1,21 @@ +dmd now supports expressive diagnostic error messages with `-verrors=pretty` + +With the new CLI option `-verrors=pretty` dmd will now show the offending line directly in its error messages. +Consider this faulty program `test.d`: + +--- +void foo() +{ + + a = 1; +} +--- + +Now run it with `-verrors=pretty`: + +$(CONSOLE +> dmd -verrors=pretty test.d +ee.d(5): $(RED Error): undefined identifier a + a = 1; + ^ +) diff --git a/src/dmd/cli.d b/src/dmd/cli.d index 12030092a02e..91fc9eeb2b6f 100644 --- a/src/dmd/cli.d +++ b/src/dmd/cli.d @@ -553,6 +553,9 @@ dmd -cov -unittest myprog.d Option("verrors=spec", "show errors from speculative compiles such as __traits(compiles,...)" ), + Option("verrors=pretty", + "Pretty-print error messages with annotation of the erroring source line" + ), Option("-version", "print compiler version and exit" ), diff --git a/src/dmd/errors.d b/src/dmd/errors.d index 0c7c4fe9604d..2b654f6049b7 100644 --- a/src/dmd/errors.d +++ b/src/dmd/errors.d @@ -236,6 +236,36 @@ private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* head else fputs(tmp.peekString(), stderr); fputc('\n', stderr); + + if (global.params.prettyPrintErrors) + { + auto fp = fopen(loc.filename, "r"); + scope(exit) fclose(fp); + + if (fp) + { + char* lineptr; + ulong n = 1024; + import core.sys.posix.stdio; + foreach (_; 0 .. loc.linnum) + { + assert(getline(&lineptr, &n, fp) > 0); + if (lineptr is null) + goto end; + } + if (lineptr is null) + goto end; + fprintf(stderr, "%s", lineptr); + + if (loc.charnum >= 1) + foreach (_; 1 .. loc.charnum) + fputc(' ', stderr); + + fputc('^', stderr); + } + fputc('\n', stderr); + } +end: fflush(stderr); // ensure it gets written out in case of compiler aborts } diff --git a/src/dmd/globals.d b/src/dmd/globals.d index 4d4a4481507c..8dc0aeb624cc 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -158,6 +158,7 @@ struct Param */ bool showGaggedErrors; // print gagged errors anyway + bool prettyPrintErrors; // pretty print errors with the actual line bool manual; // open browser on compiler manual bool usage; // print usage and exit bool mcpuUsage; // print help on -mcpu switch diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 0f8e977be63f..c7d8814d50c4 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -1732,6 +1732,10 @@ private bool parseCommandLine(const ref Strings arguments, const size_t argc, re { params.showGaggedErrors = true; } + else if (startsWith(p + 9, "pretty")) + { + params.prettyPrintErrors = true; + } else goto Lerror; } diff --git a/test/fail_compilation/fail_pretty_errors.d b/test/fail_compilation/fail_pretty_errors.d new file mode 100644 index 000000000000..cffd784ab4f2 --- /dev/null +++ b/test/fail_compilation/fail_pretty_errors.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: -verrors=pretty +TEST_OUTPUT: +--- +fail_compilation/fail_pretty_errors.d(14): Error: undefined identifier `a` + a = 1; + ^ +--- +*/ + +void foo() +{ + + a = 1; +}