QErrorPathItem::QErrorPathItem(const ErrorLogger::ErrorMessage::FileLocation &loc) : file(QString::fromStdString(loc.getfile(false))) , line(loc.line) , col(loc.col) , info(QString::fromStdString(loc.getinfo())) { }
void FileLocationSetFile() { ErrorLogger::ErrorMessage::FileLocation loc; loc.setfile("foo.cpp"); ASSERT_EQUALS("foo.cpp", loc.getfile()); ASSERT_EQUALS(0, loc.line); }
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; }
void FileLocationDefaults() const { ErrorLogger::ErrorMessage::FileLocation loc; ASSERT_EQUALS("", loc.getfile()); ASSERT_EQUALS(0, loc.line); }