diff --git a/frontend/include/chpl/framework/ErrorWriter.h b/frontend/include/chpl/framework/ErrorWriter.h index 0424ca1fc4c9..f5bd7016edfb 100644 --- a/frontend/include/chpl/framework/ErrorWriter.h +++ b/frontend/include/chpl/framework/ErrorWriter.h @@ -393,6 +393,15 @@ class ErrorWriter : public ErrorWriterBase { std::ostream& oss_; ErrorWriterBase::OutputFormat outputFormat_; bool useColor_; + std::string lastFilePath_; + + /* Called when the error tries to print a particular file path to indicate + the location of an error. Returns true if this is needed, which happens + when the previously-printed file path was different. Otherwise, + the error message can skip printing file path information, since + it has not changed. + */ + bool noteFilePath(std::string newPath); void setColor(TermColorName color); diff --git a/frontend/lib/framework/ErrorWriter.cpp b/frontend/lib/framework/ErrorWriter.cpp index 02a485dda1c9..9977685e6157 100644 --- a/frontend/lib/framework/ErrorWriter.cpp +++ b/frontend/lib/framework/ErrorWriter.cpp @@ -78,6 +78,12 @@ static std::string fileText(Context* context, const Location& loc) { return fileText.text(); } +bool ErrorWriter::noteFilePath(std::string newPath) { + bool toReturn = lastFilePath_ != newPath; + lastFilePath_ = std::move(newPath); + return toReturn; +} + void ErrorWriter::setColor(TermColorName color) { if (useColor_) { oss_ << getColorFormat(color); @@ -104,18 +110,29 @@ static TermColorName kindColor(ErrorBase::Kind kind) { return CLEAR; } -static void writeFile(Context* context, - std::ostream& oss, - const Location& loc) { +static std::string locToPath(Context* context, const Location& loc) { UniqueString pathUstr = loc.path(); if (context) pathUstr = context->adjustPathForErrorMsg(pathUstr); auto path = pathUstr.c_str(); - int lineno = loc.line(); bool validPath = (path != nullptr && path[0] != '\0'); + if (validPath) return path; + return ""; +} + +static void writeFile(Context* context, + std::ostream& oss, + const Location& loc, + std::string* outFilePath = nullptr) { + int lineno = loc.line(); + auto path = locToPath(context, loc); + if (outFilePath) *outFilePath = path; - if (validPath && lineno > 0) oss << path << ":" << lineno; - else if (validPath) oss << path; - else oss << "(unknown location)"; + if (!path.empty()) { + if (lineno > 0) oss << path << ":" << lineno; + else oss << path; + } else { + oss << "(unknown location)"; + } } void ErrorWriter::writeHeading(ErrorBase::Kind kind, ErrorType type, @@ -129,7 +146,13 @@ void ErrorWriter::writeHeading(ErrorBase::Kind kind, ErrorType type, oss_ << kindText(kind); setColor(CLEAR); oss_ << " in "; - writeFile(context, oss_, errordetail::locate(context, loc)); + + // Printing the header prints the file path, so we need to update the + // 'lastFilePath_' field. + std::string printedPath; + writeFile(context, oss_, errordetail::locate(context, loc), &printedPath); + noteFilePath(std::move(printedPath)); + if (outputFormat_ == DETAILED) { // Second part of the error decoration const char* name = ErrorBase::getTypeName(type); @@ -207,6 +230,14 @@ void ErrorWriter::writeCode(const Location& location, size_t codeIndent = gutterSize+3; int lineNumber = location.firstLine(); + // Print the file path if it's changed since the last code block. Printing + // a code block will display the file path if needed, so lastFilePath_ needs + // to be updated. + if (noteFilePath(locToPath(context, location))) { + printBlank(oss_, codeIndent - 1); + oss_ << "--> " << lastFilePath_ << std::endl; + } + printBlank(oss_, codeIndent); oss_ << "|"; oss_ << std::endl;