1 //===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This diagnostic client prints out their diagnostic messages. 10 // 11 //===----------------------------------------------------------------------===// 12 // 13 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "flang/Frontend/TextDiagnosticPrinter.h" 18 #include "flang/Frontend/TextDiagnostic.h" 19 #include "clang/Basic/DiagnosticOptions.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/Support/ErrorHandling.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 using namespace Fortran::frontend; 28 29 TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &diagOs, 30 clang::DiagnosticOptions *diags) 31 : os(diagOs), diagOpts(diags) {} 32 33 TextDiagnosticPrinter::~TextDiagnosticPrinter() {} 34 35 // For remarks only, print the remark option and pass name that was used to a 36 // raw_ostream. This also supports warnings from invalid remark arguments 37 // provided. 38 static void printRemarkOption(llvm::raw_ostream &os, 39 clang::DiagnosticsEngine::Level level, 40 const clang::Diagnostic &info) { 41 llvm::StringRef opt = 42 info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag( 43 info.getID()); 44 if (!opt.empty()) { 45 // We still need to check if the level is a Remark since, an unknown option 46 // warning could be printed i.e. [-Wunknown-warning-option] 47 os << " [" << (level == clang::DiagnosticsEngine::Remark ? "-R" : "-W") 48 << opt; 49 llvm::StringRef optValue = info.getFlagValue(); 50 if (!optValue.empty()) 51 os << "=" << optValue; 52 os << ']'; 53 } 54 } 55 56 // For remarks only, if we are receiving a message of this format 57 // [file location with line and column];;[path to file];;[the remark message] 58 // then print the absolute file path, line and column number. 59 void TextDiagnosticPrinter::printLocForRemarks( 60 llvm::raw_svector_ostream &diagMessageStream, llvm::StringRef &diagMsg) { 61 // split incoming string to get the absolute path and filename in the 62 // case we are receiving optimization remarks from BackendRemarkConsumer 63 diagMsg = diagMessageStream.str(); 64 llvm::StringRef delimiter = ";;"; 65 66 size_t pos = 0; 67 llvm::SmallVector<llvm::StringRef> tokens; 68 while ((pos = diagMsg.find(delimiter)) != std::string::npos) { 69 tokens.push_back(diagMsg.substr(0, pos)); 70 diagMsg = diagMsg.drop_front(pos + delimiter.size()); 71 } 72 73 // tokens will always be of size 2 in the case of optimization 74 // remark message received 75 if (tokens.size() == 2) { 76 // Extract absolute path 77 llvm::SmallString<128> absPath = llvm::sys::path::relative_path(tokens[1]); 78 llvm::sys::path::remove_filename(absPath); 79 // Add the last separator before the file name 80 llvm::sys::path::append(absPath, llvm::sys::path::get_separator()); 81 llvm::sys::path::make_preferred(absPath); 82 83 // Used for changing only the bold attribute 84 if (diagOpts->ShowColors) 85 os.changeColor(llvm::raw_ostream::SAVEDCOLOR, true); 86 87 // Print path, file name, line and column 88 os << absPath << tokens[0] << ": "; 89 } 90 } 91 92 void TextDiagnosticPrinter::HandleDiagnostic( 93 clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { 94 // Default implementation (Warnings/errors count). 95 DiagnosticConsumer::HandleDiagnostic(level, info); 96 97 // Render the diagnostic message into a temporary buffer eagerly. We'll use 98 // this later as we print out the diagnostic to the terminal. 99 llvm::SmallString<100> outStr; 100 info.FormatDiagnostic(outStr); 101 102 llvm::raw_svector_ostream diagMessageStream(outStr); 103 printRemarkOption(diagMessageStream, level, info); 104 105 if (!prefix.empty()) 106 os << prefix << ": "; 107 108 // We only emit diagnostics in contexts that lack valid source locations. 109 assert(!info.getLocation().isValid() && 110 "Diagnostics with valid source location are not supported"); 111 112 llvm::StringRef diagMsg; 113 printLocForRemarks(diagMessageStream, diagMsg); 114 115 Fortran::frontend::TextDiagnostic::printDiagnosticLevel(os, level, 116 diagOpts->ShowColors); 117 Fortran::frontend::TextDiagnostic::printDiagnosticMessage( 118 os, 119 /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, diagMsg, 120 diagOpts->ShowColors); 121 122 os.flush(); 123 } 124