summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libs/qmljs/qmljscheck.cpp79
-rw-r--r--src/libs/qmljs/qmljscheck.h13
-rw-r--r--src/libs/qmljs/qmljsstaticanalysismessage.cpp2
-rw-r--r--src/libs/qmljs/qmljsstaticanalysismessage.h1
-rw-r--r--tests/auto/qml/codemodel/check/suppression.qml15
5 files changed, 92 insertions, 18 deletions
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index ad4596fb95..64055f881d 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -535,7 +535,11 @@ Check::~Check()
QList<Message> Check::operator()()
{
_messages.clear();
+ scanCommentsForAnnotations();
+
Node::accept(_doc->ast(), this);
+ warnAboutUnnecessarySuppressions();
+
return _messages;
}
@@ -1147,36 +1151,75 @@ static bool hasOnlySpaces(const QString &s)
void Check::addMessage(const Message &message)
{
if (message.isValid() && _enabledMessages.contains(message.type)) {
- // check for 'ignore this message'-type comments
- const QString &suppressMessage = message.suppressionString();
- foreach (const SourceLocation &commentLoc, _doc->engine()->comments()) {
- if (commentLoc.startLine > message.location.startLine)
+ if (m_disabledMessageTypesByLine.contains(message.location.startLine)) {
+ QList<MessageTypeAndSuppression> &disabledMessages = m_disabledMessageTypesByLine[message.location.startLine];
+ for (int i = 0; i < disabledMessages.size(); ++i) {
+ if (disabledMessages[i].type == message.type) {
+ disabledMessages[i].wasSuppressed = true;
+ return;
+ }
+ }
+ }
+
+ _messages += message;
+ }
+}
+
+void Check::addMessage(Type type, const SourceLocation &location, const QString &arg1, const QString &arg2)
+{
+ addMessage(Message(type, location, arg1, arg2));
+}
+
+void Check::scanCommentsForAnnotations()
+{
+ m_disabledMessageTypesByLine.clear();
+
+ // find all disable annotations
+ const QRegExp disableCommentPattern(QLatin1String("@disable M(\\d+)"));
+ foreach (const SourceLocation &commentLoc, _doc->engine()->comments()) {
+ const QString &comment = _doc->source().mid(commentLoc.begin(), commentLoc.length);
+ int lastOffset = -1;
+ QList<MessageTypeAndSuppression> disabledMessageTypes;
+ forever {
+ lastOffset = disableCommentPattern.indexIn(comment, lastOffset + 1);
+ if (lastOffset == -1)
break;
- if (commentLoc.startLine < message.location.startLine - 1)
- continue;
+ MessageTypeAndSuppression entry;
+ entry.type = static_cast<StaticAnalysis::Type>(disableCommentPattern.cap(1).toInt());
+ entry.wasSuppressed = false;
+ entry.suppressionSource = SourceLocation(commentLoc.offset + lastOffset,
+ disableCommentPattern.matchedLength(),
+ commentLoc.startLine,
+ commentLoc.startColumn + lastOffset);
+ disabledMessageTypes += entry;
+ }
+ if (!disabledMessageTypes.isEmpty()) {
+ int appliesToLine = commentLoc.startLine;
- // only look at comments on the previous line if there's only spaces before the comment
+ // if the comment is preceded by spaces only, it applies to the next line
// note: startColumn is 1-based and *after* the starting // or /*
- if (commentLoc.startLine == message.location.startLine - 1
- && commentLoc.startColumn > 3) {
+ if (commentLoc.startColumn > 3) {
const QString &beforeComment = _doc->source().mid(commentLoc.begin() - commentLoc.startColumn + 1,
commentLoc.startColumn - 3);
- if (!hasOnlySpaces(beforeComment))
- continue;
+ if (hasOnlySpaces(beforeComment))
+ ++appliesToLine;
}
- const QString &comment = _doc->source().mid(commentLoc.begin(), commentLoc.length);
- if (comment.contains(suppressMessage))
- return;
+ m_disabledMessageTypesByLine[appliesToLine] += disabledMessageTypes;
}
-
- _messages += message;
}
}
-void Check::addMessage(Type type, const SourceLocation &location, const QString &arg1, const QString &arg2)
+void Check::warnAboutUnnecessarySuppressions()
{
- addMessage(Message(type, location, arg1, arg2));
+ QHashIterator< int, QList<MessageTypeAndSuppression> > it(m_disabledMessageTypesByLine);
+ while (it.hasNext()) {
+ it.next();
+ foreach (const MessageTypeAndSuppression &entry, it.value()) {
+ if (!entry.wasSuppressed)
+ addMessage(WarnUnnecessaryMessageSuppression, entry.suppressionSource);
+ }
+ }
}
bool Check::visit(NewExpression *ast)
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index d824d43514..f15a5f3b84 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -119,6 +119,9 @@ private:
void addMessage(StaticAnalysis::Type type, const AST::SourceLocation &location,
const QString &arg1 = QString(), const QString &arg2 = QString());
+ void scanCommentsForAnnotations();
+ void warnAboutUnnecessarySuppressions();
+
AST::Node *parent(int distance = 0);
Document::Ptr _doc;
@@ -135,6 +138,16 @@ private:
QStack<StringSet> m_idStack;
QStack<StringSet> m_propertyStack;
+ class MessageTypeAndSuppression
+ {
+ public:
+ AST::SourceLocation suppressionSource;
+ StaticAnalysis::Type type;
+ bool wasSuppressed;
+ };
+
+ QHash< int, QList<MessageTypeAndSuppression> > m_disabledMessageTypesByLine;
+
bool _importsOk;
};
diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.cpp b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
index 6406a237e8..f9ab8070d8 100644
--- a/src/libs/qmljs/qmljsstaticanalysismessage.cpp
+++ b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
@@ -118,6 +118,8 @@ StaticAnalysisMessages::StaticAnalysisMessages()
tr("do not use comma expressions"));
newMsg(WarnAlreadyFormalParameter, Warning,
tr("'%1' is already a formal parameter"), 1);
+ newMsg(WarnUnnecessaryMessageSuppression, Warning,
+ tr("unnecessary message suppression"));
newMsg(WarnAlreadyFunction, Warning,
tr("'%1' is already a function"), 1);
newMsg(WarnVarUsedBeforeDeclaration, Warning,
diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.h b/src/libs/qmljs/qmljsstaticanalysismessage.h
index 3d9e00aa89..0375beebf9 100644
--- a/src/libs/qmljs/qmljsstaticanalysismessage.h
+++ b/src/libs/qmljs/qmljsstaticanalysismessage.h
@@ -73,6 +73,7 @@ enum Type
WarnUnreachable = 28,
WarnWith = 29,
WarnComma = 30,
+ WarnUnnecessaryMessageSuppression = 31,
WarnAlreadyFormalParameter = 103,
WarnAlreadyFunction = 104,
WarnVarUsedBeforeDeclaration = 105,
diff --git a/tests/auto/qml/codemodel/check/suppression.qml b/tests/auto/qml/codemodel/check/suppression.qml
new file mode 100644
index 0000000000..cfc67bd6a8
--- /dev/null
+++ b/tests/auto/qml/codemodel/check/suppression.qml
@@ -0,0 +1,15 @@
+import Qt 4.7
+
+Rectangle {
+ function foo() {
+ a + b // 127 9 13
+ // @disable M127
+ a + b
+ a + b // @disable M127
+
+ // @disable M127 31 12 24
+
+ // @disable M126 31 12 24
+ a + b // 127 9 13
+ }
+}