misra: the user must provide the rule texts in text file.
This commit is contained in:
parent
e65a5529ad
commit
588ec80122
|
@ -5,7 +5,6 @@
|
||||||
# Example usage of this addon (scan a sourcefile main.cpp)
|
# Example usage of this addon (scan a sourcefile main.cpp)
|
||||||
# cppcheck --dump main.cpp
|
# cppcheck --dump main.cpp
|
||||||
# python misra.py --rule-texts=<path-to-rule-texts> main.cpp.dump
|
# python misra.py --rule-texts=<path-to-rule-texts> main.cpp.dump
|
||||||
# python misra.py --misra-pdf=<path-to-misra.pdf> main.cpp.dump
|
|
||||||
#
|
#
|
||||||
# Limitations: This addon is released as open source. Rule texts can't be freely
|
# Limitations: This addon is released as open source. Rule texts can't be freely
|
||||||
# distributed. https://www.misra.org.uk/forum/viewtopic.php?f=56&t=1189
|
# distributed. https://www.misra.org.uk/forum/viewtopic.php?f=56&t=1189
|
||||||
|
@ -36,8 +35,10 @@ def reportError(location, num1, num2):
|
||||||
id = 'misra-c2012-' + str(num1) + '.' + str(num2)
|
id = 'misra-c2012-' + str(num1) + '.' + str(num2)
|
||||||
if num in ruleTexts:
|
if num in ruleTexts:
|
||||||
errmsg = ruleTexts[num] + ' [' + id + ']'
|
errmsg = ruleTexts[num] + ' [' + id + ']'
|
||||||
|
elif len(ruleTexts) == 0:
|
||||||
|
errmsg = 'misra violation (use --rule-texts=<file> to get proper output) [' + id + ']'
|
||||||
else:
|
else:
|
||||||
errmsg = 'misra violation (use --misra-pdf=<file> or --rule-texts=<file> to get proper output) [' + id + ']'
|
return
|
||||||
sys.stderr.write('[' + location.file + ':' + str(location.linenr) + '] (style): ' + errmsg + '\n')
|
sys.stderr.write('[' + location.file + ':' + str(location.linenr) + '] (style): ' + errmsg + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1106,24 +1107,6 @@ def loadRuleTexts(filename):
|
||||||
ruleTexts[num] = ruleTexts[num] + ' ' + line
|
ruleTexts[num] = ruleTexts[num] + ' ' + line
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def loadRuleTextsFromPdf(filename):
|
|
||||||
if not os.path.isfile(filename):
|
|
||||||
print('Fatal error: PDF file is not found: ' + filename)
|
|
||||||
sys.exit(1)
|
|
||||||
f = tempfile.NamedTemporaryFile(delete=False)
|
|
||||||
f.close()
|
|
||||||
#print('tempfile:' + f.name)
|
|
||||||
try:
|
|
||||||
subprocess.call(['pdftotext', filename, f.name])
|
|
||||||
except OSError as err:
|
|
||||||
print('Fatal error: Failed to execute pdftotext: ' + str(err))
|
|
||||||
sys.exit(1)
|
|
||||||
loadRuleTexts(f.name)
|
|
||||||
try:
|
|
||||||
os.remove(f.name)
|
|
||||||
except OSError as err:
|
|
||||||
print('Failed to remove temporary file ' + f.name)
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
print("""
|
print("""
|
||||||
Syntax: misra.py [OPTIONS] <dumpfiles>
|
Syntax: misra.py [OPTIONS] <dumpfiles>
|
||||||
|
@ -1132,33 +1115,25 @@ OPTIONS:
|
||||||
|
|
||||||
--rule-texts=<file> Load rule texts from plain text file.
|
--rule-texts=<file> Load rule texts from plain text file.
|
||||||
|
|
||||||
If you have the tool 'pdftotext' you can generate
|
If you have the tool 'pdftotext' you might be able
|
||||||
this textfile with such command:
|
to generate this textfile with such command:
|
||||||
|
|
||||||
$ pdftotext MISRA_C_2012.pdf MISRA_C_2012.txt
|
$ pdftotext MISRA_C_2012.pdf MISRA_C_2012.txt
|
||||||
|
|
||||||
Otherwise you can more or less copy/paste the chapter
|
Otherwise you can more or less copy/paste the chapter
|
||||||
Appendix A Summary of guidelines
|
Appendix A Summary of guidelines
|
||||||
from the MISRA pdf.
|
from the MISRA pdf. You can buy the MISRA pdf from
|
||||||
|
http://www.misra.org.uk/
|
||||||
|
|
||||||
Format:
|
Format:
|
||||||
|
|
||||||
<..arbitrary text..>
|
<..arbitrary text..>
|
||||||
Appendix A Summary of guidelines
|
Appendix A Summary of guidelines
|
||||||
Dir 1.1
|
Rule 1.1
|
||||||
Rule text for 1.1
|
Rule text for 1.1
|
||||||
Dir 1.2
|
Rule 1.2
|
||||||
Rule text for 1.2
|
Rule text for 1.2
|
||||||
<...>
|
<...>
|
||||||
|
|
||||||
--misra-pdf=<file> Misra PDF file that rule texts will be extracted from.
|
|
||||||
|
|
||||||
The tool 'pdftotext' from xpdf is used and must be installed.
|
|
||||||
Debian: sudo apt-get install xpdf
|
|
||||||
Windows: http://gnuwin32.sourceforge.net/packages/xpdf.htm
|
|
||||||
|
|
||||||
If you don't have 'pdftotext' and don't want to install it then
|
|
||||||
you can use --rule-texts=<file>.
|
|
||||||
""")
|
""")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
@ -1171,8 +1146,6 @@ for arg in sys.argv[1:]:
|
||||||
print('Fatal error: file is not found: ' + filename)
|
print('Fatal error: file is not found: ' + filename)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
loadRuleTexts(filename)
|
loadRuleTexts(filename)
|
||||||
elif arg.startswith('--misra-pdf='):
|
|
||||||
loadRuleTextsFromPdf(arg[12:])
|
|
||||||
elif ".dump" in arg:
|
elif ".dump" in arg:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -152,6 +152,7 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent)
|
||||||
connect(mUI.mBtnIncludeDown, &QPushButton::clicked, this, &ProjectFileDialog::moveIncludePathDown);
|
connect(mUI.mBtnIncludeDown, &QPushButton::clicked, this, &ProjectFileDialog::moveIncludePathDown);
|
||||||
connect(mUI.mBtnAddSuppression, &QPushButton::clicked, this, &ProjectFileDialog::addSuppression);
|
connect(mUI.mBtnAddSuppression, &QPushButton::clicked, this, &ProjectFileDialog::addSuppression);
|
||||||
connect(mUI.mBtnRemoveSuppression, &QPushButton::clicked, this, &ProjectFileDialog::removeSuppression);
|
connect(mUI.mBtnRemoveSuppression, &QPushButton::clicked, this, &ProjectFileDialog::removeSuppression);
|
||||||
|
connect(mUI.mBtnBrowseMisraFile, &QPushButton::clicked, this, &ProjectFileDialog::browseMisraFile);
|
||||||
|
|
||||||
loadFromProjectFile(projectFile);
|
loadFromProjectFile(projectFile);
|
||||||
}
|
}
|
||||||
|
@ -177,6 +178,7 @@ void ProjectFileDialog::saveSettings() const
|
||||||
|
|
||||||
static void updateAddonCheckBox(QCheckBox *cb, const ProjectFile *projectFile, const QString &dataDir, const QString &addon)
|
static void updateAddonCheckBox(QCheckBox *cb, const ProjectFile *projectFile, const QString &dataDir, const QString &addon)
|
||||||
{
|
{
|
||||||
|
if (projectFile)
|
||||||
cb->setChecked(projectFile->getAddons().contains(addon));
|
cb->setChecked(projectFile->getAddons().contains(addon));
|
||||||
if (CheckThread::getAddonFilePath(dataDir, addon + ".py").isEmpty()) {
|
if (CheckThread::getAddonFilePath(dataDir, addon + ".py").isEmpty()) {
|
||||||
cb->setEnabled(false);
|
cb->setEnabled(false);
|
||||||
|
@ -231,6 +233,16 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
|
||||||
updateAddonCheckBox(mUI.mAddonCert, projectFile, dataDir, "cert");
|
updateAddonCheckBox(mUI.mAddonCert, projectFile, dataDir, "cert");
|
||||||
updateAddonCheckBox(mUI.mAddonMisra, projectFile, dataDir, "misra");
|
updateAddonCheckBox(mUI.mAddonMisra, projectFile, dataDir, "misra");
|
||||||
|
|
||||||
|
const QString &misraFile = settings.value(SETTINGS_MISRA_FILE, QString()).toString();
|
||||||
|
mUI.mEditMisraFile->setText(misraFile);
|
||||||
|
if (!mUI.mAddonMisra->isEnabled()) {
|
||||||
|
mUI.mEditMisraFile->setEnabled(false);
|
||||||
|
mUI.mBtnBrowseMisraFile->setEnabled(false);
|
||||||
|
} else if (misraFile.isEmpty()) {
|
||||||
|
mUI.mAddonMisra->setEnabled(false);
|
||||||
|
mUI.mAddonMisra->setText(mUI.mAddonMisra->text() + ' ' + tr("(no rule texts file)"));
|
||||||
|
}
|
||||||
|
|
||||||
mUI.mToolClangAnalyzer->setChecked(projectFile->getClangAnalyzer());
|
mUI.mToolClangAnalyzer->setChecked(projectFile->getClangAnalyzer());
|
||||||
mUI.mToolClangTidy->setChecked(projectFile->getClangTidy());
|
mUI.mToolClangTidy->setChecked(projectFile->getClangTidy());
|
||||||
if (CheckThread::clangTidyCmd().isEmpty()) {
|
if (CheckThread::clangTidyCmd().isEmpty()) {
|
||||||
|
@ -658,3 +670,17 @@ void ProjectFileDialog::removeSuppression()
|
||||||
QListWidgetItem *item = mUI.mListSuppressions->takeItem(row);
|
QListWidgetItem *item = mUI.mListSuppressions->takeItem(row);
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectFileDialog::browseMisraFile()
|
||||||
|
{
|
||||||
|
const QString fileName = QFileDialog::getOpenFileName(this, tr("Select MISRA rule texts file"), QDir::homePath(), tr("Misra rule texts file (%1)").arg("*.txt"));
|
||||||
|
if (!fileName.isEmpty()) {
|
||||||
|
QSettings settings;
|
||||||
|
mUI.mEditMisraFile->setText(fileName);
|
||||||
|
settings.setValue(SETTINGS_MISRA_FILE, fileName);
|
||||||
|
|
||||||
|
mUI.mAddonMisra->setText("MISRA C 2012");
|
||||||
|
mUI.mAddonMisra->setEnabled(true);
|
||||||
|
updateAddonCheckBox(mUI.mAddonMisra, nullptr, settings.value("DATADIR", QString()).toString(), "misra");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -230,6 +230,11 @@ protected slots:
|
||||||
*/
|
*/
|
||||||
void removeSuppression();
|
void removeSuppression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Browse for misra file
|
||||||
|
*/
|
||||||
|
void browseMisraFile();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>642</width>
|
<width>642</width>
|
||||||
<height>507</height>
|
<height>549</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="mTabPathsAndDefines">
|
<widget class="QWidget" name="mTabPathsAndDefines">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
|
@ -524,6 +524,31 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Misra rule texts</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="mEditMisraFile">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="mBtnBrowseMisraFile">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -317,12 +317,16 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Misra PDF/Text file</string>
|
<string>Misra rule texts file</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="mEditMisraFile"/>
|
<widget class="QLineEdit" name="mEditMisraFile">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="mBtnBrowseMisraFile">
|
<widget class="QPushButton" name="mBtnBrowseMisraFile">
|
||||||
|
|
Loading…
Reference in New Issue