qmljsstaticanalysismessage.cpp 12.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
** Alternatively, 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.
23
**
hjk's avatar
hjk committed
24
25
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30

#include "qmljsstaticanalysismessage.h"
Fawzi Mohamed's avatar
Fawzi Mohamed committed
31
#include "qmljsconstants.h"
32
33
34

#include <utils/qtcassert.h>

35
#include <QCoreApplication>
36
37
38

using namespace QmlJS;
using namespace QmlJS::StaticAnalysis;
Fawzi Mohamed's avatar
Fawzi Mohamed committed
39
using namespace QmlJS::Severity;
40
41
42
43
44

namespace {

class StaticAnalysisMessages
{
45
    Q_DECLARE_TR_FUNCTIONS(QmlJS::StaticAnalysisMessages)
46
47

public:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
48
    void newMsg(Type type, Enum severity, const QString &message, int placeholders = 0)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    {
        PrototypeMessageData prototype;
        prototype.type = type;
        prototype.severity = severity;
        prototype.message = message;
        prototype.placeholders = placeholders;
        QTC_CHECK(placeholders <= 2);
        QTC_ASSERT(!messages.contains(type), return);
        messages[type] = prototype;
    }

    StaticAnalysisMessages();
    QHash<Type, PrototypeMessageData> messages;
};

Friedemann Kleint's avatar
Friedemann Kleint committed
64
65
static inline QString msgInvalidConstructor(const char *what)
{
66
    return StaticAnalysisMessages::tr("Do not use '%1' as a constructor.").arg(QLatin1String(what));
Friedemann Kleint's avatar
Friedemann Kleint committed
67
68
}

69
70
StaticAnalysisMessages::StaticAnalysisMessages()
{
71
72
    // When changing a message or severity, update the documentation, currently
    // in creator-editors.qdoc, accordingly.
73
    newMsg(ErrInvalidEnumValue, Error,
74
           tr("Invalid value for enum."));
75
    newMsg(ErrEnumValueMustBeStringOrNumber, Error,
76
           tr("Enum value must be a string or a number."));
77
    newMsg(ErrNumberValueExpected, Error,
78
           tr("Number value expected."));
79
    newMsg(ErrBooleanValueExpected, Error,
80
           tr("Boolean value expected."));
81
    newMsg(ErrStringValueExpected, Error,
82
           tr("String value expected."));
83
    newMsg(ErrInvalidUrl, Error,
84
           tr("Invalid URL."));
85
    newMsg(WarnFileOrDirectoryDoesNotExist, Warning,
86
           tr("File or directory does not exist."));
87
    newMsg(ErrInvalidColor, Error,
88
           tr("Invalid color."));
89
    newMsg(ErrAnchorLineExpected, Error,
90
           tr("Anchor line expected."));
91
    newMsg(ErrPropertiesCanOnlyHaveOneBinding, Error,
92
           tr("Duplicate property binding."));
93
    newMsg(ErrIdExpected, Error,
94
           tr("Id expected."));
95
    newMsg(ErrInvalidId, Error,
96
           tr("Invalid id."));
97
    newMsg(ErrDuplicateId, Error,
98
           tr("Duplicate id."));
99
    newMsg(ErrInvalidPropertyName, Error,
100
           tr("Invalid property name '%1'."), 1);
101
    newMsg(ErrDoesNotHaveMembers, Error,
102
           tr("'%1' does not have members."), 1);
103
    newMsg(ErrInvalidMember, Error,
104
           tr("'%1' is not a member of '%2'."), 2);
105
    newMsg(WarnAssignmentInCondition, Warning,
106
           tr("Assignment in condition."));
107
    newMsg(WarnCaseWithoutFlowControl, Warning,
108
           tr("Unterminated non-empty case block."));
109
    newMsg(WarnEval, Warning,
110
           tr("Do not use 'eval'."));
111
    newMsg(WarnUnreachable, Warning,
112
           tr("Unreachable."));
113
    newMsg(WarnWith, Warning,
114
           tr("Do not use 'with'."));
115
    newMsg(WarnComma, Warning,
116
           tr("Do not use comma expressions."));
117
    newMsg(WarnAlreadyFormalParameter, Warning,
118
           tr("'%1' already is a formal parameter."), 1);
119
    newMsg(WarnUnnecessaryMessageSuppression, Warning,
120
           tr("Unnecessary message suppression."));
121
    newMsg(WarnAlreadyFunction, Warning,
122
           tr("'%1' already is a function."), 1);
123
    newMsg(WarnVarUsedBeforeDeclaration, Warning,
124
           tr("var '%1' is used before its declaration."), 1);
125
    newMsg(WarnAlreadyVar, Warning,
126
           tr("'%1' already is a var."), 1);
127
    newMsg(WarnDuplicateDeclaration, Warning,
128
           tr("'%1' is declared more than once."), 1);
129
    newMsg(WarnFunctionUsedBeforeDeclaration, Warning,
130
           tr("Function '%1' is used before its declaration."), 1);
131
    newMsg(WarnBooleanConstructor, Warning,
Friedemann Kleint's avatar
Friedemann Kleint committed
132
           msgInvalidConstructor("Boolean"));
133
    newMsg(WarnStringConstructor, Warning,
Friedemann Kleint's avatar
Friedemann Kleint committed
134
           msgInvalidConstructor("String"));
135
    newMsg(WarnObjectConstructor, Warning,
Friedemann Kleint's avatar
Friedemann Kleint committed
136
           msgInvalidConstructor("Object"));
137
    newMsg(WarnArrayConstructor, Warning,
Friedemann Kleint's avatar
Friedemann Kleint committed
138
           msgInvalidConstructor("Array"));
139
    newMsg(WarnFunctionConstructor, Warning,
Friedemann Kleint's avatar
Friedemann Kleint committed
140
           msgInvalidConstructor("Function"));
141
    newMsg(HintAnonymousFunctionSpacing, Hint,
142
           tr("The 'function' keyword and the opening parenthesis should be separated by a single space."));
143
    newMsg(WarnBlock, Warning,
144
           tr("Do not use stand-alone blocks."));
145
    newMsg(WarnVoid, Warning,
146
           tr("Do not use void expressions."));
147
    newMsg(WarnConfusingPluses, Warning,
148
           tr("Confusing pluses."));
149
    newMsg(WarnConfusingMinuses, Warning,
150
           tr("Confusing minuses."));
151
    newMsg(HintDeclareVarsInOneLine, Hint,
152
           tr("Declare all function vars on a single line."));
153
    newMsg(HintExtraParentheses, Hint,
154
           tr("Unnecessary parentheses."));
155
    newMsg(MaybeWarnEqualityTypeCoercion, MaybeWarning,
156
           tr("== and != may perform type coercion, use === or !== to avoid it."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
157
    newMsg(WarnConfusingExpressionStatement, Error,
158
           tr("Expression statements should be assignments, calls or delete expressions only."));
159
    newMsg(HintDeclarationsShouldBeAtStartOfFunction, Hint,
160
           tr("Place var declarations at the start of a function."));
161
    newMsg(HintOneStatementPerLine, Hint,
162
           tr("Use only one statement per line."));
163
    newMsg(ErrUnknownComponent, Error,
164
           tr("Unknown component."));
165
    newMsg(ErrCouldNotResolvePrototypeOf, Error,
166
           tr("Could not resolve the prototype '%1' of '%2'."), 2);
167
    newMsg(ErrCouldNotResolvePrototype, Error,
168
           tr("Could not resolve the prototype '%1'."), 1);
169
    newMsg(ErrPrototypeCycle, Error,
170
           tr("Prototype cycle, the last non-repeated component is '%1'."), 1);
171
    newMsg(ErrInvalidPropertyType, Error,
172
           tr("Invalid property type '%1'."), 1);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
173
    newMsg(WarnEqualityTypeCoercion, Error,
174
           tr("== and != perform type coercion, use === or !== to avoid it."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
175
    newMsg(WarnExpectedNewWithUppercaseFunction, Error,
176
           tr("Calls of functions that start with an uppercase letter should use 'new'."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
177
    newMsg(WarnNewWithLowercaseFunction, Error,
178
           tr("Use 'new' only with functions that start with an uppercase letter."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
179
    newMsg(WarnNumberConstructor, Error,
Friedemann Kleint's avatar
Friedemann Kleint committed
180
           msgInvalidConstructor("Function"));
181
    newMsg(HintBinaryOperatorSpacing, Hint,
182
           tr("Use spaces around binary operators."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
183
    newMsg(WarnUnintentinalEmptyBlock, Error,
184
           tr("Unintentional empty block, use ({}) for empty object literal."));
185
    newMsg(HintPreferNonVarPropertyType, Hint,
186
           tr("Use %1 instead of 'var' or 'variant' to improve performance."), 1);
Leandro Melo's avatar
Leandro Melo committed
187
    newMsg(ErrMissingRequiredProperty, Error,
188
           tr("Missing property '%1'."), 1);
Leandro Melo's avatar
Leandro Melo committed
189
    newMsg(ErrObjectValueExpected, Error,
190
           tr("Object value expected."));
Leandro Melo's avatar
Leandro Melo committed
191
    newMsg(ErrArrayValueExpected, Error,
192
           tr("Array value expected."));
Leandro Melo's avatar
Leandro Melo committed
193
    newMsg(ErrDifferentValueExpected, Error,
194
           tr("%1 value expected."), 1);
Leandro Melo's avatar
Leandro Melo committed
195
    newMsg(ErrSmallerNumberValueExpected, Error,
196
           tr("Maximum number value is %1."), 1);
Leandro Melo's avatar
Leandro Melo committed
197
    newMsg(ErrLargerNumberValueExpected, Error,
198
           tr("Minimum number value is %1."), 1);
Leandro Melo's avatar
Leandro Melo committed
199
    newMsg(ErrMaximumNumberValueIsExclusive, Error,
200
           tr("Maximum number value is exclusive."));
Leandro Melo's avatar
Leandro Melo committed
201
    newMsg(ErrMinimumNumberValueIsExclusive, Error,
202
           tr("Minimum number value is exclusive."));
Leandro Melo's avatar
Leandro Melo committed
203
    newMsg(ErrInvalidStringValuePattern, Error,
204
           tr("String value does not match required pattern."));
Leandro Melo's avatar
Leandro Melo committed
205
    newMsg(ErrLongerStringValueExpected, Error,
206
           tr("Minimum string value length is %1."), 1);
Leandro Melo's avatar
Leandro Melo committed
207
    newMsg(ErrShorterStringValueExpected, Error,
208
           tr("Maximum string value length is %1."), 1);
Leandro Melo's avatar
Leandro Melo committed
209
    newMsg(ErrInvalidArrayValueLength, Error,
210
           tr("%1 elements expected in array value."), 1);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
211
    newMsg(WarnImperativeCodeNotEditableInVisualDesigner, Error,
212
            tr("Imperative code is not supported in the Qt Quick Designer."));
213
    newMsg(WarnUnsupportedTypeInVisualDesigner, Warning,
214
            tr("This type is not supported in the Qt Quick Designer."));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
215
    newMsg(WarnReferenceToParentItemNotSupportedByVisualDesigner, Error,
216
            tr("Reference to parent item cannot be resolved correctly by the Qt Quick Designer."));
217
    newMsg(WarnUndefinedValueForVisualDesigner, Warning,
218
            tr("This visual property binding cannot be evaluated in the local context "
219
               "and might not show up in Qt Quick Designer as expected."));
220
    newMsg(WarnStatesOnlyInRootItemForVisualDesigner, Warning,
221
            tr("Qt Quick Designer only supports states in the root item."));
222
223
    newMsg(WarnAboutQtQuick1InsteadQtQuick2, Warning,
            tr("Using Qt Quick 1 code model instead of Qt Quick 2."));
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
}

} // anonymous namespace

Q_GLOBAL_STATIC(StaticAnalysisMessages, messages)

QList<Type> Message::allMessageTypes()
{
    return messages()->messages.keys();
}

Message::Message()
    : type(UnknownType), severity(Hint)
{}

Leandro Melo's avatar
Leandro Melo committed
239
240
241
242
243
Message::Message(Type type,
                 AST::SourceLocation location,
                 const QString &arg1,
                 const QString &arg2,
                 bool appendTypeId)
244
245
246
    : location(location), type(type)
{
    QTC_ASSERT(messages()->messages.contains(type), return);
247
    const PrototypeMessageData &prototype = prototypeForMessageType(type);
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    severity = prototype.severity;
    message = prototype.message;
    if (prototype.placeholders == 0) {
        if (!arg1.isEmpty() || !arg2.isEmpty())
            qWarning() << "StaticAnalysis message" << type << "expects no arguments";
    } else if (prototype.placeholders == 1) {
        if (arg1.isEmpty() || !arg2.isEmpty())
            qWarning() << "StaticAnalysis message" << type << "expects exactly one argument";
        message = message.arg(arg1);
    } else if (prototype.placeholders == 2) {
        if (arg1.isEmpty() || arg2.isEmpty())
            qWarning() << "StaticAnalysis message" << type << "expects exactly two arguments";
        message = message.arg(arg1, arg2);
    }
Leandro Melo's avatar
Leandro Melo committed
262
    if (appendTypeId)
263
        message.append(QString::fromLatin1(" (M%1)").arg(QString::number(prototype.type)));
264
265
266
267
268
269
270
271
272
273
274
275
276
277
}

bool Message::isValid() const
{
    return type != UnknownType && location.isValid() && !message.isEmpty();
}

DiagnosticMessage Message::toDiagnosticMessage() const
{
    DiagnosticMessage diagnostic;
    switch (severity) {
    case Hint:
    case MaybeWarning:
    case Warning:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
278
        diagnostic.kind = Warning;
279
280
        break;
    default:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
281
        diagnostic.kind = Error;
282
283
284
285
286
287
        break;
    }
    diagnostic.loc = location;
    diagnostic.message = message;
    return diagnostic;
}
288
289
290

QString Message::suppressionString() const
{
291
    return QString::fromLatin1("@disable-check M%1").arg(QString::number(type));
292
293
294
295
296
}

QRegExp Message::suppressionPattern()
{
    return QRegExp(QLatin1String("@disable-check M(\\d+)"));
297
}
298
299
300
301
302
303
304
305

const PrototypeMessageData Message::prototypeForMessageType(Type type)
{
     QTC_CHECK(messages()->messages.contains(type));
     const PrototypeMessageData &prototype = messages()->messages.value(type);

     return prototype;
}