diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/cppeditor/cppeditorplugin.h | 3 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppfollowsymbolundercursor.cpp | 5 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp | 284 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppvirtualfunctionassistprovider.h | 17 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.pro | 6 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.qbs | 2 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolsplugin.h | 3 | ||||
-rw-r--r-- | src/plugins/cpptools/functionutils.cpp | 321 | ||||
-rw-r--r-- | src/plugins/cpptools/functionutils.h | 68 |
9 files changed, 404 insertions, 305 deletions
diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index e06355949b..6ef87cf793 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -206,9 +206,6 @@ private slots: void test_quickfix_InsertVirtualMethods_implementationFile(); void test_quickfix_InsertVirtualMethods_BaseClassInNamespace(); - void test_functionhelper_virtualFunctions(); - void test_functionhelper_virtualFunctions_data(); - // tests for "Include Hiererchy" void test_includeHierarchyModel_simpleIncludes(); void test_includeHierarchyModel_simpleIncludedBy(); diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index 6b566f9f41..1b678ba33c 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -39,6 +39,7 @@ #include <cplusplus/SimpleLexer.h> #include <cplusplus/TypeOfExpression.h> #include <cpptools/cppmodelmanagerinterface.h> +#include <cpptools/functionutils.h> #include <cpptools/symbolfinder.h> #include <texteditor/basetextdocumentlayout.h> #include <utils/qtcassert.h> @@ -128,12 +129,12 @@ bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(Function *function if (IdExpressionAST *idExpressionAST = m_baseExpressionAST->asIdExpression()) { NameAST *name = idExpressionAST->name; const bool nameIsQualified = name && name->asQualifiedName(); - result = !nameIsQualified && FunctionHelper::isVirtualFunction( + result = !nameIsQualified && FunctionUtils::isVirtualFunction( function, LookupContext(m_document, m_snapshot)); } else if (MemberAccessAST *memberAccessAST = m_baseExpressionAST->asMemberAccess()) { NameAST *name = memberAccessAST->member_name; const bool nameIsQualified = name && name->asQualifiedName(); - if (!nameIsQualified && FunctionHelper::isVirtualFunction( + if (!nameIsQualified && FunctionUtils::isVirtualFunction( function, LookupContext(m_document, m_snapshot))) { TranslationUnit *unit = m_expressionDocument->translationUnit(); QTC_ASSERT(unit, return false); diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp index aff4973e05..a3f7048909 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp @@ -40,6 +40,7 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> +#include <cpptools/functionutils.h> #include <cpptools/symbolfinder.h> #include <cpptools/typehierarchybuilder.h> @@ -55,6 +56,7 @@ using namespace CPlusPlus; using namespace CppEditor::Internal; +using namespace CppTools; using namespace TextEditor; /// Activate current item with the same shortcut that is configured for Follow Symbol Under Cursor. @@ -143,7 +145,7 @@ public: if (!functionsClass) return 0; - const QList<Symbol *> overrides = FunctionHelper::overrides( + const QList<Symbol *> overrides = FunctionUtils::overrides( m_params.function, functionsClass, m_params.staticClass, m_params.snapshot); if (overrides.isEmpty()) return 0; @@ -208,283 +210,3 @@ IAssistProcessor *VirtualFunctionAssistProvider::createProcessor() const { return new VirtualFunctionsAssistProcessor(m_params); } - -enum VirtualType { Virtual, PureVirtual }; - -static bool isVirtualFunction_helper(const Function *function, - const LookupContext &context, - VirtualType virtualType, - const Function **firstVirtual) -{ - enum { Unknown, False, True } res = Unknown; - - if (firstVirtual) - *firstVirtual = 0; - - if (!function) - return false; - - if (virtualType == PureVirtual) - res = function->isPureVirtual() ? True : False; - - if (function->isVirtual()) { - if (firstVirtual) - *firstVirtual = function; - if (res == Unknown) - res = True; - } - - if (!firstVirtual && res != Unknown) - return res == True; - - QList<LookupItem> results = context.lookup(function->name(), function->enclosingScope()); - if (!results.isEmpty()) { - const bool isDestructor = function->name()->isDestructorNameId(); - foreach (const LookupItem &item, results) { - if (Symbol *symbol = item.declaration()) { - if (Function *functionType = symbol->type()->asFunctionType()) { - if (functionType->name()->isDestructorNameId() != isDestructor) - continue; - if (functionType == function) // already tested - continue; - if (functionType->isFinal()) - return res == True; - if (functionType->isVirtual()) { - if (!firstVirtual) - return true; - if (res == Unknown) - res = True; - *firstVirtual = functionType; - } - } - } - } - } - - return res == True; -} - -bool FunctionHelper::isVirtualFunction(const Function *function, - const LookupContext &context, - const Function **firstVirtual) -{ - return isVirtualFunction_helper(function, context, Virtual, firstVirtual); -} - -bool FunctionHelper::isPureVirtualFunction(const Function *function, - const LookupContext &context, - const Function **firstVirtual) -{ - return isVirtualFunction_helper(function, context, PureVirtual, firstVirtual); -} - -QList<Symbol *> FunctionHelper::overrides(Function *function, Class *functionsClass, - Class *staticClass, const Snapshot &snapshot) -{ - QList<Symbol *> result; - QTC_ASSERT(function && functionsClass && staticClass, return result); - - FullySpecifiedType referenceType = function->type(); - const Name *referenceName = function->name(); - QTC_ASSERT(referenceName && referenceType.isValid(), return result); - - // Find overrides - CppTools::TypeHierarchyBuilder builder(staticClass, snapshot); - const CppTools::TypeHierarchy &staticClassHierarchy = builder.buildDerivedTypeHierarchy(); - - QList<CppTools::TypeHierarchy> l; - l.append(CppTools::TypeHierarchy(functionsClass)); - l.append(staticClassHierarchy); - - while (!l.isEmpty()) { - // Add derived - const CppTools::TypeHierarchy hierarchy = l.takeFirst(); - QTC_ASSERT(hierarchy.symbol(), continue); - Class *c = hierarchy.symbol()->asClass(); - QTC_ASSERT(c, continue); - - foreach (const CppTools::TypeHierarchy &t, hierarchy.hierarchy()) { - if (!l.contains(t)) - l << t; - } - - // Check member functions - for (int i = 0, total = c->memberCount(); i < total; ++i) { - Symbol *candidate = c->memberAt(i); - const Name *candidateName = candidate->name(); - const FullySpecifiedType candidateType = candidate->type(); - if (!candidateName || !candidateType.isValid()) - continue; - if (candidateName->isEqualTo(referenceName) && candidateType.isEqualTo(referenceType)) - result << candidate; - } - } - - return result; -} - -#ifdef WITH_TESTS -#include "cppeditorplugin.h" - -#include <QList> -#include <QTest> - -namespace CppEditor { -namespace Internal { - -enum Virtuality -{ - NotVirtual, - Virtual, - PureVirtual -}; -typedef QList<Virtuality> VirtualityList; -} // Internal namespace -} // CppEditor namespace - -Q_DECLARE_METATYPE(CppEditor::Internal::Virtuality) -Q_DECLARE_METATYPE(CppEditor::Internal::VirtualityList) -Q_DECLARE_METATYPE(QList<int>) - -namespace CppEditor { -namespace Internal { - -void CppEditorPlugin::test_functionhelper_virtualFunctions() -{ - // Create and parse document - QFETCH(QByteArray, source); - QFETCH(VirtualityList, virtualityList); - QFETCH(QList<int>, firstVirtualList); - Document::Ptr document = Document::create(QLatin1String("virtuals")); - document->setUtf8Source(source); - document->check(); // calls parse(); - QCOMPARE(document->diagnosticMessages().size(), 0); - QVERIFY(document->translationUnit()->ast()); - QList<const Function *> allFunctions; - const Function *firstVirtual = 0; - - // Iterate through Function symbols - Snapshot snapshot; - snapshot.insert(document); - const LookupContext context(document, snapshot); - Control *control = document->translationUnit()->control(); - Symbol **end = control->lastSymbol(); - for (Symbol **it = control->firstSymbol(); it != end; ++it) { - if (const Function *function = (*it)->asFunction()) { - allFunctions.append(function); - QTC_ASSERT(!virtualityList.isEmpty(), return); - Virtuality virtuality = virtualityList.takeFirst(); - QTC_ASSERT(!firstVirtualList.isEmpty(), return); - int firstVirtualIndex = firstVirtualList.takeFirst(); - bool isVirtual = FunctionHelper::isVirtualFunction(function, context, &firstVirtual); - bool isPureVirtual = FunctionHelper::isPureVirtualFunction(function, context, - &firstVirtual); - - // Test for regressions introduced by firstVirtual - QCOMPARE(FunctionHelper::isVirtualFunction(function, context), isVirtual); - QCOMPARE(FunctionHelper::isPureVirtualFunction(function, context), isPureVirtual); - if (isVirtual) { - if (isPureVirtual) - QCOMPARE(virtuality, PureVirtual); - else - QCOMPARE(virtuality, Virtual); - } else { - QEXPECT_FAIL("virtual-dtor-dtor", "Not implemented", Abort); - if (allFunctions.size() == 3) - QEXPECT_FAIL("dtor-virtual-dtor-dtor", "Not implemented", Abort); - QCOMPARE(virtuality, NotVirtual); - } - if (firstVirtualIndex == -1) - QVERIFY(!firstVirtual); - else - QCOMPARE(firstVirtual, allFunctions.at(firstVirtualIndex)); - } - } - QVERIFY(virtualityList.isEmpty()); - QVERIFY(firstVirtualList.isEmpty()); -} - -void CppEditorPlugin::test_functionhelper_virtualFunctions_data() -{ - typedef QByteArray _; - QTest::addColumn<QByteArray>("source"); - QTest::addColumn<VirtualityList>("virtualityList"); - QTest::addColumn<QList<int> >("firstVirtualList"); - - QTest::newRow("none") - << _("struct None { void foo() {} };\n") - << (VirtualityList() << NotVirtual) - << (QList<int>() << -1); - - QTest::newRow("single-virtual") - << _("struct V { virtual void foo() {} };\n") - << (VirtualityList() << Virtual) - << (QList<int>() << 0); - - QTest::newRow("single-pure-virtual") - << _("struct PV { virtual void foo() = 0; };\n") - << (VirtualityList() << PureVirtual) - << (QList<int>() << 0); - - QTest::newRow("virtual-derived-with-specifier") - << _("struct Base { virtual void foo() {} };\n" - "struct Derived : Base { virtual void foo() {} };\n") - << (VirtualityList() << Virtual << Virtual) - << (QList<int>() << 0 << 0); - - QTest::newRow("virtual-derived-implicit") - << _("struct Base { virtual void foo() {} };\n" - "struct Derived : Base { void foo() {} };\n") - << (VirtualityList() << Virtual << Virtual) - << (QList<int>() << 0 << 0); - - QTest::newRow("not-virtual-then-virtual") - << _("struct Base { void foo() {} };\n" - "struct Derived : Base { virtual void foo() {} };\n") - << (VirtualityList() << NotVirtual << Virtual) - << (QList<int>() << -1 << 1); - - QTest::newRow("virtual-final-not-virtual") - << _("struct Base { virtual void foo() {} };\n" - "struct Derived : Base { void foo() final {} };\n" - "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << Virtual << NotVirtual) - << (QList<int>() << 0 << 0 << -1); - - QTest::newRow("virtual-then-pure") - << _("struct Base { virtual void foo() {} };\n" - "struct Derived : Base { virtual void foo() = 0; };\n" - "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << PureVirtual << Virtual) - << (QList<int>() << 0 << 0 << 0); - - QTest::newRow("virtual-virtual-final-not-virtual") - << _("struct Base { virtual void foo() {} };\n" - "struct Derived : Base { virtual void foo() final {} };\n" - "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << Virtual << NotVirtual) - << (QList<int>() << 0 << 0 << -1); - - QTest::newRow("ctor-virtual-dtor") - << _("struct Base { Base() {} virtual ~Base() {} };\n") - << (VirtualityList() << NotVirtual << Virtual) - << (QList<int>() << -1 << 1); - - QTest::newRow("virtual-dtor-dtor") - << _("struct Base { virtual ~Base() {} };\n" - "struct Derived : Base { ~Derived() {} };\n") - << (VirtualityList() << Virtual << Virtual) - << (QList<int>() << 0 << 0); - - QTest::newRow("dtor-virtual-dtor-dtor") - << _("struct Base { ~Base() {} };\n" - "struct Derived : Base { virtual ~Derived() {} };\n" - "struct Derived2 : Derived { ~Derived2() {} };\n") - << (VirtualityList() << NotVirtual << Virtual << Virtual) - << (QList<int>() << -1 << 1 << 1); -} - -} // namespace Internal -} // namespace CppEditor - -#endif diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h index 933fa3be4e..731f1efc5a 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h @@ -70,23 +70,6 @@ private: Parameters m_params; }; -class FunctionHelper -{ -public: - static bool isVirtualFunction(const CPlusPlus::Function *function, - const CPlusPlus::LookupContext &context, - const CPlusPlus::Function **firstVirtual = 0); - - static bool isPureVirtualFunction(const CPlusPlus::Function *function, - const CPlusPlus::LookupContext &context, - const CPlusPlus::Function **firstVirtual = 0); - - static QList<CPlusPlus::Symbol *> overrides(CPlusPlus::Function *function, - CPlusPlus::Class *functionsClass, - CPlusPlus::Class *staticClass, - const CPlusPlus::Snapshot &snapshot); -}; - } // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 9700ea853a..c75af62eb9 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -51,7 +51,8 @@ HEADERS += completionsettingspage.h \ cpplocatordata.h \ cppmodelmanagersupportinternal.h \ cppcodemodelsettings.h \ - cppcodemodelsettingspage.h + cppcodemodelsettingspage.h \ + functionutils.h SOURCES += completionsettingspage.cpp \ cppclassesfilter.cpp \ @@ -100,7 +101,8 @@ SOURCES += completionsettingspage.cpp \ cpplocatordata.cpp \ cppmodelmanagersupportinternal.cpp \ cppcodemodelsettings.cpp \ - cppcodemodelsettingspage.cpp + cppcodemodelsettingspage.cpp \ + functionutils.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index e955c80e3a..14dc119d61 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -101,6 +101,8 @@ QtcPlugin { "cpptoolssettings.h", "doxygengenerator.cpp", "doxygengenerator.h", + "functionutils.cpp", + "functionutils.h", "insertionpointlocator.cpp", "insertionpointlocator.h", "searchsymbols.cpp", diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 94b30bf9e5..bb5cd9b3c6 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -204,6 +204,9 @@ private slots: void test_cpppreprocessor_includes(); + void test_functionutils_virtualFunctions(); + void test_functionutils_virtualFunctions_data(); + void test_modelmanager_paths_are_clean(); void test_modelmanager_framework_headers(); void test_modelmanager_refresh_also_includes_of_project_files(); diff --git a/src/plugins/cpptools/functionutils.cpp b/src/plugins/cpptools/functionutils.cpp new file mode 100644 index 0000000000..fd7ae1d89c --- /dev/null +++ b/src/plugins/cpptools/functionutils.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "functionutils.h" + +#include "typehierarchybuilder.h" + +#include <cplusplus/CppDocument.h> +#include <cplusplus/LookupContext.h> +#include <cplusplus/Symbols.h> +#include <utils/qtcassert.h> + +#include <QList> + +using namespace CPlusPlus; +using namespace CppTools; + +enum VirtualType { Virtual, PureVirtual }; + +static bool isVirtualFunction_helper(const Function *function, + const LookupContext &context, + VirtualType virtualType, + const Function **firstVirtual) +{ + enum { Unknown, False, True } res = Unknown; + + if (firstVirtual) + *firstVirtual = 0; + + if (!function) + return false; + + if (virtualType == PureVirtual) + res = function->isPureVirtual() ? True : False; + + if (function->isVirtual()) { + if (firstVirtual) + *firstVirtual = function; + if (res == Unknown) + res = True; + } + + if (!firstVirtual && res != Unknown) + return res == True; + + QList<LookupItem> results = context.lookup(function->name(), function->enclosingScope()); + if (!results.isEmpty()) { + const bool isDestructor = function->name()->isDestructorNameId(); + foreach (const LookupItem &item, results) { + if (Symbol *symbol = item.declaration()) { + if (Function *functionType = symbol->type()->asFunctionType()) { + if (functionType->name()->isDestructorNameId() != isDestructor) + continue; + if (functionType == function) // already tested + continue; + if (functionType->isFinal()) + return res == True; + if (functionType->isVirtual()) { + if (!firstVirtual) + return true; + if (res == Unknown) + res = True; + *firstVirtual = functionType; + } + } + } + } + } + + return res == True; +} + +bool FunctionUtils::isVirtualFunction(const Function *function, + const LookupContext &context, + const Function **firstVirtual) +{ + return isVirtualFunction_helper(function, context, Virtual, firstVirtual); +} + +bool FunctionUtils::isPureVirtualFunction(const Function *function, + const LookupContext &context, + const Function **firstVirtual) +{ + return isVirtualFunction_helper(function, context, PureVirtual, firstVirtual); +} + +QList<Symbol *> FunctionUtils::overrides(Function *function, Class *functionsClass, + Class *staticClass, const Snapshot &snapshot) +{ + QList<Symbol *> result; + QTC_ASSERT(function && functionsClass && staticClass, return result); + + FullySpecifiedType referenceType = function->type(); + const Name *referenceName = function->name(); + QTC_ASSERT(referenceName && referenceType.isValid(), return result); + + // Find overrides + TypeHierarchyBuilder builder(staticClass, snapshot); + const TypeHierarchy &staticClassHierarchy = builder.buildDerivedTypeHierarchy(); + + QList<TypeHierarchy> l; + l.append(TypeHierarchy(functionsClass)); + l.append(staticClassHierarchy); + + while (!l.isEmpty()) { + // Add derived + const TypeHierarchy hierarchy = l.takeFirst(); + QTC_ASSERT(hierarchy.symbol(), continue); + Class *c = hierarchy.symbol()->asClass(); + QTC_ASSERT(c, continue); + + foreach (const TypeHierarchy &t, hierarchy.hierarchy()) { + if (!l.contains(t)) + l << t; + } + + // Check member functions + for (int i = 0, total = c->memberCount(); i < total; ++i) { + Symbol *candidate = c->memberAt(i); + const Name *candidateName = candidate->name(); + const FullySpecifiedType candidateType = candidate->type(); + if (!candidateName || !candidateType.isValid()) + continue; + if (candidateName->isEqualTo(referenceName) && candidateType.isEqualTo(referenceType)) + result << candidate; + } + } + + return result; +} + +#ifdef WITH_TESTS +#include "cpptoolsplugin.h" + +#include <QTest> + +namespace CppTools { +namespace Internal { + +enum Virtuality +{ + NotVirtual, + Virtual, + PureVirtual +}; +typedef QList<Virtuality> VirtualityList; +} // Internal namespace +} // CppTools namespace + +Q_DECLARE_METATYPE(CppTools::Internal::Virtuality) +Q_DECLARE_METATYPE(CppTools::Internal::VirtualityList) +Q_DECLARE_METATYPE(QList<int>) + +namespace CppTools { +namespace Internal { + +void CppToolsPlugin::test_functionutils_virtualFunctions() +{ + // Create and parse document + QFETCH(QByteArray, source); + QFETCH(VirtualityList, virtualityList); + QFETCH(QList<int>, firstVirtualList); + Document::Ptr document = Document::create(QLatin1String("virtuals")); + document->setUtf8Source(source); + document->check(); // calls parse(); + QCOMPARE(document->diagnosticMessages().size(), 0); + QVERIFY(document->translationUnit()->ast()); + QList<const Function *> allFunctions; + const Function *firstVirtual = 0; + + // Iterate through Function symbols + Snapshot snapshot; + snapshot.insert(document); + const LookupContext context(document, snapshot); + Control *control = document->translationUnit()->control(); + Symbol **end = control->lastSymbol(); + for (Symbol **it = control->firstSymbol(); it != end; ++it) { + if (const Function *function = (*it)->asFunction()) { + allFunctions.append(function); + QTC_ASSERT(!virtualityList.isEmpty(), return); + Virtuality virtuality = virtualityList.takeFirst(); + QTC_ASSERT(!firstVirtualList.isEmpty(), return); + int firstVirtualIndex = firstVirtualList.takeFirst(); + bool isVirtual = FunctionUtils::isVirtualFunction(function, context, &firstVirtual); + bool isPureVirtual = FunctionUtils::isPureVirtualFunction(function, context, + &firstVirtual); + + // Test for regressions introduced by firstVirtual + QCOMPARE(FunctionUtils::isVirtualFunction(function, context), isVirtual); + QCOMPARE(FunctionUtils::isPureVirtualFunction(function, context), isPureVirtual); + if (isVirtual) { + if (isPureVirtual) + QCOMPARE(virtuality, PureVirtual); + else + QCOMPARE(virtuality, Virtual); + } else { + QEXPECT_FAIL("virtual-dtor-dtor", "Not implemented", Abort); + if (allFunctions.size() == 3) + QEXPECT_FAIL("dtor-virtual-dtor-dtor", "Not implemented", Abort); + QCOMPARE(virtuality, NotVirtual); + } + if (firstVirtualIndex == -1) + QVERIFY(!firstVirtual); + else + QCOMPARE(firstVirtual, allFunctions.at(firstVirtualIndex)); + } + } + QVERIFY(virtualityList.isEmpty()); + QVERIFY(firstVirtualList.isEmpty()); +} + +void CppToolsPlugin::test_functionutils_virtualFunctions_data() +{ + typedef QByteArray _; + QTest::addColumn<QByteArray>("source"); + QTest::addColumn<VirtualityList>("virtualityList"); + QTest::addColumn<QList<int> >("firstVirtualList"); + + QTest::newRow("none") + << _("struct None { void foo() {} };\n") + << (VirtualityList() << NotVirtual) + << (QList<int>() << -1); + + QTest::newRow("single-virtual") + << _("struct V { virtual void foo() {} };\n") + << (VirtualityList() << Virtual) + << (QList<int>() << 0); + + QTest::newRow("single-pure-virtual") + << _("struct PV { virtual void foo() = 0; };\n") + << (VirtualityList() << PureVirtual) + << (QList<int>() << 0); + + QTest::newRow("virtual-derived-with-specifier") + << _("struct Base { virtual void foo() {} };\n" + "struct Derived : Base { virtual void foo() {} };\n") + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); + + QTest::newRow("virtual-derived-implicit") + << _("struct Base { virtual void foo() {} };\n" + "struct Derived : Base { void foo() {} };\n") + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); + + QTest::newRow("not-virtual-then-virtual") + << _("struct Base { void foo() {} };\n" + "struct Derived : Base { virtual void foo() {} };\n") + << (VirtualityList() << NotVirtual << Virtual) + << (QList<int>() << -1 << 1); + + QTest::newRow("virtual-final-not-virtual") + << _("struct Base { virtual void foo() {} };\n" + "struct Derived : Base { void foo() final {} };\n" + "struct Derived2 : Derived { void foo() {} };") + << (VirtualityList() << Virtual << Virtual << NotVirtual) + << (QList<int>() << 0 << 0 << -1); + + QTest::newRow("virtual-then-pure") + << _("struct Base { virtual void foo() {} };\n" + "struct Derived : Base { virtual void foo() = 0; };\n" + "struct Derived2 : Derived { void foo() {} };") + << (VirtualityList() << Virtual << PureVirtual << Virtual) + << (QList<int>() << 0 << 0 << 0); + + QTest::newRow("virtual-virtual-final-not-virtual") + << _("struct Base { virtual void foo() {} };\n" + "struct Derived : Base { virtual void foo() final {} };\n" + "struct Derived2 : Derived { void foo() {} };") + << (VirtualityList() << Virtual << Virtual << NotVirtual) + << (QList<int>() << 0 << 0 << -1); + + QTest::newRow("ctor-virtual-dtor") + << _("struct Base { Base() {} virtual ~Base() {} };\n") + << (VirtualityList() << NotVirtual << Virtual) + << (QList<int>() << -1 << 1); + + QTest::newRow("virtual-dtor-dtor") + << _("struct Base { virtual ~Base() {} };\n" + "struct Derived : Base { ~Derived() {} };\n") + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); + + QTest::newRow("dtor-virtual-dtor-dtor") + << _("struct Base { ~Base() {} };\n" + "struct Derived : Base { virtual ~Derived() {} };\n" + "struct Derived2 : Derived { ~Derived2() {} };\n") + << (VirtualityList() << NotVirtual << Virtual << Virtual) + << (QList<int>() << -1 << 1 << 1); +} + +} // namespace Internal +} // namespace CppTools + +#endif diff --git a/src/plugins/cpptools/functionutils.h b/src/plugins/cpptools/functionutils.h new file mode 100644 index 0000000000..d44231cc19 --- /dev/null +++ b/src/plugins/cpptools/functionutils.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef FUNCTIONUTILS_H +#define FUNCTIONUTILS_H + +#include "cpptools_global.h" + +QT_BEGIN_NAMESPACE +template <class> class QList; +QT_END_NAMESPACE + +namespace CPlusPlus { +class Class; +class Function; +class LookupContext; +class Snapshot; +class Symbol; +} // namespace CPlusPlus + +namespace CppTools { + +class CPPTOOLS_EXPORT FunctionUtils +{ +public: + static bool isVirtualFunction(const CPlusPlus::Function *function, + const CPlusPlus::LookupContext &context, + const CPlusPlus::Function **firstVirtual = 0); + + static bool isPureVirtualFunction(const CPlusPlus::Function *function, + const CPlusPlus::LookupContext &context, + const CPlusPlus::Function **firstVirtual = 0); + + static QList<CPlusPlus::Symbol *> overrides(CPlusPlus::Function *function, + CPlusPlus::Class *functionsClass, + CPlusPlus::Class *staticClass, + const CPlusPlus::Snapshot &snapshot); +}; + +} // namespace CppTools + +#endif // FUNCTIONUTILS_H |