void factor_vm::primitive_callstack_to_array() { data_root<callstack> callstack(ctx->pop(),this); stack_frame_accumulator accum(this); iterate_callstack_object(callstack.untagged(),accum); accum.frames.trim(); ctx->push(accum.frames.elements.value()); }
inline void factorvm::vmprim_callstack_to_array() { gc_root<callstack> callstack(dpop(),this); stack_frame_accumulator accum(this); iterate_callstack_object(callstack.untagged(),accum); accum.frames.trim(); dpush(accum.frames.elements.value()); }
// Allocates memory void factor_vm::primitive_get_samples() { if (atomic::load(&sampling_profiler_p) || samples.empty()) { ctx->push(false_object); } else { data_root<array> samples_array(allot_array(samples.size(), false_object), this); std::vector<profiling_sample>::const_iterator from_iter = samples.begin(); cell to_i = 0; for (; from_iter != samples.end(); ++from_iter, ++to_i) { data_root<array> sample(allot_array(7, false_object), this); set_array_nth(sample.untagged(), 0, tag_fixnum(from_iter->counts.sample_count)); set_array_nth(sample.untagged(), 1, tag_fixnum(from_iter->counts.gc_sample_count)); set_array_nth(sample.untagged(), 2, tag_fixnum(from_iter->counts.jit_sample_count)); set_array_nth(sample.untagged(), 3, tag_fixnum(from_iter->counts.foreign_sample_count)); set_array_nth(sample.untagged(), 4, tag_fixnum(from_iter->counts.foreign_thread_sample_count)); set_array_nth(sample.untagged(), 5, from_iter->thread); cell callstack_size = from_iter->callstack_end - from_iter->callstack_begin; data_root<array> callstack(allot_array(callstack_size, false_object), this); std::vector<cell>::const_iterator callstacks_begin = sample_callstacks.begin(), c_from_iter = callstacks_begin + from_iter->callstack_begin, c_from_iter_end = callstacks_begin + from_iter->callstack_end; cell c_to_i = 0; for (; c_from_iter != c_from_iter_end; ++c_from_iter, ++c_to_i) set_array_nth(callstack.untagged(), c_to_i, *c_from_iter); set_array_nth(sample.untagged(), 6, callstack.value()); set_array_nth(samples_array.untagged(), to_i, sample.value()); } ctx->push(samples_array.value()); } }
void factor_vm::primitive_set_innermost_stack_frame_quot() { data_root<callstack> callstack(ctx->pop(),this); data_root<quotation> quot(ctx->pop(),this); callstack.untag_check(this); quot.untag_check(this); jit_compile_quot(quot.value(),true); stack_frame *inner = innermost_stack_frame(callstack.untagged()); cell offset = (char *)FRAME_RETURN_ADDRESS(inner,this) - (char *)inner->entry_point; inner->entry_point = quot->entry_point; FRAME_RETURN_ADDRESS(inner,this) = (char *)quot->entry_point + offset; }
inline void factorvm::vmprim_set_innermost_stack_frame_quot() { gc_root<callstack> callstack(dpop(),this); gc_root<quotation> quot(dpop(),this); callstack.untag_check(this); quot.untag_check(this); jit_compile(quot.value(),true); stack_frame *inner = innermost_stack_frame_quot(callstack.untagged()); cell offset = (char *)FRAME_RETURN_ADDRESS(inner) - (char *)inner->xt; inner->xt = quot->xt; FRAME_RETURN_ADDRESS(inner) = (char *)quot->xt + offset; }
void factor_vm::primitive_callstack_to_array() { data_root<callstack> callstack(ctx->pop(),this); stack_frame_accumulator accum(this); iterate_callstack_object(callstack.untagged(),accum); /* The callstack iterator visits frames in reverse order (top to bottom) */ std::reverse( (stack_frame_in_array*)accum.frames.elements->data(), (stack_frame_in_array*)(accum.frames.elements->data() + accum.frames.count)); accum.frames.trim(); ctx->push(accum.frames.elements.value()); }
void CppCheck::internalError(const std::string &filename, const std::string &msg) { const std::string fixedpath = Path::toNativeSeparators(filename); const std::string fullmsg("Bailing out from checking " + fixedpath + " since there was an internal error: " + msg); if (mSettings.isEnabled(Settings::INFORMATION)) { const ErrorLogger::ErrorMessage::FileLocation loc1(filename, 0); std::list<ErrorLogger::ErrorMessage::FileLocation> callstack(1, loc1); ErrorLogger::ErrorMessage errmsg(callstack, emptyString, Severity::information, fullmsg, "internalError", false); mErrorLogger.reportErr(errmsg); } else { // Report on stdout mErrorLogger.reportOut(fullmsg); } }
bool TemplateSimplifier::simplifyTemplateInstantiations( TokenList& tokenlist, ErrorLogger& errorlogger, const Settings *_settings, const Token *tok, std::list<Token *> &templateInstantiations, std::set<std::string> &expandedtemplates) { // this variable is not used at the moment. The intention was to // allow continuous instantiations until all templates has been expanded //bool done = false; // Contains tokens such as "T" std::vector<const Token *> typeParametersInDeclaration; for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) { if (Token::Match(tok, "%var% ,|>")) typeParametersInDeclaration.push_back(tok); } // bail out if the end of the file was reached if (!tok) return false; // get the position of the template name int namepos = TemplateSimplifier::getTemplateNamePosition(tok); if (namepos == -1) { // debug message that we bail out.. if (_settings->debugwarnings) { std::list<const Token *> callstack(1, tok); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false)); } return false; } // name of template function/class.. const std::string name(tok->strAt(namepos)); const bool isfunc(tok->strAt(namepos + 1) == "("); // locate template usage.. std::string::size_type amountOftemplateInstantiations = templateInstantiations.size(); unsigned int recursiveCount = 0; bool instantiated = false; for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { if (amountOftemplateInstantiations != templateInstantiations.size()) { amountOftemplateInstantiations = templateInstantiations.size(); simplifyCalculations(tokenlist.front()); ++recursiveCount; if (recursiveCount > 100) { // bail out.. break; } } Token * const tok2 = *iter2; if (tok2->str() != name) continue; if (Token::Match(tok2->previous(), "[;{}=]") && !TemplateSimplifier::instantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %var%")) continue; // New type.. std::vector<const Token *> typesUsedInTemplateInstantiation; std::string typeForNewNameStr; std::string templateMatchPattern(name + " < "); unsigned int indentlevel = 0; for (const Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) { // #2648 - unhandled parentheses => bail out // #2721 - unhandled [ => bail out if (tok3->str() == "(" || tok3->str() == "[") { typeForNewNameStr.clear(); break; } if (!tok3->next()) { typeForNewNameStr.clear(); break; } if (Token::Match(tok3->tokAt(-2), "[<,] %var% <") && templateParameters(tok3) > 0) ++indentlevel; else if (indentlevel > 0 && Token::Match(tok3, "> [,>]")) --indentlevel; else if (indentlevel > 0 && tok3->str() == ">>") { if (indentlevel == 1) { templateMatchPattern += '>'; typeForNewNameStr += '>'; break; } indentlevel -= 2; } templateMatchPattern += (tok3->str() == ">>") ? std::string("> >") : tok3->str(); templateMatchPattern += ' '; if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) typesUsedInTemplateInstantiation.push_back(tok3); // add additional type information if (tok3->str() != "class") { if (tok3->isUnsigned()) typeForNewNameStr += "unsigned"; else if (tok3->isSigned()) typeForNewNameStr += "signed"; if (tok3->isLong()) typeForNewNameStr += "long"; typeForNewNameStr += tok3->str(); } } templateMatchPattern += ">"; const std::string typeForNewName(typeForNewNameStr); if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) { if (_settings->debugwarnings) { std::list<const Token *> callstack(1, tok); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "Failed to instantiate template. The checking continues anyway.", false)); } if (typeForNewName.empty()) continue; break; } // New classname/funcname.. const std::string newName(name + "<" + typeForNewName + ">"); if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); TemplateSimplifier::expandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantiation,templateInstantiations); instantiated = true; } // Replace all these template usages.. std::list< std::pair<Token *, Token *> > removeTokens; for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) { if (Token::simpleMatch(tok4, templateMatchPattern.c_str())) { Token * tok5 = tok4->tokAt(2); unsigned int typeCountInInstantiation = 1U; // There is always at least one type const Token *typetok = (!typesUsedInTemplateInstantiation.empty()) ? typesUsedInTemplateInstantiation[0] : 0; unsigned int indentlevel5 = 0; // indentlevel for tok5 while (tok5 && (indentlevel5 > 0 || tok5->str() != ">")) { if (tok5->str() == "<" && templateParameters(tok5) > 0) ++indentlevel5; else if (indentlevel5 > 0 && Token::Match(tok5, "> [,>]")) --indentlevel5; else if (indentlevel5 == 0) { if (tok5->str() != ",") { if (!typetok || tok5->isUnsigned() != typetok->isUnsigned() || tok5->isSigned() != typetok->isSigned() || tok5->isLong() != typetok->isLong()) { break; } typetok = typetok ? typetok->next() : 0; } else { typetok = (typeCountInInstantiation < typesUsedInTemplateInstantiation.size()) ? typesUsedInTemplateInstantiation[typeCountInInstantiation] : 0; ++typeCountInInstantiation; } } tok5 = tok5->next(); } // matching template usage => replace tokens.. // Foo < int > => Foo<int> if (tok5 && tok5->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) { tok4->str(newName); for (Token *tok6 = tok4->next(); tok6 != tok5; tok6 = tok6->next()) { if (tok6->isName()) templateInstantiations.remove(tok6); } removeTokens.push_back(std::pair<Token*,Token*>(tok4, tok5->next())); } tok4 = tok5; if (!tok4) break; } } while (!removeTokens.empty()) { Token::eraseTokens(removeTokens.back().first, removeTokens.back().second); removeTokens.pop_back(); } } // Template has been instantiated .. then remove the template declaration return instantiated; }
void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varname) { const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings); std::list<const Token *> callstack(1, tok); c.mismatchAllocDealloc(callstack, varname); }
unsigned int CppCheck::checkFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream) { mExitCode = 0; mSuppressInternalErrorFound = false; // only show debug warnings for accepted C/C++ source files if (!Path::acceptFile(filename)) mSettings.debugwarnings = false; if (mSettings.terminated()) return mExitCode; if (!mSettings.quiet) { std::string fixedpath = Path::simplifyPath(filename); fixedpath = Path::toNativeSeparators(fixedpath); mErrorLogger.reportOut(std::string("Checking ") + fixedpath + ' ' + cfgname + std::string("...")); if (mSettings.verbose) { mErrorLogger.reportOut("Defines:" + mSettings.userDefines); std::string undefs; for (const std::string& U : mSettings.userUndefs) { if (!undefs.empty()) undefs += ';'; undefs += ' ' + U; } mErrorLogger.reportOut("Undefines:" + undefs); std::string includePaths; for (const std::string &I : mSettings.includePaths) includePaths += " -I" + I; mErrorLogger.reportOut("Includes:" + includePaths); mErrorLogger.reportOut(std::string("Platform:") + mSettings.platformString()); } } if (plistFile.is_open()) { plistFile << ErrorLogger::plistFooter(); plistFile.close(); } CheckUnusedFunctions checkUnusedFunctions(nullptr, nullptr, nullptr); bool internalErrorFound(false); try { Preprocessor preprocessor(mSettings, this); std::set<std::string> configurations; simplecpp::OutputList outputList; std::vector<std::string> files; simplecpp::TokenList tokens1(fileStream, files, filename, &outputList); // If there is a syntax error, report it and stop for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) { bool err; switch (it->type) { case simplecpp::Output::ERROR: case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY: case simplecpp::Output::SYNTAX_ERROR: case simplecpp::Output::UNHANDLED_CHAR_ERROR: err = true; break; case simplecpp::Output::WARNING: case simplecpp::Output::MISSING_HEADER: case simplecpp::Output::PORTABILITY_BACKSLASH: err = false; break; }; if (err) { const ErrorLogger::ErrorMessage::FileLocation loc1(it->location.file(), it->location.line); std::list<ErrorLogger::ErrorMessage::FileLocation> callstack(1, loc1); ErrorLogger::ErrorMessage errmsg(callstack, "", Severity::error, it->msg, "syntaxError", false); reportErr(errmsg); return mExitCode; } } preprocessor.loadFiles(tokens1, files); if (!mSettings.plistOutput.empty()) { std::string filename2; if (filename.find('/') != std::string::npos) filename2 = filename.substr(filename.rfind('/') + 1); else filename2 = filename; filename2 = mSettings.plistOutput + filename2.substr(0, filename2.find('.')) + ".plist"; plistFile.open(filename2); plistFile << ErrorLogger::plistHeader(version(), files); } // write dump file xml prolog std::ofstream fdump; if (mSettings.dump) { const std::string dumpfile(mSettings.dumpFile.empty() ? (filename + ".dump") : mSettings.dumpFile); fdump.open(dumpfile); if (fdump.is_open()) { fdump << "<?xml version=\"1.0\"?>" << std::endl; fdump << "<dumps>" << std::endl; fdump << " <platform" << " name=\"" << mSettings.platformString() << '\"' << " char_bit=\"" << mSettings.char_bit << '\"' << " short_bit=\"" << mSettings.short_bit << '\"' << " int_bit=\"" << mSettings.int_bit << '\"' << " long_bit=\"" << mSettings.long_bit << '\"' << " long_long_bit=\"" << mSettings.long_long_bit << '\"' << " pointer_bit=\"" << (mSettings.sizeof_pointer * mSettings.char_bit) << '\"' << "/>\n"; fdump << " <rawtokens>" << std::endl; for (unsigned int i = 0; i < files.size(); ++i) fdump << " <file index=\"" << i << "\" name=\"" << ErrorLogger::toxml(files[i]) << "\"/>" << std::endl; for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) { fdump << " <tok " << "fileIndex=\"" << tok->location.fileIndex << "\" " << "linenr=\"" << tok->location.line << "\" " << "str=\"" << ErrorLogger::toxml(tok->str()) << "\"" << "/>" << std::endl; } fdump << " </rawtokens>" << std::endl; } } // Parse comments and then remove them preprocessor.inlineSuppressions(tokens1); if (mSettings.dump && fdump.is_open()) { mSettings.nomsg.dump(fdump); } tokens1.removeComments(); preprocessor.removeComments(); if (!mSettings.buildDir.empty()) { // Get toolinfo std::ostringstream toolinfo; toolinfo << CPPCHECK_VERSION_STRING; toolinfo << (mSettings.isEnabled(Settings::WARNING) ? 'w' : ' '); toolinfo << (mSettings.isEnabled(Settings::STYLE) ? 's' : ' '); toolinfo << (mSettings.isEnabled(Settings::PERFORMANCE) ? 'p' : ' '); toolinfo << (mSettings.isEnabled(Settings::PORTABILITY) ? 'p' : ' '); toolinfo << (mSettings.isEnabled(Settings::INFORMATION) ? 'i' : ' '); toolinfo << mSettings.userDefines; mSettings.nomsg.dump(toolinfo); // Calculate checksum so it can be compared with old checksum / future checksums const unsigned int checksum = preprocessor.calculateChecksum(tokens1, toolinfo.str()); std::list<ErrorLogger::ErrorMessage> errors; if (!mAnalyzerInformation.analyzeFile(mSettings.buildDir, filename, cfgname, checksum, &errors)) { while (!errors.empty()) { reportErr(errors.front()); errors.pop_front(); } return mExitCode; // known results => no need to reanalyze file } } // Get directives preprocessor.setDirectives(tokens1); preprocessor.simplifyPragmaAsm(&tokens1); preprocessor.setPlatformInfo(&tokens1); // Get configurations.. if (mSettings.userDefines.empty() || mSettings.force) { Timer t("Preprocessor::getConfigs", mSettings.showtime, &S_timerResults); configurations = preprocessor.getConfigs(tokens1); } else { configurations.insert(mSettings.userDefines); } if (mSettings.checkConfiguration) { for (const std::string &config : configurations) (void)preprocessor.getcode(tokens1, config, files, true); return 0; } // Run define rules on raw code for (const Settings::Rule &rule : mSettings.rules) { if (rule.tokenlist != "define") continue; std::string code; const std::list<Directive> &directives = preprocessor.getDirectives(); for (const Directive &dir : directives) { if (dir.str.compare(0,8,"#define ") == 0) code += "#line " + MathLib::toString(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n'; } Tokenizer tokenizer2(&mSettings, this); std::istringstream istr2(code); tokenizer2.list.createTokens(istr2); executeRules("define", tokenizer2); break; } if (!mSettings.force && configurations.size() > mSettings.maxConfigs) { if (mSettings.isEnabled(Settings::INFORMATION)) { tooManyConfigsError(Path::toNativeSeparators(filename),configurations.size()); } else { mTooManyConfigs = true; } } std::set<unsigned long long> checksums; unsigned int checkCount = 0; bool hasValidConfig = false; std::list<std::string> configurationError; for (std::set<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) { // bail out if terminated if (mSettings.terminated()) break; // Check only a few configurations (default 12), after that bail out, unless --force // was used. if (!mSettings.force && ++checkCount > mSettings.maxConfigs) break; mCurrentConfig = *it; if (!mSettings.userDefines.empty()) { if (!mCurrentConfig.empty()) mCurrentConfig = ";" + mCurrentConfig; mCurrentConfig = mSettings.userDefines + mCurrentConfig; } if (mSettings.preprocessOnly) { Timer t("Preprocessor::getcode", mSettings.showtime, &S_timerResults); std::string codeWithoutCfg = preprocessor.getcode(tokens1, mCurrentConfig, files, true); t.Stop(); if (codeWithoutCfg.compare(0,5,"#file") == 0) codeWithoutCfg.insert(0U, "//"); std::string::size_type pos = 0; while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos) codeWithoutCfg.insert(pos+1U, "//"); pos = 0; while ((pos = codeWithoutCfg.find("\n#endfile",pos)) != std::string::npos) codeWithoutCfg.insert(pos+1U, "//"); pos = 0; while ((pos = codeWithoutCfg.find(Preprocessor::macroChar,pos)) != std::string::npos) codeWithoutCfg[pos] = ' '; reportOut(codeWithoutCfg); continue; } Tokenizer mTokenizer(&mSettings, this); if (mSettings.showtime != SHOWTIME_NONE) mTokenizer.setTimerResults(&S_timerResults); try { bool result; // Create tokens, skip rest of iteration if failed Timer timer("Tokenizer::createTokens", mSettings.showtime, &S_timerResults); const simplecpp::TokenList &tokensP = preprocessor.preprocess(tokens1, mCurrentConfig, files, true); mTokenizer.createTokens(&tokensP); timer.Stop(); hasValidConfig = true; // If only errors are printed, print filename after the check if (!mSettings.quiet && (!mCurrentConfig.empty() || it != configurations.begin())) { std::string fixedpath = Path::simplifyPath(filename); fixedpath = Path::toNativeSeparators(fixedpath); mErrorLogger.reportOut("Checking " + fixedpath + ": " + mCurrentConfig + "..."); } if (tokensP.empty()) continue; // skip rest of iteration if just checking configuration if (mSettings.checkConfiguration) continue; // Check raw tokens checkRawTokens(mTokenizer); // Simplify tokens into normal form, skip rest of iteration if failed Timer timer2("Tokenizer::simplifyTokens1", mSettings.showtime, &S_timerResults); result = mTokenizer.simplifyTokens1(mCurrentConfig); timer2.Stop(); if (!result) continue; // dump xml if --dump if (mSettings.dump && fdump.is_open()) { fdump << "<dump cfg=\"" << ErrorLogger::toxml(mCurrentConfig) << "\">" << std::endl; preprocessor.dump(fdump); mTokenizer.dump(fdump); fdump << "</dump>" << std::endl; } // Skip if we already met the same simplified token list if (mSettings.force || mSettings.maxConfigs > 1) { const unsigned long long checksum = mTokenizer.list.calculateChecksum(); if (checksums.find(checksum) != checksums.end()) { if (mSettings.debugwarnings) purgedConfigurationMessage(filename, mCurrentConfig); continue; } checksums.insert(checksum); } // Check normal tokens checkNormalTokens(mTokenizer); // Analyze info.. if (!mSettings.buildDir.empty()) checkUnusedFunctions.parseTokens(mTokenizer, filename.c_str(), &mSettings); // simplify more if required, skip rest of iteration if failed if (mSimplify) { // if further simplification fails then skip rest of iteration Timer timer3("Tokenizer::simplifyTokenList2", mSettings.showtime, &S_timerResults); result = mTokenizer.simplifyTokenList2(); timer3.Stop(); if (!result) continue; // Check simplified tokens checkSimplifiedTokens(mTokenizer); } } catch (const simplecpp::Output &o) { // #error etc during preprocessing configurationError.push_back((mCurrentConfig.empty() ? "\'\'" : mCurrentConfig) + " : [" + o.location.file() + ':' + MathLib::toString(o.location.line) + "] " + o.msg); --checkCount; // don't count invalid configurations continue; } catch (const InternalError &e) { std::list<ErrorLogger::ErrorMessage::FileLocation> locationList; ErrorLogger::ErrorMessage::FileLocation loc; if (e.token) { loc.line = e.token->linenr(); const std::string fixedpath = Path::toNativeSeparators(mTokenizer.list.file(e.token)); loc.setfile(fixedpath); } else { ErrorLogger::ErrorMessage::FileLocation loc2; loc2.setfile(Path::toNativeSeparators(filename)); locationList.push_back(loc2); loc.setfile(mTokenizer.list.getSourceFilePath()); } locationList.push_back(loc); ErrorLogger::ErrorMessage errmsg(locationList, mTokenizer.list.getSourceFilePath(), Severity::error, e.errorMessage, e.id, false); reportErr(errmsg); if (!mSuppressInternalErrorFound) internalErrorFound = true; } } if (!hasValidConfig && configurations.size() > 1 && mSettings.isEnabled(Settings::INFORMATION)) { std::string msg; msg = "This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details."; msg += "\nThis file is not analyzed. Cppcheck failed to extract a valid configuration. The tested configurations have these preprocessor errors:"; for (const std::string &s : configurationError) msg += '\n' + s; std::list<ErrorLogger::ErrorMessage::FileLocation> locationList; ErrorLogger::ErrorMessage::FileLocation loc; loc.setfile(Path::toNativeSeparators(filename)); locationList.push_back(loc); ErrorLogger::ErrorMessage errmsg(locationList, loc.getfile(), Severity::information, msg, "noValidConfiguration", false); reportErr(errmsg); } // dumped all configs, close root </dumps> element now if (mSettings.dump && fdump.is_open()) fdump << "</dumps>" << std::endl; } catch (const std::runtime_error &e) { internalError(filename, e.what()); } catch (const std::bad_alloc &e) { internalError(filename, e.what()); } catch (const InternalError &e) { internalError(filename, e.errorMessage); mExitCode=1; // e.g. reflect a syntax error } mAnalyzerInformation.setFileInfo("CheckUnusedFunctions", checkUnusedFunctions.analyzerInfo()); mAnalyzerInformation.close(); // In jointSuppressionReport mode, unmatched suppressions are // collected after all files are processed if (!mSettings.jointSuppressionReport && (mSettings.isEnabled(Settings::INFORMATION) || mSettings.checkConfiguration)) { reportUnmatchedSuppressions(mSettings.nomsg.getUnmatchedLocalSuppressions(filename, isUnusedFunctionCheckEnabled())); } mErrorList.clear(); if (internalErrorFound && (mExitCode==0)) { mExitCode = 1; } return mExitCode; }