utils.h: added `startsWith()` and started using it (#5381)
This makes the code much more readable. It also makes it less prone to errors because we do not need to specify the length of the string to match and the returnvalue is clear. The code with the bad returnvalue check was never executed and I added a test to show that.
This commit is contained in:
parent
51d1758720
commit
91070ca794
2
Makefile
2
Makefile
|
@ -618,7 +618,7 @@ $(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/color.h
|
|||
$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp
|
||||
|
||||
$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h
|
||||
$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp
|
||||
|
||||
$(libcppdir)/token.o: lib/token.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h
|
||||
|
|
|
@ -1418,5 +1418,5 @@ void CmdLineParser::printHelp()
|
|||
bool CmdLineParser::isCppcheckPremium() const {
|
||||
if (mSettings.cppcheckCfgProductName.empty())
|
||||
mSettings.loadCppcheckCfg();
|
||||
return mSettings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0;
|
||||
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "settings.h"
|
||||
#include "standards.h"
|
||||
#include "threadresult.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
@ -75,7 +76,7 @@ static bool executeCommand(std::string exe, std::vector<std::string> args, std::
|
|||
} else
|
||||
output = process.readAllStandardOutput().toStdString();
|
||||
|
||||
if (redirect.compare(0,3,"2> ") == 0) {
|
||||
if (startsWith(redirect, "2> ")) {
|
||||
std::ofstream fout(redirect.substr(3));
|
||||
fout << process.readAllStandardError().toStdString();
|
||||
}
|
||||
|
@ -157,7 +158,7 @@ void CheckThread::runAddonsAndTools(const ImportProject::FileSettings *fileSetti
|
|||
if (!fileSettings)
|
||||
continue;
|
||||
|
||||
if (!fileSettings->cfg.empty() && fileSettings->cfg.compare(0,5,"Debug") != 0)
|
||||
if (!fileSettings->cfg.empty() && !startsWith(fileSettings->cfg,"Debug"))
|
||||
continue;
|
||||
|
||||
QStringList args;
|
||||
|
|
|
@ -2407,7 +2407,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
|
|||
return false; // not a function => variable not changed
|
||||
if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
|
||||
return false;
|
||||
if (tok->isKeyword() && !isCPPCastKeyword(tok) && tok->str().compare(0,8,"operator") != 0)
|
||||
if (tok->isKeyword() && !isCPPCastKeyword(tok) && !startsWith(tok->str(),"operator"))
|
||||
return false;
|
||||
// A functional cast won't modify the variable
|
||||
if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "symboldatabase.h"
|
||||
#include "token.h"
|
||||
#include "tokenize.h"
|
||||
#include "utils.h"
|
||||
#include "vfvalue.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -824,7 +825,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
|
|||
} else if (rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) {
|
||||
// #9298, assignment through return value of a function
|
||||
const std::string &returnValue = mSettings->library.returnValue(rhs->astOperand1());
|
||||
if (returnValue.compare(0, 3, "arg") == 0) {
|
||||
if (startsWith(returnValue, "arg")) {
|
||||
int argn;
|
||||
const Token *func = getTokenArgumentFunction(tok, argn);
|
||||
if (func) {
|
||||
|
@ -850,7 +851,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
|
|||
alloc.status = VarInfo::NOALLOC;
|
||||
functionCall(tok, openingPar, varInfo, alloc, nullptr);
|
||||
const std::string &returnValue = mSettings->library.returnValue(tok);
|
||||
if (returnValue.compare(0, 3, "arg") == 0)
|
||||
if (startsWith(returnValue, "arg"))
|
||||
// the function returns one of its argument, we need to process a potential assignment
|
||||
return openingPar;
|
||||
return isCPPCast(tok->astParent()) ? openingPar : openingPar->link();
|
||||
|
|
|
@ -1273,7 +1273,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
|||
(!op1Var->valueType() || op1Var->valueType()->type == ValueType::Type::UNKNOWN_TYPE)) {
|
||||
// Check in the library if we should bailout or not..
|
||||
std::string typeName = op1Var->getTypeName();
|
||||
if (typeName.compare(0, 2, "::") == 0)
|
||||
if (startsWith(typeName, "::"))
|
||||
typeName.erase(typeName.begin(), typeName.begin() + 2);
|
||||
switch (mSettings->library.getTypeCheck("unusedvar", typeName)) {
|
||||
case Library::TypeCheck::def:
|
||||
|
|
|
@ -412,9 +412,9 @@ std::string clangimport::AstNode::getSpelling() const
|
|||
return "";
|
||||
}
|
||||
const std::string &str = mExtTokens[typeIndex - 1];
|
||||
if (str.compare(0,4,"col:") == 0)
|
||||
if (startsWith(str,"col:"))
|
||||
return "";
|
||||
if (str.compare(0,8,"<invalid") == 0)
|
||||
if (startsWith(str,"<invalid"))
|
||||
return "";
|
||||
if (nodeType == RecordDecl && str == "struct")
|
||||
return "";
|
||||
|
@ -499,9 +499,9 @@ void clangimport::AstNode::dumpAst(int num, int indent) const
|
|||
void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line, int col)
|
||||
{
|
||||
for (const std::string &ext: mExtTokens) {
|
||||
if (ext.compare(0, 5, "<col:") == 0)
|
||||
if (startsWith(ext, "<col:"))
|
||||
col = strToInt<int>(ext.substr(5, ext.find_first_of(",>", 5) - 5));
|
||||
else if (ext.compare(0, 6, "<line:") == 0) {
|
||||
else if (startsWith(ext, "<line:")) {
|
||||
line = strToInt<int>(ext.substr(6, ext.find_first_of(":,>", 6) - 6));
|
||||
const auto pos = ext.find(", col:");
|
||||
if (pos != std::string::npos)
|
||||
|
@ -542,7 +542,7 @@ const ::Type * clangimport::AstNode::addTypeTokens(TokenList *tokenList, const s
|
|||
return addTypeTokens(tokenList, str.substr(0, str.find("\':\'") + 1), scope);
|
||||
}
|
||||
|
||||
if (str.compare(0, 16, "'enum (anonymous") == 0)
|
||||
if (startsWith(str, "'enum (anonymous"))
|
||||
return nullptr;
|
||||
|
||||
std::string type;
|
||||
|
@ -943,7 +943,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
|
|||
}
|
||||
if (nodeType == DeclRefExpr) {
|
||||
int addrIndex = mExtTokens.size() - 1;
|
||||
while (addrIndex > 1 && mExtTokens[addrIndex].compare(0,2,"0x") != 0)
|
||||
while (addrIndex > 1 && !startsWith(mExtTokens[addrIndex],"0x"))
|
||||
--addrIndex;
|
||||
const std::string addr = mExtTokens[addrIndex];
|
||||
std::string name = unquote(getSpelling());
|
||||
|
@ -985,7 +985,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
|
|||
}
|
||||
if (nodeType == EnumDecl) {
|
||||
int colIndex = mExtTokens.size() - 1;
|
||||
while (colIndex > 0 && mExtTokens[colIndex].compare(0,4,"col:") != 0 && mExtTokens[colIndex].compare(0,5,"line:") != 0)
|
||||
while (colIndex > 0 && !startsWith(mExtTokens[colIndex],"col:") && !startsWith(mExtTokens[colIndex],"line:"))
|
||||
--colIndex;
|
||||
if (colIndex == 0)
|
||||
return nullptr;
|
||||
|
@ -1131,10 +1131,10 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
|
|||
Token *s = getChild(0)->createTokens(tokenList);
|
||||
Token *dot = addtoken(tokenList, ".");
|
||||
std::string memberName = getSpelling();
|
||||
if (memberName.compare(0, 2, "->") == 0) {
|
||||
if (startsWith(memberName, "->")) {
|
||||
dot->originalName("->");
|
||||
memberName = memberName.substr(2);
|
||||
} else if (memberName.compare(0, 1, ".") == 0) {
|
||||
} else if (startsWith(memberName, ".")) {
|
||||
memberName = memberName.substr(1);
|
||||
}
|
||||
if (memberName.empty())
|
||||
|
@ -1150,7 +1150,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
|
|||
return nullptr;
|
||||
const Token *defToken = addtoken(tokenList, "namespace");
|
||||
const std::string &s = mExtTokens[mExtTokens.size() - 2];
|
||||
const Token* nameToken = (s.compare(0, 4, "col:") == 0 || s.compare(0, 5, "line:") == 0) ?
|
||||
const Token* nameToken = (startsWith(s, "col:") || startsWith(s, "line:")) ?
|
||||
addtoken(tokenList, mExtTokens.back()) : nullptr;
|
||||
Scope *scope = createScope(tokenList, Scope::ScopeType::eNamespace, children, defToken);
|
||||
if (nameToken)
|
||||
|
|
|
@ -360,7 +360,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
if (executeCommand(py_exe, split("--version"), redirect, out) && out.compare(0, 7, "Python ") == 0 && std::isdigit(out[7])) {
|
||||
if (executeCommand(py_exe, split("--version"), redirect, out) && startsWith(out, "Python ") && std::isdigit(out[7])) {
|
||||
pythonExe = py_exe;
|
||||
break;
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
|
|||
std::istringstream istr(result);
|
||||
std::string line;
|
||||
while (std::getline(istr, line)) {
|
||||
if (line.compare(0,9,"Checking ", 0, 9) != 0 && !line.empty() && line[0] != '{') {
|
||||
if (!startsWith(line,"Checking ") && !line.empty() && line[0] != '{') {
|
||||
result.erase(result.find_last_not_of('\n') + 1, std::string::npos); // Remove trailing newlines
|
||||
throw InternalError(nullptr, "Failed to execute '" + pythonExe + " " + args + "'. " + result);
|
||||
}
|
||||
|
@ -834,7 +834,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
std::string code;
|
||||
const std::list<Directive> &directives = preprocessor.getDirectives();
|
||||
for (const Directive &dir : directives) {
|
||||
if (dir.str.compare(0,8,"#define ") == 0 || dir.str.compare(0,9,"#include ") == 0)
|
||||
if (startsWith(dir.str,"#define ") || startsWith(dir.str,"#include "))
|
||||
code += "#line " + std::to_string(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n';
|
||||
}
|
||||
Tokenizer tokenizer2(&mSettings, this);
|
||||
|
@ -883,7 +883,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
std::string codeWithoutCfg = preprocessor.getcode(tokens1, mCurrentConfig, files, true);
|
||||
t.stop();
|
||||
|
||||
if (codeWithoutCfg.compare(0,5,"#file") == 0)
|
||||
if (startsWith(codeWithoutCfg,"#file"))
|
||||
codeWithoutCfg.insert(0U, "//");
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos)
|
||||
|
@ -1456,7 +1456,7 @@ void CppCheck::executeAddons(const std::vector<std::string>& files)
|
|||
const bool misraC2023 = mSettings.premiumArgs.find("--misra-c-2023") != std::string::npos;
|
||||
|
||||
while (std::getline(istr, line)) {
|
||||
if (line.compare(0,1,"{") != 0)
|
||||
if (!startsWith(line,"{"))
|
||||
continue;
|
||||
|
||||
picojson::value res;
|
||||
|
@ -1486,7 +1486,7 @@ void CppCheck::executeAddons(const std::vector<std::string>& files)
|
|||
}
|
||||
|
||||
errmsg.id = obj["addon"].get<std::string>() + "-" + obj["errorId"].get<std::string>();
|
||||
if (misraC2023 && errmsg.id.compare(0, 12, "misra-c2012-") == 0)
|
||||
if (misraC2023 && startsWith(errmsg.id, "misra-c2012-"))
|
||||
errmsg.id = "misra-c2023-" + errmsg.id.substr(12);
|
||||
const std::string text = obj["message"].get<std::string>();
|
||||
errmsg.setmsg(text);
|
||||
|
|
|
@ -135,7 +135,7 @@ ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenLis
|
|||
|
||||
std::string info = e.second;
|
||||
|
||||
if (info.compare(0,8,"$symbol:") == 0 && info.find('\n') < info.size()) {
|
||||
if (startsWith(info,"$symbol:") && info.find('\n') < info.size()) {
|
||||
const std::string::size_type pos = info.find('\n');
|
||||
const std::string &symbolName = info.substr(8, pos - 8);
|
||||
info = replaceStr(info.substr(pos+1), "$symbol", symbolName);
|
||||
|
@ -215,7 +215,7 @@ void ErrorMessage::setmsg(const std::string &msg)
|
|||
if (pos == std::string::npos) {
|
||||
mShortMessage = replaceStr(msg, "$symbol", symbolName);
|
||||
mVerboseMessage = replaceStr(msg, "$symbol", symbolName);
|
||||
} else if (msg.compare(0,8,"$symbol:") == 0) {
|
||||
} else if (startsWith(msg,"$symbol:")) {
|
||||
mSymbolNames += msg.substr(8, pos-7);
|
||||
setmsg(msg.substr(pos + 1));
|
||||
} else {
|
||||
|
|
|
@ -156,7 +156,7 @@ void ImportProject::FileSettings::setIncludePaths(const std::string &basepath, c
|
|||
for (const std::string &ipath : copyIn) {
|
||||
if (ipath.empty())
|
||||
continue;
|
||||
if (ipath.compare(0,2,"%(")==0)
|
||||
if (startsWith(ipath,"%("))
|
||||
continue;
|
||||
std::string s(Path::fromNativeSeparators(ipath));
|
||||
if (!found.insert(s).second)
|
||||
|
@ -298,9 +298,9 @@ void ImportProject::FileSettings::parseCommand(const std::string& command)
|
|||
if (F=='D') {
|
||||
std::string defval = readUntil(command, &pos, " ");
|
||||
defs += fval;
|
||||
if (defval.size() >= 3 && defval.compare(0,2,"=\"")==0 && defval.back()=='\"')
|
||||
if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"')
|
||||
defval = "=" + unescape(defval.substr(2, defval.size() - 3));
|
||||
else if (defval.size() >= 5 && defval.compare(0, 3, "=\\\"") == 0 && endsWith(defval, "\\\""))
|
||||
else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\""))
|
||||
defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\"";
|
||||
if (!defval.empty())
|
||||
defs += defval;
|
||||
|
@ -313,32 +313,9 @@ void ImportProject::FileSettings::parseCommand(const std::string& command)
|
|||
i = unescape(i.substr(1, i.size() - 2));
|
||||
if (std::find(includePaths.cbegin(), includePaths.cend(), i) == includePaths.cend())
|
||||
includePaths.push_back(std::move(i));
|
||||
} else if (F=='s' && fval.compare(0,2,"td") == 0) {
|
||||
} else if (F=='s' && startsWith(fval,"td")) {
|
||||
++pos;
|
||||
const std::string stdval = readUntil(command, &pos, " ");
|
||||
standard = stdval;
|
||||
// TODO: use simplecpp::DUI::std instead of specifying it manually
|
||||
if (standard.compare(0, 3, "c++") || standard.compare(0, 5, "gnu++")) {
|
||||
const std::string stddef = simplecpp::getCppStdString(standard);
|
||||
if (stddef.empty()) {
|
||||
// TODO: log error
|
||||
continue;
|
||||
}
|
||||
|
||||
defs += "__cplusplus=";
|
||||
defs += stddef;
|
||||
defs += ";";
|
||||
} else if (standard.compare(0, 1, "c") || standard.compare(0, 3, "gnu")) {
|
||||
const std::string stddef = simplecpp::getCStdString(standard);
|
||||
if (stddef.empty()) {
|
||||
// TODO: log error
|
||||
continue;
|
||||
}
|
||||
|
||||
defs += "__STDC_VERSION__=";
|
||||
defs += stddef;
|
||||
defs += ";";
|
||||
}
|
||||
standard = readUntil(command, &pos, " ");
|
||||
} else if (F == 'i' && fval == "system") {
|
||||
++pos;
|
||||
std::string isystem = readUntil(command, &pos, " ");
|
||||
|
@ -459,9 +436,9 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (line.find("Microsoft Visual Studio Solution File") != 0) {
|
||||
if (!startsWith(line, "Microsoft Visual Studio Solution File")) {
|
||||
// Skip BOM
|
||||
if (!std::getline(istr, line) || line.find("Microsoft Visual Studio Solution File") != 0) {
|
||||
if (!std::getline(istr, line) || !startsWith(line, "Microsoft Visual Studio Solution File")) {
|
||||
printError("Visual Studio solution file header not found");
|
||||
return false;
|
||||
}
|
||||
|
@ -473,7 +450,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
|
|||
bool found = false;
|
||||
|
||||
while (std::getline(istr,line)) {
|
||||
if (line.compare(0,8,"Project(")!=0)
|
||||
if (!startsWith(line,"Project("))
|
||||
continue;
|
||||
const std::string::size_type pos = line.find(".vcxproj");
|
||||
if (pos == std::string::npos)
|
||||
|
@ -1302,7 +1279,7 @@ void ImportProject::selectOneVsConfig(cppcheck::Platform::Type platform)
|
|||
}
|
||||
const ImportProject::FileSettings &fs = *it;
|
||||
bool remove = false;
|
||||
if (fs.cfg.compare(0,5,"Debug") != 0)
|
||||
if (!startsWith(fs.cfg,"Debug"))
|
||||
remove = true;
|
||||
if (platform == cppcheck::Platform::Type::Win64 && fs.platformType != platform)
|
||||
remove = true;
|
||||
|
|
|
@ -1174,7 +1174,7 @@ const Library::Container* Library::detectContainerInternal(const Token* const ty
|
|||
if (container.startPattern.empty())
|
||||
continue;
|
||||
|
||||
const int offset = (withoutStd && container.startPattern2.find("std :: ") == 0) ? 7 : 0;
|
||||
const int offset = (withoutStd && startsWith(container.startPattern2, "std :: ")) ? 7 : 0;
|
||||
|
||||
// If endPattern is undefined, it will always match, but itEndPattern has to be defined.
|
||||
if (detect != IteratorOnly && container.endPattern.empty()) {
|
||||
|
@ -1754,7 +1754,7 @@ std::shared_ptr<Token> createTokenFromExpression(const std::string& returnValue,
|
|||
|
||||
// set varids
|
||||
for (Token* tok2 = tokenList->front(); tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str().compare(0, 3, "arg") != 0)
|
||||
if (!startsWith(tok2->str(), "arg"))
|
||||
continue;
|
||||
nonneg int const id = strToInt<nonneg int>(tok2->str().c_str() + 3);
|
||||
tok2->varId(id);
|
||||
|
|
|
@ -171,7 +171,7 @@ bool Path::isAbsolute(const std::string& path)
|
|||
return false;
|
||||
|
||||
// On Windows, 'C:\foo\bar' is an absolute path, while 'C:foo\bar' is not
|
||||
return nativePath.compare(0, 2, "\\\\") == 0 || (std::isalpha(nativePath[0]) != 0 && nativePath.compare(1, 2, ":\\") == 0);
|
||||
return startsWith(nativePath, "\\\\") || (std::isalpha(nativePath[0]) != 0 && nativePath.compare(1, 2, ":\\") == 0);
|
||||
#else
|
||||
return !nativePath.empty() && nativePath[0] == '/';
|
||||
#endif
|
||||
|
@ -227,7 +227,7 @@ bool Path::acceptFile(const std::string &path, const std::set<std::string> &extr
|
|||
bool Path::isHeader(const std::string &path)
|
||||
{
|
||||
const std::string extension = getFilenameExtensionInLowerCase(path);
|
||||
return (extension.compare(0, 2, ".h") == 0);
|
||||
return startsWith(extension, ".h");
|
||||
}
|
||||
|
||||
std::string Path::getAbsoluteFilePath(const std::string& filePath)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "settings.h"
|
||||
#include "standards.h"
|
||||
#include "suppressions.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
@ -370,7 +371,7 @@ static const simplecpp::Token *gotoEndIf(const simplecpp::Token *cmdtok)
|
|||
int level = 0;
|
||||
while (nullptr != (cmdtok = cmdtok->next)) {
|
||||
if (cmdtok->op == '#' && !sameline(cmdtok->previous,cmdtok) && sameline(cmdtok, cmdtok->next)) {
|
||||
if (cmdtok->next->str().compare(0,2,"if")==0)
|
||||
if (startsWith(cmdtok->next->str(),"if"))
|
||||
++level;
|
||||
else if (cmdtok->next->str() == "endif") {
|
||||
--level;
|
||||
|
@ -755,7 +756,7 @@ void Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh
|
|||
for (const simplecpp::Output &out : outputList) {
|
||||
switch (out.type) {
|
||||
case simplecpp::Output::ERROR:
|
||||
if (out.msg.compare(0,6,"#error")!=0 || showerror)
|
||||
if (!startsWith(out.msg,"#error") || showerror)
|
||||
error(out.location.file(), out.location.line, out.msg);
|
||||
break;
|
||||
case simplecpp::Output::WARNING:
|
||||
|
|
|
@ -172,7 +172,7 @@ std::vector<Suppressions::Suppression> Suppressions::parseMultiSuppressComment(c
|
|||
break;
|
||||
if (word.find_first_not_of("+-*/%#;") == std::string::npos)
|
||||
break;
|
||||
if (word.compare(0, 11, "symbolName=") == 0) {
|
||||
if (startsWith(word, "symbolName=")) {
|
||||
s.symbolName = word.substr(11);
|
||||
} else {
|
||||
if (errorMessage && errorMessage->empty())
|
||||
|
@ -316,7 +316,7 @@ bool Suppressions::Suppression::parseComment(std::string comment, std::string *e
|
|||
break;
|
||||
if (word.find_first_not_of("+-*/%#;") == std::string::npos)
|
||||
break;
|
||||
if (word.compare(0,11,"symbolName=")==0)
|
||||
if (startsWith(word,"symbolName="))
|
||||
symbolName = word.substr(11);
|
||||
else if (errorMessage && errorMessage->empty())
|
||||
*errorMessage = "Bad suppression attribute '" + word + "'. You can write comments in the comment after a ; or //. Valid suppression attributes; symbolName=sym";
|
||||
|
@ -377,7 +377,7 @@ std::string Suppressions::Suppression::getText() const
|
|||
ret += " symbolName=" + symbolName;
|
||||
if (hash > 0)
|
||||
ret += " hash=" + std::to_string(hash);
|
||||
if (ret.compare(0,1," ")==0)
|
||||
if (startsWith(ret," "))
|
||||
return ret.substr(1);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -2389,7 +2389,7 @@ static bool isOperator(const Token *tokenDef)
|
|||
if (tokenDef->isOperatorKeyword())
|
||||
return true;
|
||||
const std::string &name = tokenDef->str();
|
||||
return name.size() > 8 && name.compare(0,8,"operator")==0 && std::strchr("+-*/%&|~^<>!=[(", name[8]);
|
||||
return name.size() > 8 && startsWith(name,"operator") && std::strchr("+-*/%&|~^<>!=[(", name[8]);
|
||||
}
|
||||
|
||||
Function::Function(const Tokenizer *mTokenizer,
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "mathlib.h"
|
||||
#include "sourcelocation.h"
|
||||
#include "token.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
@ -1061,7 +1062,7 @@ public:
|
|||
|
||||
bool isAnonymous() const {
|
||||
// TODO: Check if class/struct is anonymous
|
||||
return className.size() > 9 && className.compare(0,9,"Anonymous") == 0 && std::isdigit(className[9]);
|
||||
return className.size() > 9 && startsWith(className,"Anonymous") && std::isdigit(className[9]);
|
||||
}
|
||||
|
||||
const Enumerator * findEnumerator(const std::string & name) const {
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "timer.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
@ -61,7 +63,7 @@ void TimerResults::showResults(SHOWTIME_MODES mode) const
|
|||
bool hasParent = false;
|
||||
{
|
||||
// Do not use valueFlow.. in "Overall time" because those are included in Tokenizer already
|
||||
if (iter->first.compare(0,9,"valueFlow") == 0)
|
||||
if (startsWith(iter->first,"valueFlow"))
|
||||
hasParent = true;
|
||||
|
||||
// Do not use inner timers in "Overall time"
|
||||
|
|
|
@ -246,7 +246,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token
|
|||
if (end)
|
||||
end = end->next();
|
||||
} else if (end->str() == "(") {
|
||||
if (tok->previous()->str().compare(0, 8, "operator") == 0)
|
||||
if (startsWith(tok->previous()->str(), "operator"))
|
||||
// conversion operator
|
||||
return false;
|
||||
if (tok->previous()->str() == "typedef")
|
||||
|
@ -8124,7 +8124,7 @@ static bool isNonMacro(const Token* tok)
|
|||
return true;
|
||||
if (cAlternativeTokens.count(tok->str()) > 0)
|
||||
return true;
|
||||
if (tok->str().compare(0, 2, "__") == 0) // attribute/annotation
|
||||
if (startsWith(tok->str(), "__")) // attribute/annotation
|
||||
return true;
|
||||
if (Token::simpleMatch(tok, "alignas ("))
|
||||
return true;
|
||||
|
@ -8236,7 +8236,7 @@ void Tokenizer::reportUnknownMacros() const
|
|||
continue;
|
||||
if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
|
||||
continue;
|
||||
if (tok->next()->str().compare(0, 2, "__") == 0) // attribute/annotation
|
||||
if (startsWith(tok->next()->str(), "__")) // attribute/annotation
|
||||
continue;
|
||||
unknownMacroError(tok->next());
|
||||
}
|
||||
|
@ -8990,7 +8990,7 @@ void Tokenizer::simplifyCppcheckAttribute()
|
|||
if (!tok->previous())
|
||||
continue;
|
||||
const std::string &attr = tok->previous()->str();
|
||||
if (attr.compare(0, 11, "__cppcheck_") != 0) // TODO: starts_with("__cppcheck_")
|
||||
if (!startsWith(attr, "__cppcheck_"))
|
||||
continue;
|
||||
if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
|
||||
continue;
|
||||
|
@ -8998,7 +8998,7 @@ void Tokenizer::simplifyCppcheckAttribute()
|
|||
Token *vartok = tok->link();
|
||||
while (Token::Match(vartok->next(), "%name%|*|&|::")) {
|
||||
vartok = vartok->next();
|
||||
if (Token::Match(vartok, "%name% (") && vartok->str().compare(0,11,"__cppcheck_") == 0)
|
||||
if (Token::Match(vartok, "%name% (") && startsWith(vartok->str(),"__cppcheck_"))
|
||||
vartok = vartok->linkAt(1);
|
||||
}
|
||||
|
||||
|
@ -10471,7 +10471,7 @@ bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
|
|||
assert(mPreprocessor);
|
||||
|
||||
return std::any_of(mPreprocessor->getDirectives().cbegin(), mPreprocessor->getDirectives().cend(), [&](const Directive& d) {
|
||||
return d.str.compare(0, 3, "#if") == 0 &&
|
||||
return startsWith(d.str, "#if") &&
|
||||
d.linenr >= start->linenr() &&
|
||||
d.linenr <= end->linenr() &&
|
||||
start->fileIndex() < list.getFiles().size() &&
|
||||
|
|
11
lib/utils.h
11
lib/utils.h
|
@ -80,6 +80,17 @@ struct EnumClassHash {
|
|||
}
|
||||
};
|
||||
|
||||
inline bool startsWith(const std::string& str, const char start[], std::size_t startlen)
|
||||
{
|
||||
return str.compare(0, startlen, start) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
bool startsWith(const std::string& str, const char (&start)[N])
|
||||
{
|
||||
return startsWith(str, start, N - 1);
|
||||
}
|
||||
|
||||
inline bool endsWith(const std::string &str, char c)
|
||||
{
|
||||
return !str.empty() && str.back() == c;
|
||||
|
|
|
@ -4494,7 +4494,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList &tokenlist, ErrorLog
|
|||
valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
|
||||
} else {
|
||||
const std::string& retVal = settings->library.returnValue(tok);
|
||||
if (retVal.compare(0, 3, "arg") == 0) {
|
||||
if (startsWith(retVal, "arg")) {
|
||||
std::size_t iArg{};
|
||||
try {
|
||||
iArg = strToInt<std::size_t>(retVal.substr(3));
|
||||
|
|
|
@ -224,4 +224,31 @@ def test_project_missing_subproject(tmpdir):
|
|||
ret, stdout, stderr = cppcheck(['--project=' + project_file, '--template=cppcheck1'])
|
||||
assert ret == 1, stdout
|
||||
assert stdout == "cppcheck: error: failed to open project '{}/dummy.json'. The file does not exist.\n".format(str(tmpdir).replace('\\', '/'))
|
||||
assert stderr == ''
|
||||
assert stderr == ''
|
||||
|
||||
|
||||
def test_project_std(tmpdir):
|
||||
with open(os.path.join(tmpdir, 'bug1.cpp'), 'wt') as f:
|
||||
f.write("""
|
||||
#if __cplusplus == 201402L
|
||||
int x = 123 / 0;
|
||||
#endif
|
||||
""")
|
||||
|
||||
compile_commands = os.path.join(tmpdir, 'compile_commands.json')
|
||||
|
||||
compilation_db = [
|
||||
{
|
||||
"directory": str(tmpdir),
|
||||
"command": "c++ -o bug1.o -c bug1.cpp -std=c++14",
|
||||
"file": "bug1.cpp",
|
||||
"output": "bug1.o"
|
||||
}
|
||||
]
|
||||
|
||||
with open(compile_commands, 'wt') as f:
|
||||
f.write(json.dumps(compilation_db))
|
||||
|
||||
ret, stdout, stderr = cppcheck(['--project=' + compile_commands, '--enable=all', '-rp=' + str(tmpdir), '--template=cppcheck1'])
|
||||
assert ret == 0, stdout
|
||||
assert (stderr == '[bug1.cpp:3]: (error) Division by zero.\n')
|
|
@ -28,6 +28,7 @@
|
|||
#include "suppressions.h"
|
||||
#include "fixture.h"
|
||||
#include "timer.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
@ -272,7 +273,7 @@ private:
|
|||
const char * const argv[] = {"cppcheck"};
|
||||
ASSERT(parser->parseFromArgs(1, argv));
|
||||
ASSERT_EQUALS(true, parser->getShowHelp());
|
||||
ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0);
|
||||
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "Cppcheck - A tool for static C/C++ code analysis"));
|
||||
}
|
||||
|
||||
void helpshort() {
|
||||
|
@ -280,7 +281,7 @@ private:
|
|||
const char * const argv[] = {"cppcheck", "-h"};
|
||||
ASSERT(parser->parseFromArgs(2, argv));
|
||||
ASSERT_EQUALS(true, parser->getShowHelp());
|
||||
ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0);
|
||||
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "Cppcheck - A tool for static C/C++ code analysis"));
|
||||
}
|
||||
|
||||
void helplong() {
|
||||
|
@ -288,7 +289,7 @@ private:
|
|||
const char * const argv[] = {"cppcheck", "--help"};
|
||||
ASSERT(parser->parseFromArgs(2, argv));
|
||||
ASSERT_EQUALS(true, parser->getShowHelp());
|
||||
ASSERT(GET_REDIRECT_OUTPUT.find("Cppcheck - A tool for static C/C++ code analysis") == 0);
|
||||
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "Cppcheck - A tool for static C/C++ code analysis"));
|
||||
}
|
||||
|
||||
void showversion() {
|
||||
|
@ -1594,7 +1595,7 @@ private:
|
|||
const char * const argv[] = {"cppcheck", "--doc"};
|
||||
ASSERT(parser->parseFromArgs(2, argv));
|
||||
ASSERT(parser->exitAfterPrinting());
|
||||
ASSERT(GET_REDIRECT_OUTPUT.find("## ") == 0);
|
||||
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "## "));
|
||||
}
|
||||
|
||||
void showtime() {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "fixture.h"
|
||||
#include "token.h"
|
||||
#include "tokenize.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <simplecpp.h>
|
||||
|
||||
|
@ -1391,7 +1392,7 @@ private:
|
|||
"STAMP(B, A);\n"
|
||||
"STAMP(C, B);\n";
|
||||
tok(code, cppcheck::Platform::Type::Native, /*debugwarnings*/ true, /*preprocess*/ true);
|
||||
ASSERT_EQUALS(errout.str().compare(0, 64, "[test.cpp:6]: (debug) Failed to parse 'using C = S < S < S < int"), 0);
|
||||
ASSERT(startsWith(errout.str(), "[test.cpp:6]: (debug) Failed to parse 'using C = S < S < S < int"));
|
||||
}
|
||||
|
||||
void scopeInfo1() {
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
TEST_CASE(isCharLiteral);
|
||||
TEST_CASE(strToInt);
|
||||
TEST_CASE(id_string);
|
||||
TEST_CASE(startsWith);
|
||||
}
|
||||
|
||||
void isValidGlobPattern() const {
|
||||
|
@ -345,6 +346,19 @@ private:
|
|||
ASSERT_EQUALS(std::string(16,'f'), id_string_i(~0ULL));
|
||||
}
|
||||
}
|
||||
|
||||
void startsWith() const
|
||||
{
|
||||
ASSERT(::startsWith("test", "test"));
|
||||
ASSERT(::startsWith("test2", "test"));
|
||||
ASSERT(::startsWith("test test", "test"));
|
||||
ASSERT(::startsWith("test", "t"));
|
||||
ASSERT(!::startsWith("2test", "test"));
|
||||
ASSERT(!::startsWith("", "test"));
|
||||
ASSERT(!::startsWith("tes", "test"));
|
||||
ASSERT(!::startsWith("2test", "t"));
|
||||
ASSERT(!::startsWith("t", "test"));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestUtils)
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
static std::string builddir(std::string filename)
|
||||
{
|
||||
if (filename.compare(0,4,"lib/") == 0)
|
||||
if (startsWith(filename,"lib/"))
|
||||
filename = "$(libcppdir)" + filename.substr(3);
|
||||
return filename;
|
||||
}
|
||||
|
@ -77,13 +77,13 @@ static void getDeps(const std::string &filename, std::vector<std::string> &depfi
|
|||
* Files are searched according to the following priority:
|
||||
* [test, tools] -> cli -> lib -> externals
|
||||
*/
|
||||
if (filename.compare(0, 4, "cli/") == 0)
|
||||
if (startsWith(filename, "cli/"))
|
||||
getDeps("lib" + filename.substr(filename.find('/')), depfiles);
|
||||
else if (filename.compare(0, 5, "test/") == 0)
|
||||
else if (startsWith(filename, "test/"))
|
||||
getDeps("cli" + filename.substr(filename.find('/')), depfiles);
|
||||
else if (filename.compare(0, 6, "tools/") == 0)
|
||||
else if (startsWith(filename, "tools/"))
|
||||
getDeps("cli" + filename.substr(filename.find('/')), depfiles);
|
||||
else if (filename.compare(0, 4, "lib/") == 0) {
|
||||
else if (startsWith(filename, "lib/")) {
|
||||
for (const std::string & external : externalfolders)
|
||||
getDeps(external + filename.substr(filename.find('/')), depfiles);
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ static void getDeps(const std::string &filename, std::vector<std::string> &depfi
|
|||
static void compilefiles(std::ostream &fout, const std::vector<std::string> &files, const std::string &args)
|
||||
{
|
||||
for (const std::string &file : files) {
|
||||
const bool external(file.compare(0,10,"externals/") == 0);
|
||||
const bool external(startsWith(file,"externals/"));
|
||||
fout << objfile(file) << ": " << file;
|
||||
std::vector<std::string> depfiles;
|
||||
getDeps(file, depfiles);
|
||||
|
|
Loading…
Reference in New Issue