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_EXPECTED = []
|
||||
VERIFY_ACTUAL = []
|
||||
CLI = False
|
||||
|
||||
def reportError(token, severity, msg, id):
|
||||
if VERIFY:
|
||||
VERIFY_ACTUAL.append(str(token.linenr) + ':' + id)
|
||||
else:
|
||||
sys.stderr.write(
|
||||
'[' + token.file + ':' + str(token.linenr) + '] (' + severity + '): ' + msg + ' [' + id + ']\n')
|
||||
msg = '[' + token.file + ':' + str(token.linenr) + ']: (' + severity + ') ' + msg + ' [' + id + ']'
|
||||
if CLI:
|
||||
print(msg)
|
||||
else:
|
||||
sys.stderr.write(msg + '\n')
|
||||
|
||||
def simpleMatch(token, pattern):
|
||||
for p in pattern.split(' '):
|
||||
|
@ -239,6 +243,9 @@ for arg in sys.argv[1:]:
|
|||
if arg == '-verify':
|
||||
VERIFY = True
|
||||
continue
|
||||
if arg == '--cli':
|
||||
CLI = True
|
||||
continue
|
||||
print('Checking ' + arg + '...')
|
||||
data = cppcheckdata.parsedump(arg)
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ typeBits = {
|
|||
VERIFY = False
|
||||
QUIET = False
|
||||
SHOW_SUMMARY = True
|
||||
CLI = False # Executed by Cppcheck binary?
|
||||
|
||||
def printStatus(*args, **kwargs):
|
||||
if not QUIET:
|
||||
|
@ -1964,8 +1965,11 @@ class MisraChecker:
|
|||
errorId = id,
|
||||
suppressions = self.dumpfileSuppressions)
|
||||
if formattedMsg:
|
||||
sys.stderr.write(formattedMsg)
|
||||
sys.stderr.write('\n')
|
||||
if CLI:
|
||||
print(formattedMsg)
|
||||
else:
|
||||
sys.stderr.write(formattedMsg)
|
||||
sys.stderr.write('\n')
|
||||
if not severity in self.violations:
|
||||
self.violations[severity] = []
|
||||
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("--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("--cli", help="Addon is executed from Cppcheck", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
checker = MisraChecker()
|
||||
|
@ -2215,6 +2220,10 @@ else:
|
|||
if args.file_prefix:
|
||||
checker.setFilePrefix(args.file_prefix)
|
||||
|
||||
if args.cli:
|
||||
CLI = True
|
||||
QUIET = True
|
||||
SHOW_SUMMARY = False
|
||||
if args.quiet:
|
||||
QUIET = True
|
||||
if args.no_summary:
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <iostream> // <- TEMPORARY
|
||||
|
||||
#ifdef HAVE_RULES
|
||||
#define PCRE_STATIC
|
||||
|
@ -216,9 +218,10 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
|
||||
// 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);
|
||||
std::string dumpFile;
|
||||
if (mSettings.dump || !mSettings.addons.empty()) {
|
||||
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;
|
||||
|
@ -247,7 +250,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
|
||||
// Parse comments and then remove them
|
||||
preprocessor.inlineSuppressions(tokens1);
|
||||
if (mSettings.dump && fdump.is_open()) {
|
||||
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open()) {
|
||||
mSettings.nomsg.dump(fdump);
|
||||
}
|
||||
tokens1.removeComments();
|
||||
|
@ -409,7 +412,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
continue;
|
||||
|
||||
// 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;
|
||||
preprocessor.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
|
||||
if (mSettings.dump && fdump.is_open())
|
||||
if ((mSettings.dump || !mSettings.addons.empty()) && fdump.is_open())
|
||||
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) {
|
||||
internalError(filename, e.what());
|
||||
} catch (const std::bad_alloc &e) {
|
||||
|
@ -879,6 +944,27 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token
|
|||
#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()
|
||||
{
|
||||
return mSettings;
|
||||
|
|
|
@ -179,6 +179,12 @@ private:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -1017,7 +1017,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
|||
else if (strcmp(node->Name(), AnalyzeAllVsConfigsElementName) == 0)
|
||||
; // FIXME: Write some warning
|
||||
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)
|
||||
node->Attribute(TagElementName); // FIXME: Write some warning
|
||||
else if (strcmp(node->Name(), ToolsElementName) == 0)
|
||||
|
@ -1030,6 +1030,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
|||
settings->includePaths = temp.includePaths;
|
||||
settings->userDefines = temp.userDefines;
|
||||
settings->userUndefs = temp.userUndefs;
|
||||
settings->addons = temp.addons;
|
||||
for (const std::string &path : paths)
|
||||
guiProject.pathNames.push_back(path);
|
||||
for (const std::string &supp : suppressions)
|
||||
|
|
|
@ -277,6 +277,8 @@ public:
|
|||
*/
|
||||
std::list<Rule> rules;
|
||||
|
||||
std::list<std::string> addons;
|
||||
|
||||
/** Is the 'configuration checking' wanted? */
|
||||
bool checkConfiguration;
|
||||
|
||||
|
|
Loading…
Reference in New Issue