//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This diagnostic client prints out their diagnostic messages. // //===----------------------------------------------------------------------===// // // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ // //===----------------------------------------------------------------------===// #include "flang/Frontend/TextDiagnosticPrinter.h" #include "flang/Frontend/TextDiagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace Fortran::frontend; TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &diagOs, clang::DiagnosticOptions *diags) : os(diagOs), diagOpts(diags) {} TextDiagnosticPrinter::~TextDiagnosticPrinter() {} // For remarks only, print the remark option and pass name that was used to a // raw_ostream. This also supports warnings from invalid remark arguments // provided. static void printRemarkOption(llvm::raw_ostream &os, clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { llvm::StringRef opt = clang::DiagnosticIDs::getWarningOptionForDiag(info.getID()); if (!opt.empty()) { // We still need to check if the level is a Remark since, an unknown option // warning could be printed i.e. [-Wunknown-warning-option] os << " [" << (level == clang::DiagnosticsEngine::Remark ? "-R" : "-W") << opt; llvm::StringRef optValue = info.getDiags()->getFlagValue(); if (!optValue.empty()) os << "=" << optValue; os << ']'; } } // For remarks only, if we are receiving a message of this format // [file location with line and column];;[path to file];;[the remark message] // then print the absolute file path, line and column number. void TextDiagnosticPrinter::printLocForRemarks( llvm::raw_svector_ostream &diagMessageStream, llvm::StringRef &diagMsg) { // split incoming string to get the absolute path and filename in the // case we are receiving optimization remarks from BackendRemarkConsumer diagMsg = diagMessageStream.str(); llvm::StringRef delimiter = ";;"; size_t pos = 0; llvm::SmallVector tokens; while ((pos = diagMsg.find(delimiter)) != std::string::npos) { tokens.push_back(diagMsg.substr(0, pos)); diagMsg = diagMsg.drop_front(pos + delimiter.size()); } // tokens will always be of size 2 in the case of optimization // remark message received if (tokens.size() == 2) { // Extract absolute path llvm::SmallString<128> absPath = llvm::sys::path::relative_path(tokens[1]); llvm::sys::path::remove_filename(absPath); // Add the last separator before the file name llvm::sys::path::append(absPath, llvm::sys::path::get_separator()); llvm::sys::path::make_preferred(absPath); // Used for changing only the bold attribute if (diagOpts->ShowColors) os.changeColor(llvm::raw_ostream::SAVEDCOLOR, true); // Print path, file name, line and column os << absPath << tokens[0] << ": "; } } void TextDiagnosticPrinter::HandleDiagnostic( clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(level, info); // Render the diagnostic message into a temporary buffer eagerly. We'll use // this later as we print out the diagnostic to the terminal. llvm::SmallString<100> outStr; info.FormatDiagnostic(outStr); llvm::raw_svector_ostream diagMessageStream(outStr); printRemarkOption(diagMessageStream, level, info); if (!prefix.empty()) os << prefix << ": "; // We only emit diagnostics in contexts that lack valid source locations. assert(!info.getLocation().isValid() && "Diagnostics with valid source location are not supported"); llvm::StringRef diagMsg; printLocForRemarks(diagMessageStream, diagMsg); Fortran::frontend::TextDiagnostic::printDiagnosticLevel(os, level, diagOpts->ShowColors); Fortran::frontend::TextDiagnostic::printDiagnosticMessage( os, /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, diagMsg, diagOpts->ShowColors); os.flush(); }