Skip to content

Commit

Permalink
feat: Add TypedSymbol
Browse files Browse the repository at this point in the history
This symbol has information about the type of whatever it represents.

Care has also been taken to support pointers, const-qualifiers and other type specifiers.
  • Loading branch information
LeonMatthesKDAB committed Jul 26, 2024
1 parent 8c0e224 commit f662fc5
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 2 deletions.
31 changes: 31 additions & 0 deletions docs/API/knut/typedsymbol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# TypedSymbol

Represents a symbol with a type [More...](#detailed-description)

```qml
import Knut
```

## Properties

| | Name |
|-|-|
|string|**[type](#type)**|

## Detailed Description

This symbol has a type associated with it, like a variable or a member of a class.

## Property Documentation

#### <a name="type"></a>string **type**

The type of this symbol.

The type is the part of the symbol that describes what kind of value it holds. For example, the type of a variable.
This symbol will extract the type as-written in the original source, but with whitespace
[simplified](https://doc.qt.io/qt-6/qstring.html#simplified). So if e.g. the source code is `const string &`, it
will be extracted as `const string &`. The type will **not** be resolved to a fully qualified path (like
`std::string` for the previous example).

This property is read-only.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ nav:
- QueryCapture: API/knut/querycapture.md
- QueryMatch: API/knut/querymatch.md
- Symbol: API/knut/symbol.md
- TypedSymbol: API/knut/typedsymbol.md
- CppDocument:
- CppDocument: API/knut/cppdocument.md
- DataExchange: API/knut/dataexchange.md
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ set(PROJECT_SOURCES
textdocument_p.h
texteditor.h
texteditor.cpp
typedsymbol.h
typedsymbol.cpp
qtuidocument.h
qtuidocument.cpp
qttsdocument.h
Expand Down
5 changes: 3 additions & 2 deletions src/core/cppdocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,13 @@ auto queryMemberSymbols(CodeDocument *const document) -> QList<Core::Symbol *>
auto fieldIdentifier = "(field_identifier) @name @selectionRange";
auto members = document->query(QString(R"EOF(
(field_declaration
type: (_) @type
(type_qualifier)? @type @typeAndName
type: (_) @type @typeAndName
declarator: [
%1
(_ %1) @decl_type
(_ (_ %1) @decl_type) @decl_type
]
] @typeAndName
; We need to filter out functions, they are already captured
; by the functionSymbols query
(#not_is? @decl_type function_declarator)) @range)EOF")
Expand Down
4 changes: 4 additions & 0 deletions src/core/symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "functionsymbol.h"
#include "logger.h"
#include "project.h"
#include "typedsymbol.h"
#include "utils/log.h"

#include <kdalgorithms.h>
Expand Down Expand Up @@ -101,6 +102,9 @@ Symbol *Symbol::makeSymbol(QObject *parent, const QueryMatch &match, Kind kind)
if (kind == Class || kind == Struct) {
return new ClassSymbol(parent, match, kind);
}
if (kind == Field || kind == Variable) {
return new TypedSymbol(parent, match, kind);
}
return new Symbol(parent, match, kind);
}

Expand Down
48 changes: 48 additions & 0 deletions src/core/typedsymbol.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "typedsymbol.h"

#include <kdalgorithms.h>

namespace Core {

/*!
* \qmltype TypedSymbol
* \brief Represents a symbol with a type
* \inqmlmodule Knut
* \ingroup CodeDocument
*
* This symbol has a type associated with it, like a variable or a member of a class.
*/

/*!
* \qmlproperty string TypedSymbol::type
* The type of this symbol.
*
* The type is the part of the symbol that describes what kind of value it holds. For example, the type of a variable.
* This symbol will extract the type as-written in the original source, but with whitespace
* [simplified](https://doc.qt.io/qt-6/qstring.html#simplified). So if e.g. the source code is `const string &`, it
* will be extracted as `const string &`. The type will **not** be resolved to a fully qualified path (like
* `std::string` for the previous example).
*
* This property is read-only.
*/

TypedSymbol::TypedSymbol(QObject *parent, const QueryMatch &match, Kind kind)
: Symbol(parent, match, kind)
{
// C++ has a strange way of parsing, where pointer and reference specifiers are parsed as a parent
// of the identifier, and not part of the type. The easiest way to remedy this is to get the whole
// range spanning the type and name and then erase the name.
auto typeAndName = match.getAllJoined("typeAndName");
if (typeAndName.isValid()) {
m_type = typeAndName.textExcept(match.get("name")).simplified();
} else {
m_type = kdalgorithms::transformed(match.getAll("type"), &RangeMark::text).join(" ").simplified();
}
}

QString TypedSymbol::type() const
{
return m_type;
}

}
23 changes: 23 additions & 0 deletions src/core/typedsymbol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "symbol.h"

namespace Core {

class TypedSymbol : public Symbol
{
Q_OBJECT

Q_PROPERTY(QString type READ type CONSTANT)

public:
QString type() const;

private:
friend class Symbol;
TypedSymbol(QObject *parent, const QueryMatch &match, Kind kind);

QString m_type;
};

}
11 changes: 11 additions & 0 deletions test_data/tst_symbol/typedsymbol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <string>

class TestClass {
private:
void *m_ptr;
const std::string &m_lvalue_reference;
std::string&& m_rvalue_reference;
const class T*const m_const_ptr;
};
32 changes: 32 additions & 0 deletions tests/tst_symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "core/knutcore.h"
#include "core/project.h"
#include "core/symbol.h"
#include "core/typedsymbol.h"

#include <QTest>
#include <QThread>
Expand Down Expand Up @@ -172,6 +173,14 @@ private slots:
QCOMPARE(members.at(2)->kind(), Core::Symbol::Method);
QCOMPARE(members.last()->name(), "MyObject::m_enum");
QCOMPARE(members.last()->kind(), Core::Symbol::Field);

auto typedsymbol = qobject_cast<Core::TypedSymbol *>(members.at(8));
QVERIFY(typedsymbol);
QCOMPARE(typedsymbol->type(), "std::string");

typedsymbol = qobject_cast<Core::TypedSymbol *>(members.last());
QVERIFY(typedsymbol);
QCOMPARE(typedsymbol->type(), "MyEnum");
}

void references()
Expand Down Expand Up @@ -225,6 +234,29 @@ private slots:
}),
6);
}

void typedSymbol()
{

Core::KnutCore core;
Core::Project::instance()->setRoot(Test::testDataPath() + "/tst_symbol/");

auto codeDocument = qobject_cast<Core::CodeDocument *>(Core::Project::instance()->open("typedsymbol.h"));
QVERIFY(codeDocument);

auto testTypedSymbol = [&codeDocument](const QString &symbolName, const QString &expectedType) {
auto symbol = codeDocument->findSymbol(symbolName);
QVERIFY(symbol);
auto typedSymbol = qobject_cast<Core::TypedSymbol *>(symbol);
QVERIFY(typedSymbol);
QCOMPARE(typedSymbol->type(), expectedType);
};

testTypedSymbol("TestClass::m_ptr", "void *");
testTypedSymbol("TestClass::m_lvalue_reference", "const std::string &");
testTypedSymbol("TestClass::m_rvalue_reference", "std::string&&");
testTypedSymbol("TestClass::m_const_ptr", "const class T*const");
}
};

QTEST_MAIN(TestSymbol)
Expand Down

0 comments on commit f662fc5

Please sign in to comment.