Warning, file /kdevelop/kdevelop/kdevplatform/outputview/outputfilteringstrategies.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2012 Morten Danielsen Volden <mvolden2@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "outputfilteringstrategies.h"
0008 #include "outputformats.h"
0009 #include "filtereditem.h"
0010 #include <util/path.h>
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <QFileInfo>
0015 
0016 #include <algorithm>
0017 
0018 namespace KDevelop
0019 {
0020 void initializeFilteredItem(FilteredItem& item, const ErrorFormat& filter, const QRegularExpressionMatch& match)
0021 {
0022     item.lineNo = match.capturedRef(filter.lineGroup).toInt() - 1;
0023     item.columnNo = filter.columnNumber(match);
0024 }
0025 
0026 
0027 template<typename ErrorFormats>
0028 FilteredItem match(const ErrorFormats& errorFormats, const QString& line)
0029 {
0030     FilteredItem item(line);
0031     for( const ErrorFormat& curErrFilter : errorFormats ) {
0032         const auto match = curErrFilter.expression.match(line);
0033         if( match.hasMatch() ) {
0034             initializeFilteredItem(item, curErrFilter, match);
0035             item.url = QUrl::fromUserInput(match.captured( curErrFilter.fileGroup ));
0036 
0037             item.type = FilteredItem::ErrorItem;
0038 
0039             // Make the item clickable if it comes with the necessary file & line number information
0040             if (curErrFilter.fileGroup > 0 && curErrFilter.lineGroup > 0) {
0041                 item.isActivatable = true;
0042             }
0043             break;
0044         }
0045     }
0046     return item;
0047 }
0048 
0049 /// --- No filter strategy ---
0050 
0051 NoFilterStrategy::NoFilterStrategy()
0052 {
0053 }
0054 
0055 FilteredItem NoFilterStrategy::actionInLine(const QString& line)
0056 {
0057     return FilteredItem( line );
0058 }
0059 
0060 FilteredItem NoFilterStrategy::errorInLine(const QString& line)
0061 {
0062     return FilteredItem( line );
0063 }
0064 
0065 /// --- Compiler error filter strategy ---
0066 
0067 /// Impl. of CompilerFilterStrategy.
0068 class CompilerFilterStrategyPrivate
0069 {
0070 public:
0071     explicit CompilerFilterStrategyPrivate(const QUrl& buildDir);
0072     Path pathForFile( const QString& ) const;
0073     bool isMultiLineCase(const ErrorFormat& curErrFilter) const;
0074     void putDirAtEnd(const Path& pathToInsert);
0075 
0076     QVector<Path> m_currentDirs;
0077     Path m_buildDir;
0078 
0079     using PositionMap = QHash<Path, int>;
0080     PositionMap m_positionInCurrentDirs;
0081 };
0082 
0083 CompilerFilterStrategyPrivate::CompilerFilterStrategyPrivate(const QUrl& buildDir)
0084     : m_buildDir(buildDir)
0085 {
0086 }
0087 
0088 Path CompilerFilterStrategyPrivate::pathForFile(const QString& filename) const
0089 {
0090     QFileInfo fi( filename );
0091     Path currentPath;
0092     if( fi.isRelative() ) {
0093         if( m_currentDirs.isEmpty() ) {
0094             return Path(m_buildDir, filename );
0095         }
0096 
0097         auto it = m_currentDirs.constEnd() - 1;
0098         do {
0099             currentPath = Path(*it, filename);
0100         } while( (it-- !=  m_currentDirs.constBegin()) && !QFileInfo::exists(currentPath.toLocalFile()) );
0101 
0102         return currentPath;
0103     } else {
0104         currentPath = Path(filename);
0105     }
0106     return currentPath;
0107 }
0108 
0109 bool CompilerFilterStrategyPrivate::isMultiLineCase(const KDevelop::ErrorFormat& curErrFilter) const
0110 {
0111     if(curErrFilter.compiler == QLatin1String("gfortran") || curErrFilter.compiler == QLatin1String("cmake")) {
0112         return true;
0113     }
0114     return false;
0115 }
0116 
0117 void CompilerFilterStrategyPrivate::putDirAtEnd(const Path& pathToInsert)
0118 {
0119     CompilerFilterStrategyPrivate::PositionMap::iterator it = m_positionInCurrentDirs.find( pathToInsert );
0120     // Encountered new build directory?
0121     if (it == m_positionInCurrentDirs.end()) {
0122         m_currentDirs.push_back( pathToInsert );
0123         m_positionInCurrentDirs.insert( pathToInsert, m_currentDirs.size() - 1 );
0124     } else {
0125         // Build dir already in currentDirs, but move it to back of currentDirs list
0126         // (this gives us most-recently-used semantics in pathForFile)
0127         std::rotate(m_currentDirs.begin() + it.value(), m_currentDirs.begin() + it.value() + 1, m_currentDirs.end() );
0128         it.value() = m_currentDirs.size() - 1;
0129     }
0130 }
0131 
0132 CompilerFilterStrategy::CompilerFilterStrategy(const QUrl& buildDir)
0133     : d_ptr(new CompilerFilterStrategyPrivate(buildDir))
0134 {
0135 }
0136 
0137 CompilerFilterStrategy::~CompilerFilterStrategy() = default;
0138 
0139 QVector<QString> CompilerFilterStrategy::currentDirs() const
0140 {
0141     Q_D(const CompilerFilterStrategy);
0142 
0143     QVector<QString> ret;
0144     ret.reserve(d->m_currentDirs.size());
0145     for (const auto& path : qAsConst(d->m_currentDirs)) {
0146         ret << path.pathOrUrl();
0147     }
0148     return ret;
0149 }
0150 
0151 FilteredItem CompilerFilterStrategy::actionInLine(const QString& line)
0152 {
0153     Q_D(CompilerFilterStrategy);
0154 
0155     // A list of filters for possible compiler, linker, and make actions
0156     static const ActionFormat ACTION_FILTERS[] = {
0157         ActionFormat( 2,
0158                       QStringLiteral("(?:^|[^=])\\b(gcc|CC|cc|distcc|c\\+\\+|g\\+\\+|clang(?:\\+\\+)|mpicc|icc|icpc)\\s+.*-c.*[/ '\\\\]+(\\w+\\.(?:cpp|CPP|c|C|cxx|CXX|cs|java|hpf|f|F|f90|F90|f95|F95))")),
0159         //moc and uic
0160         ActionFormat( 2, QStringLiteral("/(moc|uic)\\b.*\\s-o\\s([^\\s;]+)")),
0161         //libtool linking
0162         ActionFormat( QStringLiteral("libtool"), QStringLiteral("/bin/sh\\s.*libtool.*--mode=link\\s.*\\s-o\\s([^\\s;]+)"), 1 ),
0163         //unsermake
0164         ActionFormat( 1, QStringLiteral("^compiling (.*)") ),
0165         ActionFormat( 2, QStringLiteral("^generating (.*)") ),
0166         ActionFormat( 2, QStringLiteral("(gcc|cc|c\\+\\+|g\\+\\+|clang(?:\\+\\+)|mpicc|icc|icpc)\\S* (?:\\S* )*-o ([^\\s;]+)")),
0167         ActionFormat( 2, QStringLiteral("^linking (.*)") ),
0168         //cmake
0169         ActionFormat( 1, QStringLiteral("\\[.+%\\] Built target (.*)") ),
0170         ActionFormat( QStringLiteral("cmake"),
0171                       QStringLiteral("\\[.+%\\] Building .* object (.*)"), 1 ),
0172         ActionFormat( 1, QStringLiteral("\\[.+%\\] Generating (.*)") ),
0173         ActionFormat( 1, QStringLiteral("^Linking (.*)") ),
0174         ActionFormat( QStringLiteral("cmake"),
0175                       QStringLiteral("(-- (?:Configuring|Generating) (?:done|incomplete)|-- Found|-- Adding|-- Enabling)"), -1 ),
0176         ActionFormat( 1, QStringLiteral("-- Installing (.*)") ),
0177         //cmake - cd - filter for project directory
0178         ActionFormat( QStringLiteral("cd"),
0179                       QStringLiteral("cmake(?:\\.exe|\\.bat)? (?:.*?) ((?:[A-Za-z]:|/).*$)"), 1),
0180         //libtool install
0181         ActionFormat( {},
0182                       QStringLiteral("/(?:bin/sh\\s.*mkinstalldirs).*\\s([^\\s;]+)"), 1 ),
0183         ActionFormat( {},
0184                       QStringLiteral("/(?:usr/bin/install|bin/sh\\s.*mkinstalldirs|bin/sh\\s.*libtool.*--mode=install).*\\s([^\\s;]+)"), 1 ),
0185         //dcop
0186         ActionFormat( QStringLiteral("dcopidl"),
0187                       QStringLiteral("dcopidl .* > ([^\\s;]+)"), 1 ),
0188         ActionFormat( QStringLiteral("dcopidl2cpp"),
0189                       QStringLiteral("dcopidl2cpp (?:\\S* )*([^\\s;]+)"), 1 ),
0190         // match against Entering directory to update current build dir
0191         ActionFormat( QStringLiteral("cd"),
0192                       QStringLiteral("make\\[\\d+\\]: Entering directory (\\`|\\')(.+)'"), 2),
0193         // waf and scons use the same basic convention as make
0194         ActionFormat( QStringLiteral("cd"),
0195                       QStringLiteral("(Waf|scons): Entering directory (\\`|\\')(.+)'"), 3)
0196     };
0197 
0198     FilteredItem item(line);
0199     for (const auto& curActFilter : ACTION_FILTERS) {
0200         const auto match = curActFilter.expression.match(line);
0201         if( match.hasMatch() ) {
0202             item.type = FilteredItem::ActionItem;
0203 
0204             if( curActFilter.tool == QLatin1String("cd") ) {
0205                 const Path path(match.captured(curActFilter.fileGroup));
0206                 d->m_currentDirs.push_back( path );
0207                 d->m_positionInCurrentDirs.insert( path , d->m_currentDirs.size() - 1 );
0208             }
0209 
0210             // Special case for cmake: we parse the "Compiling <objectfile>" expression
0211             // and use it to find out about the build paths encountered during a build.
0212             // They are later searched by pathForFile to find source files corresponding to
0213             // compiler errors.
0214             // Note: CMake objectfile has the format: "/path/to/four/CMakeFiles/file.o"
0215             if ( curActFilter.fileGroup != -1 && curActFilter.tool == QLatin1String("cmake") && line.contains(QLatin1String("Building"))) {
0216                 const auto objectFile = match.captured(curActFilter.fileGroup);
0217                 const auto dir = objectFile.section(QStringLiteral("CMakeFiles/"), 0, 0);
0218                 d->putDirAtEnd(Path(d->m_buildDir, dir));
0219             }
0220             break;
0221         }
0222     }
0223     return item;
0224 }
0225 
0226 FilteredItem CompilerFilterStrategy::errorInLine(const QString& line)
0227 {
0228     Q_D(CompilerFilterStrategy);
0229 
0230     // All the possible string that indicate an error if we via Regex have been able to
0231     // extract file and linenumber from a given outputline
0232     // TODO: This seems clumsy -- and requires another scan of the line.
0233     // Merge this information into ErrorFormat? --Kevin
0234     using Indicator = QPair<QString, FilteredItem::FilteredOutputItemType>;
0235     static const Indicator INDICATORS[] = {
0236         // ld
0237         Indicator(QStringLiteral("undefined reference"), FilteredItem::ErrorItem),
0238         Indicator(QStringLiteral("undefined symbol"), FilteredItem::ErrorItem),
0239         Indicator(QStringLiteral("ld: cannot find"), FilteredItem::ErrorItem),
0240         Indicator(QStringLiteral("no such file"), FilteredItem::ErrorItem),
0241         // gcc
0242         Indicator(QStringLiteral("error"), FilteredItem::ErrorItem),
0243         // generic
0244         Indicator(QStringLiteral("warning"), FilteredItem::WarningItem),
0245         Indicator(QStringLiteral("info"), FilteredItem::InformationItem),
0246         Indicator(QStringLiteral("note"), FilteredItem::InformationItem),
0247     };
0248 
0249     // A list of filters for possible compiler, linker, and make errors
0250     static const ErrorFormat ERROR_FILTERS[] = {
0251 #ifdef Q_OS_WIN
0252         // MSVC
0253         ErrorFormat( QStringLiteral("^([a-zA-Z]:\\\\.+)\\(([1-9][0-9]*)\\): ((?:error|warning) .+\\:).*$"), 1, 2, 3 ),
0254 #endif
0255         // GCC - another case, eg. for #include "pixmap.xpm" which does not exists
0256         ErrorFormat( QStringLiteral("^(.:?[^:\\t]+):([0-9]+):([0-9]+):([^0-9]+)"), 1, 2, 4, 3 ),
0257         // ant
0258         ErrorFormat( QStringLiteral("\\[javac\\][\\s]+([^:\\t]+):([0-9]+): (warning: .*|error: .*)"), 1, 2, 3, QStringLiteral("javac")),
0259         // GCC
0260         ErrorFormat( QStringLiteral("^(.:?[^:\\t]+):([0-9]+):([^0-9]+)"), 1, 2, 3 ),
0261         // GCC
0262         ErrorFormat( QStringLiteral("^(In file included from |[ ]+from )(..[^:\\t]+):([0-9]+)(:|,)(|[0-9]+)"), 2, 3, 5 ),
0263         // ICC
0264         ErrorFormat( QStringLiteral("^(.:?[^:\\t]+)\\(([0-9]+)\\):([^0-9]+)"), 1, 2, 3, QStringLiteral("intel") ),
0265         //libtool link
0266         ErrorFormat( QStringLiteral("^(libtool):( link):( warning): "), 0, 0, 0 ),
0267         // make
0268         ErrorFormat( QStringLiteral("No rule to make target"), 0, 0, 0 ),
0269         // cmake - multiline expression
0270         ErrorFormat( QStringLiteral("((^\\/|^[a-zA-Z]:)[\\w|\\/| |\\.]+):([0-9]+):"), 1, 2, 0, QStringLiteral("cmake") ),
0271         // cmake
0272         ErrorFormat( QStringLiteral("CMake (Error|Warning) (|\\([a-zA-Z]+\\) )(in|at) ([^:]+):($|[0-9]+)"), 4, 5, 1, QStringLiteral("cmake") ),
0273         // cmake/automoc
0274         // example: AUTOMOC: error: /foo/bar.cpp The file includes (...),
0275         // example: AUTOMOC: error: /foo/bar.cpp: The file includes (...)
0276         // note: ':' after file name isn't always appended, see https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=317d8498aa02c9f486bf5071963bb2034777cdd6
0277         // example: AUTOGEN: error: /foo/bar.cpp: The file includes (...)
0278         // note: AUTOMOC got renamed to AUTOGEN at some point
0279         ErrorFormat( QStringLiteral("^(AUTOMOC|AUTOGEN): error: (.*?) (The file .*)$"), 2, 0, 0 ),
0280         // via qt4_automoc
0281         // example: automoc4: The file "/foo/bar.cpp" includes the moc file "bar1.moc", but ...
0282         ErrorFormat( QStringLiteral("^automoc4: The file \"([^\"]+)\" includes the moc file"), 1, 0, 0 ),
0283         // Fortran
0284         ErrorFormat( QStringLiteral("\"(.*)\", line ([0-9]+):(.*)"), 1, 2, 3 ),
0285         // GFortran
0286         ErrorFormat( QStringLiteral("^(.*):([0-9]+)\\.([0-9]+):(.*)"), 1, 2, 4, QStringLiteral("gfortran"), 3 ),
0287         // Jade
0288         ErrorFormat( QStringLiteral("^[a-zA-Z]+:([^:\\t]+):([0-9]+):[0-9]+:[a-zA-Z]:(.*)"), 1, 2, 3 ),
0289         // ifort
0290         ErrorFormat( QStringLiteral("^fortcom: (.*): (.*), line ([0-9]+):(.*)"), 2, 3, 1, QStringLiteral("intel") ),
0291         // PGI
0292         ErrorFormat( QStringLiteral("PGF9(.*)-(.*)-(.*)-(.*) \\((.*): ([0-9]+)\\)"), 5, 6, 4, QStringLiteral("pgi") ),
0293         // PGI (2)
0294         ErrorFormat( QStringLiteral("PGF9(.*)-(.*)-(.*)-Symbol, (.*) \\((.*)\\)"), 5, 5, 4, QStringLiteral("pgi") ),
0295     };
0296 
0297     FilteredItem item(line);
0298     for (const auto& curErrFilter : ERROR_FILTERS) {
0299         const auto match = curErrFilter.expression.match(line);
0300         if( match.hasMatch() && !( line.contains( QLatin1String("Each undeclared identifier is reported only once") )
0301                                || line.contains( QLatin1String("for each function it appears in.") ) ) )
0302         {
0303             if(curErrFilter.fileGroup > 0) {
0304                 if( curErrFilter.compiler == QLatin1String("cmake") ) { // Unfortunately we cannot know if an error or an action comes first in cmake, and therefore we need to do this
0305                     if( d->m_currentDirs.empty() ) {
0306                         d->putDirAtEnd( d->m_buildDir.parent() );
0307                     }
0308                 }
0309                 item.url = d->pathForFile( match.captured( curErrFilter.fileGroup ) ).toUrl();
0310             }
0311             initializeFilteredItem(item, curErrFilter, match);
0312 
0313             const QStringRef txt = match.capturedRef(curErrFilter.textGroup);
0314 
0315             // Find the indicator which happens most early.
0316             int earliestIndicatorIdx = txt.length();
0317             for (const auto& curIndicator : INDICATORS) {
0318                 int curIndicatorIdx = txt.indexOf(curIndicator.first, 0, Qt::CaseInsensitive);
0319                 if((curIndicatorIdx >= 0) && (earliestIndicatorIdx > curIndicatorIdx)) {
0320                     earliestIndicatorIdx = curIndicatorIdx;
0321                     item.type = curIndicator.second;
0322                 }
0323             }
0324 
0325             // Make the item clickable if it comes with the necessary file information
0326             if (item.url.isValid()) {
0327                 item.isActivatable = true;
0328                 if(item.type == FilteredItem::InvalidItem) {
0329                     // If there are no error indicators in the line
0330                     // maybe this is a multiline case
0331                     if(d->isMultiLineCase(curErrFilter)) {
0332                         item.type = FilteredItem::ErrorItem;
0333                     } else {
0334                         // Okay so we couldn't find anything to indicate an error, but we have file and lineGroup
0335                         // Lets keep this item clickable and indicate this to the user.
0336                         item.type = FilteredItem::InformationItem;
0337                     }
0338                 }
0339             }
0340             break;
0341         }
0342     }
0343     return item;
0344 }
0345 
0346 
0347 /// --- Script error filter strategy ---
0348 
0349 ScriptErrorFilterStrategy::ScriptErrorFilterStrategy()
0350 {
0351 }
0352 
0353 FilteredItem ScriptErrorFilterStrategy::actionInLine(const QString& line)
0354 {
0355     return FilteredItem(line);
0356 }
0357 
0358 FilteredItem ScriptErrorFilterStrategy::errorInLine(const QString& line)
0359 {
0360     // A list of filters for possible Python and PHP errors
0361     static const ErrorFormat SCRIPT_ERROR_FILTERS[] = {
0362         ErrorFormat( QStringLiteral("^  File \"(.*)\", line ([0-9]+)(.*$|, in(.*)$)"), 1, 2, -1 ),
0363         ErrorFormat( QStringLiteral("^.*(/.*):([0-9]+).*$"), 1, 2, -1 ),
0364         ErrorFormat( QStringLiteral("^.* in (/.*) on line ([0-9]+).*$"), 1, 2, -1 )
0365     };
0366 
0367     return match(SCRIPT_ERROR_FILTERS, line);
0368 }
0369 
0370 /// --- Native application error filter strategy ---
0371 
0372 NativeAppErrorFilterStrategy::NativeAppErrorFilterStrategy()
0373 {
0374 }
0375 
0376 FilteredItem NativeAppErrorFilterStrategy::actionInLine(const QString& line)
0377 {
0378     return FilteredItem(line);
0379 }
0380 
0381 FilteredItem NativeAppErrorFilterStrategy::errorInLine(const QString& line)
0382 {
0383     static const ErrorFormat NATIVE_APPLICATION_ERROR_FILTERS[] = {
0384         // BEGIN: C++
0385 
0386         // assert(false)
0387         // a.out: test.cpp:5: int main(): Assertion `false' failed.
0388 
0389         // this may also match custom assert message like this one from OSM2go:
0390         // code at: /osm2go/tests/osm_edit.cpp:47: int main(): Assertion foo = bar failed: foo = 5, bar = 4
0391         // If there is a technical reason not to do so: fine. But for the moment it's easy enough to catch it.
0392         ErrorFormat(QStringLiteral("^.+: (.+):([1-9][0-9]*): .+: Assertion .+ failed"), 1, 2, -1),
0393 
0394         // assert_perror(42)
0395         // a.out: test.cpp:2009: void {anonymous}::test(): Unexpected error: Broken pipe.
0396         ErrorFormat(QStringLiteral("^.+: (.+):([1-9][0-9]*): .+: Unexpected error: "), 1, 2, -1),
0397 
0398         // END: C++
0399 
0400         // BEGIN: Qt
0401 
0402         // Note: Scan the whole line for catching Qt runtime warnings (-> no ^$)
0403         // Reasoning: With QT_MESSAGE_PATTERN you can configure the output to your desire,
0404         // which means the output could be arbitrarily prefixed or suffixed with other content
0405 
0406         // QObject::connect related errors, also see err_method_notfound() in qobject.cpp
0407         // QObject::connect: No such slot Foo::bar() in /foo/bar.cpp:313
0408         ErrorFormat(QStringLiteral("QObject::connect: (?:No such|Parentheses expected,) (?:slot|signal) [^ ]* in (.*):([0-9]+)"), 1, 2, -1),
0409         // ASSERT: "errors().isEmpty()" in file /foo/bar.cpp, line 49
0410         ErrorFormat(QStringLiteral("ASSERT: \"(.*)\" in file (.*), line ([0-9]+)"), 2, 3, -1),
0411         // Catch:
0412         // FAIL!  : FooTest::testBar() Compared pointers are not the same
0413         //    Actual   ...
0414         //    Expected ...
0415         //    Loc: [/foo/bar.cpp(33)]
0416         //
0417         // Do *not* catch:
0418         //    ...
0419         //    Loc: [Unknown file(0)]
0420         ErrorFormat(QStringLiteral("   Loc: \\[(.*)\\(([1-9][0-9]*)\\)\\]"), 1, 2, -1),
0421 
0422         // file:///path/to/foo.qml:7:1: Bar is not a type
0423         // file:///path/to/foo.qml:49:5: QML Row: Binding loop detected for property "height"
0424         ErrorFormat(QStringLiteral("(file:\\/\\/(?:[^:]+)):([1-9][0-9]*):([1-9][0-9]*): (.*) (?:is not a type|is ambiguous|is instantiated recursively|Binding loop detected)"), 1, 2, -1, 3),
0425 
0426         // file:///path/to/foo.qml:52: TypeError: Cannot read property 'height' of null
0427         ErrorFormat(QStringLiteral("(file:\\/\\/(?:[^:]+)):([1-9][0-9]*): ([a-zA-Z]+)Error"), 1, 2, -1),
0428 
0429         // END: Qt
0430 
0431         // BEGIN: glib
0432 
0433         // all messages may have an initial entry like "GIO:" in case the log domain was set
0434         // the function name after the line number may be missing
0435 
0436         // g_assert(0)
0437         // ERROR:/foo/test.cpp:46:int main(): assertion failed: (0)
0438         ErrorFormat(QStringLiteral("^(.+:)?ERROR:(.+):([1-9][0-9]*):(.+:)? assertion failed"), 2, 3, -1),
0439 
0440         // g_assert_not_reached()
0441         // ERROR:/foo/test.cpp:2024:int main(): code should not be reached
0442         ErrorFormat(QStringLiteral("^(.+:)?ERROR:(.+):([1-9][0-9]*):(.+:)? code should not be reached"), 2, 3, -1),
0443 
0444         // g_assert_null() / g_assert_nonnull()
0445         // ERROR:/foo/test.cpp:18:int main(): 'bar' should not be nullptr
0446         // ERROR:/foo/test.c:18:int main(): 'bar' should not be NULL
0447         ErrorFormat(QStringLiteral("^(.+:)?ERROR:(.+):([1-9][0-9]*):(.+:)? '.+' should (not )?be (nullptr|NULL)"), 2, 3, -1),
0448 
0449         // g_assert_true() / g_assert_false()
0450         // ERROR:/foo/test.cpp:18:int main(): 'foo' should be TRUE
0451         // ERROR:/foo/test.cpp:18:int main(): 'foo' should be FALSE
0452         ErrorFormat(QStringLiteral("^(.+:)?ERROR:(.+):([1-9][0-9]*):(.+:)? '.+' should be (TRUE|FALSE)"), 2, 3, -1),
0453 
0454         // END: glib
0455     };
0456 
0457     return match(NATIVE_APPLICATION_ERROR_FILTERS, line);
0458 }
0459 
0460 /// --- Static Analysis filter strategy ---
0461 
0462 StaticAnalysisFilterStrategy::StaticAnalysisFilterStrategy()
0463 {
0464 }
0465 
0466 FilteredItem StaticAnalysisFilterStrategy::actionInLine(const QString& line)
0467 {
0468     return FilteredItem(line);
0469 }
0470 
0471 FilteredItem StaticAnalysisFilterStrategy::errorInLine(const QString& line)
0472 {
0473     // A list of filters for static analysis tools (krazy2, cppcheck)
0474     static const ErrorFormat STATIC_ANALYSIS_FILTERS[] = {
0475         // CppCheck
0476         ErrorFormat( QStringLiteral("^\\[(.*):([0-9]+)\\]:(.*)"), 1, 2, 3 ),
0477         // krazy2
0478         ErrorFormat( QStringLiteral("^\\t([^:]+).*line#([0-9]+).*"), 1, 2, -1 ),
0479         // krazy2 without line info
0480         ErrorFormat( QStringLiteral("^\\t(.*): missing license"), 1, -1, -1 )
0481     };
0482 
0483     return match(STATIC_ANALYSIS_FILTERS, line);
0484 }
0485 
0486 }