Files
qt-creator/src/libs/cplusplus/CppDocument.cpp

939 lines
25 KiB
C++
Raw Normal View History

/**************************************************************************
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator
**
2011-01-11 16:28:15 +01:00
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
2008-12-02 12:01:29 +01:00
**
2011-04-13 08:42:33 +02:00
** Contact: Nokia Corporation (info@qt.nokia.com)
2008-12-02 12:01:29 +01:00
**
**
** GNU Lesser General Public License Usage
**
2011-04-13 08:42:33 +02:00
** 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.
**
2010-12-17 16:01:08 +01:00
** In addition, as a special exception, Nokia gives you certain additional
2011-04-13 08:42:33 +02:00
** rights. These rights are described in the Nokia Qt LGPL Exception
2010-12-17 16:01:08 +01:00
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
2011-04-13 08:42:33 +02:00
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
2010-12-17 16:01:08 +01:00
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
2008-12-02 12:01:29 +01:00
**
**************************************************************************/
2008-12-02 12:01:29 +01:00
#include "CppDocument.h"
#include "FastPreprocessor.h"
#include "LookupContext.h"
#include "Overview.h"
2010-08-13 15:28:22 +02:00
#include "Bind.h"
2008-12-09 15:25:01 +01:00
2008-12-02 12:01:29 +01:00
#include <Control.h>
#include <TranslationUnit.h>
#include <DiagnosticClient.h>
#include <Literals.h>
#include <Symbols.h>
#include <Names.h>
2008-12-02 12:01:29 +01:00
#include <AST.h>
#include <ASTPatternBuilder.h>
#include <ASTMatcher.h>
2008-12-02 12:01:29 +01:00
#include <Scope.h>
#include <SymbolVisitor.h>
#include <NameVisitor.h>
#include <TypeVisitor.h>
#include <CoreTypes.h>
#include <LookupContext.h>
2008-12-02 14:09:21 +01:00
#include <QtCore/QByteArray>
#include <QtCore/QBitArray>
#include <QtCore/QDir>
#include <QtCore/QtDebug>
2008-12-02 12:01:29 +01:00
/*!
\namespace CPlusPlus
The namespace for C++ related tools.
*/
2008-12-02 12:01:29 +01:00
using namespace CPlusPlus;
namespace {
class LastVisibleSymbolAt: protected SymbolVisitor
{
Symbol *root;
unsigned line;
unsigned column;
Symbol *symbol;
public:
LastVisibleSymbolAt(Symbol *root)
: root(root), line(0), column(0), symbol(0) {}
Symbol *operator()(unsigned line, unsigned column)
{
this->line = line;
this->column = column;
this->symbol = 0;
accept(root);
if (! symbol)
symbol = root;
return symbol;
}
protected:
bool preVisit(Symbol *s)
{
if (s->asBlock()) {
if (s->line() < line || (s->line() == line && s->column() <= column)) {
return true;
}
// skip blocks
} if (s->line() < line || (s->line() == line && s->column() <= column)) {
symbol = s;
return true;
}
return false;
}
};
class FindScopeAt: protected SymbolVisitor
{
TranslationUnit *_unit;
unsigned _line;
unsigned _column;
Scope *_scope;
public:
2010-07-16 15:24:42 +02:00
/** line and column should be 1-based */
FindScopeAt(TranslationUnit *unit, unsigned line, unsigned column)
: _unit(unit), _line(line), _column(column), _scope(0) {}
Scope *operator()(Symbol *symbol)
{
accept(symbol);
return _scope;
}
protected:
2010-08-11 12:26:02 +02:00
bool process(Scope *symbol)
{
if (! _scope) {
2010-08-11 12:26:02 +02:00
Scope *scope = symbol;
2010-08-11 12:26:02 +02:00
for (unsigned i = 0; i < scope->memberCount(); ++i) {
accept(scope->memberAt(i));
if (_scope)
return false;
}
unsigned startLine, startColumn;
2010-07-19 10:42:07 +02:00
_unit->getPosition(scope->startOffset(), &startLine, &startColumn);
if (_line > startLine || (_line == startLine && _column >= startColumn)) {
unsigned endLine, endColumn;
2010-07-19 10:42:07 +02:00
_unit->getPosition(scope->endOffset(), &endLine, &endColumn);
if (_line < endLine || (_line == endLine && _column < endColumn))
_scope = scope;
}
}
return false;
}
using SymbolVisitor::visit;
virtual bool preVisit(Symbol *)
{ return ! _scope; }
virtual bool visit(UsingNamespaceDirective *) { return false; }
virtual bool visit(UsingDeclaration *) { return false; }
virtual bool visit(NamespaceAlias *) { return false; }
virtual bool visit(Declaration *) { return false; }
virtual bool visit(Argument *) { return false; }
virtual bool visit(TypenameArgument *) { return false; }
virtual bool visit(BaseClass *) { return false; }
virtual bool visit(ForwardClassDeclaration *) { return false; }
virtual bool visit(Enum *symbol)
{ return process(symbol); }
virtual bool visit(Function *symbol)
{ return process(symbol); }
virtual bool visit(Namespace *symbol)
{ return process(symbol); }
virtual bool visit(Class *symbol)
{ return process(symbol); }
virtual bool visit(Block *symbol)
{ return process(symbol); }
// Objective-C
virtual bool visit(ObjCBaseClass *) { return false; }
virtual bool visit(ObjCBaseProtocol *) { return false; }
virtual bool visit(ObjCForwardClassDeclaration *) { return false; }
virtual bool visit(ObjCForwardProtocolDeclaration *) { return false; }
virtual bool visit(ObjCPropertyDeclaration *) { return false; }
2010-05-20 16:07:11 +02:00
virtual bool visit(ObjCClass *symbol)
{ return process(symbol); }
virtual bool visit(ObjCProtocol *symbol)
{ return process(symbol); }
virtual bool visit(ObjCMethod *symbol)
{ return process(symbol); }
};
2008-12-02 14:09:21 +01:00
class DocumentDiagnosticClient : public DiagnosticClient
{
enum { MAX_MESSAGE_COUNT = 10 };
public:
DocumentDiagnosticClient(Document *doc, QList<Document::DiagnosticMessage> *messages)
: doc(doc),
2009-06-04 11:42:02 +02:00
messages(messages),
errorCount(0)
2008-12-02 14:09:21 +01:00
{ }
virtual void report(int level,
2009-12-01 11:33:13 +01:00
const StringLiteral *fileId,
2008-12-02 14:09:21 +01:00
unsigned line, unsigned column,
const char *format, va_list ap)
{
2009-06-04 11:42:02 +02:00
if (level == Error) {
++errorCount;
if (errorCount >= MAX_MESSAGE_COUNT)
return; // ignore the error
}
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
const QString fileName = QString::fromUtf8(fileId->chars(), fileId->size());
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
if (fileName != doc->fileName())
return;
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
QString message;
message.vsprintf(format, ap);
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
Document::DiagnosticMessage m(convertLevel(level), doc->fileName(),
line, column, message);
messages->append(m);
}
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
static int convertLevel(int level) {
switch (level) {
case Warning: return Document::DiagnosticMessage::Warning;
case Error: return Document::DiagnosticMessage::Error;
case Fatal: return Document::DiagnosticMessage::Fatal;
default: return Document::DiagnosticMessage::Error;
2008-12-02 12:01:29 +01:00
}
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
2009-06-04 11:42:02 +02:00
private:
2008-12-02 14:09:21 +01:00
Document *doc;
QList<Document::DiagnosticMessage> *messages;
2009-06-04 11:42:02 +02:00
int errorCount;
2008-12-02 14:09:21 +01:00
};
2008-12-02 12:01:29 +01:00
2008-12-02 14:09:21 +01:00
} // anonymous namespace
2008-12-02 12:01:29 +01:00
2008-12-02 12:01:29 +01:00
Document::Document(const QString &fileName)
: _fileName(QDir::cleanPath(fileName)),
_globalNamespace(0),
_revision(0),
_editorRevision(0),
_fastCheck(false)
2008-12-02 12:01:29 +01:00
{
_control = new Control();
_control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages));
const QByteArray localFileName = fileName.toUtf8();
const StringLiteral *fileId = _control->stringLiteral(localFileName.constData(),
2009-12-01 11:33:13 +01:00
localFileName.size());
2008-12-02 12:01:29 +01:00
_translationUnit = new TranslationUnit(_control, fileId);
_translationUnit->setQtMocRunEnabled(true);
2010-05-21 10:51:48 +02:00
_translationUnit->setCxxOxEnabled(true);
2009-02-04 11:36:17 +01:00
_translationUnit->setObjCEnabled(true);
2008-12-02 12:01:29 +01:00
(void) _control->switchTranslationUnit(_translationUnit);
}
Document::~Document()
{
delete _translationUnit;
delete _control->diagnosticClient();
delete _control;
}
Control *Document::control() const
2008-12-02 14:09:21 +01:00
{
return _control;
}
2008-12-02 12:01:29 +01:00
unsigned Document::revision() const
{
return _revision;
}
void Document::setRevision(unsigned revision)
{
_revision = revision;
}
unsigned Document::editorRevision() const
{
return _editorRevision;
}
void Document::setEditorRevision(unsigned editorRevision)
{
_editorRevision = editorRevision;
}
QDateTime Document::lastModified() const
{
return _lastModified;
}
void Document::setLastModified(const QDateTime &lastModified)
{
_lastModified = lastModified;
}
2008-12-02 12:01:29 +01:00
QString Document::fileName() const
2008-12-02 14:09:21 +01:00
{
return _fileName;
}
2008-12-02 12:01:29 +01:00
QStringList Document::includedFiles() const
2008-12-02 14:09:21 +01:00
{
QStringList files;
foreach (const Include &i, _includes)
files.append(i.fileName());
files.removeDuplicates();
return files;
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
void Document::addIncludeFile(const QString &fileName, unsigned line)
2008-12-02 14:09:21 +01:00
{
_includes.append(Include(QDir::cleanPath(fileName), line));
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
2008-12-08 12:59:33 +01:00
void Document::appendMacro(const Macro &macro)
2008-12-02 14:09:21 +01:00
{
2008-12-08 12:59:33 +01:00
_definedMacros.append(macro);
2008-12-02 12:01:29 +01:00
}
void Document::addMacroUse(const Macro &macro, unsigned offset, unsigned length,
unsigned beginLine,
const QVector<MacroArgumentReference> &actuals, bool inCondition)
{
MacroUse use(macro, offset, offset + length, beginLine);
use.setInCondition(inCondition);
foreach (const MacroArgumentReference &actual, actuals) {
const Block arg(actual.position(), actual.position() + actual.length());
use.addArgument(arg);
}
_macroUses.append(use);
}
void Document::addUndefinedMacroUse(const QByteArray &name, unsigned offset)
{
QByteArray copy(name.data(), name.size());
UndefinedMacroUse use(copy, offset);
_undefinedMacroUses.append(use);
}
/*!
\class Document::MacroUse
\brief Represents the usage of a macro in a \l {Document}.
\sa Document::UndefinedMacroUse
*/
/*!
\class Document::UndefinedMacroUse
\brief Represents a macro that was looked up, but not found.
Holds data about the reference to a macro in an \tt{#ifdef} or \tt{#ifndef}
or argument to the \tt{defined} operator inside an \tt{#if} or \tt{#elif} that does
not exist.
\sa Document::undefinedMacroUses(), Document::MacroUse, Macro
*/
/*!
\fn QByteArray Document::UndefinedMacroUse::name() const
Returns the name of the macro that was not found.
*/
/*!
\fn QList<UndefinedMacroUse> Document::undefinedMacroUses() const
Returns a list of referenced but undefined macros.
\sa Document::macroUses(), Document::definedMacros(), Macro
*/
/*!
\fn QList<MacroUse> Document::macroUses() const
Returns a list of macros used.
\sa Document::undefinedMacroUses(), Document::definedMacros(), Macro
*/
/*!
\fn QList<Macro> Document::definedMacros() const
Returns the list of macros defined.
\sa Document::macroUses(), Document::undefinedMacroUses()
*/
2008-12-02 12:01:29 +01:00
TranslationUnit *Document::translationUnit() const
2008-12-02 14:09:21 +01:00
{
return _translationUnit;
}
2008-12-02 12:01:29 +01:00
bool Document::skipFunctionBody() const
2008-12-02 14:09:21 +01:00
{
return _translationUnit->skipFunctionBody();
}
2008-12-02 12:01:29 +01:00
void Document::setSkipFunctionBody(bool skipFunctionBody)
2008-12-02 14:09:21 +01:00
{
_translationUnit->setSkipFunctionBody(skipFunctionBody);
}
2008-12-02 12:01:29 +01:00
unsigned Document::globalSymbolCount() const
{
if (! _globalNamespace)
return 0;
return _globalNamespace->memberCount();
}
Symbol *Document::globalSymbolAt(unsigned index) const
2008-12-02 14:09:21 +01:00
{
return _globalNamespace->memberAt(index);
}
2008-12-02 12:01:29 +01:00
Namespace *Document::globalNamespace() const
2008-12-02 14:09:21 +01:00
{
return _globalNamespace;
}
2008-12-02 12:01:29 +01:00
void Document::setGlobalNamespace(Namespace *globalNamespace)
{
_globalNamespace = globalNamespace;
}
Scope *Document::scopeAt(unsigned line, unsigned column)
{
FindScopeAt findScopeAt(_translationUnit, line, column);
if (Scope *scope = findScopeAt(_globalNamespace))
return scope;
2010-08-11 12:26:02 +02:00
return globalNamespace();
}
2010-05-17 13:01:56 +02:00
Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
2008-12-02 14:09:21 +01:00
{
LastVisibleSymbolAt lastVisibleSymbolAt(globalNamespace());
return lastVisibleSymbolAt(line, column);
2008-12-02 12:01:29 +01:00
}
const Macro *Document::findMacroDefinitionAt(unsigned line) const
{
foreach (const Macro &macro, _definedMacros) {
if (macro.line() == line)
return &macro;
}
return 0;
}
const Document::MacroUse *Document::findMacroUseAt(unsigned offset) const
{
foreach (const Document::MacroUse &use, _macroUses) {
if (use.contains(offset))
return &use;
}
return 0;
}
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned offset) const
{
foreach (const Document::UndefinedMacroUse &use, _undefinedMacroUses) {
if (use.contains(offset))
return &use;
}
return 0;
}
2008-12-02 12:01:29 +01:00
Document::Ptr Document::create(const QString &fileName)
{
Document::Ptr doc(new Document(fileName));
return doc;
}
2009-06-05 14:29:57 +02:00
QByteArray Document::source() const
{ return _source; }
2008-12-02 12:01:29 +01:00
void Document::setSource(const QByteArray &source)
2008-12-02 14:09:21 +01:00
{
_source = source;
_translationUnit->setSource(_source.constBegin(), _source.size());
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
void Document::startSkippingBlocks(unsigned start)
2008-12-02 14:09:21 +01:00
{
_skippedBlocks.append(Block(start, 0));
}
2008-12-02 12:01:29 +01:00
void Document::stopSkippingBlocks(unsigned stop)
{
2009-02-10 22:56:04 +01:00
if (_skippedBlocks.isEmpty())
return;
2008-12-02 12:01:29 +01:00
unsigned start = _skippedBlocks.back().begin();
if (start > stop)
_skippedBlocks.removeLast(); // Ignore this block, it's invalid.
else
_skippedBlocks.back() = Block(start, stop);
}
bool Document::isTokenized() const
{
return _translationUnit->isTokenized();
}
void Document::tokenize()
{
_translationUnit->tokenize();
}
bool Document::isParsed() const
{
return _translationUnit->isParsed();
}
bool Document::parse(ParseMode mode)
2008-12-02 14:09:21 +01:00
{
TranslationUnit::ParseMode m = TranslationUnit::ParseTranlationUnit;
switch (mode) {
case ParseTranlationUnit:
m = TranslationUnit::ParseTranlationUnit;
break;
case ParseDeclaration:
m = TranslationUnit::ParseDeclaration;
break;
case ParseExpression:
m = TranslationUnit::ParseExpression;
break;
2009-03-30 15:07:30 +02:00
case ParseDeclarator:
m = TranslationUnit::ParseDeclarator;
break;
case ParseStatement:
m = TranslationUnit::ParseStatement;
break;
default:
break;
}
return _translationUnit->parse(m);
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
2009-06-26 09:11:14 +02:00
void Document::check(CheckMode mode)
2008-12-02 12:01:29 +01:00
{
Q_ASSERT(!_globalNamespace);
2008-12-02 12:01:29 +01:00
2009-09-30 16:13:43 +02:00
if (! isParsed())
parse();
2010-08-13 15:28:22 +02:00
_globalNamespace = _control->newNamespace(0);
Bind semantic(_translationUnit);
if (mode == FastCheck) {
_fastCheck = true;
2009-06-26 09:11:14 +02:00
semantic.setSkipFunctionBodies(true);
}
2008-12-02 12:01:29 +01:00
if (! _translationUnit->ast())
return; // nothing to do.
if (TranslationUnitAST *ast = _translationUnit->ast()->asTranslationUnit()) {
2010-08-13 15:28:22 +02:00
semantic(ast, _globalNamespace);
2009-06-17 11:11:21 +02:00
} else if (ExpressionAST *ast = _translationUnit->ast()->asExpression()) {
2010-08-13 15:28:22 +02:00
semantic(ast, _globalNamespace);
} else if (DeclarationAST *ast = translationUnit()->ast()->asDeclaration()) {
semantic(ast, _globalNamespace);
2008-12-02 12:01:29 +01:00
}
}
void Document::keepSourceAndAST()
{
_keepSourceAndASTCount.ref();
}
void Document::releaseSourceAndAST()
2008-12-02 14:09:21 +01:00
{
if (!_keepSourceAndASTCount.deref()) {
_source.clear();
_translationUnit->release();
if (_fastCheck)
_control->squeeze();
}
2008-12-02 14:09:21 +01:00
}
Snapshot::Snapshot()
{
}
Snapshot::~Snapshot()
{
}
int Snapshot::size() const
{
return _documents.size();
}
bool Snapshot::isEmpty() const
{
return _documents.isEmpty();
}
Document::Ptr Snapshot::operator[](const QString &fileName) const
{
return _documents.value(fileName, Document::Ptr());
}
Snapshot::const_iterator Snapshot::find(const QString &fileName) const
{
return _documents.find(fileName);
}
void Snapshot::remove(const QString &fileName)
{
_documents.remove(fileName);
}
bool Snapshot::contains(const QString &fileName) const
{
return _documents.contains(fileName);
}
void Snapshot::insert(Document::Ptr doc)
{
if (doc)
_documents.insert(doc->fileName(), doc);
}
QByteArray Snapshot::preprocessedCode(const QString &source, const QString &fileName) const
{
FastPreprocessor pp(*this);
return pp.run(fileName, source);
}
Document::Ptr Snapshot::documentFromSource(const QByteArray &preprocessedCode,
const QString &fileName) const
{
2009-06-24 16:40:30 +02:00
Document::Ptr newDoc = Document::create(fileName);
if (Document::Ptr thisDocument = document(fileName)) {
newDoc->_revision = thisDocument->_revision;
newDoc->_editorRevision = thisDocument->_editorRevision;
newDoc->_lastModified = thisDocument->_lastModified;
newDoc->_includes = thisDocument->_includes;
newDoc->_definedMacros = thisDocument->_definedMacros;
newDoc->_macroUses = thisDocument->_macroUses;
}
2009-06-24 16:40:30 +02:00
newDoc->setSource(preprocessedCode);
return newDoc;
}
Document::Ptr Snapshot::document(const QString &fileName) const
{
2009-12-07 11:20:16 +01:00
return _documents.value(fileName);
}
2009-07-10 11:59:01 +02:00
Snapshot Snapshot::simplified(Document::Ptr doc) const
{
Snapshot snapshot;
simplified_helper(doc, &snapshot);
return snapshot;
}
void Snapshot::simplified_helper(Document::Ptr doc, Snapshot *snapshot) const
{
if (! doc)
return;
if (! snapshot->contains(doc->fileName())) {
snapshot->insert(doc);
foreach (const Document::Include &incl, doc->includes()) {
Document::Ptr includedDoc = document(incl.fileName());
2009-07-10 11:59:01 +02:00
simplified_helper(includedDoc, snapshot);
}
}
}
namespace {
class FindMatchingDefinition: public SymbolVisitor
{
Symbol *_declaration;
const OperatorNameId *_oper;
QList<Function *> _result;
public:
FindMatchingDefinition(Symbol *declaration)
: _declaration(declaration)
, _oper(0)
{
if (_declaration->name())
_oper = _declaration->name()->asOperatorNameId();
}
QList<Function *> result() const { return _result; }
using SymbolVisitor::visit;
virtual bool visit(Function *fun)
{
if (_oper) {
if (const Name *name = fun->unqualifiedName()) {
if (_oper->isEqualTo(name))
_result.append(fun);
}
} else if (const Identifier *id = _declaration->identifier()) {
if (id->isEqualTo(fun->identifier()))
_result.append(fun);
}
return false;
}
virtual bool visit(Block *)
{
return false;
}
};
} // end of anonymous namespace
// strict means the returned symbol has to match exactly,
// including argument count and argument types
Symbol *Snapshot::findMatchingDefinition(Symbol *declaration, bool strict) const
{
if (!declaration)
return 0;
Document::Ptr thisDocument = document(QString::fromUtf8(declaration->fileName(), declaration->fileNameLength()));
if (! thisDocument) {
qWarning() << "undefined document:" << declaration->fileName();
return 0;
}
Function *declarationTy = declaration->type()->asFunctionType();
if (! declarationTy) {
qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column();
return 0;
}
foreach (Document::Ptr doc, *this) {
const Identifier *id = declaration->identifier();
if (id && ! doc->control()->findIdentifier(id->chars(),
id->size()))
continue;
if (!id) {
if (!declaration->name())
continue;
const OperatorNameId *oper = declaration->name()->asOperatorNameId();
if (!oper)
continue;
if (!doc->control()->findOperatorNameId(oper->kind()))
continue;
}
FindMatchingDefinition candidates(declaration);
candidates.accept(doc->globalNamespace());
const QList<Function *> result = candidates.result();
if (! result.isEmpty()) {
LookupContext context(doc, *this);
QList<Function *> viableFunctions;
2010-05-21 11:35:03 +02:00
ClassOrNamespace *enclosingType = context.lookupType(declaration);
if (! enclosingType)
continue; // nothing to do
foreach (Function *fun, result) {
const QList<LookupItem> declarations = context.lookup(fun->name(), fun->enclosingScope());
2010-05-21 11:35:03 +02:00
if (declarations.isEmpty())
continue;
const LookupItem best = declarations.first();
if (enclosingType == context.lookupType(best.declaration()))
viableFunctions.append(fun);
}
if (viableFunctions.isEmpty())
continue;
else if (! strict && viableFunctions.length() == 1)
return viableFunctions.first();
Function *best = 0;
foreach (Function *fun, viableFunctions) {
if (! (fun->unqualifiedName() && fun->unqualifiedName()->isEqualTo(declaration->unqualifiedName())))
continue;
else if (fun->argumentCount() == declarationTy->argumentCount()) {
if (! strict && ! best)
best = fun;
unsigned argc = 0;
for (; argc < declarationTy->argumentCount(); ++argc) {
Symbol *arg = fun->argumentAt(argc);
Symbol *otherArg = declarationTy->argumentAt(argc);
if (! arg->type().isEqualTo(otherArg->type()))
break;
}
if (argc == declarationTy->argumentCount())
best = fun;
}
}
if (!strict && ! best)
best = viableFunctions.first();
return best;
}
}
return 0;
}
Class *Snapshot::findMatchingClassDeclaration(Symbol *declaration) const
{
if (! declaration->identifier())
return 0;
foreach (Document::Ptr doc, *this) {
if (! doc->control()->findIdentifier(declaration->identifier()->chars(),
declaration->identifier()->size()))
continue;
LookupContext context(doc, *this);
ClassOrNamespace *type = context.lookupType(declaration);
if (!type)
continue;
foreach (Symbol *s, type->symbols()) {
if (Class *c = s->asClass())
return c;
}
}
return 0;
}
void CPlusPlus::findMatchingDeclaration(const LookupContext &context,
Function *functionType,
QList<Declaration *> *typeMatch,
QList<Declaration *> *argumentCountMatch,
QList<Declaration *> *nameMatch)
{
Scope *enclosingScope = functionType->enclosingScope();
while (! (enclosingScope->isNamespace() || enclosingScope->isClass()))
enclosingScope = enclosingScope->enclosingScope();
Q_ASSERT(enclosingScope != 0);
const Name *functionName = functionType->name();
if (! functionName)
return; // anonymous function names are not valid c++
ClassOrNamespace *binding = 0;
const QualifiedNameId *qName = functionName->asQualifiedNameId();
if (qName) {
if (qName->base())
binding = context.lookupType(qName->base(), enclosingScope);
else
binding = context.globalNamespace();
functionName = qName->name();
}
if (!binding) { // declaration for a global function
binding = context.lookupType(enclosingScope);
if (!binding)
return;
}
const Identifier *funcId = functionName->identifier();
if (!funcId) // E.g. operator, which we might be able to handle in the future...
return;
foreach (Symbol *s, binding->symbols()) {
Class *matchingClass = s->asClass();
if (!matchingClass)
continue;
for (Symbol *s = matchingClass->find(funcId); s; s = s->next()) {
if (! s->name())
continue;
else if (! funcId->isEqualTo(s->identifier()))
continue;
else if (! s->type()->isFunctionType())
continue;
else if (Declaration *decl = s->asDeclaration()) {
if (Function *declFunTy = decl->type()->asFunctionType()) {
if (functionType->isEqualTo(declFunTy))
typeMatch->prepend(decl);
else if (functionType->argumentCount() == declFunTy->argumentCount())
argumentCountMatch->prepend(decl);
else
nameMatch->append(decl);
}
}
}
}
}
QList<Declaration *> CPlusPlus::findMatchingDeclaration(const LookupContext &context, Function *functionType)
{
QList<Declaration *> result;
QList<Declaration *> nameMatch, argumentCountMatch, typeMatch;
findMatchingDeclaration(context, functionType, &typeMatch, &argumentCountMatch, &nameMatch);
result.append(typeMatch);
result.append(argumentCountMatch);
result.append(nameMatch);
return result;
}