diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 8383beef3bbcf131976ba9592bb75f1e1e21d417..6af10cf7614ee222dcc1897368c0ae20558d1547 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -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; diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 13547593ca15cb27033b08116c6a54805c02863c..965d399d3e743e94165c39f1384aa72cb63dc3e0 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -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(); diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index de42964176aa981c0136cb73fbc302cf6330b8f9..70fad7ef3e686d5405dddbf9d9c3d9fa4488fcd1 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -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 diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp index 2177cdd9306712ab63f36f6b4c9ed520f9ad3bdf..1a0d84bd0576f7a9ebcee734e526cef3dcccfcdc 100644 --- a/src/libs/cplusplus/TypeOfExpression.cpp +++ b/src/libs/cplusplus/TypeOfExpression.cpp @@ -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()); } + diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h index c1ab1288aac582cdc1e340e604b0837c5962a0e6..bb28c6f938114ea630f8eeb1b48e14de17c1f343 100644 --- a/src/libs/cplusplus/TypeOfExpression.h +++ b/src/libs/cplusplus/TypeOfExpression.h @@ -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; /** diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 10672b0e8dceabeca07853bc896be05dfd319930..f80b61291f4b8912000d2ee35b4c5128d2298f45 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -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 diff --git a/src/shared/cplusplus/Control.cpp b/src/shared/cplusplus/Control.cpp index 4cfd8de6368b8d04890add40659075f7470c0f2f..d36e8b809f70d24047238c6bd42302cb7ad39a6a 100644 --- a/src/shared/cplusplus/Control.cpp +++ b/src/shared/cplusplus/Control.cpp @@ -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(); diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h index e475a17567ce49a138e228b591cc0808c2c012db..461c6453f6a72969dc5a165d6b7cc8962a855a21 100644 --- a/src/shared/cplusplus/Control.h +++ b/src/shared/cplusplus/Control.h @@ -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(); diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp index 0bb231e79688c460708494078e257a8f2522523d..d2b402ea5f9e60b72583612c10b56c775c844ae4 100644 --- a/src/shared/cplusplus/Symbols.cpp +++ b/src/shared/cplusplus/Symbols.cpp @@ -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) { } diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h index cd618a9c876cee6f54b9e71854b002b1ae79a58c..f27502796aa7ead84d0c257f97003e638ca4ad24 100644 --- a/src/shared/cplusplus/Symbols.h +++ b/src/shared/cplusplus/Symbols.h @@ -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);