2011-05-18 18:38:58 +02:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
2011-11-02 15:59:12 +01:00
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
2011-05-18 18:38:58 +02:00
* *
* *
* * GNU Lesser General Public License Usage
* *
* * This file may be used under the terms of the GNU Lesser General Public
* * License version 2.1 as published by the Free Software Foundation and
* * appearing in the file LICENSE . LGPL included in the packaging of this file .
* * Please review the following information to ensure the GNU Lesser General
* * Public License version 2.1 requirements will be met :
* * http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * In addition , as a special exception , Nokia gives you certain additional
* * rights . These rights are described in the Nokia Qt LGPL Exception
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
* * Other Usage
* *
* * Alternatively , this file may be used in accordance with the terms and
* * conditions contained in a signed written agreement between you and Nokia .
* *
* * If you have questions regarding the use of this file , please contact
2011-11-02 15:59:12 +01:00
* * Nokia at qt - info @ nokia . com .
2011-05-18 18:38:58 +02:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "clangparser.h"
# include "ldparser.h"
# include "taskwindow.h"
# include "projectexplorerconstants.h"
using namespace ProjectExplorer ;
namespace {
// opt. drive letter + filename: (2 brackets)
const char * const FILE_PATTERN = " (<command line>|([A-Za-z]:)?[^:]+ \\ .[^:]+) " ;
}
ClangParser : : ClangParser ( ) :
2011-05-20 11:57:30 +02:00
m_commandRegExp ( QLatin1String ( " ^clang( \\ + \\ +)?: +(fatal +)?(warning|error|note): (.*)$ " ) ) ,
2011-05-18 18:38:58 +02:00
m_inLineRegExp ( QLatin1String ( " ^In (.*) included from (.*):( \\ d+):$ " ) ) ,
2011-06-01 14:17:47 +00:00
m_messageRegExp ( QLatin1String ( " ^ " ) + QLatin1String ( FILE_PATTERN ) + QLatin1String ( " (:( \\ d+): \\ d+| \\ (( \\ d+) \\ ) *): +(fatal +)?(error|warning|note): (.*)$ " ) ) ,
2011-06-04 19:29:57 +02:00
m_summaryRegExp ( QLatin1String ( " ^ \\ d+ (warnings?|errors?)( and \\ d (warnings?|errors?))? generated.$ " ) ) ,
m_expectSnippet ( false )
2011-05-18 18:38:58 +02:00
{
setObjectName ( QLatin1String ( " ClangParser " ) ) ;
appendOutputParser ( new LdParser ) ;
}
2011-06-04 19:29:57 +02:00
ClangParser : : ~ ClangParser ( )
{
emitTask ( ) ;
}
2011-05-18 18:38:58 +02:00
void ClangParser : : stdError ( const QString & line )
{
const QString lne = line . left ( line . count ( ) - 1 ) ;
2011-06-01 14:17:47 +00:00
if ( m_summaryRegExp . indexIn ( lne ) > - 1 ) {
emitTask ( ) ;
2011-06-04 19:29:57 +02:00
m_expectSnippet = false ;
2011-06-01 14:17:47 +00:00
return ;
}
2011-05-18 18:38:58 +02:00
if ( m_commandRegExp . indexIn ( lne ) > - 1 ) {
2011-06-04 19:29:57 +02:00
m_expectSnippet = true ;
2011-05-18 18:38:58 +02:00
newTask ( Task : : Error ,
2011-05-20 11:57:30 +02:00
m_commandRegExp . cap ( 4 ) ,
2011-05-18 18:38:58 +02:00
QString ( ) , /* filename */
- 1 , /* line */
2012-01-09 16:30:33 +01:00
QLatin1String ( Constants : : TASK_CATEGORY_COMPILE ) ) ;
2011-05-20 11:57:30 +02:00
if ( m_commandRegExp . cap ( 3 ) = = QLatin1String ( " warning " ) )
2011-05-18 18:38:58 +02:00
m_currentTask . type = Task : : Warning ;
2011-05-20 11:57:30 +02:00
else if ( m_commandRegExp . cap ( 3 ) = = QLatin1String ( " note " ) )
2011-05-18 18:38:58 +02:00
m_currentTask . type = Task : : Unknown ;
return ;
}
if ( m_inLineRegExp . indexIn ( lne ) > - 1 ) {
2011-06-04 19:29:57 +02:00
m_expectSnippet = true ;
2011-05-18 18:38:58 +02:00
newTask ( Task : : Unknown ,
lne . trimmed ( ) ,
m_inLineRegExp . cap ( 2 ) , /* filename */
m_inLineRegExp . cap ( 3 ) . toInt ( ) , /* line */
2012-01-09 16:30:33 +01:00
QLatin1String ( Constants : : TASK_CATEGORY_COMPILE ) ) ;
2011-05-18 18:38:58 +02:00
return ;
}
if ( m_messageRegExp . indexIn ( lne ) > - 1 ) {
2011-06-04 19:29:57 +02:00
m_expectSnippet = true ;
2011-05-18 18:38:58 +02:00
bool ok = false ;
int lineNo = m_messageRegExp . cap ( 4 ) . toInt ( & ok ) ;
if ( ! ok )
lineNo = m_messageRegExp . cap ( 5 ) . toInt ( & ok ) ;
newTask ( Task : : Error ,
2011-05-20 11:57:30 +02:00
m_messageRegExp . cap ( 8 ) ,
2011-05-18 18:38:58 +02:00
m_messageRegExp . cap ( 1 ) , /* filename */
lineNo ,
2012-01-09 16:30:33 +01:00
QLatin1String ( Constants : : TASK_CATEGORY_COMPILE ) ) ;
if ( m_messageRegExp . cap ( 7 ) = = QLatin1String ( " warning " ) )
2011-05-18 18:38:58 +02:00
m_currentTask . type = Task : : Warning ;
2012-01-09 16:30:33 +01:00
else if ( m_messageRegExp . cap ( 7 ) = = QLatin1String ( " note " ) )
2011-05-18 18:38:58 +02:00
m_currentTask . type = Task : : Unknown ;
return ;
}
2011-06-04 19:29:57 +02:00
if ( m_expectSnippet & & ! m_currentTask . isNull ( ) ) {
QTextLayout : : FormatRange fr ;
fr . start = m_currentTask . description . count ( ) + 1 ;
fr . length = lne . count ( ) + 1 ;
2012-01-09 16:30:33 +01:00
fr . format . setFontFamily ( QLatin1String ( " Monospaced " ) ) ;
2011-06-04 19:29:57 +02:00
fr . format . setFontStyleHint ( QFont : : TypeWriter ) ;
m_currentTask . description . append ( QLatin1Char ( ' \n ' ) ) ;
m_currentTask . description . append ( lne ) ;
m_currentTask . formats . append ( fr ) ;
return ;
2011-05-18 18:38:58 +02:00
}
IOutputParser : : stdError ( line ) ;
}
void ClangParser : : newTask ( Task : : TaskType type_ , const QString & description_ ,
const QString & file_ , int line_ , const QString & category_ )
2011-06-01 14:17:47 +00:00
{
emitTask ( ) ;
m_currentTask = Task ( type_ , description_ , file_ , line_ , category_ ) ;
}
void ClangParser : : emitTask ( )
2011-05-18 18:38:58 +02:00
{
if ( ! m_currentTask . isNull ( ) )
emit addTask ( m_currentTask ) ;
2011-06-01 14:17:47 +00:00
m_currentTask = Task ( ) ;
2011-05-18 18:38:58 +02:00
}
// Unit tests:
# ifdef WITH_TESTS
# include <QTest>
# include "projectexplorer.h"
# include "metatypedeclarations.h"
# include "outputparser_test.h"
void ProjectExplorerPlugin : : testClangOutputParser_data ( )
{
QTest : : addColumn < QString > ( " input " ) ;
QTest : : addColumn < OutputParserTester : : Channel > ( " inputChannel " ) ;
QTest : : addColumn < QString > ( " childStdOutLines " ) ;
QTest : : addColumn < QString > ( " childStdErrLines " ) ;
QTest : : addColumn < QList < ProjectExplorer : : Task > > ( " tasks " ) ;
QTest : : addColumn < QString > ( " outputLines " ) ;
2012-01-09 16:30:33 +01:00
const QString categoryCompile = QLatin1String ( Constants : : TASK_CATEGORY_COMPILE ) ;
2011-05-18 18:38:58 +02:00
QTest : : newRow ( " pass-through stdout " )
< < QString : : fromLatin1 ( " Sometext " ) < < OutputParserTester : : STDOUT
< < QString : : fromLatin1 ( " Sometext \n " ) < < QString ( )
< < QList < ProjectExplorer : : Task > ( )
< < QString ( ) ;
QTest : : newRow ( " pass-through stderr " )
< < QString : : fromLatin1 ( " Sometext " ) < < OutputParserTester : : STDERR
< < QString ( ) < < QString : : fromLatin1 ( " Sometext \n " )
< < QList < ProjectExplorer : : Task > ( )
< < QString ( ) ;
QTest : : newRow ( " clang++ warning " )
< < QString : : fromLatin1 ( " clang++: warning: argument unused during compilation: '-mthreads' " )
< < OutputParserTester : : STDERR
< < QString ( ) < < QString ( )
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Warning ,
QLatin1String ( " argument unused during compilation: '-mthreads' " ) ,
QString ( ) , - 1 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-05-18 18:38:58 +02:00
< < QString ( ) ;
QTest : : newRow ( " clang++ error " )
< < QString : : fromLatin1 ( " clang++: error: no input files [err_drv_no_input_files] " )
< < OutputParserTester : : STDERR
< < QString ( ) < < QString ( )
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Error ,
QLatin1String ( " no input files [err_drv_no_input_files] " ) ,
QString ( ) , - 1 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-05-18 18:38:58 +02:00
< < QString ( ) ;
QTest : : newRow ( " complex warning " )
< < QString : : fromLatin1 ( " In file included from .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qnamespace.h:45: \n "
" .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qglobal.h(1425) : warning: unknown attribute 'dllimport' ignored [-Wunknown-attributes] \n "
" class Q_CORE_EXPORT QSysInfo { \n "
" ^ " )
< < OutputParserTester : : STDERR
2011-06-04 19:29:57 +02:00
< < QString ( ) < < QString ( )
2011-05-18 18:38:58 +02:00
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Unknown ,
QLatin1String ( " In file included from .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qnamespace.h:45: " ) ,
QLatin1String ( " .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qnamespace.h " ) , 45 ,
2012-01-09 16:30:33 +01:00
categoryCompile )
2011-05-18 18:38:58 +02:00
< < Task ( Task : : Warning ,
QLatin1String ( " unknown attribute 'dllimport' ignored [-Wunknown-attributes] \n "
" class Q_CORE_EXPORT QSysInfo { \n "
" ^ " ) ,
QLatin1String ( " .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qglobal.h " ) , 1425 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-05-18 18:38:58 +02:00
< < QString ( ) ;
QTest : : newRow ( " note " )
< < QString : : fromLatin1 ( " .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qglobal.h:1289:27: note: instantiated from: \n "
" # define Q_CORE_EXPORT Q_DECL_IMPORT \n "
" ^ " )
< < OutputParserTester : : STDERR
2011-06-04 19:29:57 +02:00
< < QString ( ) < < QString ( )
2011-05-18 18:38:58 +02:00
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Unknown ,
QLatin1String ( " instantiated from: \n "
" # define Q_CORE_EXPORT Q_DECL_IMPORT \n "
" ^ " ) ,
QLatin1String ( " .. \\ .. \\ .. \\ QtSDK1.1 \\ Desktop \\ Qt \\ 4.7.3 \\ mingw \\ include/QtCore/qglobal.h " ) , 1289 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-05-18 18:38:58 +02:00
< < QString ( ) ;
2011-05-20 11:57:30 +02:00
QTest : : newRow ( " fatal error " )
< < QString : : fromLatin1 ( " /usr/include/c++/4.6/utility:68:10: fatal error: 'bits/c++config.h' file not found \n "
" #include <bits/c++config.h> \n "
" ^ " )
< < OutputParserTester : : STDERR
2011-06-04 19:29:57 +02:00
< < QString ( ) < < QString ( )
2011-05-20 11:57:30 +02:00
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Error ,
QLatin1String ( " 'bits/c++config.h' file not found \n "
" #include <bits/c++config.h> \n "
" ^ " ) ,
QLatin1String ( " /usr/include/c++/4.6/utility " ) , 68 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-05-20 11:57:30 +02:00
< < QString ( ) ;
2011-06-04 19:29:57 +02:00
QTest : : newRow ( " line confusion " )
< < QString : : fromLatin1 ( " /home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp:567:51: warning: ?: has lower precedence than +; + will be evaluated first [-Wparentheses] \n "
" int x = option->rect.x() + horizontal ? 2 : 6; \n "
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ " )
< < OutputParserTester : : STDERR
< < QString ( ) < < QString ( )
< < ( QList < ProjectExplorer : : Task > ( )
< < Task ( Task : : Warning ,
QLatin1String ( " ?: has lower precedence than +; + will be evaluated first [-Wparentheses] \n "
" int x = option->rect.x() + horizontal ? 2 : 6; \n "
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ " ) ,
QLatin1String ( " /home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp " ) , 567 ,
2012-01-09 16:30:33 +01:00
categoryCompile ) )
2011-06-04 19:29:57 +02:00
< < QString ( ) ;
2011-05-18 18:38:58 +02:00
}
void ProjectExplorerPlugin : : testClangOutputParser ( )
{
OutputParserTester testbench ;
testbench . appendOutputParser ( new ClangParser ) ;
QFETCH ( QString , input ) ;
QFETCH ( OutputParserTester : : Channel , inputChannel ) ;
QFETCH ( QList < Task > , tasks ) ;
QFETCH ( QString , childStdOutLines ) ;
QFETCH ( QString , childStdErrLines ) ;
QFETCH ( QString , outputLines ) ;
testbench . testParsing ( input , inputChannel ,
tasks , childStdOutLines , childStdErrLines ,
outputLines ) ;
}
# endif