forked from qt-creator/qt-creator
CPlusPlus: Add more usage tags
To be used in subsequent patches. Change-Id: Id7140aa39bb2adba343cc12b0273c90f3c12abeb Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -226,6 +226,7 @@ public:
|
||||
continue;
|
||||
}
|
||||
if (const auto declarator = (*it)->asDeclarator()) {
|
||||
Usage::Tags tags;
|
||||
if (containsToken(declarator->core_declarator)) {
|
||||
if (declarator->initializer && declarator->equal_token
|
||||
&& (!declarator->postfix_declarator_list
|
||||
@@ -233,17 +234,47 @@ public:
|
||||
|| !declarator->postfix_declarator_list->value->asFunctionDeclarator())) {
|
||||
return {Usage::Tag::Declaration, Usage::Tag::Write};
|
||||
}
|
||||
return Usage::Tag::Declaration;
|
||||
}
|
||||
if (const auto decl = (*(it + 1))->asSimpleDeclaration()) {
|
||||
if (decl->symbols && decl->symbols->value) {
|
||||
return checkPotentialWrite(
|
||||
getTagsFromLhsAndRhs(decl->symbols->value->type(),
|
||||
declarator->initializer, it + 1),
|
||||
it + 1);
|
||||
tags = Usage::Tag::Declaration;
|
||||
if (declarator->postfix_declarator_list
|
||||
&& declarator->postfix_declarator_list->value) {
|
||||
if (const FunctionDeclaratorAST * const funcDecl = declarator
|
||||
->postfix_declarator_list->value->asFunctionDeclarator()) {
|
||||
for (SpecifierListAST *iter = funcDecl->cv_qualifier_list; iter;
|
||||
iter = iter->next) {
|
||||
if (!iter->value)
|
||||
continue;
|
||||
if (const auto simpleSpec = iter->value->asSimpleSpecifier();
|
||||
simpleSpec && simpleSpec->specifier_token) {
|
||||
const Control * const ctl = m_findUsages->control();
|
||||
const Identifier * const id = m_findUsages->translationUnit()
|
||||
->tokenAt(simpleSpec->specifier_token).identifier;
|
||||
if (id && (id->equalTo(ctl->cpp11Override())
|
||||
|| id->equalTo(ctl->cpp11Final()))) {
|
||||
tags |= Usage::Tag::Override;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
if (const auto decl = (*(it + 1))->asSimpleDeclaration()) {
|
||||
if (tags.toInt() && decl->qt_invokable_token)
|
||||
return tags |= Usage::Tag::MocInvokable;
|
||||
if (decl->symbols && decl->symbols->value) {
|
||||
if (!tags) {
|
||||
return checkPotentialWrite(
|
||||
getTagsFromLhsAndRhs(decl->symbols->value->type(),
|
||||
declarator->initializer, it + 1),
|
||||
it + 1);
|
||||
}
|
||||
if (const auto func = decl->symbols->value->type()->asFunctionType()) {
|
||||
if (func->isSignal() || func->isSlot() || func->isInvokable())
|
||||
return tags |= Usage::Tag::MocInvokable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
if (const auto retStmt = (*it)->asReturnStatement()) {
|
||||
for (auto funcIt = it + 1; funcIt != m_astPath.rend(); ++funcIt) {
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
Read = 1 << 1,
|
||||
Write = 1 << 2,
|
||||
WritableRef = 1 << 3,
|
||||
Override = 1 << 4,
|
||||
MocInvokable = 1 << 5,
|
||||
};
|
||||
using Tags = QFlags<Tag>;
|
||||
|
||||
|
||||
@@ -397,7 +397,17 @@ static Usage::Tags getUsageType(const ClangdAstPath &path)
|
||||
return Usage::Tag::WritableRef;
|
||||
return Usage::Tag::Read;
|
||||
}
|
||||
return Usage::Tag::Declaration;
|
||||
Usage::Tags tags = Usage::Tag::Declaration;
|
||||
const auto children = pathIt->children().value_or(QList<ClangdAstNode>());
|
||||
for (const ClangdAstNode &child : children) {
|
||||
if (child.role() == "attribute") {
|
||||
if (child.kind() == "Override" || child.kind() == "Final")
|
||||
tags |= Usage::Tag::Override;
|
||||
else if (child.kind() == "Annotate" && child.arcanaContains("qt_"))
|
||||
tags |= Usage::Tag::MocInvokable;
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
if (pathIt->kind() == "MemberInitializer")
|
||||
return pathIt == path.rbegin() ? Usage::Tag::Write : Usage::Tag::Read;
|
||||
|
||||
@@ -219,7 +219,7 @@ void ClangdTestFindReferences::test_data()
|
||||
makeItem(5, 21, Initialization), makeItem(45, 16, Usage::Tag::Read)};
|
||||
|
||||
ItemList pureVirtualRefs{makeItem(17, 17, Usage::Tag::Declaration),
|
||||
makeItem(21, 9, Usage::Tag::Declaration)};
|
||||
makeItem(21, 9, {Usage::Tag::Declaration, Usage::Tag::Override})};
|
||||
QTest::newRow("pure virtual declaration") << "defs.h" << 420 << pureVirtualRefs;
|
||||
|
||||
QTest::newRow("pointer variable") << "main.cpp" << 52 << ItemList{
|
||||
|
||||
@@ -116,6 +116,8 @@ private Q_SLOTS:
|
||||
|
||||
void variadicMacros();
|
||||
void writableRefs();
|
||||
void mocInvokables();
|
||||
void virtualOverride();
|
||||
};
|
||||
|
||||
void tst_FindUsages::dump(const QList<Usage> &usages) const
|
||||
@@ -724,7 +726,16 @@ void tst_FindUsages::qproperty_1()
|
||||
QCOMPARE(findUsages.usages().size(), 2);
|
||||
QCOMPARE(findUsages.usages().at(0).tags, Usage::Tags());
|
||||
QCOMPARE(findUsages.usages().at(1).tags, Usage::Tag::Declaration);
|
||||
QCOMPARE(findUsages.references().size(), 2);
|
||||
|
||||
Declaration *xChangedSignal = tst->memberAt(3)->asDeclaration();
|
||||
QVERIFY(xChangedSignal);
|
||||
QCOMPARE(xChangedSignal->identifier()->chars(), "xChanged");
|
||||
findUsages(xChangedSignal);
|
||||
QCOMPARE(findUsages.usages().size(), 3);
|
||||
QCOMPARE(findUsages.usages().at(0).tags, Usage::Tags());
|
||||
QCOMPARE(findUsages.usages().at(1).tags, Usage::Tags());
|
||||
QCOMPARE(findUsages.usages().at(2).tags,
|
||||
(Usage::Tags{Usage::Tag::Declaration, Usage::Tag::MocInvokable}));
|
||||
}
|
||||
|
||||
void tst_FindUsages::instantiateTemplateWithNestedClass()
|
||||
@@ -2343,5 +2354,137 @@ int main()
|
||||
QCOMPARE(find.usages().at(2).tags, Usage::Tag::Read);
|
||||
}
|
||||
|
||||
void tst_FindUsages::mocInvokables()
|
||||
{
|
||||
const QByteArray src =
|
||||
R"(
|
||||
class O : public QObject {
|
||||
public:
|
||||
void aPublicFunction();
|
||||
Q_SLOT void aSlot();
|
||||
Q_SIGNAL void aSignal();
|
||||
Q_INVOKABLE void anInvokable();
|
||||
public slots:
|
||||
void anotherSlot();
|
||||
signals:
|
||||
void anotherSignal();
|
||||
private slots:
|
||||
void yetAnotherSlot();
|
||||
private:
|
||||
void aPrivateFunction();
|
||||
};
|
||||
)";
|
||||
|
||||
Document::Ptr doc = Document::create("mocInvokables");
|
||||
doc->setUtf8Source(src);
|
||||
doc->parse();
|
||||
doc->check();
|
||||
|
||||
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||
QVERIFY(doc->globalSymbolCount() >= 1);
|
||||
|
||||
Snapshot snapshot;
|
||||
snapshot.insert(doc);
|
||||
|
||||
Class *s = doc->globalSymbolAt(0)->asClass();
|
||||
QVERIFY(s);
|
||||
QCOMPARE(s->name()->identifier()->chars(), "O");
|
||||
QCOMPARE(s->memberCount(), 8);
|
||||
|
||||
const Usage::Tags invokable{Usage::Tag::Declaration, Usage::Tag::MocInvokable};
|
||||
|
||||
Declaration *sv = s->memberAt(0)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "aPublicFunction");
|
||||
FindUsages find(src, doc, snapshot, true);
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, Usage::Tag::Declaration);
|
||||
|
||||
sv = s->memberAt(1)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "aSlot");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(2)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "aSignal");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(3)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "anInvokable");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(4)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "anotherSlot");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(5)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "anotherSignal");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(6)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "yetAnotherSlot");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, invokable);
|
||||
|
||||
sv = s->memberAt(7)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "aPrivateFunction");
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags, Usage::Tag::Declaration);
|
||||
}
|
||||
|
||||
void tst_FindUsages::virtualOverride()
|
||||
{
|
||||
const QByteArray src =
|
||||
R"(
|
||||
struct Base { virtual void foo(); };
|
||||
struct Derived : public Base { void foo() override; };
|
||||
)";
|
||||
|
||||
Document::Ptr doc = Document::create("virtualOverride");
|
||||
doc->setUtf8Source(src);
|
||||
doc->parse();
|
||||
doc->check();
|
||||
|
||||
QVERIFY(doc->diagnosticMessages().isEmpty());
|
||||
QVERIFY(doc->globalSymbolCount() >= 2);
|
||||
|
||||
Snapshot snapshot;
|
||||
snapshot.insert(doc);
|
||||
|
||||
Class *s = doc->globalSymbolAt(1)->asClass();
|
||||
QVERIFY(s);
|
||||
QCOMPARE(s->name()->identifier()->chars(), "Derived");
|
||||
QCOMPARE(s->memberCount(), 1);
|
||||
|
||||
Declaration *sv = s->memberAt(0)->asDeclaration();
|
||||
QVERIFY(sv);
|
||||
QCOMPARE(sv->name()->identifier()->chars(), "foo");
|
||||
|
||||
FindUsages find(src, doc, snapshot, true);
|
||||
find(sv);
|
||||
QCOMPARE(find.usages().size(), 1);
|
||||
QCOMPARE(find.usages().at(0).tags,
|
||||
(Usage::Tags{Usage::Tag::Declaration, Usage::Tag::Override}));
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_FindUsages)
|
||||
#include "tst_findusages.moc"
|
||||
|
||||
Reference in New Issue
Block a user