Commit e906bbdb authored by Christian Kamm's avatar Christian Kamm
Browse files

QmlJS checks: Warn about extra message suppressions.



Reviewed-by: Fawzi Mohamed
Change-Id: I4038cd863ba80c1719417cd03b755b047f7d8b5e
Reviewed-by: default avatarChristian Kamm <christian.d.kamm@nokia.com>
parent 0b75a664
......@@ -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)
......
......@@ -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;
};
......
......@@ -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,
......
......@@ -73,6 +73,7 @@ enum Type
WarnUnreachable = 28,
WarnWith = 29,
WarnComma = 30,
WarnUnnecessaryMessageSuppression = 31,
WarnAlreadyFormalParameter = 103,
WarnAlreadyFunction = 104,
WarnVarUsedBeforeDeclaration = 105,
......
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
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment