File indexing completed on 2024-05-12 05:51:45
0001 /* This file is part of the Kate project. 0002 * 0003 * SPDX-FileCopyrightText: 2018 Gregor Mi <codestruct@posteo.org> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "shellcheck.h" 0009 #include "kateproject.h" 0010 0011 #include <KLocalizedString> 0012 #include <QRegularExpression> 0013 0014 KateProjectCodeAnalysisToolShellcheck::KateProjectCodeAnalysisToolShellcheck(QObject *parent) 0015 : KateProjectCodeAnalysisTool(parent) 0016 { 0017 } 0018 0019 KateProjectCodeAnalysisToolShellcheck::~KateProjectCodeAnalysisToolShellcheck() 0020 { 0021 } 0022 0023 QString KateProjectCodeAnalysisToolShellcheck::name() const 0024 { 0025 return i18n("ShellCheck (sh/bash)"); 0026 } 0027 0028 QString KateProjectCodeAnalysisToolShellcheck::description() const 0029 { 0030 return i18n("ShellCheck is a static analysis and linting tool for sh/bash scripts"); 0031 } 0032 0033 QString KateProjectCodeAnalysisToolShellcheck::fileExtensions() const 0034 { 0035 // TODO: How to also handle files with no file extension? 0036 return QStringLiteral("sh|bash"); 0037 } 0038 0039 QStringList KateProjectCodeAnalysisToolShellcheck::filter(const QStringList &files) const 0040 { 0041 // for now we expect files with extension 0042 return files.filter(QRegularExpression(QStringLiteral("\\.(") + fileExtensions() + QStringLiteral(")$"))); 0043 } 0044 0045 QString KateProjectCodeAnalysisToolShellcheck::path() const 0046 { 0047 return QStringLiteral("shellcheck"); 0048 } 0049 0050 QStringList KateProjectCodeAnalysisToolShellcheck::arguments() 0051 { 0052 QStringList _args; 0053 0054 // shellcheck --format=gcc script.sh 0055 // Example output: 0056 // script.sh:2:12: note: Use ./*glob* or -- *glob* so names with dashes won't become options. [SC2035] 0057 // script.sh:3:11: note: Use ./*glob* or -- *glob* so names with dashes won't become options. [SC2035] 0058 // script.sh:3:20: warning: podir is referenced but not assigned. [SC2154] 0059 // script.sh:3:20: note: Double quote to prevent globbing and word splitting. [SC2086] 0060 0061 _args << QStringLiteral("--format=gcc"); 0062 0063 if (m_project) { 0064 auto &&fileList = filter(m_project->files()); 0065 setActualFilesCount(fileList.size()); 0066 _args.append(fileList); 0067 } 0068 0069 return _args; 0070 } 0071 0072 QString KateProjectCodeAnalysisToolShellcheck::notInstalledMessage() const 0073 { 0074 return i18n("Please install ShellCheck (see https://www.shellcheck.net)."); 0075 } 0076 0077 FileDiagnostics KateProjectCodeAnalysisToolShellcheck::parseLine(const QString &line) const 0078 { 0079 // Example: 0080 // IN: 0081 // script.sh:3:11: note: Use ./*glob* or -- *glob* so names with dashes won't become options. [SC2035] 0082 // OUT: 0083 // file, line, severity, message 0084 // "script.sh", "3", "note", "... ..." 0085 0086 static const QRegularExpression regex(QStringLiteral("([^:]+):(\\d+):\\d+: (\\w+): (.*)")); 0087 QRegularExpressionMatch match = regex.match(line); 0088 QStringList elements = match.capturedTexts(); 0089 elements.erase(elements.begin()); // remove first element 0090 if (elements.size() != 4) { 0091 // if parsing fails we clear the list 0092 return {}; 0093 } 0094 0095 const auto url = QUrl::fromLocalFile(elements[0]); 0096 Diagnostic d; 0097 d.message = elements[3]; 0098 d.severity = DiagnosticSeverity::Warning; 0099 int ln = elements[1].toInt() - 1; 0100 d.range = KTextEditor::Range(ln, 0, ln, -1); 0101 return {url, {d}}; 0102 } 0103 0104 bool KateProjectCodeAnalysisToolShellcheck::isSuccessfulExitCode(int exitCode) const 0105 { 0106 // "0: All files successfully scanned with no issues." 0107 // "1: All files successfully scanned with some issues." 0108 return exitCode == 0 || exitCode == 1; 0109 } 0110 0111 QString KateProjectCodeAnalysisToolShellcheck::stdinMessages() 0112 { 0113 return QString(); 0114 }