blob: 1733b224873bf6fe7b507e7a1f121d627e6adb65 [file] [log] [blame]
/*
Copyright 2019 Alain Dargelas
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* File: ErrorContainer.cpp
* Author: alain
*
* Created on March 5, 2017, 11:12 PM
*/
#include "Python.h"
#include "ErrorReporting/ErrorContainer.h"
#include <mutex>
#include <iostream>
#include <fstream>
#include "CommandLine/CommandLineParser.h"
#include "ErrorReporting/Waiver.h"
#include "antlr4-runtime.h"
using namespace antlr4;
#include "API/PythonAPI.h"
using namespace SURELOG;
ErrorContainer::ErrorContainer(SymbolTable* symbolTable)
: m_clp(NULL),
m_reportedFatalErrorLogFile(false),
m_symbolTable(symbolTable),
m_interpState(NULL) {
m_interpState = PythonAPI::getMainInterp();
/* Do nothing here */
}
#include <unistd.h>
#include <stdio.h>
void ErrorContainer::init() {
if (ErrorDefinition::init()) {
const std::string& logFileName =
m_clp->getSymbolTable()->getSymbol(m_clp->getLogFileId());
std::ofstream ofs;
ofs.open(logFileName, std::fstream::out);
if (!ofs.good()) {
std::cerr << "[FATAL:LG0001] Cannot create log file \"" << logFileName
<< "\"" << std::endl;
return;
}
ofs.close();
}
}
ErrorContainer::ErrorContainer(const ErrorContainer& orig) {}
ErrorContainer::~ErrorContainer() {}
Error& ErrorContainer::addError(Error& error, bool showDuplicates,
bool reentrantPython) {
std::tuple<std::string, bool, bool> textStatus =
createErrorMessage(error, reentrantPython);
if (std::get<2>(textStatus)) // filter Message
return error;
std::multimap<ErrorDefinition::ErrorType, Waiver::WaiverData>& waivers =
Waiver::getWaivers();
std::pair<
std::multimap<ErrorDefinition::ErrorType, Waiver::WaiverData>::iterator,
std::multimap<ErrorDefinition::ErrorType, Waiver::WaiverData>::iterator>
ret = waivers.equal_range(error.m_errorId);
for (std::multimap<ErrorDefinition::ErrorType, Waiver::WaiverData>::iterator
it = ret.first;
it != ret.second; ++it) {
if ((((*it).second.m_fileName == "") ||
(m_symbolTable->getSymbol(error.m_locations[0].m_fileId) ==
(*it).second.m_fileName)) &&
(((*it).second.m_line == 0) ||
(error.m_locations[0].m_line == (*it).second.m_line)) &&
(((*it).second.m_objectId == "") ||
(m_symbolTable->getSymbol(error.m_locations[0].m_object) ==
(*it).second.m_objectId))) {
error.m_waived = true;
break;
}
}
if (showDuplicates) {
m_errors.push_back(error);
} else {
if (m_errorSet.find(std::get<0>(textStatus)) == m_errorSet.end()) {
m_errors.push_back(error);
m_errorSet.insert(std::get<0>(textStatus));
}
}
return m_errors[m_errors.size() - 1];
}
void ErrorContainer::appendErrors(ErrorContainer& rhs) {
for (unsigned int i = 0; i < rhs.m_errors.size(); i++) {
Error err = rhs.m_errors[i];
// Translate IDs to master symbol table
for (unsigned int locItr = 0; locItr < err.m_locations.size(); locItr++) {
Location& loc = err.m_locations[locItr];
if (loc.m_fileId)
loc.m_fileId = m_symbolTable->registerSymbol(
rhs.m_symbolTable->getSymbol(loc.m_fileId));
if (loc.m_object) {
loc.m_object = m_symbolTable->registerSymbol(
rhs.m_symbolTable->getSymbol(loc.m_object));
}
}
if (!err.m_reported) addError(err);
}
}
std::tuple<std::string, bool, bool> ErrorContainer::createErrorMessage(
Error& msg, bool reentrantPython) {
const std::map<ErrorDefinition::ErrorType, ErrorDefinition::ErrorInfo>&
infoMap = ErrorDefinition::getErrorInfoMap();
std::string tmp;
bool reportFatalError = false;
bool filterMessage = false;
if ((!msg.m_reported) && (!msg.m_waived)) {
ErrorDefinition::ErrorType type = msg.m_errorId;
std::map<ErrorDefinition::ErrorType,
ErrorDefinition::ErrorInfo>::const_iterator itr =
infoMap.find(type);
if (itr != infoMap.end()) {
ErrorDefinition::ErrorInfo info = (*itr).second;
std::string severity;
switch (info.m_severity) {
case ErrorDefinition::FATAL:
severity = "FATAL";
reportFatalError = true;
break;
case ErrorDefinition::SYNTAX:
severity = "SYNTX";
break;
case ErrorDefinition::ERROR:
severity = "ERROR";
break;
case ErrorDefinition::WARNING:
severity = "WARNI";
if (m_clp->filterWarning()) filterMessage = true;
break;
case ErrorDefinition::INFO:
severity = "INFO ";
if (m_clp->filterInfo() &&
(type != ErrorDefinition::PP_PROCESSING_SOURCE_FILE))
filterMessage = true;
break;
case ErrorDefinition::NOTE:
severity = "NOTE ";
if (m_clp->filterNote()) filterMessage = true;
break;
}
std::string category = ErrorDefinition::getCategoryName(info.m_category);
Location& loc = msg.m_locations[0];
/* Object */
std::string text = info.m_errorText;
const std::string& objectName = m_symbolTable->getSymbol(loc.m_object);
if (objectName != m_symbolTable->getBadSymbol()) {
size_t objectOffset = text.find("%s");
if (objectOffset != std::string::npos) {
text = text.replace(objectOffset, 2, objectName);
}
}
/* Location */
std::string location;
if (loc.m_fileId == 0) {
} else {
const std::string& fileName = m_symbolTable->getSymbol(loc.m_fileId);
location = fileName;
if (loc.m_line > 0) {
location += ":" + std::to_string(loc.m_line);
// Emacs does not like column
// if (loc.m_column > 0)
// location += ":" + std::to_string (loc.m_column);
}
location += " ";
}
/* Extra locations */
unsigned int nbExtraLoc = msg.m_locations.size();
for (unsigned int i = 1; i < nbExtraLoc; i++) {
Location& extraLoc = msg.m_locations[i];
if (extraLoc.m_fileId) {
std::string extraLocation;
const std::string& fileName =
m_symbolTable->getSymbol(extraLoc.m_fileId);
extraLocation = fileName;
if (extraLoc.m_line > 0) {
extraLocation += ":" + std::to_string(extraLoc.m_line);
// Emacs does not like column
// if (extraLoc.m_column > 0)
// extraLocation += ":" + std::to_string (extraLoc.m_column);
}
size_t objectOffset = text.find("%exloc");
if (objectOffset != std::string::npos) {
text = text.replace(objectOffset, 6, extraLocation);
} else if (info.m_extraText != "") {
text += ",\n " + info.m_extraText;
// text += ",\n" + info.m_extraText;
size_t objectOffset = text.find("%exloc");
if (objectOffset != std::string::npos) {
text = text.replace(objectOffset, 6, extraLocation);
}
}
} else {
if (info.m_extraText != "") {
if ((nbExtraLoc == 2) && (extraLoc.m_fileId == 0))
text += ",\n" + info.m_extraText;
else
text += ",\n " + info.m_extraText;
}
}
if (extraLoc.m_object) {
const std::string& objString =
m_symbolTable->getSymbol(extraLoc.m_object);
size_t objectOffset = text.find("%exobj");
if (objectOffset != std::string::npos) {
text = text.replace(objectOffset, 6, objString);
}
}
}
text += ".";
std::string padding;
if (msg.m_errorId < 10)
padding = "000";
else if (msg.m_errorId < 100)
padding = "00";
else if (msg.m_errorId < 1000)
padding = "0";
if ((reentrantPython == false) || (!m_clp->pythonAllowed())) {
tmp = "[" + severity + ":" + category + padding +
std::to_string(msg.m_errorId) + "] " + location + text + "\n\n";
} else {
std::vector<std::string> args;
args.push_back(severity);
args.push_back(category);
args.push_back(padding + std::to_string(msg.m_errorId));
args.push_back(location);
args.push_back(text);
tmp = PythonAPI::evalScript("__main__", "SLformatMsg", args,
(PyThreadState*) m_interpState);
}
}
}
return std::make_tuple(tmp, reportFatalError, filterMessage);
}
bool ErrorContainer::hasFatalErrors() {
const std::map<ErrorDefinition::ErrorType, ErrorDefinition::ErrorInfo>&
infoMap = ErrorDefinition::getErrorInfoMap();
bool reportFatalError = false;
for (unsigned int i = 0; i < m_errors.size(); i++) {
Error& msg = m_errors[i];
ErrorDefinition::ErrorType type = msg.m_errorId;
std::map<ErrorDefinition::ErrorType,
ErrorDefinition::ErrorInfo>::const_iterator itr =
infoMap.find(type);
if (itr != infoMap.end()) {
ErrorDefinition::ErrorInfo info = (*itr).second;
std::string severity;
switch (info.m_severity) {
case ErrorDefinition::FATAL:
reportFatalError = true;
break;
default:
break;
}
}
}
return reportFatalError;
}
std::pair<std::string, bool> ErrorContainer::createReport_() {
std::string report;
bool reportFatalError = false;
for (unsigned int i = 0; i < m_errors.size(); i++) {
Error& msg = m_errors[i];
std::tuple<std::string, bool, bool> textStatus = createErrorMessage(msg);
if (std::get<1>(textStatus)) reportFatalError = true;
if (std::get<2>(textStatus)) // Filtered
continue;
report += std::get<0>(textStatus);
msg.m_reported = true;
}
return std::make_pair(report, reportFatalError);
}
std::pair<std::string, bool> ErrorContainer::createReport_(Error& error) {
std::string report;
bool reportFatalError = false;
Error& msg = error;
std::tuple<std::string, bool, bool> textStatus = createErrorMessage(msg);
if (std::get<1>(textStatus)) reportFatalError = true;
if (!std::get<2>(textStatus)) // Filtered
report += std::get<0>(textStatus);
msg.m_reported = true;
return std::make_pair(report, reportFatalError);
}
bool ErrorContainer::printStats(ErrorContainer::Stats stats, bool muteStdout) {
std::string report;
report += "[ FATAL] : " + std::to_string(stats.nbFatal) + "\n";
report += "[ SYNTAX] : " + std::to_string(stats.nbSyntax) + "\n";
report += "[ ERROR] : " + std::to_string(stats.nbError) + "\n";
report += "[WARNING] : " + std::to_string(stats.nbWarning) + "\n";
// BOGUS NUMBER IN CACHED MODE report += "[ INFO] : " +
// std::to_string(stats.nbInfo) + "\n";
report += "[ NOTE] : " + std::to_string(stats.nbNote) + "\n";
if (!muteStdout) {
std::cout << report << std::flush;
}
bool successLogFile = printToLogFile(report);
return (successLogFile && (!stats.nbFatal) && (!stats.nbSyntax));
}
ErrorContainer::Stats ErrorContainer::getErrorStats() {
const std::map<ErrorDefinition::ErrorType, ErrorDefinition::ErrorInfo>&
infoMap = ErrorDefinition::getErrorInfoMap();
ErrorContainer::Stats stats;
for (auto msg : m_errors) {
if (!msg.m_waived) {
ErrorDefinition::ErrorType type = msg.m_errorId;
std::map<ErrorDefinition::ErrorType,
ErrorDefinition::ErrorInfo>::const_iterator itr =
infoMap.find(type);
if (itr != infoMap.end()) {
ErrorDefinition::ErrorInfo info = (*itr).second;
switch (info.m_severity) {
case ErrorDefinition::FATAL:
stats.nbFatal++;
break;
case ErrorDefinition::SYNTAX:
stats.nbSyntax++;
break;
case ErrorDefinition::ERROR:
stats.nbError++;
break;
case ErrorDefinition::WARNING:
stats.nbWarning++;
break;
case ErrorDefinition::INFO:
stats.nbInfo++;
break;
case ErrorDefinition::NOTE:
stats.nbNote++;
break;
}
}
}
}
return stats;
}
static std::mutex m;
bool ErrorContainer::printToLogFile(std::string report) {
m.lock();
const std::string& logFileName =
m_clp->getSymbolTable()->getSymbol(m_clp->getLogFileId());
std::ofstream ofs;
ofs.open(logFileName, std::fstream::app);
if (!ofs.good()) {
if (!m_reportedFatalErrorLogFile) {
std::cerr << "[FATAL:LG0002] Cannot open log file \"" << logFileName
<< "\" in append mode" << std::endl;
m_reportedFatalErrorLogFile = true;
}
m.unlock();
return false;
} else {
ofs << report << std::flush;
ofs.close();
}
m.unlock();
return true;
}
bool ErrorContainer::printMessage(Error& error, bool muteStdout) {
if (error.m_reported) return false;
std::pair<std::string, bool> report = createReport_(error);
if (!muteStdout) {
std::cout << report.first << std::flush;
}
bool successLogFile = printToLogFile(report.first);
error.m_reported = true;
return (successLogFile && (!report.second));
}
bool ErrorContainer::printMessages(bool muteStdout) {
std::pair<std::string, bool> report = createReport_();
if (!muteStdout) {
std::cout << report.first << std::flush;
}
bool successLogFile = printToLogFile(report.first);
return (successLogFile && (!report.second));
}