forked from qt-creator/qt-creator
Added support to complete function-call operators.
This commit is contained in:
@@ -547,8 +547,36 @@ bool ResolveExpression::visit(TemplateIdAST *ast)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const
|
||||
{
|
||||
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 true;
|
||||
}
|
||||
|
||||
bool ResolveExpression::visit(CallAST *ast)
|
||||
{
|
||||
ResolveClass resolveClass;
|
||||
|
||||
const QList<Result> baseResults = _results;
|
||||
_results.clear();
|
||||
|
||||
// Compute the types of the actual arguments.
|
||||
QList< QList<Result> > arguments;
|
||||
for (ExpressionListAST *exprIt = ast->expression_list; exprIt;
|
||||
@@ -556,30 +584,38 @@ bool ResolveExpression::visit(CallAST *ast)
|
||||
arguments.append(operator()(exprIt->expression));
|
||||
}
|
||||
|
||||
QList<Result> baseResults = _results;
|
||||
_results.clear();
|
||||
const unsigned actualArgumentCount = arguments.count();
|
||||
|
||||
foreach (Result p, baseResults) {
|
||||
if (Function *funTy = p.first->asFunctionType()) {
|
||||
unsigned minNumberArguments = 0;
|
||||
for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) {
|
||||
Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument();
|
||||
if (arg->hasInitializer())
|
||||
break;
|
||||
Name *functionCallOp = control()->operatorNameId(OperatorNameId::FunctionCallOp);
|
||||
|
||||
foreach (const Result &result, baseResults) {
|
||||
FullySpecifiedType ty = result.first.simplified();
|
||||
Symbol *lastVisibleSymbol = result.second;
|
||||
|
||||
if (NamedType *namedTy = ty->asNamedType()) {
|
||||
const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, _context);
|
||||
|
||||
foreach (Symbol *classObject, classObjectCandidates) {
|
||||
const QList<Result> overloads = resolveMember(functionCallOp, classObject->asClass(), namedTy->name());
|
||||
|
||||
foreach (const Result &o, overloads) {
|
||||
FullySpecifiedType overloadTy = o.first.simplified();
|
||||
|
||||
if (Function *funTy = overloadTy->asFunctionType()) {
|
||||
if (maybeValidPrototype(funTy, actualArgumentCount))
|
||||
addResult(funTy->returnType().simplified(), lastVisibleSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
const unsigned actualArgumentCount = arguments.count();
|
||||
if (actualArgumentCount < minNumberArguments) {
|
||||
// not enough arguments.
|
||||
} else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) {
|
||||
// too many arguments.
|
||||
} else {
|
||||
p.first = funTy->returnType();
|
||||
addResult(p);
|
||||
}
|
||||
} else if (Class *classTy = p.first->asClassType()) {
|
||||
|
||||
} else if (Function *funTy = ty->asFunctionType()) {
|
||||
if (maybeValidPrototype(funTy, actualArgumentCount))
|
||||
addResult(funTy->returnType().simplified(), lastVisibleSymbol);
|
||||
|
||||
} else if (Class *classTy = ty->asClassType()) {
|
||||
// Constructor call
|
||||
p.first = control()->namedType(classTy->name());
|
||||
addResult(p);
|
||||
FullySpecifiedType ctorTy = control()->namedType(classTy->name());
|
||||
addResult(ctorTy, lastVisibleSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ protected:
|
||||
void addResult(const Result &result);
|
||||
void addResults(const QList<Result> &results);
|
||||
|
||||
bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
|
||||
|
||||
using ASTVisitor::visit;
|
||||
|
||||
virtual bool visit(ExpressionListAST *ast);
|
||||
|
||||
@@ -857,7 +857,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
}
|
||||
|
||||
if (! resolvedTypes.isEmpty()) {
|
||||
if (m_completionOperator == T_LPAREN && completeConstructorOrFunction(resolvedTypes)) {
|
||||
if (m_completionOperator == T_LPAREN && completeConstructorOrFunction(resolvedTypes, context)) {
|
||||
return m_startPosition;
|
||||
|
||||
} else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) &&
|
||||
@@ -884,16 +884,19 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
|
||||
QTextCursor tc(edit->document());
|
||||
tc.setPosition(index);
|
||||
QString baseExpression = expressionUnderCursor(tc);
|
||||
|
||||
const QString baseExpression = expressionUnderCursor(tc);
|
||||
|
||||
// Resolve the type of this expression
|
||||
QList<TypeOfExpression::Result> results =
|
||||
typeOfExpression(baseExpression, thisDocument, lastVisibleSymbol, TypeOfExpression::Preprocess);
|
||||
const QList<TypeOfExpression::Result> results =
|
||||
typeOfExpression(baseExpression, thisDocument,
|
||||
lastVisibleSymbol,
|
||||
TypeOfExpression::Preprocess);
|
||||
|
||||
// If it's a class, add completions for the constructors
|
||||
foreach (const TypeOfExpression::Result &result, results) {
|
||||
if (result.first->isClassType()) {
|
||||
if (completeConstructorOrFunction(results))
|
||||
if (completeConstructorOrFunction(results, context))
|
||||
return m_startPosition;
|
||||
break;
|
||||
}
|
||||
@@ -905,12 +908,13 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results)
|
||||
bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results,
|
||||
const LookupContext &context)
|
||||
{
|
||||
QList<Function *> functions;
|
||||
|
||||
foreach (const TypeOfExpression::Result &result, results) {
|
||||
FullySpecifiedType exprTy = result.first;
|
||||
FullySpecifiedType exprTy = result.first.simplified();
|
||||
|
||||
if (Class *klass = exprTy->asClassType()) {
|
||||
Name *className = klass->name();
|
||||
@@ -940,8 +944,8 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
}
|
||||
|
||||
if (functions.isEmpty()) {
|
||||
foreach (const TypeOfExpression::Result &p, results) {
|
||||
FullySpecifiedType ty = p.first;
|
||||
foreach (const TypeOfExpression::Result &result, results) {
|
||||
FullySpecifiedType ty = result.first.simplified();
|
||||
|
||||
if (Function *fun = ty->asFunctionType()) {
|
||||
|
||||
@@ -950,10 +954,6 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
else if (! functions.isEmpty() && functions.first()->scope() != fun->scope())
|
||||
continue; // skip fun, it's an hidden declaration.
|
||||
|
||||
Name *name = fun->name();
|
||||
if (QualifiedNameId *q = fun->name()->asQualifiedNameId())
|
||||
name = q->unqualifiedNameId();
|
||||
|
||||
bool newOverload = true;
|
||||
|
||||
foreach (Function *f, functions) {
|
||||
@@ -967,7 +967,35 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
functions.append(fun);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (functions.isEmpty()) {
|
||||
ResolveExpression resolveExpression(context);
|
||||
ResolveClass resolveClass;
|
||||
Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
|
||||
|
||||
foreach (const TypeOfExpression::Result &result, results) {
|
||||
FullySpecifiedType ty = result.first.simplified();
|
||||
|
||||
if (NamedType *namedTy = ty->asNamedType()) {
|
||||
const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, context);
|
||||
|
||||
foreach (Symbol *classObjectCandidate, classObjectCandidates) {
|
||||
if (Class *klass = classObjectCandidate->asClass()) {
|
||||
const QList<TypeOfExpression::Result> overloads =
|
||||
resolveExpression.resolveMember(functionCallOp, klass,
|
||||
namedTy->name());
|
||||
|
||||
foreach (const TypeOfExpression::Result &overloadResult, overloads) {
|
||||
FullySpecifiedType overloadTy = overloadResult.first.simplified();
|
||||
|
||||
if (Function *funTy = overloadTy->asFunctionType())
|
||||
functions.append(funTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! functions.isEmpty()) {
|
||||
|
||||
@@ -113,7 +113,8 @@ private:
|
||||
|
||||
bool completeInclude(const QTextCursor &cursor);
|
||||
|
||||
bool completeConstructorOrFunction(const QList<CPlusPlus::TypeOfExpression::Result> &);
|
||||
bool completeConstructorOrFunction(const QList<CPlusPlus::TypeOfExpression::Result> &,
|
||||
const CPlusPlus::LookupContext &);
|
||||
|
||||
bool completeMember(const QList<CPlusPlus::TypeOfExpression::Result> &,
|
||||
const CPlusPlus::LookupContext &context);
|
||||
|
||||
Reference in New Issue
Block a user