1
/****************************************************************************
2
**
3
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the test suite of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
43
#include <qcoreapplication.h>
44
#include <qprocess.h>
45
#include <qtemporaryfile.h>
46
#include <qdebug.h>
47
48
#include <QtTest/QtTest>
49
50
#ifdef QT_NO_PROCESS
51
QTEST_NOOP_MAIN
52
#else
53
54
#include <stdlib.h>
55
56
QT_USE_NAMESPACE
57
58
class tst_CompilerWarnings: public QObject
59
{
60
    Q_OBJECT
61
62
private slots:
63
    void warnings_data();
64
    void warnings();
65
66
private:
67
    bool shouldIgnoreWarning(QString const&);
68
};
69
70
#if 0
71
/*
72
    Return list of all documented qfeatures (QT_NO_*)
73
 */
74
static QStringList getFeatures()
75
{
76
    QStringList srcDirs;
77
    srcDirs << QString::fromLocal8Bit(qgetenv("QTDIR"))
78
            << QString::fromLocal8Bit(qgetenv("QTSRCDIR"));
79
80
    QString featurefile;
81
    foreach (QString dir, srcDirs) {
82
        QString str = dir + "/src/corelib/global/qfeatures.txt";
83
        if (QFile::exists(str)) {
84
            featurefile = str;
85
            break;
86
        }
87
    }
88
89
    if (featurefile.isEmpty()) {
90
        qWarning("Unable to find qfeatures.txt");
91
        return QStringList();
92
    }
93
94
    QFile file(featurefile);
95
    if (!file.open(QIODevice::ReadOnly)) {
96
	qWarning("Unable to open feature file '%s'", qPrintable(featurefile));
97
	return QStringList();
98
    }
99
100
    QStringList features;
101
    QTextStream s(&file);
102
    QRegExp regexp("Feature:\\s+(\\w+)\\s*");
103
    for (QString line = s.readLine(); !s.atEnd(); line = s.readLine()) {
104
        if (regexp.exactMatch(line))
105
            features << regexp.cap(1);
106
    }
107
108
    return features;
109
}
110
#endif
111
112
void tst_CompilerWarnings::warnings_data()
113
{
114
    QTest::addColumn<QStringList>("cflags");
115
116
    QTest::newRow("standard") << QStringList();
117
    QTest::newRow("warn deprecated, fast plus, no debug") << (QStringList() << "-DQT_DEPRECATED_WARNINGS"
118
        << "-DQT_USE_FAST_OPERATOR_PLUS" << "-DQT_NU_DEBUG" << "-DQT_NO_DEBUG_STREAM" << "-DQT_NO_WARNING_OUTPUT");
119
    QTest::newRow("no deprecated, no keywords") << (QStringList() << "-DQT_NO_DEPRECATED" << "-DQT_NO_KEYWORDS");
120
121
#if 0
122
#ifdef Q_WS_QWS
123
    QStringList features = getFeatures();
124
    foreach (QString feature, features) {
125
        QStringList args;
126
        QString macro = QString("QT_NO_%1").arg(feature);
127
        args << (QString("-D%1").arg(macro));
128
        QTest::newRow(qPrintable(macro)) << args;
129
    }
130
#endif
131
#endif
132
}
133
134
void tst_CompilerWarnings::warnings()
135
{
136
    QFETCH(QStringList, cflags);
137
138
#if !defined(Q_CC_INTEL) && defined(Q_CC_GNU) && __GNUC__ == 3
139
    QSKIP("gcc 3.x outputs too many bogus warnings", SkipAll);
140
#endif
141
142
    /*static*/ QString tmpFile;
143
    if (tmpFile.isEmpty()) {
144
        QTemporaryFile tmpQFile;
145
        tmpQFile.open();
146
        tmpFile = tmpQFile.fileName();
147
        tmpQFile.close();
148
    }
149
    /*static*/ QString tmpSourceFile;
150
    bool openResult = true;
151
    const QString tmpBaseName("XXXXXX-test.cpp");
152
    QString templatePath = QDir::temp().absoluteFilePath(tmpBaseName);
153
    QFile tmpQSourceFile(templatePath);
154
    if (tmpSourceFile.isEmpty()) {
155
        tmpQSourceFile.open(QIODevice::ReadWrite | QIODevice::Truncate);
156
        tmpSourceFile = tmpQSourceFile.fileName();
157
        QFile cppSource(":/test_cpp.txt");
158
        bool openResult = cppSource.open(QIODevice::ReadOnly);
159
        if (openResult)
160
        {
161
            QTextStream in(&cppSource);
162
            QTextStream out(&tmpQSourceFile);
163
            out << in.readAll();
164
        }
165
    }
166
    tmpQSourceFile.close();
167
    QVERIFY2(openResult, "Need resource temporary \"test_cpp.txt\"");
168
169
    QStringList args;
170
    QString compilerName;
171
172
    static QString qtDir = QString::fromLocal8Bit(qgetenv("QTDIR"));
173
    QVERIFY2(!qtDir.isEmpty(), "This test needs $QTDIR");
174
175
    args << cflags;
176
#if !defined(Q_CC_INTEL) && defined(Q_CC_GNU)
177
    compilerName = "g++";
178
    args << "-I" + qtDir + "/include";
179
    args << "-I/usr/X11R6/include/";
180
#ifdef Q_OS_HPUX
181
    args << "-I/usr/local/mesa/aCC-64/include";
182
#endif
183
    args << "-c";
184
    args << "-Wall" << "-Wold-style-cast" << "-Woverloaded-virtual" << "-pedantic" << "-ansi"
185
         << "-Wno-long-long" << "-Wshadow" << "-Wpacked" << "-Wunreachable-code"
186
         << "-Wundef" << "-Wchar-subscripts" << "-Wformat-nonliteral" << "-Wformat-security"
187
         << "-Wcast-align"
188
         << "-o" << tmpFile
189
         << tmpSourceFile;
190
#elif defined(Q_CC_XLC)
191
    compilerName = "xlC_r";
192
    args << "-I" + qtDir + "/include"
193
# if QT_POINTER_SIZE == 8
194
         << "-q64"
195
# endif
196
         << "-c" << "-o" << tmpFile
197
         << "-info=all"
198
         << tmpSourceFile;
199
#elif defined(Q_CC_MSVC)
200
    compilerName = "cl";
201
    args << "-I" + qtDir + "/include"
202
         << "-nologo" << "-W3"
203
         << tmpSourceFile;
204
#elif defined (Q_CC_SUN)
205
    compilerName = "CC";
206
    // +w or +w2 outputs too much bogus
207
    args << "-I" + qtDir + "/include"
208
# if QT_POINTER_SIZE == 8
209
         << "-xarch=v9"
210
# endif
211
         << "-o" << tmpFile
212
         << tmpSourceFile;
213
#elif defined (Q_CC_HPACC)
214
    compilerName = "aCC";
215
    args << "-I" + qtDir + "/include"
216
         << "-I/usr/local/mesa/aCC-64/include"
217
         << "-I/opt/graphics/OpenGL/include"
218
# if QT_POINTER_SIZE == 8 && !defined __ia64
219
         << "+DA2.0W"
220
# endif
221
         // aCC generates too much bogus.
222
         << "-DQT_NO_STL" << "-c" << "-w"
223
         << "-o" << tmpFile
224
         << tmpSourceFile;
225
#elif defined(Q_CC_MIPS)
226
    compilerName = "CC";
227
    args << "-I" + qtDir + "/include"
228
         << "-c"
229
         << "-woff" << "3303" // const qualifier on return
230
         << "-o" << tmpFile
231
         << tmpSourceFile;
232
#else
233
    QSKIP("Test not implemented for this compiler", SkipAll);
234
#endif
235
236
    QProcess proc;
237
    proc.start(compilerName, args, QIODevice::ReadOnly);
238
    QVERIFY2(proc.waitForFinished(6000000), proc.errorString().toLocal8Bit());
239
240
#ifdef Q_CC_MSVC
241
    QString errs = QString::fromLocal8Bit(proc.readAllStandardOutput().constData());
242
    if (errs.startsWith(tmpBaseName))
243
        errs = errs.mid(tmpBaseName.size()).simplified();;
244
#else
245
    QString errs = QString::fromLocal8Bit(proc.readAllStandardError().constData());
246
#endif
247
    QStringList errList;
248
    if (!errs.isEmpty()) {
249
        errList = errs.split("\n");
250
        qDebug() << "Arguments:" << args;
251
        QStringList validErrors;
252
        foreach (QString const& err, errList) {
253
            bool ignore = shouldIgnoreWarning(err);
254
            qDebug() << err << (ignore ? " [ignored]" : "");
255
            if (!ignore) {
256
                validErrors << err;
257
            }
258
        }
259
        errList = validErrors;
260
    }
261
    QCOMPARE(errList.count(), 0); // verbose info how many lines of errors in output
262
263
    tmpQSourceFile.remove();
264
}
265
266
bool tst_CompilerWarnings::shouldIgnoreWarning(QString const& warning)
267
{
268
    if (warning.isEmpty()) {
269
        return true;
270
    }
271
272
    // icecc outputs warnings if some icecc node breaks
273
    if (warning.startsWith("ICECC[")) {
274
        return true;
275
    }
276
277
    // Add more bogus warnings here
278
279
    return false;
280
}
281
282
QTEST_APPLESS_MAIN(tst_CompilerWarnings)
283
284
#include "tst_compilerwarnings.moc"
285
#endif // QT_NO_PROCESS