Addons: Adding support in Cppcheck CLI to execute addons
This commit is contained in:
parent
64f0744242
commit
bf9006737a
|
@ -16,13 +16,17 @@ import re
|
||||||
VERIFY = ('-verify' in sys.argv)
|
VERIFY = ('-verify' in sys.argv)
|
||||||
VERIFY_EXPECTED = []
|
VERIFY_EXPECTED = []
|
||||||
VERIFY_ACTUAL = []
|
VERIFY_ACTUAL = []
|
||||||
|
CLI = False
|
||||||
|
|
||||||
def reportError(token, severity, msg, id):
|
def reportError(token, severity, msg, id):
|
||||||
if VERIFY:
|
if VERIFY:
|
||||||
VERIFY_ACTUAL.append(str(token.linenr) + ':' + id)
|
VERIFY_ACTUAL.append(str(token.linenr) + ':' + id)
|
||||||
else:
|
else:
|
||||||
sys.stderr.write(
|
msg = '[' + token.file + ':' + str(token.linenr) + ']: (' + severity + ') ' + msg + ' [' + id + ']'
|
||||||
'[' + token.file + ':' + str(token.linenr) + '] (' + severity + '): ' + msg + ' [' + id + ']\n')
|
if CLI:
|
||||||
|
print(msg)
|
||||||
|
else:
|
||||||
|
sys.stderr.write(msg + '\n')
|
||||||
|
|
||||||
def simpleMatch(token, pattern):
|
def simpleMatch(token, pattern):
|
||||||
for p in pattern.split(' '):
|
for p in pattern.split(' '):
|
||||||
|
@ -239,6 +243,9 @@ for arg in sys.argv[1:]:
|
||||||
if arg == '-verify':
|
if arg == '-verify':
|
||||||
VERIFY = True
|
VERIFY = True
|
||||||
continue
|
continue
|
||||||
|
if arg == '--cli':
|
||||||
|
CLI = True
|
||||||
|
continue
|
||||||
print('Checking ' + arg + '...')
|
print('Checking ' + arg + '...')
|
||||||
data = cppcheckdata.parsedump(arg)
|
data = cppcheckdata.parsedump(arg)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ typeBits = {
|
||||||
VERIFY = False
|
VERIFY = False
|
||||||
QUIET = False
|
QUIET = False
|
||||||
SHOW_SUMMARY = True
|
SHOW_SUMMARY = True
|
||||||
|
CLI = False # Executed by Cppcheck binary?
|
||||||
|
|
||||||
def printStatus(*args, **kwargs):
|
def printStatus(*args, **kwargs):
|
||||||
if not QUIET:
|
if not QUIET:
|
||||||
|
@ -1964,8 +1965,11 @@ class MisraChecker:
|
||||||
errorId = id,
|
errorId = id,
|
||||||
suppressions = self.dumpfileSuppressions)
|
suppressions = self.dumpfileSuppressions)
|
||||||
if formattedMsg:
|
if formattedMsg:
|
||||||
sys.stderr.write(formattedMsg)
|
if CLI:
|
||||||
sys.stderr.write('\n')
|
print(formattedMsg)
|
||||||
|
else:
|
||||||
|
sys.stderr.write(formattedMsg)
|
||||||
|
sys.stderr.write('\n')
|
||||||
if not severity in self.violations:
|
if not severity in self.violations:
|
||||||
self.violations[severity] = []
|
self.violations[severity] = []
|
||||||
self.violations[severity].append(id)
|
self.violations[severity].append(id)
|
||||||
|
@ -2193,6 +2197,7 @@ parser.add_argument("-generate-table", help=argparse.SUPPRESS, action="store_tru
|
||||||
parser.add_argument("dumpfile", nargs='*', help="Path of dump file from cppcheck")
|
parser.add_argument("dumpfile", nargs='*', help="Path of dump file from cppcheck")
|
||||||
parser.add_argument("--show-suppressed-rules", help="Print rule suppression list", action="store_true")
|
parser.add_argument("--show-suppressed-rules", help="Print rule suppression list", action="store_true")
|
||||||
parser.add_argument("-P", "--file-prefix", type=str, help="Prefix to strip when matching suppression file rules")
|
parser.add_argument("-P", "--file-prefix", type=str, help="Prefix to strip when matching suppression file rules")
|
||||||
|
parser.add_argument("--cli", help="Addon is executed from Cppcheck", action="store_true")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
checker = MisraChecker()
|
checker = MisraChecker()
|
||||||
|
@ -2215,6 +2220,10 @@ else:
|
||||||
if args.file_prefix:
|
if args.file_prefix:
|
||||||
checker.setFilePrefix(args.file_prefix)
|
checker.setFilePrefix(args.file_prefix)
|
||||||
|
|
||||||
|
if args.cli:
|
||||||
|
CLI = True
|
||||||
|
QUIET = True
|
||||||
|
SHOW_SUMMARY = False
|
||||||
if args.quiet:
|
if args.quiet:
|
||||||
QUIET = True
|
QUIET = True
|
||||||
if args.no_summary:
|
if args.no_summary:
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream> // <- TEMPORARY
|
||||||
|
|
||||||
#ifdef HAVE_RULES
|
#ifdef HAVE_RULES
|
||||||
#define PCRE_STATIC
|
#define PCRE_STATIC
|
||||||
|
@ -216,9 +218,10 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
||||||
|
|
||||||
// write dump file xml prolog
|
// write dump file xml prolog
|
||||||
std::ofstream fdump;
|
std::ofstream fdump;
|
||||||
if (mSettings.dump) {
|
std::string dumpFile;
|
||||||
const std::string dumpfile(mSettings.dumpFile.empty() ? (filename + ".dump") : mSettings.dumpFile);
|
if (mSettings.dump || !mSettings.addons.empty()) {
|
||||||
fdump.open(dumpfile);
|
dumpFile = (mSettings.dumpFile.empty()) ? (filename + ".dump") : mSettings.dumpFile;
|
||||||
|
fdump.open(dumpFile);
|
||||||
if (fdump.is_open()) {
|
if (fdump.is_open()) {
|
||||||
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
||||||
fdump << "<dumps>" << std::endl;
|
fdump << "<dumps>" << std::endl;
|
||||||
|
@ -247,7 +250,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
||||||
|
|
||||||
// Parse comments and then remove them
|
// Parse comments and then remove them
|
||||||
preprocessor.inlineSuppressions(tokens1);
|
preprocessor.inlineSuppressions(tokens1);
|
||||||
if (mSettings.dump && fdump.is_open()) {
|
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open()) {
|
||||||
mSettings.nomsg.dump(fdump);
|
mSettings.nomsg.dump(fdump);
|
||||||
}
|
}
|
||||||
tokens1.removeComments();
|
tokens1.removeComments();
|
||||||
|
@ -409,7 +412,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// dump xml if --dump
|
// dump xml if --dump
|
||||||
if (mSettings.dump && fdump.is_open()) {
|
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open()) {
|
||||||
fdump << "<dump cfg=\"" << ErrorLogger::toxml(mCurrentConfig) << "\">" << std::endl;
|
fdump << "<dump cfg=\"" << ErrorLogger::toxml(mCurrentConfig) << "\">" << std::endl;
|
||||||
preprocessor.dump(fdump);
|
preprocessor.dump(fdump);
|
||||||
mTokenizer.dump(fdump);
|
mTokenizer.dump(fdump);
|
||||||
|
@ -504,9 +507,71 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
||||||
}
|
}
|
||||||
|
|
||||||
// dumped all configs, close root </dumps> element now
|
// dumped all configs, close root </dumps> element now
|
||||||
if (mSettings.dump && fdump.is_open())
|
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open())
|
||||||
fdump << "</dumps>" << std::endl;
|
fdump << "</dumps>" << std::endl;
|
||||||
|
|
||||||
|
if (!mSettings.addons.empty()) {
|
||||||
|
fdump.close();
|
||||||
|
|
||||||
|
for (const std::string &addon : mSettings.addons) {
|
||||||
|
const std::string &results = executeAddon(addon, dumpFile);
|
||||||
|
for (std::string::size_type pos = 0; pos < results.size();) {
|
||||||
|
const std::string::size_type pos2 = results.find("\n", pos);
|
||||||
|
if (pos2 == std::string::npos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const std::string::size_type pos1 = pos;
|
||||||
|
pos = pos2 + 1;
|
||||||
|
|
||||||
|
if (pos1 + 5 > pos2)
|
||||||
|
continue;
|
||||||
|
if (results[pos1] != '[')
|
||||||
|
continue;
|
||||||
|
if (results[pos2-1] != ']')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::string line = results.substr(pos1, pos2-pos1);
|
||||||
|
|
||||||
|
const std::string::size_type loc1 = 1;
|
||||||
|
const std::string::size_type loc2 = line.find(':');
|
||||||
|
const std::string::size_type loc3 = line.find("]: (");
|
||||||
|
if (loc2 == std::string::npos || loc3 == std::string::npos)
|
||||||
|
continue;
|
||||||
|
if (!(loc1 < loc2 && loc2 < loc3))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::string::size_type sev1 = loc3 + 4;
|
||||||
|
const std::string::size_type sev2 = line.find(")", sev1);
|
||||||
|
if (sev2 == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::string::size_type id1 = line.rfind("[" + addon + "-");
|
||||||
|
if (id1 == std::string::npos || id1 < loc3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ErrorLogger::ErrorMessage errmsg;
|
||||||
|
|
||||||
|
const std::string filename = line.substr(loc1, loc2-loc1);
|
||||||
|
const int lineNumber = std::atoi(line.c_str() + loc2 + 1);
|
||||||
|
errmsg._callStack.emplace_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber));
|
||||||
|
|
||||||
|
errmsg._id = line.substr(id1+1, line.size()-id1-2);
|
||||||
|
std::string text = line.substr(loc3 + 11, id1 - loc3 - 11);
|
||||||
|
if (text[0] == ' ')
|
||||||
|
text = text.substr(1);
|
||||||
|
if (endsWith(text, " ", 1))
|
||||||
|
text = text.erase(text.size() - 1);
|
||||||
|
errmsg.setmsg(text);
|
||||||
|
errmsg._severity = Severity::fromString(line.substr(sev1, sev2-sev1));
|
||||||
|
if (errmsg._severity == Severity::SeverityType::none)
|
||||||
|
continue;
|
||||||
|
errmsg.file0 = filename;
|
||||||
|
|
||||||
|
reportErr(errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
internalError(filename, e.what());
|
internalError(filename, e.what());
|
||||||
} catch (const std::bad_alloc &e) {
|
} catch (const std::bad_alloc &e) {
|
||||||
|
@ -879,6 +944,27 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CppCheck::executeAddon(const std::string &addon, const std::string &dumpFile)
|
||||||
|
{
|
||||||
|
const std::string addonFile = "addons/" + addon + ".py";
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
return "";
|
||||||
|
#else
|
||||||
|
const std::string cmd = "python " + addonFile + " --cli " + dumpFile;
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
std::string result;
|
||||||
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||||
|
if (!pipe)
|
||||||
|
return "";
|
||||||
|
while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) {
|
||||||
|
result += buffer;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Settings &CppCheck::settings()
|
Settings &CppCheck::settings()
|
||||||
{
|
{
|
||||||
return mSettings;
|
return mSettings;
|
||||||
|
|
|
@ -179,6 +179,12 @@ private:
|
||||||
*/
|
*/
|
||||||
void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer);
|
void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Execute a given addon
|
||||||
|
* @return results in std::string
|
||||||
|
*/
|
||||||
|
std::string executeAddon(const std::string &addon, const std::string &dumpFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Errors and warnings are directed here.
|
* @brief Errors and warnings are directed here.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1017,7 +1017,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
else if (strcmp(node->Name(), AnalyzeAllVsConfigsElementName) == 0)
|
else if (strcmp(node->Name(), AnalyzeAllVsConfigsElementName) == 0)
|
||||||
; // FIXME: Write some warning
|
; // FIXME: Write some warning
|
||||||
else if (strcmp(node->Name(), AddonsElementName) == 0)
|
else if (strcmp(node->Name(), AddonsElementName) == 0)
|
||||||
node->Attribute(AddonElementName); // FIXME: Handle addons
|
temp.addons = readXmlStringList(node, AddonElementName, nullptr);
|
||||||
else if (strcmp(node->Name(), TagsElementName) == 0)
|
else if (strcmp(node->Name(), TagsElementName) == 0)
|
||||||
node->Attribute(TagElementName); // FIXME: Write some warning
|
node->Attribute(TagElementName); // FIXME: Write some warning
|
||||||
else if (strcmp(node->Name(), ToolsElementName) == 0)
|
else if (strcmp(node->Name(), ToolsElementName) == 0)
|
||||||
|
@ -1030,6 +1030,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
settings->includePaths = temp.includePaths;
|
settings->includePaths = temp.includePaths;
|
||||||
settings->userDefines = temp.userDefines;
|
settings->userDefines = temp.userDefines;
|
||||||
settings->userUndefs = temp.userUndefs;
|
settings->userUndefs = temp.userUndefs;
|
||||||
|
settings->addons = temp.addons;
|
||||||
for (const std::string &path : paths)
|
for (const std::string &path : paths)
|
||||||
guiProject.pathNames.push_back(path);
|
guiProject.pathNames.push_back(path);
|
||||||
for (const std::string &supp : suppressions)
|
for (const std::string &supp : suppressions)
|
||||||
|
|
|
@ -277,6 +277,8 @@ public:
|
||||||
*/
|
*/
|
||||||
std::list<Rule> rules;
|
std::list<Rule> rules;
|
||||||
|
|
||||||
|
std::list<std::string> addons;
|
||||||
|
|
||||||
/** Is the 'configuration checking' wanted? */
|
/** Is the 'configuration checking' wanted? */
|
||||||
bool checkConfiguration;
|
bool checkConfiguration;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue