diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h index 5adbeaa43e2..5653adffb57 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -30,6 +30,8 @@ #ifndef CPLUSPLUS_CHECKSYMBOLS_H #define CPLUSPLUS_CHECKSYMBOLS_H +#include "cpptools_global.h" + #include "cppsemanticinfo.h" #include @@ -45,7 +47,7 @@ namespace CPlusPlus { -class CheckSymbols: +class CPPTOOLS_EXPORT CheckSymbols: protected ASTVisitor, public QRunnable, public QFutureInterface diff --git a/tests/auto/cplusplus/checksymbols/checksymbols.pro b/tests/auto/cplusplus/checksymbols/checksymbols.pro new file mode 100644 index 00000000000..c7ea673be88 --- /dev/null +++ b/tests/auto/cplusplus/checksymbols/checksymbols.pro @@ -0,0 +1,4 @@ +include(../../qttest.pri) +include(../shared/shared.pri) +include(../../../../src/plugins/cpptools/cpptools.pri) +SOURCES += tst_checksymbols.cpp diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp new file mode 100644 index 00000000000..34d4569a315 --- /dev/null +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** 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 +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! + Tests CheckSymbols, the "data provider" of the semantic highlighter. + */ + +using namespace CPlusPlus; +using namespace CppTools; + +typedef CheckSymbols::Use Use; +typedef CheckSymbols::UseKind UseKind; + +static QString useKindToString(UseKind useKind) +{ + switch (useKind) { + case SemanticInfo::Unknown: + return QLatin1String("SemanticInfo::Unknown"); + case SemanticInfo::TypeUse: + return QLatin1String("SemanticInfo::TypeUse"); + case SemanticInfo::LocalUse: + return QLatin1String("SemanticInfo::LocalUse"); + case SemanticInfo::FieldUse: + return QLatin1String("SemanticInfo::FieldUse"); + case SemanticInfo::EnumerationUse: + return QLatin1String("SemanticInfo::EnumerationUse"); + case SemanticInfo::VirtualMethodUse: + return QLatin1String("SemanticInfo::VirtualMethodUse"); + case SemanticInfo::LabelUse: + return QLatin1String("SemanticInfo::LabelUse"); + case SemanticInfo::MacroUse: + return QLatin1String("SemanticInfo::MacroUse"); + case SemanticInfo::FunctionUse: + return QLatin1String("SemanticInfo::FunctionUse"); + case SemanticInfo::PseudoKeywordUse: + return QLatin1String("SemanticInfo::PseudoKeywordUse"); + default: + return QLatin1String("Unknown Kind"); + } +} + +// The following two functions are "enhancements" for QCOMPARE(). +namespace QTest { + +bool operator==(const Use& lhs, const Use& rhs) +{ + return + lhs.line == rhs.line && + lhs.column == rhs.column && + lhs.length == rhs.length && + lhs.kind == rhs.kind; +} + +template<> +char *toString(const Use &use) +{ + QByteArray ba = "Use("; + ba += QByteArray::number(use.line); + ba += ", " + QByteArray::number(use.column); + ba += ", " + QByteArray::number(use.length); + ba += ", " + useKindToString(static_cast(use.kind)).toLatin1(); + ba += ")"; + return qstrdup(ba.data()); +} + +} // namespace QTest + +namespace { + +class TestData +{ +public: + Snapshot snapshot; + Document::Ptr document; + + TestData(const QByteArray &source, + Document::ParseMode parseMode = Document::ParseTranlationUnit) + { + // Write source to temprorary file + const QString filePath = QDir::tempPath() + QLatin1String("/file.h"); + document = Document::create(filePath); + Utils::FileSaver documentSaver(document->fileName()); + documentSaver.write(source); + documentSaver.finalize(); + + // Preprocess source + Environment env; + Preprocessor preprocess(0, &env); + const QByteArray preprocessedSource = preprocess.run(filePath, QLatin1String(source)); + document->setUtf8Source(preprocessedSource); + QVERIFY(document->parse(parseMode)); + document->check(); + snapshot.insert(document); + } + + static void check(QByteArray source, QList expectedUses, + QList macroUses = QList()) + { + TestData env(source); + + // Collect symbols + LookupContext context(env.document, env.snapshot); + CheckSymbols::Future future = CheckSymbols::go(env.document, context, macroUses); + future.waitForFinished(); + + const int resultCount = future.resultCount(); + QList actualUses; + for (int i = 0; i < resultCount; ++i) { + const Use use = future.resultAt(i); + // When adding tests, you may want to uncomment the + // following line in order to print out all found uses. +// qDebug() << QTest::toString(use); + actualUses.append(use); + } + + // Checks + QVERIFY(resultCount > 0); + QCOMPARE(resultCount, expectedUses.count()); + + for (int i = 0; i < resultCount; ++i) { + const Use actualUse = actualUses.at(i); + const Use expectedUse = expectedUses.at(i); + QVERIFY(actualUse.isValid()); + QVERIFY(expectedUse.isValid()); + QCOMPARE(actualUse, expectedUse); + } + } +}; + +} // anonymous namespace + +class tst_CheckSymbols: public QObject +{ + Q_OBJECT + +private slots: + void test_checksymbols_TypeUse(); + void test_checksymbols_LocalUse(); + void test_checksymbols_FieldUse(); + void test_checksymbols_EnumerationUse(); + void test_checksymbols_VirtualMethodUse(); + void test_checksymbols_LabelUse(); + void test_checksymbols_MacroUse(); + void test_checksymbols_FunctionUse(); + void test_checksymbols_PseudoKeywordUse(); +}; + +void tst_CheckSymbols::test_checksymbols_TypeUse() +{ + const QByteArray source = + "namespace N {}\n" + "using namespace N;\n"; + const QList expectedUses = QList() + << Use(1, 11, 1, SemanticInfo::TypeUse) + << Use(2, 17, 1, SemanticInfo::TypeUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_LocalUse() +{ + const QByteArray source = + "int f()\n" + "{\n" + " int i;\n" + "}\n"; + const QList expectedUses = QList() + << Use(1, 5, 1, SemanticInfo::FunctionUse) + << Use(3, 8, 1, SemanticInfo::LocalUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_FieldUse() +{ + const QByteArray source = + "struct F {\n" + " int i;\n" + " F() { i = 0; }\n" + "};\n" + "int f()\n" + "{\n" + " F s;\n" + " s.i = 2;\n" + "}\n"; + const QList expectedUses = QList() + << Use(1, 8, 1, SemanticInfo::TypeUse) + << Use(2, 9, 1, SemanticInfo::FieldUse) + << Use(3, 5, 1, SemanticInfo::TypeUse) + << Use(3, 11, 1, SemanticInfo::FieldUse) + << Use(5, 5, 1, SemanticInfo::FunctionUse) + << Use(7, 5, 1, SemanticInfo::TypeUse) + << Use(7, 7, 1, SemanticInfo::LocalUse) + << Use(8, 7, 1, SemanticInfo::FieldUse) + << Use(8, 5, 1, SemanticInfo::LocalUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_EnumerationUse() +{ + const QByteArray source = + "enum E { Red, Green, Blue };\n" + "E e = Red\n"; + const QList expectedUses = QList() + << Use(1, 22, 4, SemanticInfo::EnumerationUse) + << Use(1, 15, 5, SemanticInfo::EnumerationUse) + << Use(1, 6, 1, SemanticInfo::TypeUse) + << Use(1, 10, 3, SemanticInfo::EnumerationUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_VirtualMethodUse() +{ + const QByteArray source = + "class B {\n" + " virtual isThere();\n" + "};\n" + "class D: public B {\n" + " isThere();\n" + "};\n"; + const QList expectedUses = QList() + << Use(1, 7, 1, SemanticInfo::TypeUse) + << Use(2, 13, 7, SemanticInfo::VirtualMethodUse) + << Use(4, 17, 1, SemanticInfo::TypeUse) + << Use(4, 7, 1, SemanticInfo::TypeUse) + << Use(5, 5, 7, SemanticInfo::VirtualMethodUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_LabelUse() +{ + const QByteArray source = + "int f()\n" + "{\n" + " goto g;\n" + " g: return 1;\n" + "}\n"; + const QList expectedUses = QList() + << Use(1, 5, 1, SemanticInfo::FunctionUse) + << Use(3, 9, 1, SemanticInfo::LabelUse) + << Use(4, 4, 1, SemanticInfo::LabelUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_MacroUse() +{ + const QByteArray source = + "#define FOO 1+1\n" + "int f() { FOO }\n"; + const QList macroUses = QList() + << Use(1, 9, 3, SemanticInfo::MacroUse) + << Use(2, 11, 3, SemanticInfo::MacroUse); + const QList expectedUses = QList() + << Use(1, 9, 3, SemanticInfo::MacroUse) + << Use(2, 11, 3, SemanticInfo::MacroUse) + << Use(2, 5, 1, SemanticInfo::FunctionUse); + + TestData::check(source, expectedUses, macroUses); +} + +void tst_CheckSymbols::test_checksymbols_FunctionUse() +{ + const QByteArray source = + "int f();\n" + "int g() { f(); }\n"; + const QList expectedUses = QList() + << Use(1, 5, 1, SemanticInfo::FunctionUse) + << Use(2, 5, 1, SemanticInfo::FunctionUse) + << Use(2, 11, 1, SemanticInfo::FunctionUse); + + TestData::check(source, expectedUses); +} + +void tst_CheckSymbols::test_checksymbols_PseudoKeywordUse() +{ + const QByteArray source = + "class D : public B {" + " virtual void f() override {}\n" + " virtual void f() final {}\n" + "};\n"; + const QList expectedUses = QList() + << Use(1, 7, 1, SemanticInfo::TypeUse) + << Use(1, 37, 1, SemanticInfo::VirtualMethodUse) + << Use(1, 41, 8, SemanticInfo::PseudoKeywordUse) + << Use(2, 17, 1, SemanticInfo::VirtualMethodUse) + << Use(2, 21, 5, SemanticInfo::PseudoKeywordUse); + + TestData::check(source, expectedUses); +} + +QTEST_APPLESS_MAIN(tst_CheckSymbols) +#include "tst_checksymbols.moc" diff --git a/tests/auto/cplusplus/cplusplus.pro b/tests/auto/cplusplus/cplusplus.pro index 6a7091a552d..f5d49f3b2d7 100644 --- a/tests/auto/cplusplus/cplusplus.pro +++ b/tests/auto/cplusplus/cplusplus.pro @@ -11,4 +11,5 @@ SUBDIRS = \ typeprettyprinter \ simplifytypes \ misc \ - cxx11 + cxx11 \ + checksymbols