2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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.
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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.
|
|
|
|
**
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
#include "cppchecksymbols.h"
|
2013-03-27 18:54:03 +01:00
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
#include "cpplocalsymbols.h"
|
|
|
|
|
2012-01-23 17:44:49 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDebug>
|
2010-07-05 18:52:52 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
// This is for experimeting highlighting ctors/dtors as functions (instead of types).
|
|
|
|
// Whenever this feature is considered "accepted" the switch below should be permanently
|
|
|
|
// removed, unless we decide to actually make this a user setting - that is why it's
|
|
|
|
// currently a bool instead of a define.
|
2012-07-17 16:12:03 +02:00
|
|
|
static const bool highlightCtorDtorAsType = true;
|
2012-07-12 12:47:33 +02:00
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
using namespace CPlusPlus;
|
2012-02-07 15:09:08 +01:00
|
|
|
using namespace CppTools;
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
namespace {
|
|
|
|
|
2010-07-19 11:08:39 +02:00
|
|
|
class FriendlyThread: public QThread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using QThread::msleep;
|
|
|
|
};
|
|
|
|
|
2010-08-10 10:54:40 +02:00
|
|
|
class CollectSymbols: protected SymbolVisitor
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
|
|
|
Document::Ptr _doc;
|
|
|
|
Snapshot _snapshot;
|
|
|
|
QSet<QByteArray> _types;
|
2012-07-12 12:47:33 +02:00
|
|
|
QSet<QByteArray> _fields;
|
2010-10-18 17:45:49 +02:00
|
|
|
QSet<QByteArray> _functions;
|
2010-08-09 18:07:09 +02:00
|
|
|
QSet<QByteArray> _statics;
|
2010-05-25 14:53:21 +02:00
|
|
|
bool _mainDocument;
|
|
|
|
|
|
|
|
public:
|
2010-08-10 10:54:40 +02:00
|
|
|
CollectSymbols(Document::Ptr doc, const Snapshot &snapshot)
|
2010-05-25 14:53:21 +02:00
|
|
|
: _doc(doc), _snapshot(snapshot), _mainDocument(false)
|
|
|
|
{
|
|
|
|
QSet<Namespace *> processed;
|
|
|
|
process(doc, &processed);
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSet<QByteArray> &types() const
|
|
|
|
{
|
|
|
|
return _types;
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
const QSet<QByteArray> &fields() const
|
2010-07-15 16:03:48 +02:00
|
|
|
{
|
2012-07-12 12:47:33 +02:00
|
|
|
return _fields;
|
2010-07-15 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
const QSet<QByteArray> &functions() const
|
2010-08-03 17:34:51 +02:00
|
|
|
{
|
2010-10-18 17:45:49 +02:00
|
|
|
return _functions;
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
|
2010-08-09 18:07:09 +02:00
|
|
|
const QSet<QByteArray> &statics() const
|
|
|
|
{
|
|
|
|
return _statics;
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
protected:
|
|
|
|
void process(Document::Ptr doc, QSet<Namespace *> *processed)
|
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!doc)
|
2010-05-25 14:53:21 +02:00
|
|
|
return;
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!processed->contains(doc->globalNamespace())) {
|
2010-05-25 14:53:21 +02:00
|
|
|
processed->insert(doc->globalNamespace());
|
|
|
|
|
2013-07-25 11:21:31 +02:00
|
|
|
foreach (const Document::Include &i, doc->resolvedIncludes())
|
2013-06-06 09:35:40 +02:00
|
|
|
process(_snapshot.document(i.resolvedFileName()), processed);
|
2010-05-25 14:53:21 +02:00
|
|
|
|
|
|
|
_mainDocument = (doc == _doc); // ### improve
|
|
|
|
accept(doc->globalNamespace());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void addType(const Identifier *id)
|
|
|
|
{
|
|
|
|
if (id)
|
|
|
|
_types.insert(QByteArray::fromRawData(id->chars(), id->size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void addType(const Name *name)
|
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!name) {
|
2010-05-25 14:53:21 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
|
2010-07-12 13:41:54 +02:00
|
|
|
addType(q->base());
|
|
|
|
addType(q->name());
|
2010-05-25 14:53:21 +02:00
|
|
|
|
|
|
|
} else if (name->isNameId() || name->isTemplateNameId()) {
|
|
|
|
addType(name->identifier());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
void addField(const Name *name)
|
2010-07-15 16:03:48 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!name) {
|
2010-07-15 16:03:48 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (name->isNameId()) {
|
|
|
|
const Identifier *id = name->identifier();
|
2012-07-12 12:47:33 +02:00
|
|
|
_fields.insert(QByteArray::fromRawData(id->chars(), id->size()));
|
2010-07-15 16:03:48 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
void addFunction(const Name *name)
|
2010-08-03 17:34:51 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!name) {
|
2010-08-03 17:34:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (name->isNameId()) {
|
|
|
|
const Identifier *id = name->identifier();
|
2010-10-18 17:45:49 +02:00
|
|
|
_functions.insert(QByteArray::fromRawData(id->chars(), id->size()));
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-09 18:07:09 +02:00
|
|
|
void addStatic(const Name *name)
|
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!name) {
|
2010-08-09 18:07:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (name->isNameId() || name->isTemplateNameId()) {
|
|
|
|
const Identifier *id = name->identifier();
|
|
|
|
_statics.insert(QByteArray::fromRawData(id->chars(), id->size()));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
// nothing to do
|
|
|
|
virtual bool visit(UsingNamespaceDirective *) { return true; }
|
|
|
|
virtual bool visit(UsingDeclaration *) { return true; }
|
|
|
|
virtual bool visit(Argument *) { return true; }
|
|
|
|
virtual bool visit(BaseClass *) { return true; }
|
|
|
|
|
|
|
|
virtual bool visit(Function *symbol)
|
|
|
|
{
|
2010-10-18 17:45:49 +02:00
|
|
|
addFunction(symbol->name());
|
2010-05-25 14:53:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
virtual bool visit(Block *)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(NamespaceAlias *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Declaration *symbol)
|
|
|
|
{
|
2010-08-11 12:26:02 +02:00
|
|
|
if (symbol->enclosingEnum() != 0)
|
2010-08-09 18:07:09 +02:00
|
|
|
addStatic(symbol->name());
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
if (symbol->type()->isFunctionType())
|
|
|
|
addFunction(symbol->name());
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
if (symbol->isTypedef())
|
|
|
|
addType(symbol->name());
|
2013-07-24 11:59:39 +02:00
|
|
|
else if (!symbol->type()->isFunctionType() && symbol->enclosingScope()->isClass())
|
2012-07-12 12:47:33 +02:00
|
|
|
addField(symbol->name());
|
2010-05-25 14:53:21 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(TypenameArgument *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Enum *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Namespace *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-11 15:24:55 +02:00
|
|
|
virtual bool visit(Template *)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
virtual bool visit(Class *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ForwardClassDeclaration *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Objective-C
|
|
|
|
virtual bool visit(ObjCBaseClass *) { return true; }
|
|
|
|
virtual bool visit(ObjCBaseProtocol *) { return true; }
|
|
|
|
virtual bool visit(ObjCPropertyDeclaration *) { return true; }
|
2010-08-05 12:19:07 +02:00
|
|
|
virtual bool visit(ObjCMethod *) { return true; }
|
2010-05-25 14:53:21 +02:00
|
|
|
|
|
|
|
virtual bool visit(ObjCClass *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCForwardClassDeclaration *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCProtocol *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCForwardProtocolDeclaration *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
static bool sortByLinePredicate(const CheckSymbols::Result &lhs, const CheckSymbols::Result &rhs)
|
2010-11-03 11:02:25 +01:00
|
|
|
{
|
2013-03-04 13:05:40 +01:00
|
|
|
if (lhs.line == rhs.line)
|
|
|
|
return lhs.column < rhs.column;
|
|
|
|
else
|
|
|
|
return lhs.line < rhs.line;
|
2010-11-03 11:02:25 +01:00
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
static bool acceptName(NameAST *ast, unsigned *referenceToken)
|
|
|
|
{
|
|
|
|
*referenceToken = ast->firstToken();
|
|
|
|
DestructorNameAST *dtor = ast->asDestructorName();
|
|
|
|
if (dtor)
|
|
|
|
*referenceToken = dtor->unqualified_name->firstToken();
|
|
|
|
|
|
|
|
if (highlightCtorDtorAsType)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return !dtor
|
|
|
|
&& !ast->asConversionFunctionId()
|
|
|
|
&& !ast->asOperatorFunctionId();
|
|
|
|
}
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context, const QList<CheckSymbols::Result> ¯oUses)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
2012-01-23 17:44:49 +01:00
|
|
|
QTC_ASSERT(doc, return Future());
|
2010-07-19 11:08:39 +02:00
|
|
|
|
2010-11-03 11:02:25 +01:00
|
|
|
return (new CheckSymbols(doc, context, macroUses))->start();
|
2010-07-05 18:52:52 +02:00
|
|
|
}
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context, const QList<CheckSymbols::Result> ¯oUses)
|
2010-07-07 09:42:56 +02:00
|
|
|
: ASTVisitor(doc->translationUnit()), _doc(doc), _context(context)
|
2010-11-03 11:02:25 +01:00
|
|
|
, _lineOfLastUsage(0), _macroUses(macroUses)
|
2009-08-26 14:22:00 +02:00
|
|
|
{
|
2013-02-26 11:11:43 +01:00
|
|
|
unsigned line = 0;
|
|
|
|
getTokenEndPosition(translationUnit()->ast()->lastToken(), &line, 0);
|
2013-03-04 13:05:40 +01:00
|
|
|
_chunkSize = qMax(50U, line / 200);
|
2013-02-26 11:11:43 +01:00
|
|
|
_usages.reserve(_chunkSize);
|
|
|
|
|
|
|
|
_astStack.reserve(200);
|
|
|
|
|
2010-08-03 12:22:16 +02:00
|
|
|
typeOfExpression.init(_doc, _context.snapshot(), _context.bindings());
|
2013-01-19 13:17:34 +01:00
|
|
|
// make possible to instantiate templates
|
|
|
|
typeOfExpression.setExpandTemplates(true);
|
2009-08-26 14:22:00 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
CheckSymbols::~CheckSymbols()
|
2010-05-21 15:44:35 +02:00
|
|
|
{ }
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::run()
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
2013-04-16 16:48:10 +02:00
|
|
|
CollectSymbols collectTypes(_doc, _context.snapshot());
|
|
|
|
|
|
|
|
_fileName = _doc->fileName();
|
|
|
|
_potentialTypes = collectTypes.types();
|
|
|
|
_potentialFields = collectTypes.fields();
|
|
|
|
_potentialFunctions = collectTypes.functions();
|
|
|
|
_potentialStatics = collectTypes.statics();
|
|
|
|
|
2010-11-03 11:02:25 +01:00
|
|
|
qSort(_macroUses.begin(), _macroUses.end(), sortByLinePredicate);
|
2010-10-18 17:45:49 +02:00
|
|
|
_doc->clearDiagnosticMessages();
|
2010-07-05 18:52:52 +02:00
|
|
|
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!isCanceled()) {
|
2010-07-19 11:08:39 +02:00
|
|
|
if (_doc->translationUnit()) {
|
|
|
|
accept(_doc->translationUnit()->ast());
|
2013-04-16 16:48:10 +02:00
|
|
|
_usages << QVector<Result>::fromList(_macroUses);
|
2010-07-19 11:08:39 +02:00
|
|
|
flush();
|
|
|
|
}
|
2010-07-06 12:42:55 +02:00
|
|
|
}
|
2010-07-19 11:08:39 +02:00
|
|
|
|
|
|
|
reportFinished();
|
2009-07-13 11:40:54 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
2010-05-21 15:44:35 +02:00
|
|
|
Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length);
|
2010-10-18 17:45:49 +02:00
|
|
|
_doc->addDiagnosticMessage(m);
|
2009-07-13 11:40:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::warning(AST *ast, const QString &text)
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
2010-05-21 15:44:35 +02:00
|
|
|
const Token &firstToken = tokenAt(ast->firstToken());
|
|
|
|
const Token &lastToken = tokenAt(ast->lastToken() - 1);
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
const unsigned length = lastToken.end() - firstToken.begin();
|
|
|
|
unsigned line = 1, column = 1;
|
|
|
|
getTokenStartPosition(ast->firstToken(), &line, &column);
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
warning(line, column, text, length);
|
|
|
|
return false;
|
2009-08-26 14:22:00 +02:00
|
|
|
}
|
|
|
|
|
2011-01-19 14:14:19 +01:00
|
|
|
FunctionDefinitionAST *CheckSymbols::enclosingFunctionDefinition(bool skipTopOfStack) const
|
2010-08-05 12:19:07 +02:00
|
|
|
{
|
2011-01-19 14:14:19 +01:00
|
|
|
int index = _astStack.size() - 1;
|
|
|
|
if (skipTopOfStack && !_astStack.isEmpty())
|
|
|
|
--index;
|
|
|
|
for (; index != -1; --index) {
|
2010-08-05 12:19:07 +02:00
|
|
|
AST *ast = _astStack.at(index);
|
|
|
|
|
|
|
|
if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition())
|
|
|
|
return funDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TemplateDeclarationAST *CheckSymbols::enclosingTemplateDeclaration() const
|
|
|
|
{
|
|
|
|
for (int index = _astStack.size() - 1; index != -1; --index) {
|
|
|
|
AST *ast = _astStack.at(index);
|
|
|
|
|
|
|
|
if (TemplateDeclarationAST *funDef = ast->asTemplateDeclaration())
|
|
|
|
return funDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Scope *CheckSymbols::enclosingScope() const
|
|
|
|
{
|
|
|
|
for (int index = _astStack.size() - 1; index != -1; --index) {
|
|
|
|
AST *ast = _astStack.at(index);
|
|
|
|
|
|
|
|
if (NamespaceAST *ns = ast->asNamespace()) {
|
|
|
|
if (ns->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return ns->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (ClassSpecifierAST *classSpec = ast->asClassSpecifier()) {
|
|
|
|
if (classSpec->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return classSpec->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) {
|
|
|
|
if (funDef->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return funDef->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
2013-05-16 10:15:02 +02:00
|
|
|
} else if (TemplateDeclarationAST *templateDeclaration = ast->asTemplateDeclaration()) {
|
|
|
|
if (DeclarationAST *decl = templateDeclaration->declaration) {
|
|
|
|
if (FunctionDefinitionAST *funDef = decl->asFunctionDefinition()) {
|
|
|
|
if (funDef->symbol)
|
|
|
|
return funDef->symbol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
} else if (CompoundStatementAST *blockStmt = ast->asCompoundStatement()) {
|
|
|
|
if (blockStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return blockStmt->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (IfStatementAST *ifStmt = ast->asIfStatement()) {
|
|
|
|
if (ifStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return ifStmt->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (WhileStatementAST *whileStmt = ast->asWhileStatement()) {
|
|
|
|
if (whileStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return whileStmt->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (ForStatementAST *forStmt = ast->asForStatement()) {
|
|
|
|
if (forStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return forStmt->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
|
|
|
} else if (ForeachStatementAST *foreachStmt = ast->asForeachStatement()) {
|
|
|
|
if (foreachStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return foreachStmt->symbol;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
2012-02-19 16:33:25 +04:00
|
|
|
} else if (RangeBasedForStatementAST *rangeBasedForStmt = ast->asRangeBasedForStatement()) {
|
|
|
|
if (rangeBasedForStmt->symbol)
|
|
|
|
return rangeBasedForStmt->symbol;
|
|
|
|
|
2010-08-06 11:29:41 +02:00
|
|
|
} else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) {
|
|
|
|
if (switchStmt->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return switchStmt->symbol;
|
2010-08-06 11:29:41 +02:00
|
|
|
|
|
|
|
} else if (CatchClauseAST *catchClause = ast->asCatchClause()) {
|
|
|
|
if (catchClause->symbol)
|
2010-08-11 12:26:02 +02:00
|
|
|
return catchClause->symbol;
|
2010-08-06 11:29:41 +02:00
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-11 12:26:02 +02:00
|
|
|
return _doc->globalNamespace();
|
2010-08-05 12:19:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CheckSymbols::preVisit(AST *ast)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
_astStack.append(ast);
|
|
|
|
|
2010-07-07 09:42:56 +02:00
|
|
|
if (isCanceled())
|
2010-07-05 18:52:52 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
void CheckSymbols::postVisit(AST *)
|
|
|
|
{
|
|
|
|
_astStack.takeLast();
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(NamespaceAST *ast)
|
2009-08-26 14:22:00 +02:00
|
|
|
{
|
2010-05-25 17:49:29 +02:00
|
|
|
if (ast->identifier_token) {
|
|
|
|
const Token &tok = tokenAt(ast->identifier_token);
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!tok.generated()) {
|
2010-05-25 17:49:29 +02:00
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(ast->identifier_token, &line, &column);
|
2013-04-16 16:48:10 +02:00
|
|
|
Result use(line, column, tok.length(), CppHighlightingSupport::TypeUse);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
2010-05-25 17:49:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2009-08-26 14:22:00 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(UsingDirectiveAST *)
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-09 18:07:09 +02:00
|
|
|
bool CheckSymbols::visit(EnumeratorAST *ast)
|
|
|
|
{
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->identifier_token, CppHighlightingSupport::EnumerationUse);
|
2010-08-09 18:07:09 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-03 17:34:51 +02:00
|
|
|
bool CheckSymbols::visit(SimpleDeclarationAST *ast)
|
|
|
|
{
|
2012-07-12 12:47:33 +02:00
|
|
|
NameAST *declrIdNameAST = 0;
|
2010-08-03 17:34:51 +02:00
|
|
|
if (ast->declarator_list && !ast->declarator_list->next) {
|
2013-07-24 11:59:39 +02:00
|
|
|
if (ast->symbols && !ast->symbols->next && !ast->symbols->value->isGenerated()) {
|
2010-08-03 17:34:51 +02:00
|
|
|
Symbol *decl = ast->symbols->value;
|
2012-07-12 12:47:33 +02:00
|
|
|
if (NameAST *nameAST = declaratorId(ast->declarator_list->value)) {
|
2010-08-03 17:34:51 +02:00
|
|
|
if (Function *funTy = decl->type()->asFunctionType()) {
|
2012-07-12 12:47:33 +02:00
|
|
|
if (funTy->isVirtual()
|
|
|
|
|| (nameAST->asDestructorName()
|
|
|
|
&& hasVirtualDestructor(_context.lookupType(funTy->enclosingScope())))) {
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(nameAST, CppHighlightingSupport::VirtualMethodUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
declrIdNameAST = nameAST;
|
|
|
|
} else if (maybeAddFunction(_context.lookup(decl->name(),
|
|
|
|
decl->enclosingScope()),
|
|
|
|
nameAST, funTy->argumentCount())) {
|
|
|
|
declrIdNameAST = nameAST;
|
2012-06-25 23:49:17 +04:00
|
|
|
|
|
|
|
// Add a diagnostic message if non-virtual function has override/final marker
|
2013-04-16 16:48:10 +02:00
|
|
|
if ((_usages.back().kind != CppHighlightingSupport::VirtualMethodUse)) {
|
2012-06-25 23:49:17 +04:00
|
|
|
if (funTy->isOverride())
|
2012-11-24 21:06:36 +02:00
|
|
|
warning(declrIdNameAST, QCoreApplication::translate(
|
2013-10-07 13:34:40 +02:00
|
|
|
"CPlusplus::CheckSymbols", "Only virtual functions can be marked 'override'"));
|
2012-06-25 23:49:17 +04:00
|
|
|
else if (funTy->isFinal())
|
2012-11-24 21:06:36 +02:00
|
|
|
warning(declrIdNameAST, QCoreApplication::translate(
|
2013-10-07 13:34:40 +02:00
|
|
|
"CPlusPlus::CheckSymbols", "Only virtual functions can be marked 'final'"));
|
2012-06-25 23:49:17 +04:00
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
accept(ast->decl_specifier_list);
|
2009-10-05 18:02:01 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
for (DeclaratorListAST *it = ast->declarator_list; it ; it = it->next) {
|
|
|
|
DeclaratorAST *declr = it->value;
|
|
|
|
if (declrIdNameAST
|
|
|
|
&& declr->core_declarator
|
|
|
|
&& declr->core_declarator->asDeclaratorId()
|
|
|
|
&& declr->core_declarator->asDeclaratorId()->name == declrIdNameAST) {
|
|
|
|
accept(declr->attribute_list);
|
|
|
|
accept(declr->postfix_declarator_list);
|
|
|
|
accept(declr->post_attribute_list);
|
|
|
|
accept(declr->initializer);
|
|
|
|
} else {
|
|
|
|
accept(declr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2009-10-05 18:02:01 +02:00
|
|
|
}
|
2009-11-11 09:32:05 +01:00
|
|
|
|
2010-08-12 11:57:38 +02:00
|
|
|
bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast)
|
|
|
|
{
|
|
|
|
accept(ast->attribute_list);
|
|
|
|
accept(ast->name);
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->name, CppHighlightingSupport::TypeUse);
|
2010-08-12 11:57:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
bool CheckSymbols::visit(MemberAccessAST *ast)
|
|
|
|
{
|
|
|
|
accept(ast->base_expression);
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!ast->member_name)
|
2010-08-03 12:22:16 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (const Name *name = ast->member_name->name) {
|
|
|
|
if (const Identifier *ident = name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
2012-07-12 12:47:33 +02:00
|
|
|
if (_potentialFields.contains(id)) {
|
2010-08-03 12:22:16 +02:00
|
|
|
const Token start = tokenAt(ast->firstToken());
|
|
|
|
const Token end = tokenAt(ast->lastToken() - 1);
|
2012-01-12 17:53:56 +01:00
|
|
|
const QByteArray expression = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
|
2010-08-03 12:22:16 +02:00
|
|
|
|
2012-01-11 14:26:09 +01:00
|
|
|
const QList<LookupItem> candidates =
|
2012-01-12 17:35:37 +01:00
|
|
|
typeOfExpression(expression, enclosingScope(), TypeOfExpression::Preprocess);
|
2012-07-12 12:47:33 +02:00
|
|
|
maybeAddField(candidates, ast->member_name);
|
2010-08-03 12:22:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-03 17:34:51 +02:00
|
|
|
bool CheckSymbols::visit(CallAST *ast)
|
|
|
|
{
|
|
|
|
if (ast->base_expression) {
|
|
|
|
unsigned argumentCount = 0;
|
|
|
|
for (ExpressionListAST *it = ast->expression_list; it; it = it->next)
|
|
|
|
++argumentCount;
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
ExpressionAST *expr = ast->base_expression;
|
2010-08-03 17:34:51 +02:00
|
|
|
if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) {
|
|
|
|
if (access->member_name && access->member_name->name) {
|
2010-10-18 17:45:49 +02:00
|
|
|
if (maybeFunction(access->member_name->name)) {
|
2012-07-12 12:47:33 +02:00
|
|
|
expr = access->base_expression;
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
const QByteArray expression = textOf(access);
|
2012-01-11 14:26:09 +01:00
|
|
|
const QList<LookupItem> candidates =
|
2012-01-12 17:35:37 +01:00
|
|
|
typeOfExpression(expression, enclosingScope(),
|
|
|
|
TypeOfExpression::Preprocess);
|
2010-08-03 18:14:34 +02:00
|
|
|
|
|
|
|
NameAST *memberName = access->member_name;
|
2012-07-12 12:47:33 +02:00
|
|
|
if (QualifiedNameAST *q = memberName->asQualifiedName()) {
|
|
|
|
checkNestedName(q);
|
2010-08-03 18:14:34 +02:00
|
|
|
memberName = q->unqualified_name;
|
2013-04-12 13:45:02 +02:00
|
|
|
} else if (TemplateIdAST *tId = memberName->asTemplateId()) {
|
|
|
|
accept(tId->template_argument_list);
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
2010-08-03 18:14:34 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
if (!maybeAddFunction(candidates, memberName, argumentCount)
|
|
|
|
&& highlightCtorDtorAsType) {
|
|
|
|
expr = ast->base_expression;
|
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) {
|
|
|
|
if (const Name *name = idExpr->name->name) {
|
2010-10-18 17:45:49 +02:00
|
|
|
if (maybeFunction(name)) {
|
2012-07-12 12:47:33 +02:00
|
|
|
expr = 0;
|
|
|
|
|
2010-08-03 18:14:34 +02:00
|
|
|
NameAST *exprName = idExpr->name;
|
2012-07-12 12:47:33 +02:00
|
|
|
if (QualifiedNameAST *q = exprName->asQualifiedName()) {
|
|
|
|
checkNestedName(q);
|
2010-08-03 18:14:34 +02:00
|
|
|
exprName = q->unqualified_name;
|
2013-04-12 13:45:02 +02:00
|
|
|
} else if (TemplateIdAST *tId = exprName->asTemplateId()) {
|
|
|
|
accept(tId->template_argument_list);
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
2010-08-03 18:14:34 +02:00
|
|
|
|
2012-01-11 14:26:09 +01:00
|
|
|
const QList<LookupItem> candidates =
|
2012-01-12 17:35:37 +01:00
|
|
|
typeOfExpression(textOf(idExpr), enclosingScope(),
|
2012-01-11 14:26:09 +01:00
|
|
|
TypeOfExpression::Preprocess);
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
if (!maybeAddFunction(candidates, exprName, argumentCount)
|
|
|
|
&& highlightCtorDtorAsType) {
|
|
|
|
expr = ast->base_expression;
|
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
accept(expr);
|
2010-08-03 17:34:51 +02:00
|
|
|
accept(ast->expression_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool CheckSymbols::visit(NewExpressionAST *ast)
|
|
|
|
{
|
|
|
|
accept(ast->new_placement);
|
|
|
|
accept(ast->type_id);
|
|
|
|
|
|
|
|
if (highlightCtorDtorAsType) {
|
|
|
|
accept(ast->new_type_id);
|
|
|
|
} else {
|
|
|
|
ClassOrNamespace *binding = 0;
|
|
|
|
NameAST *nameAST = 0;
|
|
|
|
if (ast->new_type_id) {
|
|
|
|
for (SpecifierListAST *it = ast->new_type_id->type_specifier_list; it; it = it->next) {
|
|
|
|
if (NamedTypeSpecifierAST *spec = it->value->asNamedTypeSpecifier()) {
|
|
|
|
nameAST = spec->name;
|
|
|
|
if (QualifiedNameAST *qNameAST = nameAST->asQualifiedName()) {
|
|
|
|
binding = checkNestedName(qNameAST);
|
|
|
|
if (binding)
|
|
|
|
binding = binding->findType(qNameAST->unqualified_name->name);
|
|
|
|
nameAST = qNameAST->unqualified_name;
|
|
|
|
} else if (maybeType(nameAST->name)) {
|
|
|
|
binding = _context.lookupType(nameAST->name, enclosingScope());
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (binding && nameAST) {
|
|
|
|
int arguments = 0;
|
|
|
|
if (ast->new_initializer) {
|
2012-09-19 11:26:33 +02:00
|
|
|
ExpressionListAST *list = 0;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (ExpressionListParenAST *exprListParen = ast->new_initializer->asExpressionListParen())
|
2012-09-19 11:26:33 +02:00
|
|
|
list = exprListParen->expression_list;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (BracedInitializerAST *braceInit = ast->new_initializer->asBracedInitializer())
|
2012-09-19 11:26:33 +02:00
|
|
|
list = braceInit->expression_list;
|
|
|
|
for (ExpressionListAST *it = list; it; it = it->next)
|
|
|
|
++arguments;
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Scope *scope = enclosingScope();
|
|
|
|
foreach (Symbol *s, binding->symbols()) {
|
|
|
|
if (Class *klass = s->asClass()) {
|
|
|
|
scope = klass;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
maybeAddFunction(_context.lookup(nameAST->name, scope), nameAST, arguments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
accept(ast->new_initializer);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-03 17:34:51 +02:00
|
|
|
QByteArray CheckSymbols::textOf(AST *ast) const
|
|
|
|
{
|
|
|
|
const Token start = tokenAt(ast->firstToken());
|
|
|
|
const Token end = tokenAt(ast->lastToken() - 1);
|
2012-01-12 17:53:56 +01:00
|
|
|
const QByteArray text = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
|
2010-08-03 17:34:51 +02:00
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::checkNamespace(NameAST *name)
|
2009-11-11 09:32:05 +01:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!name)
|
2010-05-21 15:44:35 +02:00
|
|
|
return;
|
2010-02-06 14:32:25 +01:00
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(name->firstToken(), &line, &column);
|
2010-02-06 14:32:25 +01:00
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) {
|
2010-05-21 15:44:35 +02:00
|
|
|
foreach (Symbol *s, b->symbols()) {
|
|
|
|
if (s->isNamespace())
|
|
|
|
return;
|
2010-02-06 14:32:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
|
2012-11-21 22:36:47 +02:00
|
|
|
warning(line, column, QCoreApplication::translate("CPlusPlus::CheckSymbols", "Expected a namespace-name"), length);
|
2010-02-06 14:32:25 +01:00
|
|
|
}
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-08-09 17:06:00 +02:00
|
|
|
bool CheckSymbols::hasVirtualDestructor(Class *klass) const
|
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!klass)
|
2010-08-09 17:06:00 +02:00
|
|
|
return false;
|
|
|
|
const Identifier *id = klass->identifier();
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!id)
|
2010-08-09 17:06:00 +02:00
|
|
|
return false;
|
2010-08-11 12:26:02 +02:00
|
|
|
for (Symbol *s = klass->find(id); s; s = s->next()) {
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!s->name())
|
2010-08-09 17:06:00 +02:00
|
|
|
continue;
|
2013-07-17 00:01:45 +03:00
|
|
|
if (s->name()->isDestructorNameId()) {
|
2010-08-09 17:06:00 +02:00
|
|
|
if (Function *funTy = s->type()->asFunctionType()) {
|
|
|
|
if (funTy->isVirtual() && id->isEqualTo(s->identifier()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CheckSymbols::hasVirtualDestructor(ClassOrNamespace *binding) const
|
|
|
|
{
|
|
|
|
QSet<ClassOrNamespace *> processed;
|
|
|
|
QList<ClassOrNamespace *> todo;
|
|
|
|
todo.append(binding);
|
|
|
|
|
2013-07-24 11:59:39 +02:00
|
|
|
while (!todo.isEmpty()) {
|
2010-08-09 17:06:00 +02:00
|
|
|
ClassOrNamespace *b = todo.takeFirst();
|
2013-07-24 11:59:39 +02:00
|
|
|
if (b && !processed.contains(b)) {
|
2010-08-09 17:06:00 +02:00
|
|
|
processed.insert(b);
|
|
|
|
foreach (Symbol *s, b->symbols()) {
|
|
|
|
if (Class *k = s->asClass()) {
|
|
|
|
if (hasVirtualDestructor(k))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
todo += b->usings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-03 13:01:24 +02:00
|
|
|
void CheckSymbols::checkName(NameAST *ast, Scope *scope)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2010-07-09 13:45:12 +02:00
|
|
|
if (ast && ast->name) {
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!scope)
|
2010-08-05 12:19:07 +02:00
|
|
|
scope = enclosingScope();
|
|
|
|
|
2011-01-19 17:19:03 +01:00
|
|
|
if (ast->asDestructorName() != 0) {
|
2010-08-11 12:26:02 +02:00
|
|
|
Class *klass = scope->asClass();
|
2012-07-12 12:47:33 +02:00
|
|
|
if (!klass && scope->asFunction())
|
|
|
|
klass = scope->asFunction()->enclosingScope()->asClass();
|
|
|
|
|
|
|
|
if (klass) {
|
|
|
|
if (hasVirtualDestructor(_context.lookupType(klass))) {
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast, CppHighlightingSupport::VirtualMethodUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
} else {
|
|
|
|
bool added = false;
|
|
|
|
if (highlightCtorDtorAsType && maybeType(ast->name))
|
|
|
|
added = maybeAddTypeOrStatic(_context.lookup(ast->name, klass), ast);
|
|
|
|
|
|
|
|
if (!added)
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast, CppHighlightingSupport::FunctionUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
|
|
|
}
|
2010-08-09 18:07:09 +02:00
|
|
|
} else if (maybeType(ast->name) || maybeStatic(ast->name)) {
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!maybeAddTypeOrStatic(_context.lookup(ast->name, scope), ast)) {
|
2013-01-29 15:19:50 +01:00
|
|
|
// it can be a local variable
|
|
|
|
if (maybeField(ast->name))
|
|
|
|
maybeAddField(_context.lookup(ast->name, scope), ast);
|
|
|
|
}
|
2012-07-12 12:47:33 +02:00
|
|
|
} else if (maybeField(ast->name)) {
|
|
|
|
maybeAddField(_context.lookup(ast->name, scope), ast);
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
}
|
2010-05-25 17:49:29 +02:00
|
|
|
}
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(SimpleNameAST *ast)
|
2010-05-25 17:49:29 +02:00
|
|
|
{
|
|
|
|
checkName(ast);
|
2010-05-25 14:53:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TemplateIdAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2010-05-25 17:49:29 +02:00
|
|
|
checkName(ast);
|
2010-05-25 14:53:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(DestructorNameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2010-06-01 11:57:25 +02:00
|
|
|
checkName(ast);
|
2010-05-25 14:53:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
bool CheckSymbols::visit(ParameterDeclarationAST *ast)
|
|
|
|
{
|
|
|
|
accept(ast->type_specifier_list);
|
|
|
|
// Skip parameter name, it does not need to be colored
|
|
|
|
accept(ast->expression);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(QualifiedNameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
|
|
|
if (ast->name) {
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
ClassOrNamespace *binding = checkNestedName(ast);
|
|
|
|
|
|
|
|
if (binding && ast->unqualified_name) {
|
|
|
|
if (ast->unqualified_name->asDestructorName() != 0) {
|
|
|
|
if (hasVirtualDestructor(binding)) {
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->unqualified_name, CppHighlightingSupport::VirtualMethodUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
} else {
|
|
|
|
bool added = false;
|
|
|
|
if (highlightCtorDtorAsType && maybeType(ast->name))
|
|
|
|
added = maybeAddTypeOrStatic(binding->find(ast->unqualified_name->name),
|
|
|
|
ast->unqualified_name);
|
|
|
|
if (!added)
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->unqualified_name, CppHighlightingSupport::FunctionUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
|
|
|
} else {
|
2013-08-11 22:10:26 +02:00
|
|
|
QList<LookupItem> items = binding->find(ast->unqualified_name->name);
|
|
|
|
if (items.empty())
|
|
|
|
items = _context.lookup(ast->name, enclosingScope());
|
|
|
|
maybeAddTypeOrStatic(items, ast->unqualified_name);
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (TemplateIdAST *template_id = ast->unqualified_name->asTemplateId())
|
|
|
|
accept(template_id->template_argument_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClassOrNamespace *CheckSymbols::checkNestedName(QualifiedNameAST *ast)
|
|
|
|
{
|
|
|
|
ClassOrNamespace *binding = 0;
|
|
|
|
|
|
|
|
if (ast->name) {
|
2010-05-25 14:53:21 +02:00
|
|
|
if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
|
|
|
|
NestedNameSpecifierAST *nested_name_specifier = it->value;
|
2010-06-04 10:48:24 +02:00
|
|
|
if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-06-01 11:57:25 +02:00
|
|
|
if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
|
|
|
|
accept(template_id->template_argument_list);
|
|
|
|
|
2010-06-04 10:48:24 +02:00
|
|
|
const Name *name = class_or_namespace_name->name;
|
2010-08-12 12:18:49 +02:00
|
|
|
binding = _context.lookupType(name, enclosingScope());
|
2013-05-16 10:15:02 +02:00
|
|
|
if (binding)
|
|
|
|
addType(binding, class_or_namespace_name);
|
|
|
|
else
|
|
|
|
// for the case when we use template parameter as qualifier
|
|
|
|
// e.g.: template <typename T> void fun() { T::type type; }
|
|
|
|
accept(nested_name_specifier->class_or_namespace_name);
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-08-12 12:18:49 +02:00
|
|
|
for (it = it->next; it; it = it->next) {
|
2010-06-04 10:48:24 +02:00
|
|
|
NestedNameSpecifierAST *nested_name_specifier = it->value;
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-06-04 10:48:24 +02:00
|
|
|
if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
|
2010-08-12 12:18:49 +02:00
|
|
|
if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) {
|
|
|
|
if (template_id->template_token) {
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(template_id, CppHighlightingSupport::TypeUse);
|
2010-08-12 12:18:49 +02:00
|
|
|
binding = 0; // there's no way we can find a binding.
|
|
|
|
}
|
2010-06-01 11:57:25 +02:00
|
|
|
|
2010-08-12 12:18:49 +02:00
|
|
|
accept(template_id->template_argument_list);
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!binding)
|
2010-08-12 12:18:49 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (binding) {
|
|
|
|
binding = binding->findType(class_or_namespace_name->name);
|
|
|
|
addType(binding, class_or_namespace_name);
|
|
|
|
}
|
2010-06-04 10:48:24 +02:00
|
|
|
}
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
return binding;
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->name, CppHighlightingSupport::TypeUse);
|
2010-08-05 12:19:07 +02:00
|
|
|
accept(ast->type_id);
|
|
|
|
return false;
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
accept(ast->template_parameter_list);
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->name, CppHighlightingSupport::TypeUse);
|
2010-08-05 12:19:07 +02:00
|
|
|
accept(ast->type_id);
|
|
|
|
return false;
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-08-03 13:01:24 +02:00
|
|
|
bool CheckSymbols::visit(MemInitializerAST *ast)
|
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) {
|
|
|
|
if (ast->name && enclosingFunction->symbol) {
|
|
|
|
if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) {
|
|
|
|
foreach (Symbol *s, binding->symbols()) {
|
2012-07-12 12:47:33 +02:00
|
|
|
if (Class *klass = s->asClass()) {
|
|
|
|
NameAST *nameAST = ast->name;
|
|
|
|
if (QualifiedNameAST *q = nameAST->asQualifiedName()) {
|
|
|
|
checkNestedName(q);
|
|
|
|
nameAST = q->unqualified_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (highlightCtorDtorAsType && maybeType(nameAST->name)) {
|
|
|
|
checkName(nameAST, klass);
|
|
|
|
} else if (maybeField(nameAST->name)) {
|
|
|
|
maybeAddField(_context.lookup(nameAST->name, klass), nameAST);
|
|
|
|
} else {
|
2012-09-17 09:58:09 +02:00
|
|
|
// It's a constructor, count the number of arguments
|
2012-07-12 12:47:33 +02:00
|
|
|
unsigned arguments = 0;
|
2012-09-17 09:58:09 +02:00
|
|
|
if (ast->expression) {
|
|
|
|
ExpressionListAST *expr_list = 0;
|
|
|
|
if (ExpressionListParenAST *parenExprList = ast->expression->asExpressionListParen())
|
|
|
|
expr_list = parenExprList->expression_list;
|
|
|
|
else if (BracedInitializerAST *bracedInitList = ast->expression->asBracedInitializer())
|
|
|
|
expr_list = bracedInitList->expression_list;
|
|
|
|
for (ExpressionListAST *it = expr_list; it; it = it->next)
|
|
|
|
++arguments;
|
|
|
|
}
|
2012-07-12 12:47:33 +02:00
|
|
|
maybeAddFunction(_context.lookup(nameAST->name, klass), nameAST, arguments);
|
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
break;
|
|
|
|
}
|
2010-08-03 13:01:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-17 09:58:09 +02:00
|
|
|
accept(ast->expression);
|
2010-08-05 12:19:07 +02:00
|
|
|
}
|
2010-08-03 13:01:24 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-07 15:59:08 +01:00
|
|
|
bool CheckSymbols::visit(GotoStatementAST *ast)
|
|
|
|
{
|
|
|
|
if (ast->identifier_token)
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->identifier_token, CppHighlightingSupport::LabelUse);
|
2012-02-07 15:59:08 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CheckSymbols::visit(LabeledStatementAST *ast)
|
|
|
|
{
|
2012-08-15 14:43:35 +02:00
|
|
|
if (ast->label_token && !tokenAt(ast->label_token).isKeyword())
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->label_token, CppHighlightingSupport::LabelUse);
|
2012-02-07 15:59:08 +01:00
|
|
|
|
|
|
|
accept(ast->statement);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-06-25 23:49:17 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Highlights "override" and "final" pseudokeywords like true keywords
|
|
|
|
*/
|
|
|
|
bool CheckSymbols::visit(SimpleSpecifierAST *ast)
|
|
|
|
{
|
|
|
|
if (ast->specifier_token)
|
|
|
|
{
|
|
|
|
const Token &tk = tokenAt(ast->specifier_token);
|
|
|
|
if (tk.is(T_IDENTIFIER))
|
|
|
|
{
|
|
|
|
const Identifier &id = *(tk.identifier);
|
|
|
|
if (id.equalTo(_doc->control()->cpp11Override())
|
|
|
|
|| id.equalTo(_doc->control()->cpp11Final()))
|
|
|
|
{
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->specifier_token, CppHighlightingSupport::PseudoKeywordUse);
|
2012-06-25 23:49:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CheckSymbols::visit(ClassSpecifierAST *ast)
|
|
|
|
{
|
|
|
|
if (ast->final_token)
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(ast->final_token, CppHighlightingSupport::PseudoKeywordUse);
|
2012-06-25 23:49:17 +04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
bool CheckSymbols::visit(FunctionDefinitionAST *ast)
|
|
|
|
{
|
2010-08-05 12:23:55 +02:00
|
|
|
AST *thisFunction = _astStack.takeLast();
|
2010-07-15 16:27:29 +02:00
|
|
|
accept(ast->decl_specifier_list);
|
2010-08-05 12:23:55 +02:00
|
|
|
_astStack.append(thisFunction);
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool processEntireDeclr = true;
|
2013-07-24 11:59:39 +02:00
|
|
|
if (ast->declarator && ast->symbol && !ast->symbol->isGenerated()) {
|
2010-08-03 17:34:51 +02:00
|
|
|
Function *fun = ast->symbol;
|
|
|
|
if (NameAST *declId = declaratorId(ast->declarator)) {
|
2012-07-12 12:47:33 +02:00
|
|
|
processEntireDeclr = false;
|
|
|
|
|
|
|
|
if (QualifiedNameAST *q = declId->asQualifiedName()) {
|
|
|
|
checkNestedName(q);
|
2010-08-03 17:34:51 +02:00
|
|
|
declId = q->unqualified_name;
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
if (fun->isVirtual()
|
|
|
|
|| (declId->asDestructorName()
|
|
|
|
&& hasVirtualDestructor(_context.lookupType(fun->enclosingScope())))) {
|
2013-04-16 16:48:10 +02:00
|
|
|
addUse(declId, CppHighlightingSupport::VirtualMethodUse);
|
2012-07-12 12:47:33 +02:00
|
|
|
} else if (!maybeAddFunction(_context.lookup(fun->name(),
|
|
|
|
fun->enclosingScope()),
|
|
|
|
declId, fun->argumentCount())) {
|
|
|
|
processEntireDeclr = true;
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
if (ast->declarator) {
|
|
|
|
if (processEntireDeclr) {
|
|
|
|
accept(ast->declarator);
|
|
|
|
} else {
|
|
|
|
accept(ast->declarator->attribute_list);
|
|
|
|
accept(ast->declarator->postfix_declarator_list);
|
|
|
|
accept(ast->declarator->post_attribute_list);
|
|
|
|
accept(ast->declarator->initializer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-15 16:27:29 +02:00
|
|
|
accept(ast->ctor_initializer);
|
|
|
|
accept(ast->function_body);
|
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
const LocalSymbols locals(_doc, ast);
|
2013-04-16 16:48:10 +02:00
|
|
|
foreach (const QList<Result> &uses, locals.uses) {
|
|
|
|
foreach (const Result &u, uses)
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(u);
|
2010-07-15 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
2011-01-19 14:14:19 +01:00
|
|
|
if (!enclosingFunctionDefinition(true))
|
2013-02-26 11:11:43 +01:00
|
|
|
if (_usages.size() >= _chunkSize)
|
|
|
|
flush();
|
2011-01-19 14:14:19 +01:00
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
void CheckSymbols::addUse(NameAST *ast, Kind kind)
|
2010-08-05 12:19:07 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!ast)
|
2010-08-05 12:19:07 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (QualifiedNameAST *q = ast->asQualifiedName())
|
|
|
|
ast = q->unqualified_name;
|
2012-02-16 10:54:44 +01:00
|
|
|
if (DestructorNameAST *dtor = ast->asDestructorName())
|
|
|
|
ast = dtor->unqualified_name;
|
2010-08-05 12:19:07 +02:00
|
|
|
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!ast)
|
2010-08-05 12:19:07 +02:00
|
|
|
return; // nothing to do
|
|
|
|
else if (ast->asOperatorFunctionId() != 0 || ast->asConversionFunctionId() != 0)
|
|
|
|
return; // nothing to do
|
|
|
|
|
|
|
|
unsigned startToken = ast->firstToken();
|
|
|
|
|
2012-02-16 10:54:44 +01:00
|
|
|
if (TemplateIdAST *templ = ast->asTemplateId())
|
2010-08-12 12:18:49 +02:00
|
|
|
startToken = templ->identifier_token;
|
|
|
|
|
2010-08-09 18:07:09 +02:00
|
|
|
addUse(startToken, kind);
|
|
|
|
}
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
void CheckSymbols::addUse(unsigned tokenIndex, Kind kind)
|
2010-08-09 18:07:09 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!tokenIndex)
|
2010-08-09 18:07:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
const Token &tok = tokenAt(tokenIndex);
|
2010-08-05 12:19:07 +02:00
|
|
|
if (tok.generated())
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned line, column;
|
2010-08-09 18:07:09 +02:00
|
|
|
getTokenStartPosition(tokenIndex, &line, &column);
|
2010-08-05 12:19:07 +02:00
|
|
|
const unsigned length = tok.length();
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
const Result use(line, column, length, kind);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
|
|
|
}
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
void CheckSymbols::addUse(const Result &use)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
2013-02-14 14:25:31 +01:00
|
|
|
if (use.isInvalid())
|
2011-08-30 10:52:41 +02:00
|
|
|
return;
|
|
|
|
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!enclosingFunctionDefinition()) {
|
2013-02-26 11:11:43 +01:00
|
|
|
if (_usages.size() >= _chunkSize) {
|
2011-09-01 09:22:50 +02:00
|
|
|
if (use.line > _lineOfLastUsage)
|
2010-07-15 16:03:48 +02:00
|
|
|
flush();
|
2010-07-15 13:41:51 +02:00
|
|
|
}
|
|
|
|
}
|
2010-07-06 12:42:55 +02:00
|
|
|
|
2010-11-03 11:02:25 +01:00
|
|
|
while (!_macroUses.isEmpty() && _macroUses.first().line <= use.line)
|
|
|
|
_usages.append(_macroUses.takeFirst());
|
|
|
|
|
2011-09-01 09:22:50 +02:00
|
|
|
_lineOfLastUsage = qMax(_lineOfLastUsage, use.line);
|
2010-07-16 18:00:54 +02:00
|
|
|
_usages.append(use);
|
2010-07-05 18:52:52 +02:00
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2012-07-12 12:47:33 +02:00
|
|
|
unsigned startToken;
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!b || !acceptName(ast, &startToken))
|
2010-05-25 14:53:21 +02:00
|
|
|
return;
|
|
|
|
|
2010-06-01 11:57:25 +02:00
|
|
|
const Token &tok = tokenAt(startToken);
|
2010-05-25 14:53:21 +02:00
|
|
|
if (tok.generated())
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned line, column;
|
2010-06-01 11:57:25 +02:00
|
|
|
getTokenStartPosition(startToken, &line, &column);
|
2010-05-25 14:53:21 +02:00
|
|
|
const unsigned length = tok.length();
|
2013-04-16 16:48:10 +02:00
|
|
|
const Result use(line, column, length, CppHighlightingSupport::TypeUse);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
|
2010-08-11 15:39:00 +02:00
|
|
|
bool CheckSymbols::isTemplateClass(Symbol *symbol) const
|
|
|
|
{
|
|
|
|
if (symbol) {
|
|
|
|
if (Template *templ = symbol->asTemplate()) {
|
|
|
|
if (Symbol *declaration = templ->declaration()) {
|
2010-08-12 11:03:17 +02:00
|
|
|
if (declaration->isClass() || declaration->isForwardClassDeclaration())
|
2010-08-11 15:39:00 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool CheckSymbols::maybeAddTypeOrStatic(const QList<LookupItem> &candidates, NameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2012-07-12 12:47:33 +02:00
|
|
|
unsigned startToken;
|
|
|
|
if (!acceptName(ast, &startToken))
|
|
|
|
return false;
|
2010-06-01 11:57:25 +02:00
|
|
|
|
|
|
|
const Token &tok = tokenAt(startToken);
|
2010-05-25 14:53:21 +02:00
|
|
|
if (tok.generated())
|
2012-07-12 12:47:33 +02:00
|
|
|
return false;
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-07-16 11:03:39 +02:00
|
|
|
foreach (const LookupItem &r, candidates) {
|
|
|
|
Symbol *c = r.declaration();
|
2010-05-25 17:49:29 +02:00
|
|
|
if (c->isUsingDeclaration()) // skip using declarations...
|
|
|
|
continue;
|
|
|
|
else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
|
|
|
|
continue;
|
|
|
|
else if (c->isTypedef() || c->isNamespace() ||
|
2013-01-29 13:18:08 +01:00
|
|
|
c->isStatic() || //consider also static variable
|
2010-08-11 15:39:00 +02:00
|
|
|
c->isClass() || c->isEnum() || isTemplateClass(c) ||
|
2010-08-11 12:26:02 +02:00
|
|
|
c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != 0) {
|
2010-08-09 15:40:14 +02:00
|
|
|
|
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(startToken, &line, &column);
|
|
|
|
const unsigned length = tok.length();
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
Kind kind = CppHighlightingSupport::TypeUse;
|
2010-08-11 12:26:02 +02:00
|
|
|
if (c->enclosingEnum() != 0)
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = CppHighlightingSupport::EnumerationUse;
|
2013-01-29 13:18:08 +01:00
|
|
|
else if (c->isStatic())
|
|
|
|
// treat static variable as a field(highlighting)
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = CppHighlightingSupport::FieldUse;
|
2010-08-09 18:07:09 +02:00
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
const Result use(line, column, length, kind);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
return true;
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
2010-07-15 16:03:48 +02:00
|
|
|
}
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
return false;
|
2010-07-15 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool CheckSymbols::maybeAddField(const QList<LookupItem> &candidates, NameAST *ast)
|
2010-07-15 16:03:48 +02:00
|
|
|
{
|
2012-07-12 12:47:33 +02:00
|
|
|
unsigned startToken;
|
|
|
|
if (!acceptName(ast, &startToken))
|
|
|
|
return false;
|
2010-07-15 16:03:48 +02:00
|
|
|
|
|
|
|
const Token &tok = tokenAt(startToken);
|
|
|
|
if (tok.generated())
|
2012-07-12 12:47:33 +02:00
|
|
|
return false;
|
2010-07-15 16:03:48 +02:00
|
|
|
|
2010-07-16 11:03:39 +02:00
|
|
|
foreach (const LookupItem &r, candidates) {
|
|
|
|
Symbol *c = r.declaration();
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!c)
|
2010-07-16 11:03:39 +02:00
|
|
|
continue;
|
2013-07-24 11:59:39 +02:00
|
|
|
else if (!c->isDeclaration())
|
2012-07-12 12:47:33 +02:00
|
|
|
return false;
|
2013-07-24 11:59:39 +02:00
|
|
|
else if (!(c->enclosingScope() && c->enclosingScope()->isClass()))
|
2012-07-12 12:47:33 +02:00
|
|
|
return false; // shadowed
|
2013-01-29 09:55:34 +01:00
|
|
|
else if (c->isTypedef() || (c->type() && c->type()->isFunctionType()))
|
2012-07-12 12:47:33 +02:00
|
|
|
return false; // shadowed
|
2010-07-15 16:03:48 +02:00
|
|
|
|
2010-08-09 15:40:14 +02:00
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(startToken, &line, &column);
|
|
|
|
const unsigned length = tok.length();
|
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
const Result use(line, column, length, CppHighlightingSupport::FieldUse);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
2010-08-09 18:07:09 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
return true;
|
2010-08-09 18:07:09 +02:00
|
|
|
}
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
return false;
|
2010-08-09 18:07:09 +02:00
|
|
|
}
|
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
|
2010-08-03 17:34:51 +02:00
|
|
|
{
|
|
|
|
unsigned startToken = ast->firstToken();
|
2012-07-12 12:47:33 +02:00
|
|
|
bool isDestructor = false;
|
2013-04-07 09:05:22 +02:00
|
|
|
bool isConstructor = false;
|
2012-07-12 12:47:33 +02:00
|
|
|
if (DestructorNameAST *dtor = ast->asDestructorName()) {
|
|
|
|
isDestructor = true;
|
2012-02-16 10:54:44 +01:00
|
|
|
if (dtor->unqualified_name)
|
|
|
|
startToken = dtor->unqualified_name->firstToken();
|
2012-07-12 12:47:33 +02:00
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
|
|
|
|
const Token &tok = tokenAt(startToken);
|
|
|
|
if (tok.generated())
|
2012-07-12 12:47:33 +02:00
|
|
|
return false;
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
enum { Match_None, Match_TooManyArgs, Match_TooFewArgs, Match_Ok } matchType = Match_None;
|
2013-04-16 16:48:10 +02:00
|
|
|
Kind kind = CppHighlightingSupport::FunctionUse;
|
2010-08-03 17:34:51 +02:00
|
|
|
foreach (const LookupItem &r, candidates) {
|
|
|
|
Symbol *c = r.declaration();
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
// Skip current if there's no declaration or name.
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!c || !c->name())
|
2012-07-12 12:47:33 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// In addition check for destructors, since the leading ~ is not taken into consideration.
|
|
|
|
// We don't want to compare destructors with something else or the other way around.
|
|
|
|
if (isDestructor != c->name()->isDestructorNameId())
|
2010-08-03 17:34:51 +02:00
|
|
|
continue;
|
|
|
|
|
2013-04-07 09:05:22 +02:00
|
|
|
isConstructor = isConstructorDeclaration(c);
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
Function *funTy = c->type()->asFunctionType();
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!funTy) {
|
2010-10-18 17:45:49 +02:00
|
|
|
//Try to find a template function
|
|
|
|
if (Template * t = r.type()->asTemplateType())
|
|
|
|
if ((c = t->declaration()))
|
|
|
|
funTy = c->type()->asFunctionType();
|
|
|
|
}
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!funTy)
|
2010-10-18 17:45:49 +02:00
|
|
|
continue; // TODO: add diagnostic messages and color call-operators calls too?
|
|
|
|
|
|
|
|
if (argumentCount < funTy->minimumArgumentCount()) {
|
|
|
|
if (matchType != Match_Ok) {
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = funTy->isVirtual() ? CppHighlightingSupport::VirtualMethodUse : CppHighlightingSupport::FunctionUse;
|
2010-10-18 17:45:49 +02:00
|
|
|
matchType = Match_TooFewArgs;
|
|
|
|
}
|
2013-07-24 11:59:39 +02:00
|
|
|
} else if (argumentCount > funTy->argumentCount() && !funTy->isVariadic()) {
|
2010-10-18 17:45:49 +02:00
|
|
|
if (matchType != Match_Ok) {
|
|
|
|
matchType = Match_TooManyArgs;
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = funTy->isVirtual() ? CppHighlightingSupport::VirtualMethodUse : CppHighlightingSupport::FunctionUse;
|
2010-10-18 17:45:49 +02:00
|
|
|
}
|
|
|
|
} else if (!funTy->isVirtual()) {
|
|
|
|
matchType = Match_Ok;
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = CppHighlightingSupport::FunctionUse;
|
2010-10-18 17:45:49 +02:00
|
|
|
//continue, to check if there is a matching candidate which is virtual
|
|
|
|
} else {
|
|
|
|
matchType = Match_Ok;
|
2013-04-16 16:48:10 +02:00
|
|
|
kind = CppHighlightingSupport::VirtualMethodUse;
|
2010-10-18 17:45:49 +02:00
|
|
|
break;
|
2010-08-09 15:40:14 +02:00
|
|
|
}
|
2010-10-18 17:45:49 +02:00
|
|
|
}
|
2010-08-09 15:40:14 +02:00
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
if (matchType != Match_None) {
|
2013-04-07 09:05:22 +02:00
|
|
|
// decide how constructor and destructor should be highlighted
|
2012-07-12 12:47:33 +02:00
|
|
|
if (highlightCtorDtorAsType
|
2013-04-07 09:05:22 +02:00
|
|
|
&& (isConstructor || isDestructor)
|
2012-07-12 12:47:33 +02:00
|
|
|
&& maybeType(ast->name)
|
2013-04-16 16:48:10 +02:00
|
|
|
&& kind == CppHighlightingSupport::FunctionUse) {
|
2012-07-12 12:47:33 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-09 15:40:14 +02:00
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(startToken, &line, &column);
|
|
|
|
const unsigned length = tok.length();
|
2010-08-03 17:34:51 +02:00
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
// Add a diagnostic message if argument count does not match
|
|
|
|
if (matchType == Match_TooFewArgs)
|
2012-11-21 22:36:47 +02:00
|
|
|
warning(line, column, QCoreApplication::translate("CplusPlus::CheckSymbols", "Too few arguments"), length);
|
2010-10-18 17:45:49 +02:00
|
|
|
else if (matchType == Match_TooManyArgs)
|
2012-11-21 22:36:47 +02:00
|
|
|
warning(line, column, QCoreApplication::translate("CPlusPlus::CheckSymbols", "Too many arguments"), length);
|
2010-10-18 17:45:49 +02:00
|
|
|
|
2013-04-16 16:48:10 +02:00
|
|
|
const Result use(line, column, length, kind);
|
2010-08-05 12:19:07 +02:00
|
|
|
addUse(use);
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
return true;
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
2012-07-12 12:47:33 +02:00
|
|
|
|
|
|
|
return false;
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
NameAST *CheckSymbols::declaratorId(DeclaratorAST *ast) const
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
if (ast && ast->core_declarator) {
|
|
|
|
if (NestedDeclaratorAST *nested = ast->core_declarator->asNestedDeclarator())
|
|
|
|
return declaratorId(nested->declarator);
|
2013-07-17 00:01:45 +03:00
|
|
|
if (DeclaratorIdAST *declId = ast->core_declarator->asDeclaratorId())
|
2010-08-05 12:19:07 +02:00
|
|
|
return declId->name;
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
return 0;
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
bool CheckSymbols::maybeType(const Name *name) const
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
if (name) {
|
|
|
|
if (const Identifier *ident = name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
|
|
|
if (_potentialTypes.contains(id))
|
|
|
|
return true;
|
|
|
|
}
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
return false;
|
2010-06-01 11:57:25 +02:00
|
|
|
}
|
2010-07-06 12:42:55 +02:00
|
|
|
|
2012-07-12 12:47:33 +02:00
|
|
|
bool CheckSymbols::maybeField(const Name *name) const
|
2010-08-03 17:34:51 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
if (name) {
|
|
|
|
if (const Identifier *ident = name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
2012-07-12 12:47:33 +02:00
|
|
|
if (_potentialFields.contains(id))
|
2010-08-05 12:19:07 +02:00
|
|
|
return true;
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-05 12:19:07 +02:00
|
|
|
return false;
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
|
2010-08-09 18:07:09 +02:00
|
|
|
bool CheckSymbols::maybeStatic(const Name *name) const
|
|
|
|
{
|
|
|
|
if (name) {
|
|
|
|
if (const Identifier *ident = name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
|
|
|
if (_potentialStatics.contains(id))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-18 17:45:49 +02:00
|
|
|
bool CheckSymbols::maybeFunction(const Name *name) const
|
2010-08-03 17:34:51 +02:00
|
|
|
{
|
2010-08-05 12:19:07 +02:00
|
|
|
if (name) {
|
|
|
|
if (const Identifier *ident = name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
2010-10-18 17:45:49 +02:00
|
|
|
if (_potentialFunctions.contains(id))
|
2010-08-05 12:19:07 +02:00
|
|
|
return true;
|
|
|
|
}
|
2010-08-03 17:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::flush()
|
2010-07-06 12:42:55 +02:00
|
|
|
{
|
2011-08-30 10:52:41 +02:00
|
|
|
_lineOfLastUsage = 0;
|
2010-07-15 13:41:51 +02:00
|
|
|
|
2010-07-16 18:00:54 +02:00
|
|
|
if (_usages.isEmpty())
|
2010-07-06 12:42:55 +02:00
|
|
|
return;
|
|
|
|
|
2011-08-30 10:52:41 +02:00
|
|
|
qSort(_usages.begin(), _usages.end(), sortByLinePredicate);
|
2010-07-16 18:00:54 +02:00
|
|
|
reportResults(_usages);
|
2013-02-26 11:11:43 +01:00
|
|
|
int cap = _usages.capacity();
|
2010-07-16 18:00:54 +02:00
|
|
|
_usages.clear();
|
2013-02-26 11:11:43 +01:00
|
|
|
_usages.reserve(cap);
|
2010-07-06 12:42:55 +02:00
|
|
|
}
|
2013-04-07 09:05:22 +02:00
|
|
|
|
|
|
|
bool CheckSymbols::isConstructorDeclaration(Symbol *declaration)
|
|
|
|
{
|
|
|
|
Class *clazz = declaration->enclosingClass();
|
|
|
|
if (clazz && clazz->name())
|
|
|
|
return declaration->name()->isEqualTo(clazz->name());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|