2009-07-13 11:40:54 +02:00
|
|
|
/**************************************************************************
|
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2010-03-05 11:25:49 +01:00
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
**
|
|
|
|
** Commercial Usage
|
|
|
|
**
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
**
|
|
|
|
** 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.
|
|
|
|
**
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2009-07-13 11:40:54 +02:00
|
|
|
**
|
|
|
|
**************************************************************************/
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
#include "cppchecksymbols.h"
|
2010-07-05 17:35:54 +02:00
|
|
|
#include <cplusplus/Overview.h>
|
2009-07-13 11:40:54 +02:00
|
|
|
|
|
|
|
#include <Names.h>
|
|
|
|
#include <Literals.h>
|
|
|
|
#include <Symbols.h>
|
|
|
|
#include <TranslationUnit.h>
|
|
|
|
#include <Scope.h>
|
|
|
|
#include <AST.h>
|
2010-05-25 14:53:21 +02:00
|
|
|
#include <SymbolVisitor.h>
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-07-05 18:52:52 +02:00
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
#include <QtCore/QThreadPool>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
|
|
|
#include <qtconcurrent/runextensions.h>
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-05-21 15:44:35 +02:00
|
|
|
using namespace CPlusPlus;
|
2009-07-13 11:40:54 +02:00
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class CollectTypes: protected SymbolVisitor
|
|
|
|
{
|
|
|
|
Document::Ptr _doc;
|
|
|
|
Snapshot _snapshot;
|
|
|
|
QSet<QByteArray> _types;
|
|
|
|
QList<ScopedSymbol *> _scopes;
|
|
|
|
QList<NameAST *> _names;
|
|
|
|
bool _mainDocument;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CollectTypes(Document::Ptr doc, const Snapshot &snapshot)
|
|
|
|
: _doc(doc), _snapshot(snapshot), _mainDocument(false)
|
|
|
|
{
|
|
|
|
QSet<Namespace *> processed;
|
|
|
|
process(doc, &processed);
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSet<QByteArray> &types() const
|
|
|
|
{
|
|
|
|
return _types;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<ScopedSymbol *> &scopes() const
|
|
|
|
{
|
|
|
|
return _scopes;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Scope *findScope(unsigned tokenOffset, const QList<ScopedSymbol *> &scopes)
|
|
|
|
{
|
|
|
|
for (int i = scopes.size() - 1; i != -1; --i) {
|
|
|
|
ScopedSymbol *symbol = scopes.at(i);
|
|
|
|
const unsigned start = symbol->startOffset();
|
|
|
|
const unsigned end = symbol->endOffset();
|
|
|
|
|
|
|
|
if (tokenOffset >= start && tokenOffset < end)
|
|
|
|
return symbol->members();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void process(Document::Ptr doc, QSet<Namespace *> *processed)
|
|
|
|
{
|
|
|
|
if (! doc)
|
|
|
|
return;
|
|
|
|
else if (! processed->contains(doc->globalNamespace())) {
|
|
|
|
processed->insert(doc->globalNamespace());
|
|
|
|
|
|
|
|
foreach (const Document::Include &i, doc->includes())
|
|
|
|
process(_snapshot.document(i.fileName()), processed);
|
|
|
|
|
|
|
|
_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)
|
|
|
|
{
|
|
|
|
if (! name) {
|
|
|
|
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());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void addScope(ScopedSymbol *symbol)
|
|
|
|
{
|
|
|
|
if (_mainDocument)
|
|
|
|
_scopes.append(symbol);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-06-01 11:57:25 +02:00
|
|
|
for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
|
|
|
|
Scope *scope = p->scope();
|
|
|
|
for (unsigned i = 0; i < scope->symbolCount(); ++i)
|
|
|
|
accept(scope->symbolAt(i));
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
addScope(symbol);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Block *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(NamespaceAlias *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Declaration *symbol)
|
|
|
|
{
|
|
|
|
if (symbol->isTypedef())
|
|
|
|
addType(symbol->name());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(TypenameArgument *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Enum *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Namespace *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(Class *symbol)
|
|
|
|
{
|
2010-06-01 11:57:25 +02:00
|
|
|
for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
|
|
|
|
Scope *scope = p->scope();
|
|
|
|
for (unsigned i = 0; i < scope->symbolCount(); ++i)
|
|
|
|
accept(scope->symbolAt(i));
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
addScope(symbol);
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ForwardClassDeclaration *symbol)
|
|
|
|
{
|
2010-06-01 11:57:25 +02:00
|
|
|
for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
|
|
|
|
Scope *scope = p->scope();
|
|
|
|
for (unsigned i = 0; i < scope->symbolCount(); ++i)
|
|
|
|
accept(scope->symbolAt(i));
|
|
|
|
}
|
|
|
|
|
2010-05-25 14:53:21 +02:00
|
|
|
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; }
|
|
|
|
|
|
|
|
virtual bool visit(ObjCMethod *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCClass *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCForwardClassDeclaration *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCProtocol *symbol)
|
|
|
|
{
|
|
|
|
addScope(symbol);
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(ObjCForwardProtocolDeclaration *symbol)
|
|
|
|
{
|
|
|
|
addType(symbol->name());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
|
|
|
Q_ASSERT(doc);
|
2010-07-13 15:25:05 +02:00
|
|
|
return (new CheckSymbols(doc, context))->start();
|
2010-07-05 18:52:52 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context)
|
2010-07-07 09:42:56 +02:00
|
|
|
: ASTVisitor(doc->translationUnit()), _doc(doc), _context(context)
|
2009-08-26 14:22:00 +02:00
|
|
|
{
|
2010-07-05 18:52:52 +02:00
|
|
|
_fileName = doc->fileName();
|
|
|
|
CollectTypes collectTypes(doc, context.snapshot());
|
2010-05-25 14:53:21 +02:00
|
|
|
_potentialTypes = collectTypes.types();
|
|
|
|
_scopes = collectTypes.scopes();
|
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()
|
2010-07-07 09:42:56 +02:00
|
|
|
{
|
|
|
|
if (! isCanceled())
|
|
|
|
runFunctor();
|
|
|
|
|
|
|
|
reportFinished();
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::runFunctor()
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
2010-05-21 15:44:35 +02:00
|
|
|
_diagnosticMessages.clear();
|
2010-07-05 18:52:52 +02:00
|
|
|
|
2010-07-06 12:42:55 +02:00
|
|
|
if (_doc->translationUnit()) {
|
2010-07-05 18:52:52 +02:00
|
|
|
accept(_doc->translationUnit()->ast());
|
2010-07-06 12:42:55 +02:00
|
|
|
flush();
|
|
|
|
}
|
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);
|
|
|
|
_diagnosticMessages.append(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
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::preVisit(AST *)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
2010-07-07 09:42:56 +02:00
|
|
|
if (isCanceled())
|
2010-07-05 18:52:52 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
if (! tok.generated()) {
|
|
|
|
unsigned line, column;
|
|
|
|
getTokenStartPosition(ast->identifier_token, &line, &column);
|
|
|
|
Use use(line, column, tok.length());
|
2010-07-05 18:52:52 +02:00
|
|
|
addTypeUsage(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-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(SimpleDeclarationAST *)
|
2009-07-13 11:40:54 +02:00
|
|
|
{
|
2010-05-25 17:49:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
2009-10-05 18:02:01 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(NamedTypeSpecifierAST *)
|
2010-05-25 17:49:29 +02:00
|
|
|
{
|
2010-05-25 14:53:21 +02:00
|
|
|
return true;
|
2009-10-05 18:02:01 +02:00
|
|
|
}
|
2009-11-11 09:32:05 +01:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::checkNamespace(NameAST *name)
|
2009-11-11 09:32:05 +01:00
|
|
|
{
|
2010-05-21 15:44:35 +02:00
|
|
|
if (! name)
|
|
|
|
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-07-05 18:52:52 +02:00
|
|
|
Scope *enclosingScope = _doc->scopeAt(line, column);
|
2010-05-21 15:44:35 +02:00
|
|
|
if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope)) {
|
|
|
|
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();
|
|
|
|
warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length);
|
2010-02-06 14:32:25 +01:00
|
|
|
}
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::checkName(NameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2010-07-09 13:45:12 +02:00
|
|
|
if (ast && ast->name) {
|
2010-06-01 11:57:25 +02:00
|
|
|
if (const Identifier *ident = ast->name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
|
|
|
if (_potentialTypes.contains(id)) {
|
|
|
|
Scope *scope = findScope(ast);
|
|
|
|
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
|
|
|
addTypeUsage(candidates, 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-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(QualifiedNameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
|
|
|
if (ast->name) {
|
2010-06-01 11:57:25 +02:00
|
|
|
Scope *scope = findScope(ast);
|
2010-05-25 14:53:21 +02:00
|
|
|
|
|
|
|
ClassOrNamespace *b = 0;
|
|
|
|
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;
|
|
|
|
b = _context.lookupType(name, scope);
|
|
|
|
addTypeUsage(b, class_or_namespace_name);
|
2010-05-25 14:53:21 +02:00
|
|
|
|
2010-06-04 10:48:24 +02:00
|
|
|
for (it = it->next; b && it; it = it->next) {
|
|
|
|
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) {
|
|
|
|
if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
|
|
|
|
accept(template_id->template_argument_list);
|
2010-06-01 11:57:25 +02:00
|
|
|
|
2010-06-04 10:48:24 +02:00
|
|
|
b = b->findType(class_or_namespace_name->name);
|
|
|
|
addTypeUsage(b, class_or_namespace_name);
|
|
|
|
}
|
2010-05-25 14:53:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b && ast->unqualified_name)
|
|
|
|
addTypeUsage(b->find(ast->unqualified_name->name), ast->unqualified_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
2010-06-03 17:06:18 +02:00
|
|
|
if (ast->name && ast->name->name) {
|
2010-06-01 11:57:25 +02:00
|
|
|
if (const Identifier *templId = ast->name->name->identifier()) {
|
|
|
|
const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size());
|
|
|
|
if (_potentialTypes.contains(id)) {
|
|
|
|
Scope *scope = findScope(_templateDeclarationStack.back());
|
|
|
|
const QList<Symbol *> candidates = _context.lookup(ast->name->name, scope);
|
|
|
|
addTypeUsage(candidates, ast->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
|
|
|
checkName(ast->name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
bool CheckSymbols::visit(TemplateDeclarationAST *ast)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
|
|
|
_templateDeclarationStack.append(ast);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::endVisit(TemplateDeclarationAST *)
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
|
|
|
_templateDeclarationStack.takeFirst();
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::addTypeUsage(const Use &use)
|
2010-07-05 18:52:52 +02:00
|
|
|
{
|
2010-07-06 12:42:55 +02:00
|
|
|
_typeUsages.append(use);
|
|
|
|
|
|
|
|
if (_typeUsages.size() == 50)
|
|
|
|
flush();
|
2010-07-05 18:52:52 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
|
|
|
if (! b)
|
|
|
|
return;
|
|
|
|
|
2010-06-01 11:57:25 +02:00
|
|
|
unsigned startToken = ast->firstToken();
|
|
|
|
if (DestructorNameAST *dtor = ast->asDestructorName())
|
|
|
|
startToken = dtor->identifier_token;
|
|
|
|
|
|
|
|
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();
|
2010-07-05 18:52:52 +02:00
|
|
|
const Use use(line, column, length);
|
|
|
|
addTypeUsage(use);
|
2010-05-25 14:53:21 +02:00
|
|
|
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
2010-05-25 14:53:21 +02:00
|
|
|
{
|
2010-06-01 11:57:25 +02:00
|
|
|
unsigned startToken = ast->firstToken();
|
|
|
|
if (DestructorNameAST *dtor = ast->asDestructorName())
|
|
|
|
startToken = dtor->identifier_token;
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
foreach (Symbol *c, candidates) {
|
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() ||
|
|
|
|
c->isClass() || c->isEnum() ||
|
|
|
|
c->isForwardClassDeclaration() || c->isTypenameArgument()) {
|
2010-07-05 18:52:52 +02:00
|
|
|
const Use use(line, column, length);
|
|
|
|
addTypeUsage(use);
|
2010-05-25 14:53:21 +02:00
|
|
|
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
unsigned CheckSymbols::startOfTemplateDeclaration(TemplateDeclarationAST *ast) const
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
|
|
|
if (ast->declaration) {
|
|
|
|
if (TemplateDeclarationAST *templ = ast->declaration->asTemplateDeclaration())
|
|
|
|
return startOfTemplateDeclaration(templ);
|
|
|
|
|
|
|
|
return ast->declaration->firstToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ast->firstToken();
|
|
|
|
}
|
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
Scope *CheckSymbols::findScope(AST *ast) const
|
2010-06-01 11:57:25 +02:00
|
|
|
{
|
|
|
|
Scope *scope = 0;
|
|
|
|
|
|
|
|
if (ast) {
|
|
|
|
unsigned startToken = ast->firstToken();
|
|
|
|
if (TemplateDeclarationAST *templ = ast->asTemplateDeclaration())
|
|
|
|
startToken = startOfTemplateDeclaration(templ);
|
|
|
|
|
|
|
|
const unsigned tokenOffset = tokenAt(startToken).offset;
|
|
|
|
scope = CollectTypes::findScope(tokenOffset, _scopes);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! scope)
|
2010-07-05 18:52:52 +02:00
|
|
|
scope = _doc->globalSymbols();
|
2010-06-01 11:57:25 +02:00
|
|
|
|
|
|
|
return scope;
|
|
|
|
}
|
2010-07-06 12:42:55 +02:00
|
|
|
|
2010-07-13 15:25:05 +02:00
|
|
|
void CheckSymbols::flush()
|
2010-07-06 12:42:55 +02:00
|
|
|
{
|
|
|
|
if (_typeUsages.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2010-07-07 09:42:56 +02:00
|
|
|
reportResults(_typeUsages);
|
2010-07-06 12:42:55 +02:00
|
|
|
_typeUsages.clear();
|
|
|
|
}
|