diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 94832cc1420f8606d49e51b07bfe0e5b888acf2f..cb9598614b6f869489c9ec9b647ea8990847dd68 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -740,11 +740,12 @@ Symbol *Snapshot::findMatchingDefinition(Symbol *declaration) const continue; // nothing to do 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()) continue; - else if (enclosingType == context.lookupType(declarations.first())) + const LookupItem best = declarations.first(); + if (enclosingType == context.lookupType(best.declaration())) viableFunctions.append(fun); } diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2dcec18a419ce34ad9fa063b06b5f2897722e9e7 --- /dev/null +++ b/src/libs/cplusplus/CppRewriter.cpp @@ -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); +} diff --git a/src/libs/cplusplus/CppRewriter.h b/src/libs/cplusplus/CppRewriter.h new file mode 100644 index 0000000000000000000000000000000000000000..4e6d14b3f5a03d7811796837b2fdfd9ab0ca696c --- /dev/null +++ b/src/libs/cplusplus/CppRewriter.h @@ -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 diff --git a/src/libs/cplusplus/DeprecatedGenTemplateInstance.h b/src/libs/cplusplus/DeprecatedGenTemplateInstance.h index f40c951ba50e73e32c83bed06f70877e47d6b8ae..755fc341b59029f245df73eb1c8017358fba1e55 100644 --- a/src/libs/cplusplus/DeprecatedGenTemplateInstance.h +++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.h @@ -46,7 +46,7 @@ public: typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution; 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: DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution); diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index f8119fe456f68aaedde8881d81e3674a8c9c2f5c..e703f5fddb2b4badba7a229449f93ae0b827d7dc 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -124,7 +124,7 @@ Scope *FindUsages::scopeAt(unsigned tokenIndex) const 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)) return; @@ -160,11 +160,12 @@ void FindUsages::reportResult(unsigned 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)) { 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) return true; } @@ -186,7 +187,7 @@ bool FindUsages::visit(MemInitializerAST *ast) SimpleNameAST *simple = ast->name->asSimpleName(); 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); } } @@ -223,14 +224,7 @@ void FindUsages::checkExpression(unsigned startToken, unsigned endToken) const QList<LookupItem> results = typeofExpression(expression, scope, TypeOfExpression::Preprocess); - QList<Symbol *> candidates; - - foreach (const LookupItem &r, results) { - Symbol *lastVisibleSymbol = r.declaration(); - candidates.append(lastVisibleSymbol); - } - - reportResult(endToken, candidates); + reportResult(endToken, results); } bool FindUsages::visit(QualifiedNameAST *ast) @@ -297,7 +291,7 @@ bool FindUsages::visit(EnumeratorAST *ast) { const Identifier *id = identifier(ast->identifier_token); 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); } @@ -310,7 +304,7 @@ bool FindUsages::visit(SimpleNameAST *ast) { const Identifier *id = identifier(ast->identifier_token); 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); } @@ -321,7 +315,7 @@ bool FindUsages::visit(DestructorNameAST *ast) { const Identifier *id = identifier(ast->identifier_token); 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); } @@ -331,7 +325,7 @@ bool FindUsages::visit(DestructorNameAST *ast) bool FindUsages::visit(TemplateIdAST *ast) { 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); } @@ -406,7 +400,7 @@ bool FindUsages::visit(ObjCSelectorAST *ast) if (ast->name) { const Identifier *id = ast->name->identifier(); 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); } } @@ -440,7 +434,7 @@ bool FindUsages::visit(TypenameTypeParameterAST *ast) const Identifier *id = name->name->identifier(); if (id == _id) { 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); } } @@ -454,7 +448,7 @@ bool FindUsages::visit(TemplateTypeParameterAST *ast) const Identifier *id = name->name->identifier(); if (id == _id) { 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); } } diff --git a/src/libs/cplusplus/FindUsages.h b/src/libs/cplusplus/FindUsages.h index ff7a3b063bed07f54bf83fbdd810a48c12245aac..f274da04d6676000c74dbc008c7b22dc54eeeaf6 100644 --- a/src/libs/cplusplus/FindUsages.h +++ b/src/libs/cplusplus/FindUsages.h @@ -74,10 +74,10 @@ protected: QString matchingLine(const Token &tk) 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); - bool checkCandidates(const QList<Symbol *> &candidates) const; + bool checkCandidates(const QList<LookupItem> &candidates) const; void checkExpression(unsigned startToken, unsigned endToken); void ensureNameIsValid(NameAST *ast); diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index ce832e2df60c7b5f911c70420489488fdfd1a0b5..5c935eb6a11babaaa9df83444c01264a570187ca 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -39,13 +39,17 @@ #include <Scope.h> #include <Control.h> -#include <QtDebug> +#include <QtCore/QStack> +#include <QtCore/QHash> +#include <QtCore/QVarLengthArray> +#include <QtCore/QtDebug> + +using namespace CPlusPlus; namespace { - const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty(); -} +const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty(); +} // end of anonymous namespace -using namespace CPlusPlus; static void addNames(const Name *name, QList<const Name *> *names, bool addAllNames = false) { @@ -241,16 +245,16 @@ ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const 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) return candidates; for (; scope; scope = scope->enclosingScope()) { 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()) break; // it's a local. @@ -274,10 +278,10 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const } else if (scope->isFunctionScope()) { 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()) - bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0); + bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0, /*binding=*/ 0); if (! candidates.isEmpty()) 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()) { 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()) 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(); 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()) break; // it's an argument or a template parameter. @@ -398,19 +402,19 @@ ClassOrNamespace *ClassOrNamespace::globalNamespace() const return e; } -QList<Symbol *> ClassOrNamespace::find(const Name *name) +QList<LookupItem> ClassOrNamespace::find(const Name *name) { return lookup_helper(name, false); } -QList<Symbol *> ClassOrNamespace::lookup(const Name *name) +QList<LookupItem> ClassOrNamespace::lookup(const Name *name) { 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 (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, - QList<Symbol *> *result, - QSet<ClassOrNamespace *> *processed, - const TemplateNameId *templateId) + QList<LookupItem> *result, + QSet<ClassOrNamespace *> *processed, + const TemplateNameId *templateId) { if (binding && ! processed->contains(binding)) { processed->insert(binding); @@ -448,16 +452,20 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding if (ScopedSymbol *scoped = s->asScopedSymbol()) { if (Class *klass = scoped->asClass()) { if (const Identifier *id = klass->identifier()) { - if (nameId && nameId->isEqualTo(id)) - result->append(klass); + if (nameId && nameId->isEqualTo(id)) { + 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()) - _factory->lookupInScope(name, e->members(), result, templateId); + _factory->lookupInScope(name, e->members(), result, templateId, binding); foreach (ClassOrNamespace *u, binding->usings()) 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, - QList<Symbol *> *result, - const TemplateNameId *templateId) + QList<LookupItem> *result, + const TemplateNameId *templateId, + ClassOrNamespace *binding) { Q_UNUSED(templateId); @@ -480,7 +489,10 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, else if (! s->name()->isEqualTo(op)) continue; - result->append(s); + LookupItem item; + item.setDeclaration(s); + item.setBinding(binding); + result->append(item); } } else if (const Identifier *id = name->identifier()) { @@ -490,34 +502,17 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, else if (s->name()->isQualifiedNameId()) continue; // skip qualified ids. - if (templateId && (s->isDeclaration() || s->isFunction())) { + LookupItem item; + item.setDeclaration(s); + item.setBinding(binding); + if (templateId && (s->isDeclaration() || s->isFunction())) { FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, _control); - - 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; - } + item.setType(ty); // override the type. } - result->append(s); + result->append(item); } - } } @@ -987,3 +982,4 @@ bool CreateBindings::visit(ObjCMethod *) { return false; } + diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 3854b4cb7b7b5924d6f1556de3ffcc80972f6a96..db6163f8d06af7aed5553011fa444f5e739e45bb 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -36,6 +36,7 @@ #include <Type.h> #include <SymbolVisitor.h> #include <Control.h> +#include <Name.h> #include <QtCore/QSet> #include <map> #include <functional> @@ -57,8 +58,8 @@ public: ClassOrNamespace *globalNamespace() const; - QList<Symbol *> lookup(const Name *name); - QList<Symbol *> find(const Name *name); + QList<LookupItem> lookup(const Name *name); + QList<LookupItem> find(const Name *name); ClassOrNamespace *lookupType(const Name *name); ClassOrNamespace *findType(const Name *name); @@ -76,12 +77,12 @@ private: void addUsing(ClassOrNamespace *u); 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, - QList<Symbol *> *result, - QSet<ClassOrNamespace *> *processed, - const TemplateNameId *templateId); + QList<LookupItem> *result, + QSet<ClassOrNamespace *> *processed, + const TemplateNameId *templateId); ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed, bool searchInEnclosingScope); @@ -134,8 +135,8 @@ public: /// Searches in \a scope for symbols with the given \a name. /// Store the result in \a results. /// \internal - void lookupInScope(const Name *name, Scope *scope, QList<Symbol *> *result, - const TemplateNameId *templateId); + void lookupInScope(const Name *name, Scope *scope, QList<LookupItem> *result, + const TemplateNameId *templateId, ClassOrNamespace *binding); /// Create bindings for the symbols reachable from \a rootSymbol. /// \internal @@ -214,7 +215,7 @@ public: 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(Symbol *symbol) const; ClassOrNamespace *lookupParent(Symbol *symbol) const; diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp index 2502c02790b6f5617136d0314b2be6676d08fb21..1bc49303a3114705e6ae52fa8f186a16caa39e73 100644 --- a/src/libs/cplusplus/LookupItem.cpp +++ b/src/libs/cplusplus/LookupItem.cpp @@ -44,11 +44,16 @@ uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key) } LookupItem::LookupItem() - : _scope(0), _declaration(0) + : _scope(0), _declaration(0), _binding(0) { } FullySpecifiedType LookupItem::type() const -{ return _type; } +{ + if (! _type && _declaration) + return _declaration->type(); + + return _type; +} void LookupItem::setType(const FullySpecifiedType &type) { _type = type; } @@ -70,9 +75,16 @@ Scope *LookupItem::scope() const void LookupItem::setScope(Scope *scope) { _scope = scope; } +ClassOrNamespace *LookupItem::binding() const +{ return _binding; } + +void LookupItem::setBinding(ClassOrNamespace *binding) +{ _binding = binding; } + 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 false; diff --git a/src/libs/cplusplus/LookupItem.h b/src/libs/cplusplus/LookupItem.h index 14ba99c5734ff1cdeaac98e79f3f15edc4a5bed4..489fe31a09709bc10248afb2e497a1a75a0b1d43 100644 --- a/src/libs/cplusplus/LookupItem.h +++ b/src/libs/cplusplus/LookupItem.h @@ -35,6 +35,8 @@ namespace CPlusPlus { +class ClassOrNamespace; + class CPLUSPLUS_EXPORT LookupItem { public: @@ -59,6 +61,9 @@ public: /// Sets this item's scope. void setScope(Scope *scope); + ClassOrNamespace *binding() const; + void setBinding(ClassOrNamespace *binding); + bool operator == (const LookupItem &other) const; bool operator != (const LookupItem &other) const; @@ -66,6 +71,7 @@ private: FullySpecifiedType _type; Scope *_scope; Symbol *_declaration; + ClassOrNamespace *_binding; }; uint qHash(const CPlusPlus::LookupItem &result); diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index b02b7ecf5d1dda510e5a499f587b56decbd329ce..3f2ae7ac82e12157d8e62e53544e2f481f1207ae 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -31,6 +31,7 @@ #include "LookupContext.h" #include "Overview.h" #include "DeprecatedGenTemplateInstance.h" +#include "CppRewriter.h" #include <Control.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) { LookupItem item; @@ -395,7 +401,7 @@ bool ResolveExpression::visit(CompoundLiteralAST *ast) bool ResolveExpression::visit(QualifiedNameAST *ast) { if (const Name *name = ast->name) { - const QList<Symbol *> candidates = _context.lookup(name, _scope); + const QList<LookupItem> candidates = _context.lookup(name, _scope); addResults(candidates); } @@ -404,14 +410,14 @@ bool ResolveExpression::visit(QualifiedNameAST *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); return false; } 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); return false; } @@ -477,7 +483,8 @@ bool ResolveExpression::visit(CallAST *ast) if (NamedType *namedTy = ty->asNamedType()) { 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 (maybeValidPrototype(funTy, actualArgumentCount)) { if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) @@ -520,7 +527,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) } else if (NamedType *namedTy = ty->asNamedType()) { 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 *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) // ### TODO: check the actual arguments @@ -534,6 +542,56 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) 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) { // 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)) { // lookup for overloads of operator-> + const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp); + foreach (const LookupItem &r, binding->find(arrowOp)) { + Symbol *overload = r.declaration(); + if (! overload) + continue; - foreach (Symbol *overload, binding->find(arrowOp)) { if (overload->type()->isFunctionType()) { FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload); Function *instantiatedFunction = overloadTy->asFunctionType(); @@ -604,14 +666,10 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &bas if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), scope)) return retBinding; } - - if (debug) { - Overview oo; - qDebug() << "no class for:" << oo(ptrTy->elementType()); - } } } } + } } else if (accessOp == T_DOT) { if (replacedDotOperator) { @@ -663,9 +721,11 @@ bool ResolveExpression::visit(ObjCMessageExpressionAST *ast) } 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()) addResult(m->returnType(), result.scope()); + } } } diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index 8496631af4c2247cd95be0760560a4134f145ff8..19692a37def993f21b8d905a7d22b71305af901a 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -59,10 +59,13 @@ protected: QList<LookupItem> switchResults(const QList<LookupItem> &symbols); FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const; + Q_DECL_DEPRECATED QList<LookupItem> getMembers(ClassOrNamespace *binding, const Name *memberName) const; + void thisObject(); void addResult(const FullySpecifiedType &ty, Scope *scope); void addResults(const QList<Symbol *> &symbols); + void addResults(const QList<LookupItem> &items); bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const; diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index 24bb51cf5e2c9216b00754d32d2b5cf2d9a506a5..2a718d5712b359407a1a85ed9856d4b28bef2836 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -27,6 +27,7 @@ SOURCES += \ HEADERS += \ $$PWD/SimpleLexer.h \ $$PWD/CppDocument.h \ + $$PWD/CppRewriter.h \ $$PWD/Overview.h \ $$PWD/NamePrettyPrinter.h \ $$PWD/TypeOfExpression.h \ @@ -52,6 +53,7 @@ HEADERS += \ SOURCES += \ $$PWD/SimpleLexer.cpp \ $$PWD/CppDocument.cpp \ + $$PWD/CppRewriter.cpp \ $$PWD/Overview.cpp \ $$PWD/NamePrettyPrinter.cpp \ $$PWD/TypeOfExpression.cpp \ diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index b38ba8e879284c3f8990ea19952a0e45cbc79bac..90261bb979b1ee8dd43b8ec2efa5acf0ebf0adf3 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -408,11 +408,11 @@ void CheckSymbols::checkName(NameAST *ast) const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); if (_potentialTypes.contains(id)) { Scope *scope = findScope(ast); - const QList<Symbol *> candidates = _context.lookup(ast->name, scope); + const QList<LookupItem> candidates = _context.lookup(ast->name, scope); addTypeUsage(candidates, ast); } else if (_potentialMembers.contains(id)) { 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); } } @@ -426,11 +426,11 @@ void CheckSymbols::checkMemberName(NameAST *ast) const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); if (_potentialMembers.contains(id)) { 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); } else if (_potentialMembers.contains(id)) { 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); } } @@ -500,7 +500,7 @@ bool CheckSymbols::visit(TypenameTypeParameterAST *ast) const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size()); if (_potentialTypes.contains(id)) { Scope *scope = findScope(_templateDeclarationStack.back()); - const QList<Symbol *> candidates = _context.lookup(ast->name->name, scope); + const QList<LookupItem> candidates = _context.lookup(ast->name->name, scope); addTypeUsage(candidates, ast->name); } } @@ -582,7 +582,7 @@ void CheckSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast) //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(); if (DestructorNameAST *dtor = ast->asDestructorName()) @@ -596,7 +596,8 @@ void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast) getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.length(); - foreach (Symbol *c, candidates) { + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); if (c->isUsingDeclaration()) // skip using declarations... continue; 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(); if (DestructorNameAST *dtor = ast->asDestructorName()) @@ -626,8 +627,11 @@ void CheckSymbols::addMemberUsage(const QList<Symbol *> &candidates, NameAST *as getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.length(); - foreach (Symbol *c, candidates) { - if (! c->isDeclaration()) + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); + if (! c) + continue; + else if (! c->isDeclaration()) continue; else if (c->isTypedef()) continue; diff --git a/src/plugins/cppeditor/cppchecksymbols.h b/src/plugins/cppeditor/cppchecksymbols.h index bb996fb691d9cc2ee0f7e5347e3a215e865cac7a..8db7fda967d643b8bfbc4bdaef8bcde00979fce5 100644 --- a/src/plugins/cppeditor/cppchecksymbols.h +++ b/src/plugins/cppeditor/cppchecksymbols.h @@ -84,11 +84,11 @@ protected: void checkName(NameAST *ast); void checkNamespace(NameAST *name); 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 checkMemberName(NameAST *ast); - void addMemberUsage(const QList<Symbol *> &candidates, NameAST *ast); + void addMemberUsage(const QList<LookupItem> &candidates, NameAST *ast); virtual bool preVisit(AST *); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 663bc73f6226fa8eabf6edd122bb5b6c10368b52..9dae26316d091fe29db29dfbd27a628d0f64cfdc 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -995,8 +995,9 @@ void CPPEditor::switchDeclarationDefinition() LookupContext context(thisDocument, snapshot); Function *functionDefinition = functionScope->owner()->asFunction(); - const QList<Symbol *> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope()); - foreach (Symbol *decl, declarations) { + const QList<LookupItem> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope()); + foreach (const LookupItem &r, declarations) { + Symbol *decl = r.declaration(); // TODO: check decl. openCppEditorAt(linkToSymbol(decl)); break; diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index b717d632541392c1cc55635d29e5702b6f5d7979..15c827bc89b4e5abc19fbff55870b03237498a50 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -920,7 +920,8 @@ public: ClassOrNamespace *b = context.lookupType(function); if (b) { // 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()) { m_option = useTr; // no context required for tr @@ -1302,9 +1303,10 @@ protected: if (Enum *e = result.declaration()->type()->asEnumType()) return e; if (NamedType *namedType = fst->asNamedType()) { - QList<Symbol *> candidates = + QList<LookupItem> candidates = typeOfExpression.context().lookup(namedType->name(), scope); - foreach (Symbol *candidate, candidates) { + foreach (const LookupItem &r, candidates) { + Symbol *candidate = r.declaration(); if (Enum *e = candidate->asEnum()) { return e; } diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 7b4303731e6e8fa6122acc4d28e2774d2915f0ca..44f8b861fac7507500271249d9d0346de503a545 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1175,11 +1175,13 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r if (NamedType *namedTy = ty->asNamedType()) { 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(); - if (Function *funTy = overloadTy->asFunctionType()) + if (Function *funTy = overloadTy->asFunctionType()) { functions.append(funTy); + } } } } diff --git a/src/shared/cplusplus/FullySpecifiedType.cpp b/src/shared/cplusplus/FullySpecifiedType.cpp index da6c16a54a2de19c504bde4590c609c3424ead4a..764c56a1ccbfc6735eba8dce0ec96fe1c3c42cfb 100644 --- a/src/shared/cplusplus/FullySpecifiedType.cpp +++ b/src/shared/cplusplus/FullySpecifiedType.cpp @@ -235,6 +235,12 @@ FullySpecifiedType FullySpecifiedType::simplified() const return *this; } +unsigned FullySpecifiedType::flags() const +{ return _flags; } + +void FullySpecifiedType::setFlags(unsigned flags) +{ _flags = flags; } + void FullySpecifiedType::copySpecifiers(const FullySpecifiedType &type) { // class storage specifiers diff --git a/src/shared/cplusplus/FullySpecifiedType.h b/src/shared/cplusplus/FullySpecifiedType.h index 7905df162de6c95e3977ef0392ff8ca582a66e13..2d0824556a0d49d0a59771da63e14d1c3c5b30b4 100644 --- a/src/shared/cplusplus/FullySpecifiedType.h +++ b/src/shared/cplusplus/FullySpecifiedType.h @@ -134,6 +134,9 @@ public: void copySpecifiers(const FullySpecifiedType &type); + unsigned flags() const; + void setFlags(unsigned flags); + private: Type *_type; struct Flags { diff --git a/tests/auto/cplusplus/lookup/tst_lookup.cpp b/tests/auto/cplusplus/lookup/tst_lookup.cpp index fdf432704e39990f1806214682eb9bb2dac0acb6..6aae4b0b7926d8cf8aeace186a8ab7e85a144638 100644 --- a/tests/auto/cplusplus/lookup/tst_lookup.cpp +++ b/tests/auto/cplusplus/lookup/tst_lookup.cpp @@ -64,6 +64,13 @@ private Q_SLOTS: void class_with_baseclass(); void class_with_protocol_with_protocol(); 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() @@ -169,14 +176,14 @@ void tst_Lookup::simple_class_1() QVERIFY(klass->symbols().contains(impl)); // 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.at(0), allocMethodIface); - QCOMPARE(results.at(1), allocMethodImpl); + QCOMPARE(results.at(0).declaration(), allocMethodIface); + QCOMPARE(results.at(1).declaration(), allocMethodImpl); results = context.lookup(deallocMethod->name(), impl->members()); QCOMPARE(results.size(), 1); - QCOMPARE(results.at(0), deallocMethod); + QCOMPARE(results.at(0).declaration(), deallocMethod); } void tst_Lookup::class_with_baseclass() @@ -230,13 +237,13 @@ void tst_Lookup::class_with_baseclass() QVERIFY(objClass != 0); 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.at(0), baseDecl); + QCOMPARE(results.at(0).declaration(), baseDecl); results = context.lookup(baseMethod->name(), zooImpl->members()); QCOMPARE(results.size(), 1); - QCOMPARE(results.at(0), baseMethod); + QCOMPARE(results.at(0).declaration(), baseMethod); } 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 QList<Symbol *> candidates = context.lookup(P1->name(), zooImpl->scope()); + const QList<LookupItem> candidates = context.lookup(P1->name(), zooImpl->scope()); 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); - 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.at(0), p1method); + QCOMPARE(results.at(0).declaration(), p1method); } void tst_Lookup::iface_impl_scoping() @@ -341,9 +348,9 @@ void tst_Lookup::iface_impl_scoping() QVERIFY(arg->name()->identifier()); 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); - QVERIFY(candidates.at(0)->type()->asIntegerType()); + QVERIFY(candidates.at(0).declaration()->type()->asIntegerType()); } Declaration *method2 = iface->memberAt(1)->asDeclaration(); @@ -351,11 +358,174 @@ void tst_Lookup::iface_impl_scoping() QCOMPARE(method2->identifier()->chars(), "method2"); { // 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.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) #include "tst_lookup.moc"