diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 0824e6839e4..53fdf5f3409 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -65,7 +65,6 @@ HEADERS += \ SOURCES += \ $$PWD/sourcerangefilter.cpp \ $$PWD/symbolindexer.cpp \ - $$PWD/symbolentry.cpp \ $$PWD/projectpartartefact.cpp \ $$PWD/filestatuscache.cpp \ $$PWD/indexdataconsumer.cpp diff --git a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h index 7f044a2b742..b3f86ae539c 100644 --- a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h +++ b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h @@ -243,7 +243,9 @@ public: if (usr) { m_symbolEntries.emplace(std::piecewise_construct, std::forward_as_tuple(globalId), - std::forward_as_tuple(std::move(usr.value()), macroName)); + std::forward_as_tuple(std::move(usr.value()), + macroName, + SymbolKind::Macro)); } } diff --git a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp index 99befdaed1a..cc24629170e 100644 --- a/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp +++ b/src/tools/clangrefactoringbackend/source/indexdataconsumer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -56,6 +57,41 @@ SymbolType symbolType(clang::index::SymbolRoleSet roles) return SymbolType::None; } +using SymbolKindAndTags = std::pair; + +class IndexingDeclVisitor : public clang::ConstDeclVisitor +{ +public: + SymbolKindAndTags VisitTagDecl(const clang::TagDecl *declaration) + { + SymbolKindAndTags result = {SymbolKind::Tag, {}}; + switch (declaration->getTagKind()) { + case clang::TTK_Struct: result.second.push_back(SymbolTag::Struct); break; + case clang::TTK_Interface: result.second.push_back(SymbolTag::MsvcInterface); break; + case clang::TTK_Union: result.second.push_back(SymbolTag::Union); break; + case clang::TTK_Class: result.second.push_back(SymbolTag::Class); break; + case clang::TTK_Enum: result.second.push_back(SymbolTag::Enumeration); break; + } + + return result; + } + + SymbolKindAndTags VisitFunctionDecl(const clang::FunctionDecl*) + { + return {SymbolKind::Function, {}}; + } + + SymbolKindAndTags VisitVarDecl(const clang::VarDecl*) + { + return {SymbolKind::Variable, {}}; + } +}; + +SymbolKindAndTags symbolKindAndTags(const clang::Decl *declaration) +{ + static IndexingDeclVisitor visitor; + return visitor.Visit(declaration); +} } bool IndexDataConsumer::handleDeclOccurence(const clang::Decl *declaration, @@ -78,9 +114,13 @@ bool IndexDataConsumer::handleDeclOccurence(const clang::Decl *declaration, if (found == m_symbolEntries.end()) { Utils::optional usr = generateUSR(namedDeclaration); if (usr) { + auto kindAndTags = symbolKindAndTags(declaration); m_symbolEntries.emplace(std::piecewise_construct, std::forward_as_tuple(globalId), - std::forward_as_tuple(std::move(usr.value()), symbolName(namedDeclaration))); + std::forward_as_tuple(std::move(usr.value()), + symbolName(namedDeclaration), + kindAndTags.first, + kindAndTags.second)); } } diff --git a/src/tools/clangrefactoringbackend/source/symbolentry.cpp b/src/tools/clangrefactoringbackend/source/symbolentry.cpp deleted file mode 100644 index ee606cf9ab8..00000000000 --- a/src/tools/clangrefactoringbackend/source/symbolentry.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "symbolentry.h" - -#include - -namespace ClangBackEnd { - -std::ostream &operator<<(std::ostream &out, const SymbolEntry &entry) -{ - out << "(" - << entry.symbolName << ", " - << entry.usr <<")"; - - return out; -} - -} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolentry.h b/src/tools/clangrefactoringbackend/source/symbolentry.h index 7312f45bd68..64e750ddff8 100644 --- a/src/tools/clangrefactoringbackend/source/symbolentry.h +++ b/src/tools/clangrefactoringbackend/source/symbolentry.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -37,26 +38,53 @@ namespace ClangBackEnd { using SymbolIndex = long long; +enum class SymbolKind : uchar +{ + None = 0, + Tag, + Function, + Variable, + Macro +}; + +enum class SymbolTag : uchar +{ + None = 0, + Class, + Struct, + Enumeration, + Union, + MsvcInterface +}; + +using SymbolTags = Utils::SizedArray; + class SymbolEntry { public: SymbolEntry(Utils::PathString &&usr, - Utils::SmallString &&symbolName) + Utils::SmallString &&symbolName, + SymbolKind symbolKind, + SymbolTags symbolTags={}) : usr(std::move(usr)), - symbolName(std::move(symbolName)) + symbolName(std::move(symbolName)), + symbolKind(symbolKind), + symbolTags(symbolTags) {} Utils::PathString usr; Utils::SmallString symbolName; + SymbolKind symbolKind; + SymbolTags symbolTags; friend bool operator==(const SymbolEntry &first, const SymbolEntry &second) { - return first.usr == second.usr && first.symbolName == second.symbolName; + return first.usr == second.usr + && first.symbolName == second.symbolName + && first.symbolKind == second.symbolKind; } }; using SymbolEntries = std::unordered_map; -std::ostream &operator<<(std::ostream &out, const SymbolEntry &entry); - } // namespace ClangBackEnd diff --git a/tests/unit/unittest/conditionally-disabled-tests.h b/tests/unit/unittest/conditionally-disabled-tests.h index 3cac7591352..0b6f2799750 100644 --- a/tests/unit/unittest/conditionally-disabled-tests.h +++ b/tests/unit/unittest/conditionally-disabled-tests.h @@ -34,6 +34,12 @@ # define DISABLED_ON_WINDOWS(x) x #endif +#ifndef Q_OS_WIN +# define DISABLED_ON_NON_WINDOWS(x) DISABLED_##x +#else +# define DISABLED_ON_NON_WINDOWS(x) x +#endif + #ifdef IS_PRETTY_DECL_SUPPORTED # define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) x #else diff --git a/tests/unit/unittest/data/symbolscollector_symbolkind.cpp b/tests/unit/unittest/data/symbolscollector_symbolkind.cpp new file mode 100644 index 00000000000..e8f9bae5305 --- /dev/null +++ b/tests/unit/unittest/data/symbolscollector_symbolkind.cpp @@ -0,0 +1,13 @@ +class Class {}; +struct Struct {}; +enum Enumeration {}; +enum ScopedEnumeration {}; +union Union {}; + +#ifdef _MSC_VER +__interface MsvcInterface {}; +#endif + +void Function() {} + +int Variable; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index a2cd4c3d41b..063efa7bbd9 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -906,6 +907,61 @@ std::ostream &operator<<(std::ostream &out, const CompilerMacro &compilerMacro) << ")"; } +std::ostream &operator<<(std::ostream &out, const SymbolEntry &entry) +{ + out << "(" + << entry.symbolName << ", " + << entry.usr << ", " + << entry.symbolKind <<")"; + + return out; +} + +const char *symbolKindString(SymbolKind symbolKind) +{ + using ClangBackEnd::SymbolKind; + + switch (symbolKind) { + case SymbolKind::None: return "SymbolKind::None"; + case SymbolKind::Tag: return "SymbolKind::Tag"; + case SymbolKind::Function: return "SymbolKind::Function"; + case SymbolKind::Macro: return "SymbolKind::Macro"; + } + + return ""; +} + +std::ostream &operator<<(std::ostream &out, SymbolKind symbolKind) +{ + return out << symbolKindString(symbolKind); +} + +const char *symbolTagString(SymbolTag symbolTag) +{ + using ClangBackEnd::SymbolTag; + + switch (symbolTag) { + case SymbolTag::Class: return "Class"; + case SymbolTag::Struct: return "Struct"; + case SymbolTag::Enumeration: return "Enumeration"; + case SymbolTag::MsvcInterface: return "MsvcInterface"; + } + + return ""; +} + +std::ostream &operator<<(std::ostream &out, SymbolTag symbolTag) +{ + return out << symbolTagString(symbolTag); +} + +std::ostream &operator<<(std::ostream &out, SymbolTags symbolTags) +{ + std::copy(symbolTags.cbegin(), symbolTags.cend(), std::ostream_iterator(out, ", ")); + + return out; +} + void PrintTo(const FilePath &filePath, ::std::ostream *os) { *os << filePath; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 4f03d76d077..aa46ef32e59 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -156,6 +156,10 @@ class FileStatus; class SourceDependency; class ProjectPartArtefact; class CompilerMacro; +class SymbolEntry; +enum class SymbolKind : uchar; +enum class SymbolTag : uchar; +using SymbolTags = Utils::SizedArray; std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); @@ -228,6 +232,10 @@ std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus); std::ostream &operator<<(std::ostream &out, const SourceDependency &sourceDependency); std::ostream &operator<<(std::ostream &out, const ProjectPartArtefact &projectPartArtefact); std::ostream &operator<<(std::ostream &out, const CompilerMacro &compilerMacro); +std::ostream &operator<<(std::ostream &out, const SymbolEntry &symbolEntry); +std::ostream &operator<<(std::ostream &out, SymbolKind symbolKind); +std::ostream &operator<<(std::ostream &out, SymbolTag symbolTag); +std::ostream &operator<<(std::ostream &out, SymbolTags symbolTags); void PrintTo(const FilePath &filePath, ::std::ostream *os); void PrintTo(const FilePathView &filePathView, ::std::ostream *os); diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index b2a471bf100..f87097bd3e6 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -57,6 +57,7 @@ using ClangBackEnd::SymbolEntry; using ClangBackEnd::SourceDependencies; using ClangBackEnd::SourceLocationEntries; using ClangBackEnd::SourceLocationEntry; +using ClangBackEnd::SymbolKind; using ClangBackEnd::SymbolType; using ClangBackEnd::UsedMacros; using OptionalProjectPartArtefact = Utils::optional; @@ -142,7 +143,7 @@ protected: FileContainers unsaved{{{TESTDATA_DIR, "query_simplefunction.h"}, "void f();", {}}}; - SymbolEntries symbolEntries{{1, {"function", "function"}}}; + SymbolEntries symbolEntries{{1, {"function", "function", SymbolKind::Function}}}; SourceLocationEntries sourceLocations{{1, {1, 1}, {42, 23}, SymbolType::Declaration}}; FilePathIds sourceFileIds{{1, 1}, {42, 23}}; UsedMacros usedMacros{{"Foo", {1, 1}}}; diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index c010940ac34..67aab88d0df 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -53,6 +53,8 @@ using ClangBackEnd::V2::FileContainers; using ClangBackEnd::SourceDependency; using ClangBackEnd::SourceLocationEntry; using ClangBackEnd::SymbolEntry; +using ClangBackEnd::SymbolKind; +using ClangBackEnd::SymbolTag; using ClangBackEnd::SymbolType; using ClangBackEnd::SymbolIndex; using ClangBackEnd::UsedMacro; @@ -97,6 +99,28 @@ MATCHER_P(HasSymbolName, symbolName, return entry.symbolName == symbolName; } +MATCHER_P(HasSymbolKind, symbolKind, + std::string(negation ? "hasn't" : "has") + + " and symbol kind: " + + PrintToString(symbolKind) + ) +{ + const SymbolEntry &entry = arg.second; + + return entry.symbolKind == symbolKind; +} + +MATCHER_P(HasSymbolTag, symbolTag, + std::string(negation ? "hasn't" : "has") + + " and symbol tag: " + + PrintToString(symbolTag) + ) +{ + const SymbolEntry &entry = arg.second; + + return entry.symbolTags.contains(symbolTag); +} + class SymbolsCollector : public testing::Test { protected: @@ -527,7 +551,7 @@ TEST_F(SymbolsCollector, CollectMacroDefinitionSymbols) collector.collectSymbols(); ASSERT_THAT(collector.symbols(), - Contains(HasSymbolName("IF_NOT_DEFINE"))); + Contains(AllOf(HasSymbolName("IF_NOT_DEFINE"), HasSymbolKind(SymbolKind::Macro)))); } TEST_F(SymbolsCollector, CollectMacroBuiltInSymbols) @@ -538,7 +562,7 @@ TEST_F(SymbolsCollector, CollectMacroBuiltInSymbols) collector.collectSymbols(); ASSERT_THAT(collector.symbols(), - Contains(HasSymbolName("__clang__"))); + Contains(AllOf(HasSymbolName("__clang__"), HasSymbolKind(SymbolKind::Macro)))); } TEST_F(SymbolsCollector, CollectMacroCompilerArgumentSymbols) @@ -549,7 +573,7 @@ TEST_F(SymbolsCollector, CollectMacroCompilerArgumentSymbols) collector.collectSymbols(); ASSERT_THAT(collector.symbols(), - Contains(HasSymbolName("COMPILER_ARGUMENT"))); + Contains(AllOf(HasSymbolName("COMPILER_ARGUMENT"), HasSymbolKind(SymbolKind::Macro)))); } TEST_F(SymbolsCollector, CollectFileStatuses) @@ -583,4 +607,106 @@ TEST_F(SymbolsCollector, CollectSourceDependencies) SourceDependency(header1FileId, header2FileId))); } +TEST_F(SymbolsCollector, IsClassSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("Class"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::Class)))); +} + +TEST_F(SymbolsCollector, IsStructSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("Struct"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::Struct)))); +} + +TEST_F(SymbolsCollector, IsEnumerationSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + AllOf( + Contains( + AllOf( + HasSymbolName("Enumeration"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::Enumeration))), + Contains( + AllOf( + HasSymbolName("ScopedEnumeration"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::Enumeration))))); +} + +TEST_F(SymbolsCollector, IsUnionSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("Union"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::Union)))); +} + +TEST_F(SymbolsCollector, DISABLED_ON_NON_WINDOWS(IsMsvcInterfaceSymbol)) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("MsvcInterface"), + HasSymbolKind(SymbolKind::Tag), + HasSymbolTag(SymbolTag::MsvcInterface)))); +} + +TEST_F(SymbolsCollector, IsFunctionSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("Function"), + HasSymbolKind(SymbolKind::Function)))); +} + +TEST_F(SymbolsCollector, IsVariableSymbol) +{ + collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_symbolkind.cpp")}, {"cc"}); + + collector.collectSymbols(); + + ASSERT_THAT(collector.symbols(), + Contains( + AllOf( + HasSymbolName("Variable"), + HasSymbolKind(SymbolKind::Variable)))); +} + } diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index f69d49c9ae9..3eb5a13a78c 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -48,6 +48,7 @@ using ClangBackEnd::SourceLocationEntry; using ClangBackEnd::StorageSqliteStatementFactory; using ClangBackEnd::SymbolIndex; using ClangBackEnd::SymbolType; +using ClangBackEnd::SymbolKind; using Sqlite::Database; using Sqlite::Table; @@ -89,8 +90,8 @@ protected: MockSqliteReadStatement &getLowestLastModifiedTimeOfDependencies = statementFactory.getLowestLastModifiedTimeOfDependencies; MockSqliteReadStatement &getPrecompiledHeader = statementFactory.getPrecompiledHeader; - SymbolEntries symbolEntries{{1, {"functionUSR", "function"}}, - {2, {"function2USR", "function2"}}}; + SymbolEntries symbolEntries{{1, {"functionUSR", "function", SymbolKind::Function}}, + {2, {"function2USR", "function2", SymbolKind::Function}}}; SourceLocationEntries sourceLocations{{1, {1, 3}, {42, 23}, SymbolType::Declaration}, {2, {1, 4}, {7, 11}, SymbolType::Declaration}}; ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFOO\"]", "{\"FOO\":\"1\"}", "[\"/includes\"]", 74};