From ca291fbc7ba860b1856b45eff5a02daa56a39d65 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen <erik.verbruggen@digia.com> Date: Thu, 2 May 2013 14:55:56 +0200 Subject: [PATCH] C++: fix functionAt(), moved it, and added test. Thanks to Jesper K. Pedersen for the fix! Change-Id: Ie49c3352e26a9632b1500596b00d559bfe932dff Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com> --- src/libs/cplusplus/CppDocument.cpp | 51 +++++++++++++++++++ src/libs/cplusplus/CppDocument.h | 1 + .../cpptools/abstracteditorsupport.cpp | 28 +++------- tests/auto/cplusplus/lookup/tst_lookup.cpp | 25 +++++++++ 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index ee6d7f3a9d6..84092fc93da 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -464,6 +464,57 @@ void Document::setGlobalNamespace(Namespace *globalNamespace) _globalNamespace = globalNamespace; } +/*! + * Extract the function name including scope at the given position. + * + * Note that a function (scope) starts at the name of that function, not at the return type. The + * implication is that this method will return an empty string when the line/column is on the + * return type. + * + * \param line the line number, starting with line 1 + * \param column the column number, starting with column 1 + */ +QString Document::functionAt(int line, int column) const +{ + if (line < 1 || column < 1) + return QString(); + + CPlusPlus::Symbol *symbol = lastVisibleSymbolAt(line, column); + if (!symbol) + return QString(); + + // Find the enclosing function scope (which might be several levels up, or we might be standing + // on it) + Scope *scope; + if (symbol->isScope()) + scope = symbol->asScope(); + else + scope = symbol->enclosingScope(); + + while (scope && !scope->isFunction() ) + scope = scope->enclosingScope(); + + if (!scope) + return QString(); + + // We found the function scope, extract its name. + const Overview o; + QString rc = o.prettyName(scope->name()); + + // Prepend namespace "Foo::Foo::foo()" up to empty root namespace + for (const Symbol *owner = scope->enclosingNamespace(); + owner; owner = owner->enclosingNamespace()) { + const QString name = o.prettyName(owner->name()); + if (name.isEmpty()) { + break; + } else { + rc.prepend(QLatin1String("::")); + rc.prepend(name); + } + } + return rc; +} + Scope *Document::scopeAt(unsigned line, unsigned column) { FindScopeAt findScopeAt(_translationUnit, line, column); diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index 589e2b9503a..b9a58f547fc 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -99,6 +99,7 @@ public: QList<Macro> definedMacros() const { return _definedMacros; } + QString functionAt(int line, int column) const; Symbol *lastVisibleSymbolAt(unsigned line, unsigned column = 0) const; Scope *scopeAt(unsigned line, unsigned column = 0); diff --git a/src/plugins/cpptools/abstracteditorsupport.cpp b/src/plugins/cpptools/abstracteditorsupport.cpp index 6410473e34d..cdbd86f342b 100644 --- a/src/plugins/cpptools/abstracteditorsupport.cpp +++ b/src/plugins/cpptools/abstracteditorsupport.cpp @@ -55,29 +55,13 @@ QString AbstractEditorSupport::functionAt(const CppModelManagerInterface *modelM const QString &fileName, int line, int column) { - const CPlusPlus::Snapshot snapshot = modelManager->snapshot(); - const CPlusPlus::Document::Ptr document = snapshot.document(fileName); - if (!document) + if (!modelManager) return QString(); - if (const CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column)) - if (const CPlusPlus::Scope *scope = symbol->enclosingScope()) - if (const CPlusPlus::Scope *functionScope = scope->enclosingFunction()) - if (const CPlusPlus::Symbol *function = functionScope) { - const CPlusPlus::Overview o; - QString rc = o.prettyName(function->name()); - // Prepend namespace "Foo::Foo::foo()" up to empty root namespace - for (const CPlusPlus::Symbol *owner = function->enclosingNamespace(); - owner; owner = owner->enclosingNamespace()) { - const QString name = o.prettyName(owner->name()); - if (name.isEmpty()) { - break; - } else { - rc.prepend(QLatin1String("::")); - rc.prepend(name); - } - } - return rc; - } + + const CPlusPlus::Snapshot snapshot = modelManager->snapshot(); + if (const CPlusPlus::Document::Ptr document = snapshot.document(fileName)) + return document->functionAt(line, column); + return QString(); } diff --git a/tests/auto/cplusplus/lookup/tst_lookup.cpp b/tests/auto/cplusplus/lookup/tst_lookup.cpp index a0df89de24f..c1d448b62bd 100644 --- a/tests/auto/cplusplus/lookup/tst_lookup.cpp +++ b/tests/auto/cplusplus/lookup/tst_lookup.cpp @@ -87,6 +87,7 @@ class tst_Lookup: public QObject private Q_SLOTS: void base_class_defined_1(); + void document_functionAt_1(); // Objective-C void simple_class_1(); @@ -153,6 +154,30 @@ void tst_Lookup::base_class_defined_1() QVERIFY(classToAST.value(derivedClass) != 0); } +void tst_Lookup::document_functionAt_1() +{ + const QByteArray source = "\n" + "void Foo::Bar() {\n" // line 1 + " \n" // line 2 + " for (int i=0; i < 10; ++i) {\n" + " \n" // line 4 + " }\n" + "}\n"; // line 7 + + Document::Ptr doc = Document::create("document_functionAt_1"); + doc->setUtf8Source(source); + doc->parse(); + doc->check(); + + QVERIFY(doc->diagnosticMessages().isEmpty()); + QCOMPARE(doc->functionAt(1, 2), QString()); + QCOMPARE(doc->functionAt(1, 11), QString(QLatin1String("Foo::Bar"))); + QCOMPARE(doc->functionAt(2, 2), QString(QLatin1String("Foo::Bar"))); + QCOMPARE(doc->functionAt(3, 10), QString(QLatin1String("Foo::Bar"))); + QCOMPARE(doc->functionAt(4, 3), QString(QLatin1String("Foo::Bar"))); + QCOMPARE(doc->functionAt(6, 1), QString(QLatin1String("Foo::Bar"))); +} + void tst_Lookup::simple_class_1() { const QByteArray source = "\n" -- GitLab