Commit 63138eb8 authored by Roberto Raggi's avatar Roberto Raggi

Added some initial support for function overloading.

parent 610023f8
......@@ -42,6 +42,9 @@
#include <AST.h>
#include <Scope.h>
#include <SymbolVisitor.h>
#include <NameVisitor.h>
#include <TypeVisitor.h>
#include <CoreTypes.h>
#include <QtCore/QByteArray>
#include <QtCore/QBitArray>
......@@ -789,9 +792,8 @@ Symbol *Snapshot::findMatchingDefinition(Symbol *declaration) const
Function *best = 0;
foreach (Function *fun, viableFunctions) {
if (fun->unqualifiedName()->isEqualTo(declaration->unqualifiedName()))
if (! (fun->unqualifiedName() && fun->unqualifiedName()->isEqualTo(declaration->unqualifiedName())))
continue;
else if (fun->argumentCount() == declarationTy->argumentCount()) {
if (! best)
best = fun;
......
......@@ -75,7 +75,8 @@ ResolveExpression::ResolveExpression(const LookupContext &context)
: ASTVisitor(context.expressionDocument()->translationUnit()),
_scope(0),
_context(context),
bind(context.expressionDocument()->translationUnit())
bind(context.expressionDocument()->translationUnit()),
_reference(false)
{ }
ResolveExpression::~ResolveExpression()
......@@ -84,19 +85,26 @@ ResolveExpression::~ResolveExpression()
QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast, Scope *scope)
{ return resolve(ast, scope); }
QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope)
QList<LookupItem> ResolveExpression::reference(ExpressionAST *ast, Scope *scope)
{ return resolve(ast, scope, true); }
QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope, bool ref)
{
if (! scope)
return QList<LookupItem>();
Scope *previousVisibleSymbol = _scope;
_scope = scope;
const QList<LookupItem> result = resolve(ast);
_scope = previousVisibleSymbol;
std::swap(_scope, scope);
std::swap(_reference, ref);
const QList<LookupItem> result = expression(ast);
std::swap(_reference, ref);
std::swap(_scope, scope);
return result;
}
QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast)
QList<LookupItem> ResolveExpression::expression(ExpressionAST *ast)
{
const QList<LookupItem> previousResults = switchResults(QList<LookupItem>());
accept(ast);
......@@ -441,27 +449,18 @@ bool ResolveExpression::visit(ConversionFunctionIdAST *)
return false;
}
bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const
bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount)
{
unsigned minNumberArguments = 0;
for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) {
Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument();
if (arg->hasInitializer())
break;
}
if (actualArgumentCount < minNumberArguments) {
// not enough arguments.
return false;
} else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) {
// too many arguments.
return false;
}
return funTy->maybeValidPrototype(actualArgumentCount);
}
return true;
bool ResolveExpression::implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const
{
if (sourceTy.isEqualTo(targetTy))
return true;
else if (sourceTy.simplified().isEqualTo(targetTy.simplified()))
return true;
return false;
}
bool ResolveExpression::visit(CallAST *ast)
......@@ -469,14 +468,55 @@ bool ResolveExpression::visit(CallAST *ast)
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
// Compute the types of the actual arguments.
int actualArgumentCount = 0;
unsigned actualArgumentCount = 0;
//QList< QList<Result> > arguments;
QList< QList<LookupItem> > arguments;
for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) {
//arguments.append(resolve(exprIt->expression));
if (_reference)
arguments.append(resolve(exprIt->value, _scope));
++actualArgumentCount;
}
if (_reference) {
_results.clear();
foreach (const LookupItem &base, baseResults) {
if (Function *funTy = base.type()->asFunctionType()) {
if (! maybeValidPrototype(funTy, actualArgumentCount))
continue;
int score = 0;
for (unsigned i = 0; i < funTy->argumentCount(); ++i) {
const FullySpecifiedType formalTy = funTy->argumentAt(i)->type();
FullySpecifiedType actualTy;
if (i < unsigned(arguments.size())) {
const QList<LookupItem> actual = arguments.at(i);
if (actual.isEmpty())
continue;
actualTy = actual.first().type();
} else
actualTy = formalTy;
if (implicitConversion(actualTy, formalTy))
++score;
}
if (score)
_results.prepend(base);
else
_results.append(base);
}
}
if (_results.isEmpty())
_results = baseResults;
return false;
}
const Name *functionCallOp = control()->operatorNameId(OperatorNameId::FunctionCallOp);
foreach (const LookupItem &result, baseResults) {
......@@ -513,7 +553,7 @@ bool ResolveExpression::visit(CallAST *ast)
bool ResolveExpression::visit(ArrayAccessAST *ast)
{
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
const QList<LookupItem> indexResults = resolve(ast->expression);
const QList<LookupItem> indexResults = resolve(ast->expression, _scope);
const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
......@@ -709,7 +749,7 @@ bool ResolveExpression::visit(PostIncrDecrAST *ast)
bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
{
const QList<LookupItem> receiverResults = resolve(ast->receiver_expression);
const QList<LookupItem> receiverResults = resolve(ast->receiver_expression, _scope);
foreach (const LookupItem &result, receiverResults) {
FullySpecifiedType ty = result.type().simplified();
......
......@@ -45,7 +45,8 @@ public:
virtual ~ResolveExpression();
QList<LookupItem> operator()(ExpressionAST *ast, Scope *scope);
QList<LookupItem> resolve(ExpressionAST *ast, Scope *scope);
QList<LookupItem> resolve(ExpressionAST *ast, Scope *scope, bool ref = false);
QList<LookupItem> reference(ExpressionAST *ast, Scope *scope);
ClassOrNamespace *baseExpression(const QList<LookupItem> &baseResults,
int accessOp,
......@@ -56,7 +57,7 @@ public:
protected:
ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope) const;
QList<LookupItem> resolve(ExpressionAST *ast);
QList<LookupItem> expression(ExpressionAST *ast);
QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const;
......@@ -69,7 +70,8 @@ protected:
void addResults(const QList<Symbol *> &symbols);
void addResults(const QList<LookupItem> &items);
bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount);
bool implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const;
using ASTVisitor::visit;
......@@ -119,6 +121,7 @@ private:
LookupContext _context;
Bind bind;
QList<LookupItem> _results;
bool _reference;
};
} // end of namespace CPlusPlus
......
......@@ -84,6 +84,20 @@ QList<LookupItem> TypeOfExpression::operator()(const QString &expression,
scope);
}
QList<LookupItem> TypeOfExpression::reference(const QString &expression,
Scope *scope,
PreprocessMode mode)
{
QString code = expression;
if (mode == Preprocess)
code = preprocessedExpression(expression);
Document::Ptr expressionDoc = documentForExpression(code);
expressionDoc->check();
return reference(extractExpressionAST(expressionDoc), expressionDoc, scope);
}
QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression,
Document::Ptr document,
Scope *scope)
......@@ -104,6 +118,26 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression,
return items;
}
QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression,
Document::Ptr document,
Scope *scope)
{
m_ast = expression;
m_scope = scope;
m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot);
m_lookupContext.setBindings(m_bindings);
ResolveExpression resolve(m_lookupContext);
const QList<LookupItem> items = resolve.reference(m_ast, scope);
if (! m_bindings)
m_lookupContext = resolve.context();
return items;
}
QString TypeOfExpression::preprocess(const QString &expression) const
{
return preprocessedExpression(expression);
......@@ -179,3 +213,4 @@ QString TypeOfExpression::preprocessedExpression(const QString &expression) cons
const QByteArray preprocessedCode = preproc("<expression>", code);
return QString::fromUtf8(preprocessedCode.constData(), preprocessedCode.size());
}
......@@ -98,6 +98,14 @@ public:
Document::Ptr document,
Scope *scope);
QList<LookupItem> reference(const QString &expression,
Scope *scope,
PreprocessMode mode = NoPreprocess);
QList<LookupItem> reference(ExpressionAST *expression,
Document::Ptr document,
Scope *scope);
QString preprocess(const QString &expression) const;
/**
......
......@@ -76,6 +76,7 @@
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/basetextdocumentlayout.h>
#include <texteditor/fontsettings.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorconstants.h>
......@@ -1265,6 +1266,13 @@ CPPEditor::Link CPPEditor::attemptFuncDeclDef(const QTextCursor &cursor, const D
return result;
}
for (int i = path.size() - 1; i != -1; --i) {
AST *node = path.at(i);
if (node->asParameterDeclaration() != 0)
return result;
}
AST *declParent = 0;
DeclaratorAST *decl = 0;
for (int i = path.size() - 2; i > 0; --i) {
......@@ -1431,11 +1439,27 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
// Evaluate the type of the expression under the cursor
ExpressionUnderCursor expressionUnderCursor;
const QString expression = expressionUnderCursor(tc);
QString expression = expressionUnderCursor(tc);
for (int pos = tc.position();; ++pos) {
const QChar ch = characterAt(pos);
if (ch.isSpace())
continue;
else {
if (ch == QLatin1Char('(') && ! expression.isEmpty()) {
tc.setPosition(pos);
if (TextEditor::TextBlockUserData::findNextClosingParenthesis(&tc, true)) {
expression.append(tc.selectedText());
}
}
break;
}
}
TypeOfExpression typeOfExpression;
typeOfExpression.init(doc, snapshot);
const QList<LookupItem> resolvedSymbols = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
const QList<LookupItem> resolvedSymbols = typeOfExpression.reference(expression, scope, TypeOfExpression::Preprocess);
if (!resolvedSymbols.isEmpty()) {
LookupItem result = skipForwardDeclarations(resolvedSymbols);
......@@ -1473,16 +1497,6 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
link.begin = beginOfToken;
link.end = endOfToken;
return link;
// This would jump to the type of a name
#if 0
} else if (NamedType *namedType = firstType->asNamedType()) {
QList<Symbol *> candidates = context.resolve(namedType->name());
if (!candidates.isEmpty()) {
Symbol *s = candidates.takeFirst();
openCppEditorAt(s->fileName(), s->line(), s->column());
}
#endif
}
} else {
// Handle macro uses
......
......@@ -759,6 +759,22 @@ const Identifier *Control::objcCopyId() const
const Identifier *Control::objcNonatomicId() const
{ return d->objcNonatomicId; }
Symbol **Control::firstSymbol() const
{
if (d->symbols.empty())
return 0;
return &*d->symbols.begin();
}
Symbol **Control::lastSymbol() const
{
if (d->symbols.empty())
return 0;
return &*d->symbols.begin() + d->symbols.size();
}
bool Control::hasSymbol(Symbol *symbol) const
{
return std::find(d->symbols.begin(), d->symbols.end(), symbol) != d->symbols.end();
......
......@@ -212,6 +212,9 @@ public:
const NumericLiteral *numericLiteral(const char *chars, unsigned size);
const NumericLiteral *numericLiteral(const char *chars);
Symbol **firstSymbol() const;
Symbol **lastSymbol() const;
bool hasSymbol(Symbol *symbol) const;
void squeeze();
......
......@@ -362,6 +362,30 @@ void Function::visitSymbol0(SymbolVisitor *visitor)
}
}
bool Function::maybeValidPrototype(unsigned actualArgumentCount) const
{
unsigned minNumberArguments = 0;
for (; minNumberArguments < this->argumentCount(); ++minNumberArguments) {
Argument *arg = this->argumentAt(minNumberArguments)->asArgument();
if (arg->hasInitializer())
break;
}
if (actualArgumentCount < minNumberArguments) {
// not enough arguments.
return false;
} else if (! this->isVariadic() && actualArgumentCount > this->argumentCount()) {
// too many arguments.
return false;
}
return true;
}
Block::Block(TranslationUnit *translationUnit, unsigned sourceLocation)
: Scope(translationUnit, sourceLocation, /*name = */ 0)
{ }
......
......@@ -350,6 +350,8 @@ public:
bool isAmbiguous() const; // internal
void setAmbiguous(bool isAmbiguous); // internal
bool maybeValidPrototype(unsigned actualArgumentCount) const;
protected:
virtual void visitSymbol0(SymbolVisitor *visitor);
virtual void accept0(TypeVisitor *visitor);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment