forked from qt-creator/qt-creator
Introduced helpers to rewrite types and names.
Done-with: Erik Verbruggen
This commit is contained in:
@@ -740,11 +740,12 @@ Symbol *Snapshot::findMatchingDefinition(Symbol *declaration) const
|
|||||||
continue; // nothing to do
|
continue; // nothing to do
|
||||||
|
|
||||||
foreach (Function *fun, result) {
|
foreach (Function *fun, result) {
|
||||||
const QList<Symbol *> declarations = context.lookup(fun->name(), fun->scope());
|
const QList<LookupItem> declarations = context.lookup(fun->name(), fun->scope());
|
||||||
if (declarations.isEmpty())
|
if (declarations.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
else if (enclosingType == context.lookupType(declarations.first()))
|
const LookupItem best = declarations.first();
|
||||||
|
if (enclosingType == context.lookupType(best.declaration()))
|
||||||
viableFunctions.append(fun);
|
viableFunctions.append(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
364
src/libs/cplusplus/CppRewriter.cpp
Normal file
364
src/libs/cplusplus/CppRewriter.cpp
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
** contact the sales department at http://qt.nokia.com/contact.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
#include "CppRewriter.h"
|
||||||
|
#include <TypeVisitor.h>
|
||||||
|
#include <NameVisitor.h>
|
||||||
|
#include <CoreTypes.h>
|
||||||
|
#include <Symbols.h>
|
||||||
|
#include <Literals.h>
|
||||||
|
#include <Names.h>
|
||||||
|
#include <Scope.h>
|
||||||
|
|
||||||
|
#include <QtCore/QVarLengthArray>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
|
class CPlusPlus::Rewrite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Rewrite(Control *control, const SubstitutionEnvironment &env)
|
||||||
|
: control(control), env(env), rewriteType(this), rewriteName(this) {}
|
||||||
|
|
||||||
|
class RewriteType: public TypeVisitor
|
||||||
|
{
|
||||||
|
Rewrite *rewrite;
|
||||||
|
QList<FullySpecifiedType> temps;
|
||||||
|
|
||||||
|
Control *control() const
|
||||||
|
{ return rewrite->control; }
|
||||||
|
|
||||||
|
void accept(const FullySpecifiedType &ty)
|
||||||
|
{
|
||||||
|
TypeVisitor::accept(ty.type());
|
||||||
|
unsigned flags = ty.flags();
|
||||||
|
flags |= temps.back().flags();
|
||||||
|
temps.back().setFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
RewriteType(Rewrite *r): rewrite(r) {}
|
||||||
|
|
||||||
|
FullySpecifiedType operator()(const FullySpecifiedType &ty)
|
||||||
|
{
|
||||||
|
accept(ty);
|
||||||
|
return temps.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(UndefinedType *)
|
||||||
|
{
|
||||||
|
temps.append(FullySpecifiedType());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(VoidType *)
|
||||||
|
{
|
||||||
|
temps.append(control()->voidType());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(IntegerType *type)
|
||||||
|
{
|
||||||
|
temps.append(control()->integerType(type->kind()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(FloatType *type)
|
||||||
|
{
|
||||||
|
temps.append(control()->floatType(type->kind()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(PointerToMemberType *type)
|
||||||
|
{
|
||||||
|
const Name *memberName = rewrite->rewriteName(type->memberName());
|
||||||
|
const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
|
||||||
|
temps.append(control()->pointerToMemberType(memberName, elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(PointerType *type)
|
||||||
|
{
|
||||||
|
const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
|
||||||
|
temps.append(control()->pointerType(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ReferenceType *type)
|
||||||
|
{
|
||||||
|
const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
|
||||||
|
temps.append(control()->referenceType(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ArrayType *type)
|
||||||
|
{
|
||||||
|
const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
|
||||||
|
temps.append(control()->arrayType(elementType, type->size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(NamedType *type)
|
||||||
|
{
|
||||||
|
FullySpecifiedType ty = rewrite->env.apply(type->name(), rewrite);
|
||||||
|
if (! ty->isUndefinedType())
|
||||||
|
temps.append(rewrite->rewriteType(ty));
|
||||||
|
else {
|
||||||
|
const Name *name = rewrite->rewriteName(type->name());
|
||||||
|
temps.append(control()->namedType(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(Function *type)
|
||||||
|
{
|
||||||
|
Function *funTy = control()->newFunction(0, 0);
|
||||||
|
funTy->copy(type);
|
||||||
|
|
||||||
|
funTy->setName(rewrite->rewriteName(type->name()));
|
||||||
|
|
||||||
|
funTy->setReturnType(rewrite->rewriteType(type->returnType()));
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < type->argumentCount(); ++i) {
|
||||||
|
Symbol *arg = type->argumentAt(i);
|
||||||
|
|
||||||
|
Argument *newArg = control()->newArgument(0, 0);
|
||||||
|
newArg->copy(arg);
|
||||||
|
newArg->setName(rewrite->rewriteName(arg->name()));
|
||||||
|
newArg->setType(rewrite->rewriteType(arg->type()));
|
||||||
|
|
||||||
|
funTy->arguments()->enterSymbol(newArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
temps.append(funTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(Namespace *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(Class *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(Enum *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ForwardClassDeclaration *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ObjCClass *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ObjCProtocol *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ObjCMethod *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ObjCForwardClassDeclaration *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(ObjCForwardProtocolDeclaration *type)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO;
|
||||||
|
temps.append(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class RewriteName: public NameVisitor
|
||||||
|
{
|
||||||
|
Rewrite *rewrite;
|
||||||
|
QList<const Name *> temps;
|
||||||
|
|
||||||
|
Control *control() const
|
||||||
|
{ return rewrite->control; }
|
||||||
|
|
||||||
|
const Identifier *identifier(const Identifier *other) const
|
||||||
|
{
|
||||||
|
if (! other)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return control()->findOrInsertIdentifier(other->chars(), other->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
RewriteName(Rewrite *r): rewrite(r) {}
|
||||||
|
|
||||||
|
const Name *operator()(const Name *name)
|
||||||
|
{
|
||||||
|
if (! name)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
accept(name);
|
||||||
|
return temps.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const QualifiedNameId *name)
|
||||||
|
{
|
||||||
|
const Name *base = rewrite->rewriteName(name->base());
|
||||||
|
const Name *n = rewrite->rewriteName(name->name());
|
||||||
|
temps.append(control()->qualifiedNameId(base, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const NameId *name)
|
||||||
|
{
|
||||||
|
temps.append(control()->nameId(identifier(name->identifier())));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const TemplateNameId *name)
|
||||||
|
{
|
||||||
|
QVarLengthArray<FullySpecifiedType, 8> args(name->templateArgumentCount());
|
||||||
|
for (unsigned i = 0; i < name->templateArgumentCount(); ++i)
|
||||||
|
args[i] = rewrite->rewriteType(name->templateArgumentAt(i));
|
||||||
|
temps.append(control()->templateNameId(identifier(name->identifier()), args.data(), args.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const DestructorNameId *name)
|
||||||
|
{
|
||||||
|
temps.append(control()->destructorNameId(identifier(name->identifier())));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const OperatorNameId *name)
|
||||||
|
{
|
||||||
|
temps.append(control()->operatorNameId(name->kind()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const ConversionNameId *name)
|
||||||
|
{
|
||||||
|
FullySpecifiedType ty = rewrite->rewriteType(name->type());
|
||||||
|
temps.append(control()->conversionNameId(ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const SelectorNameId *name)
|
||||||
|
{
|
||||||
|
QVarLengthArray<const Name *, 8> names(name->nameCount());
|
||||||
|
for (unsigned i = 0; i < name->nameCount(); ++i)
|
||||||
|
names[i] = rewrite->rewriteName(name->nameAt(i));
|
||||||
|
temps.append(control()->selectorNameId(names.constData(), names.size(), name->hasArguments()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public: // attributes
|
||||||
|
Control *control;
|
||||||
|
SubstitutionEnvironment env;
|
||||||
|
RewriteType rewriteType;
|
||||||
|
RewriteName rewriteName;
|
||||||
|
};
|
||||||
|
|
||||||
|
ContextSubstitution::ContextSubstitution(const LookupContext &context, Scope *scope)
|
||||||
|
: _context(context), _scope(scope)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextSubstitution::~ContextSubstitution()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FullySpecifiedType ContextSubstitution::apply(const Name *name, Rewrite *rewrite) const
|
||||||
|
{
|
||||||
|
const QList<LookupItem> candidates = _context.lookup(name, _scope);
|
||||||
|
|
||||||
|
foreach (const LookupItem &r, candidates) {
|
||||||
|
Symbol *s = r.declaration();
|
||||||
|
if (s->isDeclaration() && s->isTypedef()) {
|
||||||
|
qDebug() << "resolved typedef:" << s->fileName() << s->line() << s->column();
|
||||||
|
|
||||||
|
qDebug() << "scope is:" << r.scope()->owner()->fileName()
|
||||||
|
<< r.scope()->owner()->line()
|
||||||
|
<< r.scope()->owner()->column();
|
||||||
|
|
||||||
|
ContextSubstitution subst(_context, s->scope());
|
||||||
|
rewrite->env.enter(&subst);
|
||||||
|
FullySpecifiedType ty = rewrite->rewriteType(s->type());
|
||||||
|
rewrite->env.leave();
|
||||||
|
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FullySpecifiedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SubstitutionMap::SubstitutionMap()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SubstitutionMap::~SubstitutionMap()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubstitutionMap::bind(const Name *name, const FullySpecifiedType &ty)
|
||||||
|
{
|
||||||
|
_map.append(qMakePair(name, ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
FullySpecifiedType SubstitutionMap::apply(const Name *name, Rewrite *) const
|
||||||
|
{
|
||||||
|
for (int n = _map.size() - 1; n != -1; --n) {
|
||||||
|
const QPair<const Name *, FullySpecifiedType> &p = _map.at(n);
|
||||||
|
|
||||||
|
if (name->isEqualTo(p.first))
|
||||||
|
return p.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FullySpecifiedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
FullySpecifiedType CPlusPlus::rewriteType(const FullySpecifiedType &type,
|
||||||
|
const SubstitutionEnvironment &env,
|
||||||
|
Control *control)
|
||||||
|
{
|
||||||
|
Rewrite rewrite(control, env);
|
||||||
|
return rewrite.rewriteType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Name *CPlusPlus::rewriteName(const Name *name,
|
||||||
|
const SubstitutionEnvironment &env,
|
||||||
|
Control *control)
|
||||||
|
{
|
||||||
|
Rewrite rewrite(control, env);
|
||||||
|
return rewrite.rewriteName(name);
|
||||||
|
}
|
||||||
119
src/libs/cplusplus/CppRewriter.h
Normal file
119
src/libs/cplusplus/CppRewriter.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
** contact the sales department at http://qt.nokia.com/contact.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CPLUSPLUS_REWRITER_H
|
||||||
|
#define CPLUSPLUS_REWRITER_H
|
||||||
|
|
||||||
|
#include "CppDocument.h"
|
||||||
|
#include "LookupContext.h"
|
||||||
|
|
||||||
|
namespace CPlusPlus {
|
||||||
|
|
||||||
|
class Rewrite;
|
||||||
|
|
||||||
|
class CPLUSPLUS_EXPORT Substitution
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY(Substitution)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Substitution() {}
|
||||||
|
virtual ~Substitution() {}
|
||||||
|
|
||||||
|
virtual FullySpecifiedType apply(const Name *name, Rewrite *rewrite) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPLUSPLUS_EXPORT SubstitutionEnvironment
|
||||||
|
{
|
||||||
|
QList<Substitution *> substs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FullySpecifiedType apply(const Name *name, Rewrite *rewrite) const
|
||||||
|
{
|
||||||
|
if (name) {
|
||||||
|
for (int index = substs.size() - 1; index != -1; --index) {
|
||||||
|
const Substitution *subst = substs.at(index);
|
||||||
|
|
||||||
|
FullySpecifiedType ty = subst->apply(name, rewrite);
|
||||||
|
if (! ty->isUndefinedType())
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FullySpecifiedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enter(Substitution *subst)
|
||||||
|
{
|
||||||
|
substs.append(subst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void leave()
|
||||||
|
{
|
||||||
|
substs.removeLast();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPLUSPLUS_EXPORT ContextSubstitution: public Substitution
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContextSubstitution(const LookupContext &context, Scope *scope);
|
||||||
|
virtual ~ContextSubstitution();
|
||||||
|
|
||||||
|
virtual FullySpecifiedType apply(const Name *name, Rewrite *rewrite) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LookupContext _context;
|
||||||
|
Scope *_scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CPLUSPLUS_EXPORT SubstitutionMap: public Substitution
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SubstitutionMap();
|
||||||
|
virtual ~SubstitutionMap();
|
||||||
|
|
||||||
|
void bind(const Name *name, const FullySpecifiedType &ty);
|
||||||
|
virtual FullySpecifiedType apply(const Name *name, Rewrite *rewrite) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<QPair<const Name *, FullySpecifiedType> > _map;
|
||||||
|
};
|
||||||
|
|
||||||
|
CPLUSPLUS_EXPORT FullySpecifiedType rewriteType(const FullySpecifiedType &type,
|
||||||
|
const SubstitutionEnvironment &env,
|
||||||
|
Control *control);
|
||||||
|
|
||||||
|
CPLUSPLUS_EXPORT const Name *rewriteName(const Name *name,
|
||||||
|
const SubstitutionEnvironment &env,
|
||||||
|
Control *control);
|
||||||
|
|
||||||
|
} // end of namespace CPlusPlus
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution;
|
typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, QSharedPointer<Control> control);
|
Q_DECL_DEPRECATED static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, QSharedPointer<Control> control);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution);
|
DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution);
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ Scope *FindUsages::scopeAt(unsigned tokenIndex) const
|
|||||||
return _doc->scopeAt(line, column);
|
return _doc->scopeAt(line, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindUsages::reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates)
|
void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates)
|
||||||
{
|
{
|
||||||
if (_processed.contains(tokenIndex))
|
if (_processed.contains(tokenIndex))
|
||||||
return;
|
return;
|
||||||
@@ -160,11 +160,12 @@ void FindUsages::reportResult(unsigned tokenIndex)
|
|||||||
_references.append(tokenIndex);
|
_references.append(tokenIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindUsages::checkCandidates(const QList<Symbol *> &candidates) const
|
bool FindUsages::checkCandidates(const QList<LookupItem> &candidates) const
|
||||||
{
|
{
|
||||||
if (ClassOrNamespace *c = _context.lookupType(_declSymbol)) {
|
if (ClassOrNamespace *c = _context.lookupType(_declSymbol)) {
|
||||||
for (int i = candidates.size() - 1; i != -1; --i) {
|
for (int i = candidates.size() - 1; i != -1; --i) {
|
||||||
Symbol *s = candidates.at(i);
|
const LookupItem &r = candidates.at(i);
|
||||||
|
Symbol *s = r.declaration();
|
||||||
if (_context.lookupType(s) == c)
|
if (_context.lookupType(s) == c)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -186,7 +187,7 @@ bool FindUsages::visit(MemInitializerAST *ast)
|
|||||||
|
|
||||||
SimpleNameAST *simple = ast->name->asSimpleName();
|
SimpleNameAST *simple = ast->name->asSimpleName();
|
||||||
if (identifier(simple->identifier_token) == _id) {
|
if (identifier(simple->identifier_token) == _id) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(simple->name, scopeAt(simple->identifier_token));
|
const QList<LookupItem> candidates = _context.lookup(simple->name, scopeAt(simple->identifier_token));
|
||||||
reportResult(simple->identifier_token, candidates);
|
reportResult(simple->identifier_token, candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,14 +224,7 @@ void FindUsages::checkExpression(unsigned startToken, unsigned endToken)
|
|||||||
const QList<LookupItem> results = typeofExpression(expression, scope,
|
const QList<LookupItem> results = typeofExpression(expression, scope,
|
||||||
TypeOfExpression::Preprocess);
|
TypeOfExpression::Preprocess);
|
||||||
|
|
||||||
QList<Symbol *> candidates;
|
reportResult(endToken, results);
|
||||||
|
|
||||||
foreach (const LookupItem &r, results) {
|
|
||||||
Symbol *lastVisibleSymbol = r.declaration();
|
|
||||||
candidates.append(lastVisibleSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
reportResult(endToken, candidates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindUsages::visit(QualifiedNameAST *ast)
|
bool FindUsages::visit(QualifiedNameAST *ast)
|
||||||
@@ -297,7 +291,7 @@ bool FindUsages::visit(EnumeratorAST *ast)
|
|||||||
{
|
{
|
||||||
const Identifier *id = identifier(ast->identifier_token);
|
const Identifier *id = identifier(ast->identifier_token);
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(control()->nameId(id), scopeAt(ast->identifier_token));
|
const QList<LookupItem> candidates = _context.lookup(control()->nameId(id), scopeAt(ast->identifier_token));
|
||||||
reportResult(ast->identifier_token, candidates);
|
reportResult(ast->identifier_token, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +304,7 @@ bool FindUsages::visit(SimpleNameAST *ast)
|
|||||||
{
|
{
|
||||||
const Identifier *id = identifier(ast->identifier_token);
|
const Identifier *id = identifier(ast->identifier_token);
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
||||||
reportResult(ast->identifier_token, candidates);
|
reportResult(ast->identifier_token, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +315,7 @@ bool FindUsages::visit(DestructorNameAST *ast)
|
|||||||
{
|
{
|
||||||
const Identifier *id = identifier(ast->identifier_token);
|
const Identifier *id = identifier(ast->identifier_token);
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
||||||
reportResult(ast->identifier_token, candidates);
|
reportResult(ast->identifier_token, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +325,7 @@ bool FindUsages::visit(DestructorNameAST *ast)
|
|||||||
bool FindUsages::visit(TemplateIdAST *ast)
|
bool FindUsages::visit(TemplateIdAST *ast)
|
||||||
{
|
{
|
||||||
if (_id == identifier(ast->identifier_token)) {
|
if (_id == identifier(ast->identifier_token)) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
|
||||||
reportResult(ast->identifier_token, candidates);
|
reportResult(ast->identifier_token, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +400,7 @@ bool FindUsages::visit(ObjCSelectorAST *ast)
|
|||||||
if (ast->name) {
|
if (ast->name) {
|
||||||
const Identifier *id = ast->name->identifier();
|
const Identifier *id = ast->name->identifier();
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->firstToken()));
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scopeAt(ast->firstToken()));
|
||||||
reportResult(ast->firstToken(), candidates);
|
reportResult(ast->firstToken(), candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -440,7 +434,7 @@ bool FindUsages::visit(TypenameTypeParameterAST *ast)
|
|||||||
const Identifier *id = name->name->identifier();
|
const Identifier *id = name->name->identifier();
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
|
unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
|
||||||
const QList<Symbol *> candidates = _context.lookup(name->name, scopeAt(start));
|
const QList<LookupItem> candidates = _context.lookup(name->name, scopeAt(start));
|
||||||
reportResult(ast->name->firstToken(), candidates);
|
reportResult(ast->name->firstToken(), candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,7 +448,7 @@ bool FindUsages::visit(TemplateTypeParameterAST *ast)
|
|||||||
const Identifier *id = name->name->identifier();
|
const Identifier *id = name->name->identifier();
|
||||||
if (id == _id) {
|
if (id == _id) {
|
||||||
unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
|
unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
|
||||||
const QList<Symbol *> candidates = _context.lookup(name->name, scopeAt(start));
|
const QList<LookupItem> candidates = _context.lookup(name->name, scopeAt(start));
|
||||||
reportResult(ast->name->firstToken(), candidates);
|
reportResult(ast->name->firstToken(), candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,10 +74,10 @@ protected:
|
|||||||
QString matchingLine(const Token &tk) const;
|
QString matchingLine(const Token &tk) const;
|
||||||
Scope *scopeAt(unsigned tokenIndex) const;
|
Scope *scopeAt(unsigned tokenIndex) const;
|
||||||
|
|
||||||
void reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates);
|
void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates);
|
||||||
void reportResult(unsigned tokenIndex);
|
void reportResult(unsigned tokenIndex);
|
||||||
|
|
||||||
bool checkCandidates(const QList<Symbol *> &candidates) const;
|
bool checkCandidates(const QList<LookupItem> &candidates) const;
|
||||||
void checkExpression(unsigned startToken, unsigned endToken);
|
void checkExpression(unsigned startToken, unsigned endToken);
|
||||||
|
|
||||||
void ensureNameIsValid(NameAST *ast);
|
void ensureNameIsValid(NameAST *ast);
|
||||||
|
|||||||
@@ -39,14 +39,18 @@
|
|||||||
#include <Scope.h>
|
#include <Scope.h>
|
||||||
#include <Control.h>
|
#include <Control.h>
|
||||||
|
|
||||||
#include <QtDebug>
|
#include <QtCore/QStack>
|
||||||
|
#include <QtCore/QHash>
|
||||||
namespace {
|
#include <QtCore/QVarLengthArray>
|
||||||
const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty();
|
#include <QtCore/QtDebug>
|
||||||
}
|
|
||||||
|
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty();
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
static void addNames(const Name *name, QList<const Name *> *names, bool addAllNames = false)
|
static void addNames(const Name *name, QList<const Name *> *names, bool addAllNames = false)
|
||||||
{
|
{
|
||||||
if (! name)
|
if (! name)
|
||||||
@@ -241,16 +245,16 @@ ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const
|
|||||||
return bindings()->lookupType(symbol);
|
return bindings()->lookupType(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
|
QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
||||||
{
|
{
|
||||||
QList<Symbol *> candidates;
|
QList<LookupItem> candidates;
|
||||||
|
|
||||||
if (! name)
|
if (! name)
|
||||||
return candidates;
|
return candidates;
|
||||||
|
|
||||||
for (; scope; scope = scope->enclosingScope()) {
|
for (; scope; scope = scope->enclosingScope()) {
|
||||||
if ((name->isNameId() || name->isTemplateNameId()) && scope->isBlockScope()) {
|
if ((name->isNameId() || name->isTemplateNameId()) && scope->isBlockScope()) {
|
||||||
bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0);
|
bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty())
|
||||||
break; // it's a local.
|
break; // it's a local.
|
||||||
@@ -274,10 +278,10 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
|
|
||||||
} else if (scope->isFunctionScope()) {
|
} else if (scope->isFunctionScope()) {
|
||||||
Function *fun = scope->owner()->asFunction();
|
Function *fun = scope->owner()->asFunction();
|
||||||
bindings()->lookupInScope(name, fun->arguments(), &candidates, /*templateId = */ 0);
|
bindings()->lookupInScope(name, fun->arguments(), &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
for (TemplateParameters *it = fun->templateParameters(); it && candidates.isEmpty(); it = it->previous())
|
for (TemplateParameters *it = fun->templateParameters(); it && candidates.isEmpty(); it = it->previous())
|
||||||
bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0);
|
bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty())
|
||||||
break; // it's an argument or a template parameter.
|
break; // it's an argument or a template parameter.
|
||||||
@@ -295,7 +299,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
|
|
||||||
} else if (scope->isObjCMethodScope()) {
|
} else if (scope->isObjCMethodScope()) {
|
||||||
ObjCMethod *method = scope->owner()->asObjCMethod();
|
ObjCMethod *method = scope->owner()->asObjCMethod();
|
||||||
bindings()->lookupInScope(name, method->arguments(), &candidates, /*templateId = */ 0);
|
bindings()->lookupInScope(name, method->arguments(), &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty())
|
||||||
break; // it's a formal argument.
|
break; // it's a formal argument.
|
||||||
@@ -304,7 +308,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
Class *klass = scope->owner()->asClass();
|
Class *klass = scope->owner()->asClass();
|
||||||
|
|
||||||
for (TemplateParameters *it = klass->templateParameters(); it && candidates.isEmpty(); it = it->previous())
|
for (TemplateParameters *it = klass->templateParameters(); it && candidates.isEmpty(); it = it->previous())
|
||||||
bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0);
|
bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0, /*binding=*/ 0);
|
||||||
|
|
||||||
if (! candidates.isEmpty())
|
if (! candidates.isEmpty())
|
||||||
break; // it's an argument or a template parameter.
|
break; // it's an argument or a template parameter.
|
||||||
@@ -398,19 +402,19 @@ ClassOrNamespace *ClassOrNamespace::globalNamespace() const
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Symbol *> ClassOrNamespace::find(const Name *name)
|
QList<LookupItem> ClassOrNamespace::find(const Name *name)
|
||||||
{
|
{
|
||||||
return lookup_helper(name, false);
|
return lookup_helper(name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
|
QList<LookupItem> ClassOrNamespace::lookup(const Name *name)
|
||||||
{
|
{
|
||||||
return lookup_helper(name, true);
|
return lookup_helper(name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Symbol *> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
|
QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
|
||||||
{
|
{
|
||||||
QList<Symbol *> result;
|
QList<LookupItem> result;
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
if (const QualifiedNameId *q = name->asQualifiedNameId()) {
|
if (const QualifiedNameId *q = name->asQualifiedNameId()) {
|
||||||
@@ -435,9 +439,9 @@ QList<Symbol *> ClassOrNamespace::lookup_helper(const Name *name, bool searchInE
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
|
void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
|
||||||
QList<Symbol *> *result,
|
QList<LookupItem> *result,
|
||||||
QSet<ClassOrNamespace *> *processed,
|
QSet<ClassOrNamespace *> *processed,
|
||||||
const TemplateNameId *templateId)
|
const TemplateNameId *templateId)
|
||||||
{
|
{
|
||||||
if (binding && ! processed->contains(binding)) {
|
if (binding && ! processed->contains(binding)) {
|
||||||
processed->insert(binding);
|
processed->insert(binding);
|
||||||
@@ -448,16 +452,20 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding
|
|||||||
if (ScopedSymbol *scoped = s->asScopedSymbol()) {
|
if (ScopedSymbol *scoped = s->asScopedSymbol()) {
|
||||||
if (Class *klass = scoped->asClass()) {
|
if (Class *klass = scoped->asClass()) {
|
||||||
if (const Identifier *id = klass->identifier()) {
|
if (const Identifier *id = klass->identifier()) {
|
||||||
if (nameId && nameId->isEqualTo(id))
|
if (nameId && nameId->isEqualTo(id)) {
|
||||||
result->append(klass);
|
LookupItem item;
|
||||||
|
item.setDeclaration(klass);
|
||||||
|
item.setBinding(binding);
|
||||||
|
result->append(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_factory->lookupInScope(name, scoped->members(), result, templateId);
|
_factory->lookupInScope(name, scoped->members(), result, templateId, binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Enum *e, binding->enums())
|
foreach (Enum *e, binding->enums())
|
||||||
_factory->lookupInScope(name, e->members(), result, templateId);
|
_factory->lookupInScope(name, e->members(), result, templateId, binding);
|
||||||
|
|
||||||
foreach (ClassOrNamespace *u, binding->usings())
|
foreach (ClassOrNamespace *u, binding->usings())
|
||||||
lookup_helper(name, u, result, processed, binding->_templateId);
|
lookup_helper(name, u, result, processed, binding->_templateId);
|
||||||
@@ -465,8 +473,9 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
|
void CreateBindings::lookupInScope(const Name *name, Scope *scope,
|
||||||
QList<Symbol *> *result,
|
QList<LookupItem> *result,
|
||||||
const TemplateNameId *templateId)
|
const TemplateNameId *templateId,
|
||||||
|
ClassOrNamespace *binding)
|
||||||
{
|
{
|
||||||
Q_UNUSED(templateId);
|
Q_UNUSED(templateId);
|
||||||
|
|
||||||
@@ -480,7 +489,10 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope,
|
|||||||
else if (! s->name()->isEqualTo(op))
|
else if (! s->name()->isEqualTo(op))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result->append(s);
|
LookupItem item;
|
||||||
|
item.setDeclaration(s);
|
||||||
|
item.setBinding(binding);
|
||||||
|
result->append(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (const Identifier *id = name->identifier()) {
|
} else if (const Identifier *id = name->identifier()) {
|
||||||
@@ -490,34 +502,17 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope,
|
|||||||
else if (s->name()->isQualifiedNameId())
|
else if (s->name()->isQualifiedNameId())
|
||||||
continue; // skip qualified ids.
|
continue; // skip qualified ids.
|
||||||
|
|
||||||
|
LookupItem item;
|
||||||
|
item.setDeclaration(s);
|
||||||
|
item.setBinding(binding);
|
||||||
|
|
||||||
if (templateId && (s->isDeclaration() || s->isFunction())) {
|
if (templateId && (s->isDeclaration() || s->isFunction())) {
|
||||||
|
|
||||||
FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, _control);
|
FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, _control);
|
||||||
|
item.setType(ty); // override the type.
|
||||||
if (debug) {
|
|
||||||
Overview oo;
|
|
||||||
oo.setShowFunctionSignatures(true);
|
|
||||||
oo.setShowReturnTypes(true);
|
|
||||||
qDebug() << "instantiate:" << oo(s->type(), s->name()) << "using:" << oo(templateId) << oo(ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Declaration *decl = s->asDeclaration()) {
|
|
||||||
Declaration *d = _control->newDeclaration(0, 0);
|
|
||||||
d->copy(decl);
|
|
||||||
d->setType(ty);
|
|
||||||
result->append(d);
|
|
||||||
continue;
|
|
||||||
} else if (Function *fun = s->asFunction()) {
|
|
||||||
Function *d = ty->asFunctionType();
|
|
||||||
d->copy(fun);
|
|
||||||
result->append(d);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result->append(s);
|
result->append(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -987,3 +982,4 @@ bool CreateBindings::visit(ObjCMethod *)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include <Type.h>
|
#include <Type.h>
|
||||||
#include <SymbolVisitor.h>
|
#include <SymbolVisitor.h>
|
||||||
#include <Control.h>
|
#include <Control.h>
|
||||||
|
#include <Name.h>
|
||||||
#include <QtCore/QSet>
|
#include <QtCore/QSet>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -57,8 +58,8 @@ public:
|
|||||||
|
|
||||||
ClassOrNamespace *globalNamespace() const;
|
ClassOrNamespace *globalNamespace() const;
|
||||||
|
|
||||||
QList<Symbol *> lookup(const Name *name);
|
QList<LookupItem> lookup(const Name *name);
|
||||||
QList<Symbol *> find(const Name *name);
|
QList<LookupItem> find(const Name *name);
|
||||||
|
|
||||||
ClassOrNamespace *lookupType(const Name *name);
|
ClassOrNamespace *lookupType(const Name *name);
|
||||||
ClassOrNamespace *findType(const Name *name);
|
ClassOrNamespace *findType(const Name *name);
|
||||||
@@ -76,12 +77,12 @@ private:
|
|||||||
void addUsing(ClassOrNamespace *u);
|
void addUsing(ClassOrNamespace *u);
|
||||||
void addNestedType(const Name *alias, ClassOrNamespace *e);
|
void addNestedType(const Name *alias, ClassOrNamespace *e);
|
||||||
|
|
||||||
QList<Symbol *> lookup_helper(const Name *name, bool searchInEnclosingScope);
|
QList<LookupItem> lookup_helper(const Name *name, bool searchInEnclosingScope);
|
||||||
|
|
||||||
void lookup_helper(const Name *name, ClassOrNamespace *binding,
|
void lookup_helper(const Name *name, ClassOrNamespace *binding,
|
||||||
QList<Symbol *> *result,
|
QList<LookupItem> *result,
|
||||||
QSet<ClassOrNamespace *> *processed,
|
QSet<ClassOrNamespace *> *processed,
|
||||||
const TemplateNameId *templateId);
|
const TemplateNameId *templateId);
|
||||||
|
|
||||||
ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
|
ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
|
||||||
bool searchInEnclosingScope);
|
bool searchInEnclosingScope);
|
||||||
@@ -134,8 +135,8 @@ public:
|
|||||||
/// Searches in \a scope for symbols with the given \a name.
|
/// Searches in \a scope for symbols with the given \a name.
|
||||||
/// Store the result in \a results.
|
/// Store the result in \a results.
|
||||||
/// \internal
|
/// \internal
|
||||||
void lookupInScope(const Name *name, Scope *scope, QList<Symbol *> *result,
|
void lookupInScope(const Name *name, Scope *scope, QList<LookupItem> *result,
|
||||||
const TemplateNameId *templateId);
|
const TemplateNameId *templateId, ClassOrNamespace *binding);
|
||||||
|
|
||||||
/// Create bindings for the symbols reachable from \a rootSymbol.
|
/// Create bindings for the symbols reachable from \a rootSymbol.
|
||||||
/// \internal
|
/// \internal
|
||||||
@@ -214,7 +215,7 @@ public:
|
|||||||
|
|
||||||
ClassOrNamespace *globalNamespace() const;
|
ClassOrNamespace *globalNamespace() const;
|
||||||
|
|
||||||
QList<Symbol *> lookup(const Name *name, Scope *scope) const;
|
QList<LookupItem> lookup(const Name *name, Scope *scope) const;
|
||||||
ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
|
ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
|
||||||
ClassOrNamespace *lookupType(Symbol *symbol) const;
|
ClassOrNamespace *lookupType(Symbol *symbol) const;
|
||||||
ClassOrNamespace *lookupParent(Symbol *symbol) const;
|
ClassOrNamespace *lookupParent(Symbol *symbol) const;
|
||||||
|
|||||||
@@ -44,11 +44,16 @@ uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LookupItem::LookupItem()
|
LookupItem::LookupItem()
|
||||||
: _scope(0), _declaration(0)
|
: _scope(0), _declaration(0), _binding(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
FullySpecifiedType LookupItem::type() const
|
FullySpecifiedType LookupItem::type() const
|
||||||
{ return _type; }
|
{
|
||||||
|
if (! _type && _declaration)
|
||||||
|
return _declaration->type();
|
||||||
|
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
void LookupItem::setType(const FullySpecifiedType &type)
|
void LookupItem::setType(const FullySpecifiedType &type)
|
||||||
{ _type = type; }
|
{ _type = type; }
|
||||||
@@ -70,9 +75,16 @@ Scope *LookupItem::scope() const
|
|||||||
void LookupItem::setScope(Scope *scope)
|
void LookupItem::setScope(Scope *scope)
|
||||||
{ _scope = scope; }
|
{ _scope = scope; }
|
||||||
|
|
||||||
|
ClassOrNamespace *LookupItem::binding() const
|
||||||
|
{ return _binding; }
|
||||||
|
|
||||||
|
void LookupItem::setBinding(ClassOrNamespace *binding)
|
||||||
|
{ _binding = binding; }
|
||||||
|
|
||||||
bool LookupItem::operator == (const LookupItem &other) const
|
bool LookupItem::operator == (const LookupItem &other) const
|
||||||
{
|
{
|
||||||
if (_type == other._type && _declaration == other._declaration && _scope == other._scope)
|
if (_type == other._type && _declaration == other._declaration && _scope == other._scope
|
||||||
|
&& _binding == other._binding)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
|
class ClassOrNamespace;
|
||||||
|
|
||||||
class CPLUSPLUS_EXPORT LookupItem
|
class CPLUSPLUS_EXPORT LookupItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -59,6 +61,9 @@ public:
|
|||||||
/// Sets this item's scope.
|
/// Sets this item's scope.
|
||||||
void setScope(Scope *scope);
|
void setScope(Scope *scope);
|
||||||
|
|
||||||
|
ClassOrNamespace *binding() const;
|
||||||
|
void setBinding(ClassOrNamespace *binding);
|
||||||
|
|
||||||
bool operator == (const LookupItem &other) const;
|
bool operator == (const LookupItem &other) const;
|
||||||
bool operator != (const LookupItem &other) const;
|
bool operator != (const LookupItem &other) const;
|
||||||
|
|
||||||
@@ -66,6 +71,7 @@ private:
|
|||||||
FullySpecifiedType _type;
|
FullySpecifiedType _type;
|
||||||
Scope *_scope;
|
Scope *_scope;
|
||||||
Symbol *_declaration;
|
Symbol *_declaration;
|
||||||
|
ClassOrNamespace *_binding;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint qHash(const CPlusPlus::LookupItem &result);
|
uint qHash(const CPlusPlus::LookupItem &result);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "LookupContext.h"
|
#include "LookupContext.h"
|
||||||
#include "Overview.h"
|
#include "Overview.h"
|
||||||
#include "DeprecatedGenTemplateInstance.h"
|
#include "DeprecatedGenTemplateInstance.h"
|
||||||
|
#include "CppRewriter.h"
|
||||||
|
|
||||||
#include <Control.h>
|
#include <Control.h>
|
||||||
#include <AST.h>
|
#include <AST.h>
|
||||||
@@ -121,6 +122,11 @@ void ResolveExpression::addResults(const QList<Symbol *> &symbols)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResolveExpression::addResults(const QList<LookupItem> &items)
|
||||||
|
{
|
||||||
|
_results += items;
|
||||||
|
}
|
||||||
|
|
||||||
void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
|
void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
|
||||||
{
|
{
|
||||||
LookupItem item;
|
LookupItem item;
|
||||||
@@ -395,7 +401,7 @@ bool ResolveExpression::visit(CompoundLiteralAST *ast)
|
|||||||
bool ResolveExpression::visit(QualifiedNameAST *ast)
|
bool ResolveExpression::visit(QualifiedNameAST *ast)
|
||||||
{
|
{
|
||||||
if (const Name *name = ast->name) {
|
if (const Name *name = ast->name) {
|
||||||
const QList<Symbol *> candidates = _context.lookup(name, _scope);
|
const QList<LookupItem> candidates = _context.lookup(name, _scope);
|
||||||
addResults(candidates);
|
addResults(candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,14 +410,14 @@ bool ResolveExpression::visit(QualifiedNameAST *ast)
|
|||||||
|
|
||||||
bool ResolveExpression::visit(SimpleNameAST *ast)
|
bool ResolveExpression::visit(SimpleNameAST *ast)
|
||||||
{
|
{
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
|
||||||
addResults(candidates);
|
addResults(candidates);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResolveExpression::visit(TemplateIdAST *ast)
|
bool ResolveExpression::visit(TemplateIdAST *ast)
|
||||||
{
|
{
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
|
||||||
addResults(candidates);
|
addResults(candidates);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -477,7 +483,8 @@ bool ResolveExpression::visit(CallAST *ast)
|
|||||||
|
|
||||||
if (NamedType *namedTy = ty->asNamedType()) {
|
if (NamedType *namedTy = ty->asNamedType()) {
|
||||||
if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
|
if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
|
||||||
foreach (Symbol *overload, b->find(functionCallOp)) {
|
foreach (const LookupItem &r, b->find(functionCallOp)) {
|
||||||
|
Symbol *overload = r.declaration();
|
||||||
if (Function *funTy = overload->type()->asFunctionType()) {
|
if (Function *funTy = overload->type()->asFunctionType()) {
|
||||||
if (maybeValidPrototype(funTy, actualArgumentCount)) {
|
if (maybeValidPrototype(funTy, actualArgumentCount)) {
|
||||||
if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
|
if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
|
||||||
@@ -520,7 +527,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
|
|||||||
|
|
||||||
} else if (NamedType *namedTy = ty->asNamedType()) {
|
} else if (NamedType *namedTy = ty->asNamedType()) {
|
||||||
if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
|
if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
|
||||||
foreach (Symbol *overload, b->find(arrayAccessOp)) {
|
foreach (const LookupItem &r, b->find(arrayAccessOp)) {
|
||||||
|
Symbol *overload = r.declaration();
|
||||||
if (Function *funTy = overload->type()->asFunctionType()) {
|
if (Function *funTy = overload->type()->asFunctionType()) {
|
||||||
if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
|
if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
|
||||||
// ### TODO: check the actual arguments
|
// ### TODO: check the actual arguments
|
||||||
@@ -534,6 +542,56 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<LookupItem> ResolveExpression::getMembers(ClassOrNamespace *binding, const Name *memberName) const
|
||||||
|
{
|
||||||
|
QList<LookupItem> members;
|
||||||
|
|
||||||
|
const QList<LookupItem> originalMembers = binding->find(memberName);
|
||||||
|
|
||||||
|
foreach (const LookupItem &m, originalMembers) {
|
||||||
|
if (! m.binding() || ! m.binding()->templateId()) {
|
||||||
|
members.append(m);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *decl = m.declaration();
|
||||||
|
|
||||||
|
if (Class *klass = decl->enclosingSymbol()->asClass()) {
|
||||||
|
if (klass->templateParameters() != 0) {
|
||||||
|
SubstitutionMap map;
|
||||||
|
|
||||||
|
const TemplateNameId *templateId = m.binding()->templateId();
|
||||||
|
unsigned count = qMin(klass->templateParameterCount(), templateId->templateArgumentCount());
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
|
map.bind(klass->templateParameterAt(i)->name(), templateId->templateArgumentAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
SubstitutionEnvironment env;
|
||||||
|
ContextSubstitution ctxSubst(_context, m.scope());
|
||||||
|
|
||||||
|
env.enter(&ctxSubst);
|
||||||
|
env.enter(&map);
|
||||||
|
FullySpecifiedType instantiatedTy = rewriteType(decl->type(), env, _context.control().data());
|
||||||
|
|
||||||
|
Overview oo;
|
||||||
|
oo.setShowReturnTypes(true);
|
||||||
|
oo.setShowFunctionSignatures(true);
|
||||||
|
|
||||||
|
qDebug() << "original:" << oo(decl->type(), decl->name()) << "inst:" << oo(instantiatedTy, decl->name());
|
||||||
|
|
||||||
|
LookupItem newItem;
|
||||||
|
newItem = m;
|
||||||
|
newItem.setType(instantiatedTy);
|
||||||
|
members.append(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
bool ResolveExpression::visit(MemberAccessAST *ast)
|
bool ResolveExpression::visit(MemberAccessAST *ast)
|
||||||
{
|
{
|
||||||
// The candidate types for the base expression are stored in
|
// The candidate types for the base expression are stored in
|
||||||
@@ -586,9 +644,13 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
|
|||||||
|
|
||||||
} else if (ClassOrNamespace *binding = findClass(ty, scope)) {
|
} else if (ClassOrNamespace *binding = findClass(ty, scope)) {
|
||||||
// lookup for overloads of operator->
|
// lookup for overloads of operator->
|
||||||
const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
|
|
||||||
|
|
||||||
foreach (Symbol *overload, binding->find(arrowOp)) {
|
const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
|
||||||
|
foreach (const LookupItem &r, binding->find(arrowOp)) {
|
||||||
|
Symbol *overload = r.declaration();
|
||||||
|
if (! overload)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (overload->type()->isFunctionType()) {
|
if (overload->type()->isFunctionType()) {
|
||||||
FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload);
|
FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload);
|
||||||
Function *instantiatedFunction = overloadTy->asFunctionType();
|
Function *instantiatedFunction = overloadTy->asFunctionType();
|
||||||
@@ -604,14 +666,10 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas
|
|||||||
if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), scope))
|
if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), scope))
|
||||||
return retBinding;
|
return retBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
Overview oo;
|
|
||||||
qDebug() << "no class for:" << oo(ptrTy->elementType());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (accessOp == T_DOT) {
|
} else if (accessOp == T_DOT) {
|
||||||
if (replacedDotOperator) {
|
if (replacedDotOperator) {
|
||||||
@@ -663,9 +721,11 @@ bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (binding) {
|
if (binding) {
|
||||||
foreach (Symbol *s, binding->lookup(ast->selector->name))
|
foreach (const LookupItem &r, binding->lookup(ast->selector->name)) {
|
||||||
|
Symbol *s = r.declaration();
|
||||||
if (ObjCMethod *m = s->asObjCMethod())
|
if (ObjCMethod *m = s->asObjCMethod())
|
||||||
addResult(m->returnType(), result.scope());
|
addResult(m->returnType(), result.scope());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,10 +59,13 @@ protected:
|
|||||||
QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
|
QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
|
||||||
FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const;
|
FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const;
|
||||||
|
|
||||||
|
Q_DECL_DEPRECATED QList<LookupItem> getMembers(ClassOrNamespace *binding, const Name *memberName) const;
|
||||||
|
|
||||||
void thisObject();
|
void thisObject();
|
||||||
|
|
||||||
void addResult(const FullySpecifiedType &ty, Scope *scope);
|
void addResult(const FullySpecifiedType &ty, Scope *scope);
|
||||||
void addResults(const QList<Symbol *> &symbols);
|
void addResults(const QList<Symbol *> &symbols);
|
||||||
|
void addResults(const QList<LookupItem> &items);
|
||||||
|
|
||||||
bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
|
bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/SimpleLexer.h \
|
$$PWD/SimpleLexer.h \
|
||||||
$$PWD/CppDocument.h \
|
$$PWD/CppDocument.h \
|
||||||
|
$$PWD/CppRewriter.h \
|
||||||
$$PWD/Overview.h \
|
$$PWD/Overview.h \
|
||||||
$$PWD/NamePrettyPrinter.h \
|
$$PWD/NamePrettyPrinter.h \
|
||||||
$$PWD/TypeOfExpression.h \
|
$$PWD/TypeOfExpression.h \
|
||||||
@@ -52,6 +53,7 @@ HEADERS += \
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/SimpleLexer.cpp \
|
$$PWD/SimpleLexer.cpp \
|
||||||
$$PWD/CppDocument.cpp \
|
$$PWD/CppDocument.cpp \
|
||||||
|
$$PWD/CppRewriter.cpp \
|
||||||
$$PWD/Overview.cpp \
|
$$PWD/Overview.cpp \
|
||||||
$$PWD/NamePrettyPrinter.cpp \
|
$$PWD/NamePrettyPrinter.cpp \
|
||||||
$$PWD/TypeOfExpression.cpp \
|
$$PWD/TypeOfExpression.cpp \
|
||||||
|
|||||||
@@ -408,11 +408,11 @@ void CheckSymbols::checkName(NameAST *ast)
|
|||||||
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
||||||
if (_potentialTypes.contains(id)) {
|
if (_potentialTypes.contains(id)) {
|
||||||
Scope *scope = findScope(ast);
|
Scope *scope = findScope(ast);
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
|
||||||
addTypeUsage(candidates, ast);
|
addTypeUsage(candidates, ast);
|
||||||
} else if (_potentialMembers.contains(id)) {
|
} else if (_potentialMembers.contains(id)) {
|
||||||
Scope *scope = findScope(ast);
|
Scope *scope = findScope(ast);
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
|
||||||
addMemberUsage(candidates, ast);
|
addMemberUsage(candidates, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,11 +426,11 @@ void CheckSymbols::checkMemberName(NameAST *ast)
|
|||||||
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
|
||||||
if (_potentialMembers.contains(id)) {
|
if (_potentialMembers.contains(id)) {
|
||||||
Scope *scope = findScope(ast);
|
Scope *scope = findScope(ast);
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
|
||||||
addMemberUsage(candidates, ast);
|
addMemberUsage(candidates, ast);
|
||||||
} else if (_potentialMembers.contains(id)) {
|
} else if (_potentialMembers.contains(id)) {
|
||||||
Scope *scope = findScope(ast);
|
Scope *scope = findScope(ast);
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
|
||||||
addMemberUsage(candidates, ast);
|
addMemberUsage(candidates, ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
|
|||||||
const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size());
|
const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size());
|
||||||
if (_potentialTypes.contains(id)) {
|
if (_potentialTypes.contains(id)) {
|
||||||
Scope *scope = findScope(_templateDeclarationStack.back());
|
Scope *scope = findScope(_templateDeclarationStack.back());
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name->name, scope);
|
const QList<LookupItem> candidates = _context.lookup(ast->name->name, scope);
|
||||||
addTypeUsage(candidates, ast->name);
|
addTypeUsage(candidates, ast->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -582,7 +582,7 @@ void CheckSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
|
|||||||
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
void CheckSymbols::addTypeUsage(const QList<LookupItem> &candidates, NameAST *ast)
|
||||||
{
|
{
|
||||||
unsigned startToken = ast->firstToken();
|
unsigned startToken = ast->firstToken();
|
||||||
if (DestructorNameAST *dtor = ast->asDestructorName())
|
if (DestructorNameAST *dtor = ast->asDestructorName())
|
||||||
@@ -596,7 +596,8 @@ void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
|||||||
getTokenStartPosition(startToken, &line, &column);
|
getTokenStartPosition(startToken, &line, &column);
|
||||||
const unsigned length = tok.length();
|
const unsigned length = tok.length();
|
||||||
|
|
||||||
foreach (Symbol *c, candidates) {
|
foreach (const LookupItem &r, candidates) {
|
||||||
|
Symbol *c = r.declaration();
|
||||||
if (c->isUsingDeclaration()) // skip using declarations...
|
if (c->isUsingDeclaration()) // skip using declarations...
|
||||||
continue;
|
continue;
|
||||||
else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
|
else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
|
||||||
@@ -612,7 +613,7 @@ void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckSymbols::addMemberUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
void CheckSymbols::addMemberUsage(const QList<LookupItem> &candidates, NameAST *ast)
|
||||||
{
|
{
|
||||||
unsigned startToken = ast->firstToken();
|
unsigned startToken = ast->firstToken();
|
||||||
if (DestructorNameAST *dtor = ast->asDestructorName())
|
if (DestructorNameAST *dtor = ast->asDestructorName())
|
||||||
@@ -626,8 +627,11 @@ void CheckSymbols::addMemberUsage(const QList<Symbol *> &candidates, NameAST *as
|
|||||||
getTokenStartPosition(startToken, &line, &column);
|
getTokenStartPosition(startToken, &line, &column);
|
||||||
const unsigned length = tok.length();
|
const unsigned length = tok.length();
|
||||||
|
|
||||||
foreach (Symbol *c, candidates) {
|
foreach (const LookupItem &r, candidates) {
|
||||||
if (! c->isDeclaration())
|
Symbol *c = r.declaration();
|
||||||
|
if (! c)
|
||||||
|
continue;
|
||||||
|
else if (! c->isDeclaration())
|
||||||
continue;
|
continue;
|
||||||
else if (c->isTypedef())
|
else if (c->isTypedef())
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -84,11 +84,11 @@ protected:
|
|||||||
void checkName(NameAST *ast);
|
void checkName(NameAST *ast);
|
||||||
void checkNamespace(NameAST *name);
|
void checkNamespace(NameAST *name);
|
||||||
void addTypeUsage(ClassOrNamespace *b, NameAST *ast);
|
void addTypeUsage(ClassOrNamespace *b, NameAST *ast);
|
||||||
void addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast);
|
void addTypeUsage(const QList<LookupItem> &candidates, NameAST *ast);
|
||||||
void addTypeUsage(const Use &use);
|
void addTypeUsage(const Use &use);
|
||||||
|
|
||||||
void checkMemberName(NameAST *ast);
|
void checkMemberName(NameAST *ast);
|
||||||
void addMemberUsage(const QList<Symbol *> &candidates, NameAST *ast);
|
void addMemberUsage(const QList<LookupItem> &candidates, NameAST *ast);
|
||||||
|
|
||||||
virtual bool preVisit(AST *);
|
virtual bool preVisit(AST *);
|
||||||
|
|
||||||
|
|||||||
@@ -995,8 +995,9 @@ void CPPEditor::switchDeclarationDefinition()
|
|||||||
LookupContext context(thisDocument, snapshot);
|
LookupContext context(thisDocument, snapshot);
|
||||||
|
|
||||||
Function *functionDefinition = functionScope->owner()->asFunction();
|
Function *functionDefinition = functionScope->owner()->asFunction();
|
||||||
const QList<Symbol *> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope());
|
const QList<LookupItem> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope());
|
||||||
foreach (Symbol *decl, declarations) {
|
foreach (const LookupItem &r, declarations) {
|
||||||
|
Symbol *decl = r.declaration();
|
||||||
// TODO: check decl.
|
// TODO: check decl.
|
||||||
openCppEditorAt(linkToSymbol(decl));
|
openCppEditorAt(linkToSymbol(decl));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -920,7 +920,8 @@ public:
|
|||||||
ClassOrNamespace *b = context.lookupType(function);
|
ClassOrNamespace *b = context.lookupType(function);
|
||||||
if (b) {
|
if (b) {
|
||||||
// Do we have a tr method?
|
// Do we have a tr method?
|
||||||
foreach(Symbol *s, b->find(trName)) {
|
foreach(const LookupItem &r, b->find(trName)) {
|
||||||
|
Symbol *s = r.declaration();
|
||||||
if (s->type()->isFunctionType()) {
|
if (s->type()->isFunctionType()) {
|
||||||
m_option = useTr;
|
m_option = useTr;
|
||||||
// no context required for tr
|
// no context required for tr
|
||||||
@@ -1302,9 +1303,10 @@ protected:
|
|||||||
if (Enum *e = result.declaration()->type()->asEnumType())
|
if (Enum *e = result.declaration()->type()->asEnumType())
|
||||||
return e;
|
return e;
|
||||||
if (NamedType *namedType = fst->asNamedType()) {
|
if (NamedType *namedType = fst->asNamedType()) {
|
||||||
QList<Symbol *> candidates =
|
QList<LookupItem> candidates =
|
||||||
typeOfExpression.context().lookup(namedType->name(), scope);
|
typeOfExpression.context().lookup(namedType->name(), scope);
|
||||||
foreach (Symbol *candidate, candidates) {
|
foreach (const LookupItem &r, candidates) {
|
||||||
|
Symbol *candidate = r.declaration();
|
||||||
if (Enum *e = candidate->asEnum()) {
|
if (Enum *e = candidate->asEnum()) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1175,11 +1175,13 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r
|
|||||||
|
|
||||||
if (NamedType *namedTy = ty->asNamedType()) {
|
if (NamedType *namedTy = ty->asNamedType()) {
|
||||||
if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
|
if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
|
||||||
foreach (Symbol *overload, b->lookup(functionCallOp)) {
|
foreach (const LookupItem &r, b->lookup(functionCallOp)) {
|
||||||
|
Symbol *overload = r.declaration();
|
||||||
FullySpecifiedType overloadTy = overload->type().simplified();
|
FullySpecifiedType overloadTy = overload->type().simplified();
|
||||||
|
|
||||||
if (Function *funTy = overloadTy->asFunctionType())
|
if (Function *funTy = overloadTy->asFunctionType()) {
|
||||||
functions.append(funTy);
|
functions.append(funTy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,12 @@ FullySpecifiedType FullySpecifiedType::simplified() const
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned FullySpecifiedType::flags() const
|
||||||
|
{ return _flags; }
|
||||||
|
|
||||||
|
void FullySpecifiedType::setFlags(unsigned flags)
|
||||||
|
{ _flags = flags; }
|
||||||
|
|
||||||
void FullySpecifiedType::copySpecifiers(const FullySpecifiedType &type)
|
void FullySpecifiedType::copySpecifiers(const FullySpecifiedType &type)
|
||||||
{
|
{
|
||||||
// class storage specifiers
|
// class storage specifiers
|
||||||
|
|||||||
@@ -134,6 +134,9 @@ public:
|
|||||||
|
|
||||||
void copySpecifiers(const FullySpecifiedType &type);
|
void copySpecifiers(const FullySpecifiedType &type);
|
||||||
|
|
||||||
|
unsigned flags() const;
|
||||||
|
void setFlags(unsigned flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type *_type;
|
Type *_type;
|
||||||
struct Flags {
|
struct Flags {
|
||||||
|
|||||||
@@ -64,6 +64,13 @@ private Q_SLOTS:
|
|||||||
void class_with_baseclass();
|
void class_with_baseclass();
|
||||||
void class_with_protocol_with_protocol();
|
void class_with_protocol_with_protocol();
|
||||||
void iface_impl_scoping();
|
void iface_impl_scoping();
|
||||||
|
|
||||||
|
// template instantiation:
|
||||||
|
void templates_1();
|
||||||
|
void templates_2();
|
||||||
|
void templates_3();
|
||||||
|
void templates_4();
|
||||||
|
void templates_5();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_Lookup::base_class_defined_1()
|
void tst_Lookup::base_class_defined_1()
|
||||||
@@ -169,14 +176,14 @@ void tst_Lookup::simple_class_1()
|
|||||||
QVERIFY(klass->symbols().contains(impl));
|
QVERIFY(klass->symbols().contains(impl));
|
||||||
|
|
||||||
// check method resolving:
|
// check method resolving:
|
||||||
QList<Symbol *> results = context.lookup(allocMethodImpl->name(), impl->members());
|
QList<LookupItem> results = context.lookup(allocMethodImpl->name(), impl->members());
|
||||||
QCOMPARE(results.size(), 2);
|
QCOMPARE(results.size(), 2);
|
||||||
QCOMPARE(results.at(0), allocMethodIface);
|
QCOMPARE(results.at(0).declaration(), allocMethodIface);
|
||||||
QCOMPARE(results.at(1), allocMethodImpl);
|
QCOMPARE(results.at(1).declaration(), allocMethodImpl);
|
||||||
|
|
||||||
results = context.lookup(deallocMethod->name(), impl->members());
|
results = context.lookup(deallocMethod->name(), impl->members());
|
||||||
QCOMPARE(results.size(), 1);
|
QCOMPARE(results.size(), 1);
|
||||||
QCOMPARE(results.at(0), deallocMethod);
|
QCOMPARE(results.at(0).declaration(), deallocMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Lookup::class_with_baseclass()
|
void tst_Lookup::class_with_baseclass()
|
||||||
@@ -230,13 +237,13 @@ void tst_Lookup::class_with_baseclass()
|
|||||||
QVERIFY(objClass != 0);
|
QVERIFY(objClass != 0);
|
||||||
QVERIFY(objClass->symbols().contains(baseZoo));
|
QVERIFY(objClass->symbols().contains(baseZoo));
|
||||||
|
|
||||||
QList<Symbol *> results = context.lookup(baseDecl->name(), zooImpl->members());
|
QList<LookupItem> results = context.lookup(baseDecl->name(), zooImpl->members());
|
||||||
QCOMPARE(results.size(), 1);
|
QCOMPARE(results.size(), 1);
|
||||||
QCOMPARE(results.at(0), baseDecl);
|
QCOMPARE(results.at(0).declaration(), baseDecl);
|
||||||
|
|
||||||
results = context.lookup(baseMethod->name(), zooImpl->members());
|
results = context.lookup(baseMethod->name(), zooImpl->members());
|
||||||
QCOMPARE(results.size(), 1);
|
QCOMPARE(results.size(), 1);
|
||||||
QCOMPARE(results.at(0), baseMethod);
|
QCOMPARE(results.at(0).declaration(), baseMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Lookup::class_with_protocol_with_protocol()
|
void tst_Lookup::class_with_protocol_with_protocol()
|
||||||
@@ -279,20 +286,20 @@ void tst_Lookup::class_with_protocol_with_protocol()
|
|||||||
const LookupContext context(doc, snapshot);
|
const LookupContext context(doc, snapshot);
|
||||||
|
|
||||||
{
|
{
|
||||||
const QList<Symbol *> candidates = context.lookup(P1->name(), zooImpl->scope());
|
const QList<LookupItem> candidates = context.lookup(P1->name(), zooImpl->scope());
|
||||||
QCOMPARE(candidates.size(), 1);
|
QCOMPARE(candidates.size(), 1);
|
||||||
QVERIFY(candidates.contains(P1));
|
QVERIFY(candidates.at(0).declaration() == P1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const QList<Symbol *> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->scope());
|
const QList<LookupItem> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->scope());
|
||||||
QCOMPARE(candidates.size(), 1);
|
QCOMPARE(candidates.size(), 1);
|
||||||
QVERIFY(candidates.contains(P1));
|
QVERIFY(candidates.first().declaration() == P1);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Symbol *> results = context.lookup(p1method->name(), zooImpl->members());
|
QList<LookupItem> results = context.lookup(p1method->name(), zooImpl->members());
|
||||||
QCOMPARE(results.size(), 1);
|
QCOMPARE(results.size(), 1);
|
||||||
QCOMPARE(results.at(0), p1method);
|
QCOMPARE(results.at(0).declaration(), p1method);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Lookup::iface_impl_scoping()
|
void tst_Lookup::iface_impl_scoping()
|
||||||
@@ -341,9 +348,9 @@ void tst_Lookup::iface_impl_scoping()
|
|||||||
QVERIFY(arg->name()->identifier());
|
QVERIFY(arg->name()->identifier());
|
||||||
QCOMPARE(arg->name()->identifier()->chars(), "arg");
|
QCOMPARE(arg->name()->identifier()->chars(), "arg");
|
||||||
|
|
||||||
const QList<Symbol *> candidates = context.lookup(arg->name(), method1Body->scope());
|
const QList<LookupItem> candidates = context.lookup(arg->name(), method1Body->scope());
|
||||||
QCOMPARE(candidates.size(), 1);
|
QCOMPARE(candidates.size(), 1);
|
||||||
QVERIFY(candidates.at(0)->type()->asIntegerType());
|
QVERIFY(candidates.at(0).declaration()->type()->asIntegerType());
|
||||||
}
|
}
|
||||||
|
|
||||||
Declaration *method2 = iface->memberAt(1)->asDeclaration();
|
Declaration *method2 = iface->memberAt(1)->asDeclaration();
|
||||||
@@ -351,11 +358,174 @@ void tst_Lookup::iface_impl_scoping()
|
|||||||
QCOMPARE(method2->identifier()->chars(), "method2");
|
QCOMPARE(method2->identifier()->chars(), "method2");
|
||||||
|
|
||||||
{ // verify if we can resolve "method2" in the body
|
{ // verify if we can resolve "method2" in the body
|
||||||
const QList<Symbol *> candidates = context.lookup(method2->name(), method1Body->scope());
|
const QList<LookupItem> candidates = context.lookup(method2->name(), method1Body->scope());
|
||||||
QCOMPARE(candidates.size(), 1);
|
QCOMPARE(candidates.size(), 1);
|
||||||
QCOMPARE(candidates.at(0), method2);
|
QCOMPARE(candidates.at(0).declaration(), method2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_Lookup::templates_1()
|
||||||
|
{
|
||||||
|
const QByteArray source = "\n"
|
||||||
|
"namespace std {\n"
|
||||||
|
" template <typename T>\n"
|
||||||
|
" struct _List_iterator {\n"
|
||||||
|
" T data;\n"
|
||||||
|
" };\n"
|
||||||
|
"\n"
|
||||||
|
" template <typename T>\n"
|
||||||
|
" struct list {\n"
|
||||||
|
" typedef _List_iterator<T> iterator;\n"
|
||||||
|
"\n"
|
||||||
|
" iterator begin();\n"
|
||||||
|
" _List_iterator<T> end();\n"
|
||||||
|
" };\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"struct Point {\n"
|
||||||
|
" int x, y;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::list<Point> l;\n"
|
||||||
|
" l.begin(); // std::_List_iterator<Point> .. and not only _List_iterator<Point>\n"
|
||||||
|
" l.end(); // std::_List_iterator<Point>\n"
|
||||||
|
"}\n";
|
||||||
|
Document::Ptr doc = Document::create("templates_1");
|
||||||
|
doc->setSource(source);
|
||||||
|
doc->parse();
|
||||||
|
doc->check();
|
||||||
|
|
||||||
|
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Lookup::templates_2()
|
||||||
|
{
|
||||||
|
const QByteArray source = "\n"
|
||||||
|
"template <typename T1>\n"
|
||||||
|
"struct Node {\n"
|
||||||
|
" T1 value;\n"
|
||||||
|
" Node *next;\n"
|
||||||
|
" Node<T1> *other_next;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename T2>\n"
|
||||||
|
"struct List {\n"
|
||||||
|
" Node<T2> *elements;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" List<int> *e;\n"
|
||||||
|
" e->elements; // Node<int> *\n"
|
||||||
|
" e->elements->next; // Node<int> *\n"
|
||||||
|
" e->elements->other_next; // Node<int> *\n"
|
||||||
|
"}\n"
|
||||||
|
;
|
||||||
|
Document::Ptr doc = Document::create("templates_2");
|
||||||
|
doc->setSource(source);
|
||||||
|
doc->parse();
|
||||||
|
doc->check();
|
||||||
|
|
||||||
|
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Lookup::templates_3()
|
||||||
|
{
|
||||||
|
const QByteArray source = "\n"
|
||||||
|
"struct Point {\n"
|
||||||
|
" int x, y;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename T = Point>\n"
|
||||||
|
"struct List {\n"
|
||||||
|
" const T &at(int);\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" List<> l;\n"
|
||||||
|
" l.at(0); // const Point &\n"
|
||||||
|
"}\n";
|
||||||
|
Document::Ptr doc = Document::create("templates_3");
|
||||||
|
doc->setSource(source);
|
||||||
|
doc->parse();
|
||||||
|
doc->check();
|
||||||
|
|
||||||
|
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Lookup::templates_4()
|
||||||
|
{
|
||||||
|
const QByteArray source = "\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"struct Allocator {\n"
|
||||||
|
" typedef T *pointer_type;\n"
|
||||||
|
" typedef T &reference_type;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename T>\n"
|
||||||
|
"struct SharedPtr {\n"
|
||||||
|
" typedef typename Allocator<T>::pointer_type pointer_type;\n"
|
||||||
|
" typedef typename Allocator<T>::reference_type reference_type;\n"
|
||||||
|
"\n"
|
||||||
|
" pointer_type operator->();\n"
|
||||||
|
" reference_type operator*();\n"
|
||||||
|
"\n"
|
||||||
|
" pointer_type data();\n"
|
||||||
|
" reference_type get();\n"
|
||||||
|
"\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct Point {\n"
|
||||||
|
" int x,y;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" SharedPtr<Point> l;\n"
|
||||||
|
"\n"
|
||||||
|
" l->x; // int\n"
|
||||||
|
" (*l); // Point &\n"
|
||||||
|
"}\n";
|
||||||
|
Document::Ptr doc = Document::create("templates_4");
|
||||||
|
doc->setSource(source);
|
||||||
|
doc->parse();
|
||||||
|
doc->check();
|
||||||
|
|
||||||
|
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Lookup::templates_5()
|
||||||
|
{
|
||||||
|
const QByteArray source = "\n"
|
||||||
|
"struct Point {\n"
|
||||||
|
" int x,y;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"template <typename _Tp>\n"
|
||||||
|
"struct Allocator {\n"
|
||||||
|
" typedef const _Tp &const_reference;\n"
|
||||||
|
"\n"
|
||||||
|
" const_reference get();\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Allocator<Point>::const_reference r = pt;\n"
|
||||||
|
" //r.; // const Point &\n"
|
||||||
|
"\n"
|
||||||
|
" Allocator<Point> a;\n"
|
||||||
|
" a.get(); // const Point &\n"
|
||||||
|
"}\n";
|
||||||
|
Document::Ptr doc = Document::create("templates_5");
|
||||||
|
doc->setSource(source);
|
||||||
|
doc->parse();
|
||||||
|
doc->check();
|
||||||
|
|
||||||
|
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(tst_Lookup)
|
QTEST_APPLESS_MAIN(tst_Lookup)
|
||||||
#include "tst_lookup.moc"
|
#include "tst_lookup.moc"
|
||||||
|
|||||||
Reference in New Issue
Block a user