LCOV - code coverage report
Current view: top level - lib - settings.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 185 213 86.9 %
Date: 2024-04-28 12:00:40 Functions: 16 17 94.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2024 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "config.h"
      20             : #include "settings.h"
      21             : #include "path.h"
      22             : #include "summaries.h"
      23             : #include "vfvalue.h"
      24             : 
      25             : #include <cctype>
      26             : #include <fstream>
      27             : #include <sstream>
      28             : #include <utility>
      29             : 
      30             : #include "json.h"
      31             : 
      32             : #ifndef _WIN32
      33             : #include <unistd.h> // for getpid()
      34             : #else
      35             : #include <process.h> // for getpid()
      36             : #endif
      37             : 
      38             : 
      39             : std::atomic<bool> Settings::mTerminated;
      40             : 
      41             : const char Settings::SafeChecks::XmlRootName[] = "safe-checks";
      42             : const char Settings::SafeChecks::XmlClasses[] = "class-public";
      43             : const char Settings::SafeChecks::XmlExternalFunctions[] = "external-functions";
      44             : const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions";
      45             : const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables";
      46             : 
      47        4153 : static int getPid()
      48             : {
      49             : #ifndef _WIN32
      50        4153 :     return getpid();
      51             : #else
      52             :     return _getpid();
      53             : #endif
      54             : }
      55             : 
      56        8306 : Settings::Settings()
      57             : {
      58        4151 :     severity.setEnabled(Severity::error, true);
      59        4151 :     certainty.setEnabled(Certainty::normal, true);
      60        4153 :     setCheckLevel(Settings::CheckLevel::exhaustive);
      61        4153 :     executor = defaultExecutor();
      62        4153 :     pid = getPid();
      63        4153 : }
      64             : 
      65         223 : std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppressions)
      66             : {
      67             :     // TODO: this always needs to be run *after* the Settings has been filled
      68         223 :     static const std::string cfgFilename = "cppcheck.cfg";
      69         446 :     std::string fileName;
      70             : #ifdef FILESDIR
      71             :     if (Path::isFile(Path::join(FILESDIR, cfgFilename)))
      72             :         fileName = Path::join(FILESDIR, cfgFilename);
      73             : #endif
      74             :     // cppcheck-suppress knownConditionTrueFalse
      75         223 :     if (fileName.empty()) {
      76             :         // TODO: make sure that exename is set
      77         223 :         fileName = Path::getPathFromFilename(settings.exename) + cfgFilename;
      78         223 :         if (!Path::isFile(fileName))
      79         198 :             return "";
      80             :     }
      81             : 
      82          50 :     std::ifstream fin(fileName);
      83          25 :     if (!fin.is_open())
      84           0 :         return "could not open file";
      85          50 :     picojson::value json;
      86          25 :     fin >> json;
      87             :     {
      88          25 :         const std::string& lastErr = picojson::get_last_error();
      89          25 :         if (!lastErr.empty())
      90           4 :             return "not a valid JSON - " + lastErr;
      91             :     }
      92          21 :     const picojson::object& obj = json.get<picojson::object>();
      93             :     {
      94          21 :         const picojson::object::const_iterator it = obj.find("productName");
      95          21 :         if (it != obj.cend()) {
      96           5 :             const auto& v = it->second;
      97           5 :             if (!v.is<std::string>())
      98           1 :                 return "'productName' is not a string";
      99           4 :             settings.cppcheckCfgProductName = v.get<std::string>();
     100             :         }
     101             :     }
     102             :     {
     103          20 :         const picojson::object::const_iterator it = obj.find("about");
     104          20 :         if (it != obj.cend()) {
     105           3 :             const auto& v = it->second;
     106           3 :             if (!v.is<std::string>())
     107           1 :                 return "'about' is not a string";
     108           2 :             settings.cppcheckCfgAbout = v.get<std::string>();
     109             :         }
     110             :     }
     111             :     {
     112          19 :         const picojson::object::const_iterator it = obj.find("addons");
     113          19 :         if (it != obj.cend()) {
     114           5 :             const auto& entry = it->second;
     115           5 :             if (!entry.is<picojson::array>())
     116           1 :                 return "'addons' is not an array";
     117           5 :             for (const picojson::value &v : entry.get<picojson::array>())
     118             :             {
     119           2 :                 if (!v.is<std::string>())
     120           1 :                     return "'addons' array entry is not a string";
     121           1 :                 const std::string &s = v.get<std::string>();
     122           1 :                 if (!Path::isAbsolute(s))
     123           1 :                     settings.addons.emplace(Path::join(Path::getPathFromFilename(fileName), s));
     124             :                 else
     125           0 :                     settings.addons.emplace(s);
     126             :             }
     127             :         }
     128             :     }
     129             :     {
     130          17 :         const picojson::object::const_iterator it = obj.find("suppressions");
     131          17 :         if (it != obj.cend()) {
     132           4 :             const auto& entry = it->second;
     133           4 :             if (!entry.is<picojson::array>())
     134           1 :                 return "'suppressions' is not an array";
     135           4 :             for (const picojson::value &v : entry.get<picojson::array>())
     136             :             {
     137           3 :                 if (!v.is<std::string>())
     138           1 :                     return "'suppressions' array entry is not a string";
     139           2 :                 const std::string &s = v.get<std::string>();
     140           2 :                 const std::string err = suppressions.nomsg.addSuppressionLine(s);
     141           2 :                 if (!err.empty())
     142           2 :                     return "could not parse suppression '" + s + "' - " + err;
     143             :             }
     144             :         }
     145             :     }
     146             :     {
     147          14 :         const picojson::object::const_iterator it = obj.find("safety");
     148          14 :         if (it != obj.cend()) {
     149           2 :             const auto& v = it->second;
     150           2 :             if (!v.is<bool>())
     151           0 :                 return "'safety' is not a bool";
     152           2 :             settings.safety = settings.safety || v.get<bool>();
     153             :         }
     154             :     }
     155             : 
     156          14 :     return "";
     157             : }
     158             : 
     159          10 : std::pair<std::string, std::string> Settings::getNameAndVersion(const std::string& productName) {
     160          10 :     if (productName.empty())
     161           6 :         return {};
     162           4 :     const std::string::size_type pos1 = productName.rfind(' ');
     163           4 :     if (pos1 == std::string::npos)
     164           0 :         return {};
     165           4 :     if (pos1 + 2 >= productName.length())
     166           0 :         return {};
     167          17 :     for (auto pos2 = pos1 + 1; pos2 < productName.length(); ++pos2) {
     168          15 :         const char c = productName[pos2];
     169          15 :         const char prev = productName[pos2-1];
     170          15 :         if (std::isdigit(c))
     171           8 :             continue;
     172           7 :         if (c == '.' && std::isdigit(prev))
     173           4 :             continue;
     174           3 :         if (c == 's' && pos2 + 1 == productName.length() && std::isdigit(prev))
     175           1 :             continue;
     176           2 :         return {};
     177             :     }
     178           2 :     return {productName.substr(0, pos1), productName.substr(pos1+1)};
     179             : }
     180             : 
     181         254 : std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity>, SimpleEnableGroup<Checks>> &groups)
     182             : {
     183             :     // Enable parameters may be comma separated...
     184         254 :     if (str.find(',') != std::string::npos) {
     185          27 :         std::string::size_type prevPos = 0;
     186          27 :         std::string::size_type pos = 0;
     187          55 :         while ((pos = str.find(',', pos)) != std::string::npos) {
     188          29 :             if (pos == prevPos)
     189           0 :                 return std::string("--enable parameter is empty");
     190          29 :             std::string errmsg(parseEnabled(str.substr(prevPos, pos - prevPos), groups));
     191          29 :             if (!errmsg.empty())
     192           1 :                 return errmsg;
     193          28 :             ++pos;
     194          28 :             prevPos = pos;
     195             :         }
     196          26 :         if (prevPos >= str.length())
     197           0 :             return std::string("--enable parameter is empty");
     198          52 :         return parseEnabled(str.substr(prevPos), groups);
     199             :     }
     200             : 
     201         227 :     auto& severity = std::get<0>(groups);
     202         227 :     auto& checks = std::get<1>(groups);
     203             : 
     204         227 :     if (str == "all") {
     205             :         // "error" is always enabled and cannot be controlled - so exclude it from "all"
     206           4 :         SimpleEnableGroup<Severity> newSeverity;
     207           4 :         newSeverity.fill();
     208           4 :         newSeverity.disable(Severity::error);
     209           4 :         severity.enable(newSeverity);
     210           4 :         checks.enable(Checks::missingInclude);
     211           4 :         checks.enable(Checks::unusedFunction);
     212         223 :     } else if (str == "warning") {
     213          33 :         severity.enable(Severity::warning);
     214         190 :     } else if (str == "style") {
     215          28 :         severity.enable(Severity::style);
     216         162 :     } else if (str == "performance") {
     217          29 :         severity.enable(Severity::performance);
     218         133 :     } else if (str == "portability") {
     219          33 :         severity.enable(Severity::portability);
     220         100 :     } else if (str == "information") {
     221          31 :         severity.enable(Severity::information);
     222          69 :     } else if (str == "unusedFunction") {
     223           3 :         checks.enable(Checks::unusedFunction);
     224          66 :     } else if (str == "missingInclude") {
     225          60 :         checks.enable(Checks::missingInclude);
     226             :     }
     227             : #ifdef CHECK_INTERNAL
     228             :     else if (str == "internal") {
     229             :         checks.enable(Checks::internalCheck);
     230             :     }
     231             : #endif
     232             :     else {
     233             :         // the actual option is prepending in the applyEnabled() call
     234           6 :         if (str.empty())
     235           2 :             return " parameter is empty";
     236           8 :         return " parameter with the unknown name '" + str + "'";
     237             :     }
     238             : 
     239         221 :     return "";
     240             : }
     241             : 
     242         164 : std::string Settings::addEnabled(const std::string &str)
     243             : {
     244         164 :     return applyEnabled(str, true);
     245             : }
     246             : 
     247          35 : std::string Settings::removeEnabled(const std::string &str)
     248             : {
     249          35 :     return applyEnabled(str, false);
     250             : }
     251             : 
     252         199 : std::string Settings::applyEnabled(const std::string &str, bool enable)
     253             : {
     254         199 :     std::tuple<SimpleEnableGroup<Severity>, SimpleEnableGroup<Checks>> groups;
     255         398 :     std::string errmsg = parseEnabled(str, groups);
     256         199 :     if (!errmsg.empty())
     257           6 :         return (enable ? "--enable" : "--disable") + errmsg;
     258             : 
     259         193 :     const auto s = std::get<0>(groups);
     260         193 :     const auto c = std::get<1>(groups);
     261         193 :     if (enable) {
     262         161 :         severity.enable(s);
     263         161 :         checks.enable(c);
     264             :     }
     265             :     else {
     266          32 :         severity.disable(s);
     267          32 :         checks.disable(c);
     268             :     }
     269             :     // FIXME: hack to make sure "error" is always enabled
     270         193 :     severity.enable(Severity::error);
     271         193 :     return errmsg;
     272             : }
     273             : 
     274       12501 : bool Settings::isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck) const
     275             : {
     276       12501 :     if (!severity.isEnabled(Severity::warning) && (value->condition || value->defaultArg))
     277           0 :         return false;
     278       12502 :     if (!certainty.isEnabled(Certainty::inconclusive) && (inconclusiveCheck || value->isInconclusive()))
     279           0 :         return false;
     280       12502 :     return true;
     281             : }
     282             : 
     283          25 : void Settings::loadSummaries()
     284             : {
     285          25 :     Summaries::loadReturn(buildDir, summaryReturn);
     286          25 : }
     287             : 
     288        4467 : void Settings::setCheckLevel(CheckLevel level)
     289             : {
     290        4467 :     if (level == CheckLevel::normal) {
     291             :         // Checking should finish in reasonable time.
     292         288 :         checkLevel = level;
     293         288 :         performanceValueFlowMaxSubFunctionArgs = 8;
     294         288 :         performanceValueFlowMaxIfCount = 100;
     295             :     }
     296        4179 :     else if (level == CheckLevel::exhaustive) {
     297             :         // Checking can take a little while. ~ 10 times slower than normal analysis is OK.
     298        4178 :         checkLevel = CheckLevel::exhaustive;
     299        4178 :         performanceValueFlowMaxIfCount = -1;
     300        4178 :         performanceValueFlowMaxSubFunctionArgs = 256;
     301             :     }
     302        4467 : }
     303             : 
     304             : // TODO: auto generate these tables
     305             : 
     306             : static const std::set<std::string> autosarCheckers{
     307             :     "accessMoved",
     308             :     "argumentSize",
     309             :     "arrayIndexOutOfBounds",
     310             :     "arrayIndexOutOfBoundsCond",
     311             :     "arrayIndexThenCheck",
     312             :     "bufferAccessOutOfBounds",
     313             :     "comparePointers",
     314             :     "constParameter",
     315             :     "cstyleCast",
     316             :     "ctuOneDefinitionViolation",
     317             :     "doubleFree",
     318             :     "duplInheritedMember",
     319             :     "duplicateBreak",
     320             :     "funcArgNamesDifferent",
     321             :     "functionConst",
     322             :     "functionStatic",
     323             :     "invalidContainer",
     324             :     "memleak",
     325             :     "mismatchAllocDealloc",
     326             :     "missingReturn",
     327             :     "negativeIndex",
     328             :     "noExplicitConstructor",
     329             :     "nullPointer",
     330             :     "nullPointerArithmetic",
     331             :     "nullPointerArithmeticRedundantCheck",
     332             :     "nullPointerDefaultArg",
     333             :     "nullPointerRedundantCheck",
     334             :     "objectIndex",
     335             :     "overlappingWriteFunction",
     336             :     "overlappingWriteUnion",
     337             :     "pointerOutOfBounds",
     338             :     "pointerOutOfBoundsCond",
     339             :     "preprocessorErrorDirective",
     340             :     "redundantAssignment",
     341             :     "redundantInitialization",
     342             :     "returnDanglingLifetime",
     343             :     "shiftTooManyBits",
     344             :     "sizeofSideEffects",
     345             :     "throwInDestructor",
     346             :     "throwInNoexceptFunction",
     347             :     "uninitData",
     348             :     "uninitMember",
     349             :     "unreachableCode",
     350             :     "unreadVariable",
     351             :     "unsignedLessThanZero",
     352             :     "unusedFunction",
     353             :     "unusedStructMember",
     354             :     "unusedValue",
     355             :     "unusedVariable",
     356             :     "useInitializerList",
     357             :     "variableScope",
     358             :     "virtualCallInConstructor",
     359             :     "zerodiv",
     360             :     "zerodivcond"
     361             : };
     362             : 
     363             : static const std::set<std::string> certCCheckers{
     364             :     "IOWithoutPositioning",
     365             :     "autoVariables",
     366             :     "autovarInvalidDeallocation",
     367             :     "bitwiseOnBoolean",
     368             :     "comparePointers",
     369             :     "danglingLifetime",
     370             :     "deallocret",
     371             :     "deallocuse",
     372             :     "doubleFree",
     373             :     "floatConversionOverflow",
     374             :     "invalidFunctionArg",
     375             :     "invalidLengthModifierError",
     376             :     "invalidLifetime",
     377             :     "invalidScanfFormatWidth",
     378             :     "invalidscanf",
     379             :     "leakReturnValNotUsed",
     380             :     "leakUnsafeArgAlloc",
     381             :     "memleak",
     382             :     "memleakOnRealloc",
     383             :     "mismatchAllocDealloc",
     384             :     "missingReturn",
     385             :     "nullPointer",
     386             :     "nullPointerArithmetic",
     387             :     "nullPointerArithmeticRedundantCheck",
     388             :     "nullPointerDefaultArg",
     389             :     "nullPointerRedundantCheck",
     390             :     "preprocessorErrorDirective",
     391             :     "resourceLeak",
     392             :     "sizeofCalculation",
     393             :     "stringLiteralWrite",
     394             :     "uninitStructMember",
     395             :     "uninitdata",
     396             :     "uninitvar",
     397             :     "unknownEvaluationOrder",
     398             :     "useClosedFile",
     399             :     "wrongPrintfScanfArgNum",
     400             :     "wrongPrintfScanfParameterPositionError"
     401             : };
     402             : 
     403             : static const std::set<std::string> certCppCheckers{
     404             :     "IOWithoutPositioning",
     405             :     "accessMoved",
     406             :     "comparePointers",
     407             :     "containerOutOfBounds",
     408             :     "ctuOneDefinitionViolation",
     409             :     "deallocMismatch",
     410             :     "deallocThrow",
     411             :     "deallocuse",
     412             :     "doubleFree",
     413             :     "eraseDereference",
     414             :     "exceptThrowInDestructor",
     415             :     "initializerList",
     416             :     "invalidContainer",
     417             :     "lifetime",
     418             :     "memleak",
     419             :     "missingReturn",
     420             :     "nullPointer",
     421             :     "operatorEqToSelf",
     422             :     "sizeofCalculation",
     423             :     "uninitvar",
     424             :     "virtualCallInConstructor",
     425             :     "virtualDestructor"
     426             : };
     427             : 
     428             : static const std::set<std::string> misrac2012Checkers{
     429             :     "alwaysFalse",
     430             :     "alwaysTrue",
     431             :     "argumentSize",
     432             :     "autovarInvalidDeallocation",
     433             :     "bufferAccessOutOfBounds",
     434             :     "comparePointers",
     435             :     "compareValueOutOfTypeRangeError",
     436             :     "constPointer",
     437             :     "danglingLifetime",
     438             :     "duplicateBreak",
     439             :     "error",
     440             :     "funcArgNamesDifferent",
     441             :     "incompatibleFileOpen",
     442             :     "invalidFunctionArg",
     443             :     "knownConditionTrueFalse",
     444             :     "leakNoVarFunctionCall",
     445             :     "leakReturnValNotUsed",
     446             :     "memleak",
     447             :     "memleakOnRealloc",
     448             :     "missingReturn",
     449             :     "overlappingWriteFunction",
     450             :     "overlappingWriteUnion",
     451             :     "pointerOutOfBounds",
     452             :     "preprocessorErrorDirective",
     453             :     "redundantAssignInSwitch",
     454             :     "redundantAssignment",
     455             :     "redundantCondition",
     456             :     "resourceLeak",
     457             :     "shadowVariable",
     458             :     "sizeofCalculation",
     459             :     "syntaxError",
     460             :     "uninitvar",
     461             :     "unknownEvaluationOrder",
     462             :     "unreadVariable",
     463             :     "unusedLabel",
     464             :     "unusedVariable",
     465             :     "useClosedFile",
     466             :     "writeReadOnlyFile"
     467             : };
     468             : 
     469             : static const std::set<std::string> misrac2023Checkers{
     470             :     "alwaysFalse",
     471             :     "alwaysTrue",
     472             :     "argumentSize",
     473             :     "autovarInvalidDeallocation",
     474             :     "bufferAccessOutOfBounds",
     475             :     "comparePointers",
     476             :     "compareValueOutOfTypeRangeError",
     477             :     "constPointer",
     478             :     "danglingLifetime",
     479             :     "duplicateBreak",
     480             :     "error",
     481             :     "funcArgNamesDifferent",
     482             :     "incompatibleFileOpen",
     483             :     "invalidFunctionArg",
     484             :     "knownConditionTrueFalse",
     485             :     "leakNoVarFunctionCall",
     486             :     "leakReturnValNotUsed",
     487             :     "memleak",
     488             :     "memleakOnRealloc",
     489             :     "missingReturn",
     490             :     "overlappingWriteFunction",
     491             :     "overlappingWriteUnion",
     492             :     "pointerOutOfBounds",
     493             :     "preprocessorErrorDirective",
     494             :     "redundantAssignInSwitch",
     495             :     "redundantAssignment",
     496             :     "redundantCondition",
     497             :     "resourceLeak",
     498             :     "shadowVariable",
     499             :     "sizeofCalculation",
     500             :     "syntaxError",
     501             :     "uninitvar",
     502             :     "unknownEvaluationOrder",
     503             :     "unreadVariable",
     504             :     "unusedLabel",
     505             :     "unusedVariable",
     506             :     "useClosedFile",
     507             :     "writeReadOnlyFile"
     508             : };
     509             : 
     510             : static const std::set<std::string> misracpp2008Checkers{
     511             :     "autoVariables",
     512             :     "comparePointers",
     513             :     "constParameter",
     514             :     "constVariable",
     515             :     "cstyleCast",
     516             :     "ctuOneDefinitionViolation",
     517             :     "danglingLifetime",
     518             :     "duplInheritedMember",
     519             :     "duplicateBreak",
     520             :     "exceptThrowInDestructor",
     521             :     "funcArgNamesDifferent",
     522             :     "functionConst",
     523             :     "functionStatic",
     524             :     "missingReturn",
     525             :     "noExplicit",
     526             :     "overlappingWriteFunction",
     527             :     "overlappingWriteUnion",
     528             :     "pointerOutOfBounds",
     529             :     "preprocessorErrorDirective",
     530             :     "redundantAssignment",
     531             :     "redundantInitialization",
     532             :     "returnReference",
     533             :     "returnTempReference",
     534             :     "shadowVariable",
     535             :     "shiftTooManyBits",
     536             :     "sizeofSideEffects",
     537             :     "throwInDestructor",
     538             :     "uninitDerivedMemberVar",
     539             :     "uninitDerivedMemberVarPrivate",
     540             :     "uninitMemberVar",
     541             :     "uninitMemberVarPrivate",
     542             :     "uninitStructMember",
     543             :     "uninitdata",
     544             :     "uninitvar",
     545             :     "unknownEvaluationOrder",
     546             :     "unreachableCode",
     547             :     "unreadVariable",
     548             :     "unsignedLessThanZero",
     549             :     "unusedFunction",
     550             :     "unusedStructMember",
     551             :     "unusedVariable",
     552             :     "varScope",
     553             :     "variableScope",
     554             :     "virtualCallInConstructor"
     555             : };
     556             : 
     557      147543 : bool Settings::isPremiumEnabled(const char id[]) const
     558             : {
     559      147539 :     if (premiumArgs.find("autosar") != std::string::npos && autosarCheckers.count(id))
     560           0 :         return true;
     561      147563 :     if (premiumArgs.find("cert-c-") != std::string::npos && certCCheckers.count(id))
     562           0 :         return true;
     563      147568 :     if (premiumArgs.find("cert-c++") != std::string::npos && certCppCheckers.count(id))
     564           0 :         return true;
     565      147567 :     if (premiumArgs.find("misra-c-") != std::string::npos && (misrac2012Checkers.count(id) || misrac2023Checkers.count(id)))
     566           0 :         return true;
     567      147571 :     if (premiumArgs.find("misra-c++") != std::string::npos && misracpp2008Checkers.count(id))
     568           0 :         return true;
     569      147563 :     return false;
     570             : }
     571             : 
     572          25 : void Settings::setMisraRuleTexts(const ExecuteCmdFn& executeCommand)
     573             : {
     574          25 :     if (premiumArgs.find("--misra-c-20") != std::string::npos) {
     575           0 :         const auto it = std::find_if(addonInfos.cbegin(), addonInfos.cend(), [](const AddonInfo& a) {
     576           0 :             return a.name == "premiumaddon.json";
     577           0 :         });
     578           0 :         if (it != addonInfos.cend()) {
     579           0 :             std::string arg;
     580           0 :             if (premiumArgs.find("--misra-c-2023") != std::string::npos)
     581           0 :                 arg = "--misra-c-2023-rule-texts";
     582             :             else
     583           0 :                 arg = "--misra-c-2012-rule-texts";
     584           0 :             std::string output;
     585           0 :             executeCommand(it->executable, {std::move(arg)}, "2>&1", output);
     586           0 :             setMisraRuleTexts(output);
     587             :         }
     588             :     }
     589          25 : }
     590             : 
     591           1 : void Settings::setMisraRuleTexts(const std::string& data)
     592             : {
     593           1 :     mMisraRuleTexts.clear();
     594           2 :     std::istringstream istr(data);
     595           2 :     std::string line;
     596           3 :     while (std::getline(istr, line)) {
     597           2 :         std::string::size_type pos = line.find(' ');
     598           2 :         if (pos == std::string::npos)
     599           0 :             continue;
     600           2 :         std::string id = line.substr(0, pos);
     601           2 :         std::string text = line.substr(pos + 1);
     602           2 :         if (id.empty() || text.empty())
     603           0 :             continue;
     604           2 :         mMisraRuleTexts[id] = std::move(text);
     605             :     }
     606           1 : }
     607             : 
     608           2 : std::string Settings::getMisraRuleText(const std::string& id, const std::string& text) const {
     609           2 :     if (id.compare(0, 9, "misra-c20") != 0)
     610           0 :         return text;
     611           2 :     const auto it = mMisraRuleTexts.find(id.substr(id.rfind('-') + 1));
     612           4 :     return it != mMisraRuleTexts.end() ? it->second : text;
     613             : }
     614             : 
     615        4155 : Settings::ExecutorType Settings::defaultExecutor()
     616             : {
     617             :     static constexpr ExecutorType defaultExecutor =
     618             : #if defined(HAS_THREADING_MODEL_FORK)
     619             :         ExecutorType::Process;
     620             : #elif defined(HAS_THREADING_MODEL_THREAD)
     621             :         ExecutorType::Thread;
     622             : #endif
     623        4155 :     return defaultExecutor;
     624             : }

Generated by: LCOV version 1.14