Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #12610 (Justifications for warnings using comments in the code) #6482

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 49 additions & 49 deletions Makefile

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions gui/erroritem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ ErrorItem::ErrorItem(const ErrorMessage &errmsg)
, cwe(errmsg.cwe.id)
, hash(errmsg.hash)
, symbolNames(QString::fromStdString(errmsg.symbolNames()))
, remark(QString::fromStdString(errmsg.remark))
{
for (std::list<ErrorMessage::FileLocation>::const_iterator loc = errmsg.callStack.cbegin();
loc != errmsg.callStack.cend();
++loc) {
errorPath << QErrorPathItem(*loc);
}
for (const auto& loc: errmsg.callStack)
errorPath << QErrorPathItem(loc);
}

QString ErrorItem::tool() const
Expand Down
2 changes: 2 additions & 0 deletions gui/erroritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class ErrorItem {
unsigned long long hash;
QList<QErrorPathItem> errorPath;
QString symbolNames;
QString remark;

// Special GUI properties
QString sinceDate;
Expand Down Expand Up @@ -122,6 +123,7 @@ class ErrorLine {
QString message;
QString sinceDate;
QString tags;
QString remark;
};

/// @}
Expand Down
4 changes: 4 additions & 0 deletions gui/resultstree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static constexpr char SINCEDATE[] = "sinceDate";
static constexpr char SYMBOLNAMES[] = "symbolNames";
static constexpr char SUMMARY[] = "summary";
static constexpr char TAGS[] = "tags";
static constexpr char REMARK[] = "remark";

// These must match column headers given in ResultsTree::translate()
static constexpr int COLUMN_SINCE_DATE = 6;
Expand Down Expand Up @@ -186,6 +187,7 @@ bool ResultsTree::addErrorItem(const ErrorItem &item)
if (const ProjectFile *activeProject = ProjectFile::getActiveProject()) {
line.tags = activeProject->getWarningTags(item.hash);
}
line.remark = item.remark;
//Create the base item for the error and ensure it has a proper
//file item as a parent
QStandardItem* fileItem = ensureFileItem(loc.file, item.file0, hide);
Expand Down Expand Up @@ -214,6 +216,7 @@ bool ResultsTree::addErrorItem(const ErrorItem &item)
data[SINCEDATE] = item.sinceDate;
data[SYMBOLNAMES] = item.symbolNames;
data[TAGS] = line.tags;
data[REMARK] = line.remark;
data[HIDE] = hide;
stditem->setData(QVariant(data));

Expand Down Expand Up @@ -1296,6 +1299,7 @@ void ResultsTree::readErrorItem(const QStandardItem *error, ErrorItem *item) con
item->file0 = data[FILE0].toString();
item->sinceDate = data[SINCEDATE].toString();
item->tags = data[TAGS].toString();
item->remark = data[REMARK].toString();

if (error->rowCount() == 0) {
QErrorPathItem e;
Expand Down
5 changes: 5 additions & 0 deletions gui/xmlreportv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static const QString TagsAttribute = "tag";
static const QString FilenameAttribute = "file";
static const QString IncludedFromFilenameAttribute = "file0";
static const QString InconclusiveAttribute = "inconclusive";
static const QString RemarkAttribute = "remark";
static const QString InfoAttribute = "info";
static const QString LineAttribute = "line";
static const QString ColumnAttribute = "column";
Expand Down Expand Up @@ -137,6 +138,8 @@ void XmlReportV2::writeError(const ErrorItem &error)
mXmlWriter->writeAttribute(VerboseAttribute, message);
if (error.inconclusive)
mXmlWriter->writeAttribute(InconclusiveAttribute, "true");
if (!error.remark.isEmpty())
mXmlWriter->writeAttribute(RemarkAttribute, error.remark);
if (error.cwe > 0)
mXmlWriter->writeAttribute(CWEAttribute, QString::number(error.cwe));
if (error.hash > 0)
Expand Down Expand Up @@ -231,6 +234,8 @@ ErrorItem XmlReportV2::readError(const QXmlStreamReader *reader)
item.message = XmlReport::unquoteMessage(message);
if (attribs.hasAttribute(QString(), InconclusiveAttribute))
item.inconclusive = true;
if (attribs.hasAttribute(QString(), RemarkAttribute))
item.remark = attribs.value(QString(), RemarkAttribute).toString();
if (attribs.hasAttribute(QString(), CWEAttribute))
item.cwe = attribs.value(QString(), CWEAttribute).toInt();
if (attribs.hasAttribute(QString(), HashAttribute))
Expand Down
22 changes: 21 additions & 1 deletion lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
}

// Parse comments and then remove them
mRemarkComments = preprocessor.getRemarkComments(tokens1);
preprocessor.inlineSuppressions(tokens1, mSettings.supprs.nomsg);
if (mSettings.dump || !mSettings.addons.empty()) {
std::ostringstream oss;
Expand Down Expand Up @@ -1613,7 +1614,26 @@ void CppCheck::reportErr(const ErrorMessage &msg)
mExitCode = 1;
}

mErrorLogger.reportErr(msg);
std::string remark;
if (!msg.callStack.empty()) {
for (const auto& r: mRemarkComments) {
if (r.file != msg.callStack.back().getfile(false))
continue;
if (r.lineNumber != msg.callStack.back().line)
continue;
remark = r.str;
break;
}
}

if (!remark.empty()) {
ErrorMessage msg2(msg);
msg2.remark = remark;
mErrorLogger.reportErr(msg2);
} else {
mErrorLogger.reportErr(msg);
}

// check if plistOutput should be populated and the current output file is open and the error is not suppressed
if (!mSettings.plistOutput.empty() && mPlistFile.is_open() && !mSettings.supprs.nomsg.isSuppressed(errorMessage)) {
// add error to plist output file
Expand Down
3 changes: 3 additions & 0 deletions lib/cppcheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class SHOWTIME_MODES;
struct FileSettings;
class CheckUnusedFunctions;
class Tokenizer;
class RemarkComment;

namespace simplecpp { class TokenList; }

Expand Down Expand Up @@ -253,6 +254,8 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
std::ofstream mPlistFile;

std::unique_ptr<CheckUnusedFunctions> mUnusedFunctionsCheck;

std::vector<RemarkComment> mRemarkComments;
};

/// @}
Expand Down
30 changes: 15 additions & 15 deletions lib/errorlogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,9 @@ std::string ErrorMessage::serialize() const
serializeString(oss, severityToString(severity));
serializeString(oss, std::to_string(cwe.id));
serializeString(oss, std::to_string(hash));
serializeString(oss, fixInvalidChars(remark));
serializeString(oss, file0);
if (certainty == Certainty::inconclusive) {
const std::string text("inconclusive");
serializeString(oss, text);
}
serializeString(oss, (certainty == Certainty::inconclusive) ? "1" : "0");

const std::string saneShortMessage = fixInvalidChars(mShortMessage);
const std::string saneVerboseMessage = fixInvalidChars(mVerboseMessage);
Expand Down Expand Up @@ -312,9 +310,9 @@ void ErrorMessage::deserialize(const std::string &data)
callStack.clear();

std::istringstream iss(data);
std::array<std::string, 7> results;
std::array<std::string, 9> results;
std::size_t elem = 0;
while (iss.good() && elem < 7) {
while (iss.good() && elem < 9) {
unsigned int len = 0;
if (!(iss >> len))
throw InternalError(nullptr, "Internal Error: Deserialization of error message failed - invalid length");
Expand All @@ -332,11 +330,6 @@ void ErrorMessage::deserialize(const std::string &data)

if (!iss.good())
throw InternalError(nullptr, "Internal Error: Deserialization of error message failed - premature end of data");

if (temp == "inconclusive") {
certainty = Certainty::inconclusive;
continue;
}
}

results[elem++] = std::move(temp);
Expand All @@ -345,7 +338,7 @@ void ErrorMessage::deserialize(const std::string &data)
if (!iss.good())
throw InternalError(nullptr, "Internal Error: Deserialization of error message failed - premature end of data");

if (elem != 7)
if (elem != 9)
throw InternalError(nullptr, "Internal Error: Deserialization of error message failed - insufficient elements");

id = std::move(results[0]);
Expand All @@ -362,9 +355,12 @@ void ErrorMessage::deserialize(const std::string &data)
if (!strToInt(results[3], hash, &err))
throw InternalError(nullptr, "Internal Error: Deserialization of error message failed - invalid hash - " + err);
}
file0 = std::move(results[4]);
mShortMessage = std::move(results[5]);
mVerboseMessage = std::move(results[6]);
remark = std::move(results[4]);
file0 = std::move(results[5]);
if (results[6] == "1")
certainty = Certainty::inconclusive;
mShortMessage = std::move(results[7]);
mVerboseMessage = std::move(results[8]);

unsigned int stackSize = 0;
if (!(iss >> stackSize))
Expand Down Expand Up @@ -496,6 +492,9 @@ std::string ErrorMessage::toXML() const
if (!file0.empty())
printer.PushAttribute("file0", file0.c_str());

if (!remark.empty())
printer.PushAttribute("remark", fixInvalidChars(remark).c_str());

for (std::list<FileLocation>::const_reverse_iterator it = callStack.crbegin(); it != callStack.crend(); ++it) {
printer.OpenElement("location", false);
printer.PushAttribute("file", it->getfile().c_str());
Expand Down Expand Up @@ -657,6 +656,7 @@ std::string ErrorMessage::toString(bool verbose, const std::string &templateForm
findAndReplace(result, "{severity}", severityToString(severity));
findAndReplace(result, "{cwe}", std::to_string(cwe.id));
findAndReplace(result, "{message}", verbose ? mVerboseMessage : mShortMessage);
findAndReplace(result, "{remark}", remark);
if (!callStack.empty()) {
if (result.find("{callstack}") != std::string::npos)
findAndReplace(result, "{callstack}", ErrorLogger::callStackToString(callStack));
Expand Down
3 changes: 3 additions & 0 deletions lib/errorlogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ class CPPCHECKLIB ErrorMessage {
CWE cwe;
Certainty certainty;

/** remark from REMARK comment */
std::string remark;

/** Warning hash */
std::size_t hash;

Expand Down
84 changes: 74 additions & 10 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,19 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
return true;
}

static std::string getRelativeFilename(const simplecpp::Token* tok, const Settings &settings) {
std::string relativeFilename(tok->location.file());
if (settings.relativePaths) {
for (const std::string & basePath : settings.basePaths) {
const std::string bp = basePath + "/";
if (relativeFilename.compare(0,bp.size(),bp)==0) {
relativeFilename = relativeFilename.substr(bp.size());
}
}
}
return Path::simplifyPath(relativeFilename);
}

static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Settings &settings, SuppressionList &suppressions, std::list<BadInlineSuppression> &bad)
{
std::list<SuppressionList::Suppression> inlineSuppressionsBlockBegin;
Expand Down Expand Up @@ -207,16 +220,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
continue;

// Relative filename
std::string relativeFilename(tok->location.file());
if (settings.relativePaths) {
for (const std::string & basePath : settings.basePaths) {
const std::string bp = basePath + "/";
if (relativeFilename.compare(0,bp.size(),bp)==0) {
relativeFilename = relativeFilename.substr(bp.size());
}
}
}
relativeFilename = Path::simplifyPath(relativeFilename);
const std::string relativeFilename = getRelativeFilename(tok, settings);

// Macro name
std::string macroName;
Expand Down Expand Up @@ -309,6 +313,17 @@ void Preprocessor::inlineSuppressions(const simplecpp::TokenList &tokens, Suppre
}
}

std::vector<RemarkComment> Preprocessor::getRemarkComments(const simplecpp::TokenList &tokens) const
{
std::vector<RemarkComment> ret;
addRemarkComments(tokens, ret);
for (std::map<std::string,simplecpp::TokenList*>::const_iterator it = mTokenLists.cbegin(); it != mTokenLists.cend(); ++it) {
if (it->second)
addRemarkComments(*it->second, ret);
}
return ret;
}

std::list<Directive> Preprocessor::createDirectives(const simplecpp::TokenList &tokens) const
{
// directive list..
Expand Down Expand Up @@ -1012,3 +1027,52 @@ void Preprocessor::simplifyPragmaAsmPrivate(simplecpp::TokenList *tokenList)
tokenList->deleteToken(tok4->next);
}
}


void Preprocessor::addRemarkComments(const simplecpp::TokenList &tokens, std::vector<RemarkComment> &remarkComments) const
{
for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
if (!tok->comment)
continue;

const std::string& comment = tok->str();

// is it a remark comment?
const std::string::size_type pos1 = comment.find_first_not_of("/* \t");
if (pos1 == std::string::npos)
continue;
const std::string::size_type pos2 = comment.find_first_of(": \t", pos1);
if (pos2 != pos1 + 6 || comment.compare(pos1, 6, "REMARK") != 0)
continue;
const std::string::size_type pos3 = comment.find_first_not_of(": \t", pos2);
if (pos3 == std::string::npos)
continue;
if (comment.compare(0,2,"/*") == 0 && pos3 + 2 >= tok->str().size())
continue;

const std::string::size_type pos4 = (comment.compare(0,2,"/*") == 0) ? comment.size()-2 : comment.size();
const std::string remarkText = comment.substr(pos3, pos4-pos3);

// Get remarked token
const simplecpp::Token* remarkedToken = nullptr;
for (const simplecpp::Token* after = tok->next; after; after = after->next) {
if (after->comment)
continue;
remarkedToken = after;
break;
}
for (const simplecpp::Token* prev = tok->previous; prev; prev = prev->previous) {
if (prev->comment)
continue;
if (sameline(prev, tok))
remarkedToken = prev;
break;
}

// Relative filename
const std::string relativeFilename = getRelativeFilename(remarkedToken, mSettings);

// Add the suppressions.
remarkComments.emplace_back(relativeFilename, remarkedToken->location.line, remarkText);
}
}
22 changes: 22 additions & 0 deletions lib/preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ struct CPPCHECKLIB Directive {
Directive(std::string _file, const int _linenr, const std::string &_str);
};

class CPPCHECKLIB RemarkComment {
public:
RemarkComment(std::string file, unsigned int lineNumber, std::string str)
: file(std::move(file))
, lineNumber(lineNumber)
, str(std::move(str))
{}

/** name of file */
std::string file;

/** line number for the code that the remark comment is about */
unsigned int lineNumber;

/** remark text */
std::string str;
};

/// @addtogroup Core
/// @{

Expand Down Expand Up @@ -96,6 +114,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {

std::set<std::string> getConfigs(const simplecpp::TokenList &tokens) const;

std::vector<RemarkComment> getRemarkComments(const simplecpp::TokenList &tokens) const;

void handleErrors(const simplecpp::OutputList &outputList, bool throwError);

bool loadFiles(const simplecpp::TokenList &rawtokens, std::vector<std::string> &files);
Expand Down Expand Up @@ -138,6 +158,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {

static bool hasErrors(const simplecpp::OutputList &outputList);

void addRemarkComments(const simplecpp::TokenList &tokens, std::vector<RemarkComment> &remarkComments) const;

const Settings& mSettings;
ErrorLogger &mErrorLogger;

Expand Down
Loading
Loading