Skip to content

Commit 91070ca

Browse files
authored
utils.h: added startsWith() and started using it (danmar#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.
1 parent 51d1758 commit 91070ca

25 files changed

Lines changed: 126 additions & 89 deletions

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ $(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/color.h
618618
$(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
619619
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp
620620

621-
$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h
621+
$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h lib/utils.h
622622
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp
623623

624624
$(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

cli/cmdlineparser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1418,5 +1418,5 @@ void CmdLineParser::printHelp()
14181418
bool CmdLineParser::isCppcheckPremium() const {
14191419
if (mSettings.cppcheckCfgProductName.empty())
14201420
mSettings.loadCppcheckCfg();
1421-
return mSettings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0;
1421+
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
14221422
}

gui/checkthread.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "settings.h"
2828
#include "standards.h"
2929
#include "threadresult.h"
30+
#include "utils.h"
3031

3132
#include <algorithm>
3233
#include <cstddef>
@@ -75,7 +76,7 @@ static bool executeCommand(std::string exe, std::vector<std::string> args, std::
7576
} else
7677
output = process.readAllStandardOutput().toStdString();
7778

78-
if (redirect.compare(0,3,"2> ") == 0) {
79+
if (startsWith(redirect, "2> ")) {
7980
std::ofstream fout(redirect.substr(3));
8081
fout << process.readAllStandardError().toStdString();
8182
}
@@ -157,7 +158,7 @@ void CheckThread::runAddonsAndTools(const ImportProject::FileSettings *fileSetti
157158
if (!fileSettings)
158159
continue;
159160

160-
if (!fileSettings->cfg.empty() && fileSettings->cfg.compare(0,5,"Debug") != 0)
161+
if (!fileSettings->cfg.empty() && !startsWith(fileSettings->cfg,"Debug"))
161162
continue;
162163

163164
QStringList args;

lib/astutils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
24072407
return false; // not a function => variable not changed
24082408
if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
24092409
return false;
2410-
if (tok->isKeyword() && !isCPPCastKeyword(tok) && tok->str().compare(0,8,"operator") != 0)
2410+
if (tok->isKeyword() && !isCPPCastKeyword(tok) && !startsWith(tok->str(),"operator"))
24112411
return false;
24122412
// A functional cast won't modify the variable
24132413
if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))

lib/checkleakautovar.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "symboldatabase.h"
3333
#include "token.h"
3434
#include "tokenize.h"
35+
#include "utils.h"
3536
#include "vfvalue.h"
3637

3738
#include <algorithm>
@@ -824,7 +825,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
824825
} else if (rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) {
825826
// #9298, assignment through return value of a function
826827
const std::string &returnValue = mSettings->library.returnValue(rhs->astOperand1());
827-
if (returnValue.compare(0, 3, "arg") == 0) {
828+
if (startsWith(returnValue, "arg")) {
828829
int argn;
829830
const Token *func = getTokenArgumentFunction(tok, argn);
830831
if (func) {
@@ -850,7 +851,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
850851
alloc.status = VarInfo::NOALLOC;
851852
functionCall(tok, openingPar, varInfo, alloc, nullptr);
852853
const std::string &returnValue = mSettings->library.returnValue(tok);
853-
if (returnValue.compare(0, 3, "arg") == 0)
854+
if (startsWith(returnValue, "arg"))
854855
// the function returns one of its argument, we need to process a potential assignment
855856
return openingPar;
856857
return isCPPCast(tok->astParent()) ? openingPar : openingPar->link();

lib/checkunusedvar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
12731273
(!op1Var->valueType() || op1Var->valueType()->type == ValueType::Type::UNKNOWN_TYPE)) {
12741274
// Check in the library if we should bailout or not..
12751275
std::string typeName = op1Var->getTypeName();
1276-
if (typeName.compare(0, 2, "::") == 0)
1276+
if (startsWith(typeName, "::"))
12771277
typeName.erase(typeName.begin(), typeName.begin() + 2);
12781278
switch (mSettings->library.getTypeCheck("unusedvar", typeName)) {
12791279
case Library::TypeCheck::def:

lib/clangimport.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,9 @@ std::string clangimport::AstNode::getSpelling() const
412412
return "";
413413
}
414414
const std::string &str = mExtTokens[typeIndex - 1];
415-
if (str.compare(0,4,"col:") == 0)
415+
if (startsWith(str,"col:"))
416416
return "";
417-
if (str.compare(0,8,"<invalid") == 0)
417+
if (startsWith(str,"<invalid"))
418418
return "";
419419
if (nodeType == RecordDecl && str == "struct")
420420
return "";
@@ -499,9 +499,9 @@ void clangimport::AstNode::dumpAst(int num, int indent) const
499499
void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line, int col)
500500
{
501501
for (const std::string &ext: mExtTokens) {
502-
if (ext.compare(0, 5, "<col:") == 0)
502+
if (startsWith(ext, "<col:"))
503503
col = strToInt<int>(ext.substr(5, ext.find_first_of(",>", 5) - 5));
504-
else if (ext.compare(0, 6, "<line:") == 0) {
504+
else if (startsWith(ext, "<line:")) {
505505
line = strToInt<int>(ext.substr(6, ext.find_first_of(":,>", 6) - 6));
506506
const auto pos = ext.find(", col:");
507507
if (pos != std::string::npos)
@@ -542,7 +542,7 @@ const ::Type * clangimport::AstNode::addTypeTokens(TokenList *tokenList, const s
542542
return addTypeTokens(tokenList, str.substr(0, str.find("\':\'") + 1), scope);
543543
}
544544

545-
if (str.compare(0, 16, "'enum (anonymous") == 0)
545+
if (startsWith(str, "'enum (anonymous"))
546546
return nullptr;
547547

548548
std::string type;
@@ -943,7 +943,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
943943
}
944944
if (nodeType == DeclRefExpr) {
945945
int addrIndex = mExtTokens.size() - 1;
946-
while (addrIndex > 1 && mExtTokens[addrIndex].compare(0,2,"0x") != 0)
946+
while (addrIndex > 1 && !startsWith(mExtTokens[addrIndex],"0x"))
947947
--addrIndex;
948948
const std::string addr = mExtTokens[addrIndex];
949949
std::string name = unquote(getSpelling());
@@ -985,7 +985,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
985985
}
986986
if (nodeType == EnumDecl) {
987987
int colIndex = mExtTokens.size() - 1;
988-
while (colIndex > 0 && mExtTokens[colIndex].compare(0,4,"col:") != 0 && mExtTokens[colIndex].compare(0,5,"line:") != 0)
988+
while (colIndex > 0 && !startsWith(mExtTokens[colIndex],"col:") && !startsWith(mExtTokens[colIndex],"line:"))
989989
--colIndex;
990990
if (colIndex == 0)
991991
return nullptr;
@@ -1131,10 +1131,10 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
11311131
Token *s = getChild(0)->createTokens(tokenList);
11321132
Token *dot = addtoken(tokenList, ".");
11331133
std::string memberName = getSpelling();
1134-
if (memberName.compare(0, 2, "->") == 0) {
1134+
if (startsWith(memberName, "->")) {
11351135
dot->originalName("->");
11361136
memberName = memberName.substr(2);
1137-
} else if (memberName.compare(0, 1, ".") == 0) {
1137+
} else if (startsWith(memberName, ".")) {
11381138
memberName = memberName.substr(1);
11391139
}
11401140
if (memberName.empty())
@@ -1150,7 +1150,7 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
11501150
return nullptr;
11511151
const Token *defToken = addtoken(tokenList, "namespace");
11521152
const std::string &s = mExtTokens[mExtTokens.size() - 2];
1153-
const Token* nameToken = (s.compare(0, 4, "col:") == 0 || s.compare(0, 5, "line:") == 0) ?
1153+
const Token* nameToken = (startsWith(s, "col:") || startsWith(s, "line:")) ?
11541154
addtoken(tokenList, mExtTokens.back()) : nullptr;
11551155
Scope *scope = createScope(tokenList, Scope::ScopeType::eNamespace, children, defToken);
11561156
if (nameToken)

lib/cppcheck.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
360360
break;
361361
}
362362
#endif
363-
if (executeCommand(py_exe, split("--version"), redirect, out) && out.compare(0, 7, "Python ") == 0 && std::isdigit(out[7])) {
363+
if (executeCommand(py_exe, split("--version"), redirect, out) && startsWith(out, "Python ") && std::isdigit(out[7])) {
364364
pythonExe = py_exe;
365365
break;
366366
}
@@ -393,7 +393,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
393393
std::istringstream istr(result);
394394
std::string line;
395395
while (std::getline(istr, line)) {
396-
if (line.compare(0,9,"Checking ", 0, 9) != 0 && !line.empty() && line[0] != '{') {
396+
if (!startsWith(line,"Checking ") && !line.empty() && line[0] != '{') {
397397
result.erase(result.find_last_not_of('\n') + 1, std::string::npos); // Remove trailing newlines
398398
throw InternalError(nullptr, "Failed to execute '" + pythonExe + " " + args + "'. " + result);
399399
}
@@ -834,7 +834,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
834834
std::string code;
835835
const std::list<Directive> &directives = preprocessor.getDirectives();
836836
for (const Directive &dir : directives) {
837-
if (dir.str.compare(0,8,"#define ") == 0 || dir.str.compare(0,9,"#include ") == 0)
837+
if (startsWith(dir.str,"#define ") || startsWith(dir.str,"#include "))
838838
code += "#line " + std::to_string(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n';
839839
}
840840
Tokenizer tokenizer2(&mSettings, this);
@@ -883,7 +883,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
883883
std::string codeWithoutCfg = preprocessor.getcode(tokens1, mCurrentConfig, files, true);
884884
t.stop();
885885

886-
if (codeWithoutCfg.compare(0,5,"#file") == 0)
886+
if (startsWith(codeWithoutCfg,"#file"))
887887
codeWithoutCfg.insert(0U, "//");
888888
std::string::size_type pos = 0;
889889
while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos)
@@ -1456,7 +1456,7 @@ void CppCheck::executeAddons(const std::vector<std::string>& files)
14561456
const bool misraC2023 = mSettings.premiumArgs.find("--misra-c-2023") != std::string::npos;
14571457

14581458
while (std::getline(istr, line)) {
1459-
if (line.compare(0,1,"{") != 0)
1459+
if (!startsWith(line,"{"))
14601460
continue;
14611461

14621462
picojson::value res;
@@ -1486,7 +1486,7 @@ void CppCheck::executeAddons(const std::vector<std::string>& files)
14861486
}
14871487

14881488
errmsg.id = obj["addon"].get<std::string>() + "-" + obj["errorId"].get<std::string>();
1489-
if (misraC2023 && errmsg.id.compare(0, 12, "misra-c2012-") == 0)
1489+
if (misraC2023 && startsWith(errmsg.id, "misra-c2012-"))
14901490
errmsg.id = "misra-c2023-" + errmsg.id.substr(12);
14911491
const std::string text = obj["message"].get<std::string>();
14921492
errmsg.setmsg(text);

lib/errorlogger.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenLis
135135

136136
std::string info = e.second;
137137

138-
if (info.compare(0,8,"$symbol:") == 0 && info.find('\n') < info.size()) {
138+
if (startsWith(info,"$symbol:") && info.find('\n') < info.size()) {
139139
const std::string::size_type pos = info.find('\n');
140140
const std::string &symbolName = info.substr(8, pos - 8);
141141
info = replaceStr(info.substr(pos+1), "$symbol", symbolName);
@@ -215,7 +215,7 @@ void ErrorMessage::setmsg(const std::string &msg)
215215
if (pos == std::string::npos) {
216216
mShortMessage = replaceStr(msg, "$symbol", symbolName);
217217
mVerboseMessage = replaceStr(msg, "$symbol", symbolName);
218-
} else if (msg.compare(0,8,"$symbol:") == 0) {
218+
} else if (startsWith(msg,"$symbol:")) {
219219
mSymbolNames += msg.substr(8, pos-7);
220220
setmsg(msg.substr(pos + 1));
221221
} else {

lib/importproject.cpp

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ void ImportProject::FileSettings::setIncludePaths(const std::string &basepath, c
156156
for (const std::string &ipath : copyIn) {
157157
if (ipath.empty())
158158
continue;
159-
if (ipath.compare(0,2,"%(")==0)
159+
if (startsWith(ipath,"%("))
160160
continue;
161161
std::string s(Path::fromNativeSeparators(ipath));
162162
if (!found.insert(s).second)
@@ -298,9 +298,9 @@ void ImportProject::FileSettings::parseCommand(const std::string& command)
298298
if (F=='D') {
299299
std::string defval = readUntil(command, &pos, " ");
300300
defs += fval;
301-
if (defval.size() >= 3 && defval.compare(0,2,"=\"")==0 && defval.back()=='\"')
301+
if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"')
302302
defval = "=" + unescape(defval.substr(2, defval.size() - 3));
303-
else if (defval.size() >= 5 && defval.compare(0, 3, "=\\\"") == 0 && endsWith(defval, "\\\""))
303+
else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\""))
304304
defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\"";
305305
if (!defval.empty())
306306
defs += defval;
@@ -313,32 +313,9 @@ void ImportProject::FileSettings::parseCommand(const std::string& command)
313313
i = unescape(i.substr(1, i.size() - 2));
314314
if (std::find(includePaths.cbegin(), includePaths.cend(), i) == includePaths.cend())
315315
includePaths.push_back(std::move(i));
316-
} else if (F=='s' && fval.compare(0,2,"td") == 0) {
316+
} else if (F=='s' && startsWith(fval,"td")) {
317317
++pos;
318-
const std::string stdval = readUntil(command, &pos, " ");
319-
standard = stdval;
320-
// TODO: use simplecpp::DUI::std instead of specifying it manually
321-
if (standard.compare(0, 3, "c++") || standard.compare(0, 5, "gnu++")) {
322-
const std::string stddef = simplecpp::getCppStdString(standard);
323-
if (stddef.empty()) {
324-
// TODO: log error
325-
continue;
326-
}
327-
328-
defs += "__cplusplus=";
329-
defs += stddef;
330-
defs += ";";
331-
} else if (standard.compare(0, 1, "c") || standard.compare(0, 3, "gnu")) {
332-
const std::string stddef = simplecpp::getCStdString(standard);
333-
if (stddef.empty()) {
334-
// TODO: log error
335-
continue;
336-
}
337-
338-
defs += "__STDC_VERSION__=";
339-
defs += stddef;
340-
defs += ";";
341-
}
318+
standard = readUntil(command, &pos, " ");
342319
} else if (F == 'i' && fval == "system") {
343320
++pos;
344321
std::string isystem = readUntil(command, &pos, " ");
@@ -459,9 +436,9 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
459436
return false;
460437
}
461438

462-
if (line.find("Microsoft Visual Studio Solution File") != 0) {
439+
if (!startsWith(line, "Microsoft Visual Studio Solution File")) {
463440
// Skip BOM
464-
if (!std::getline(istr, line) || line.find("Microsoft Visual Studio Solution File") != 0) {
441+
if (!std::getline(istr, line) || !startsWith(line, "Microsoft Visual Studio Solution File")) {
465442
printError("Visual Studio solution file header not found");
466443
return false;
467444
}
@@ -473,7 +450,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
473450
bool found = false;
474451

475452
while (std::getline(istr,line)) {
476-
if (line.compare(0,8,"Project(")!=0)
453+
if (!startsWith(line,"Project("))
477454
continue;
478455
const std::string::size_type pos = line.find(".vcxproj");
479456
if (pos == std::string::npos)
@@ -1302,7 +1279,7 @@ void ImportProject::selectOneVsConfig(cppcheck::Platform::Type platform)
13021279
}
13031280
const ImportProject::FileSettings &fs = *it;
13041281
bool remove = false;
1305-
if (fs.cfg.compare(0,5,"Debug") != 0)
1282+
if (!startsWith(fs.cfg,"Debug"))
13061283
remove = true;
13071284
if (platform == cppcheck::Platform::Type::Win64 && fs.platformType != platform)
13081285
remove = true;

0 commit comments

Comments
 (0)