Commit 4c46f097 authored by Heinz Wiesinger's avatar Heinz Wiesinger

Add support for class constant visibility

Syntax according to https://wiki.php.net/rfc/class_const_visibility
parent 97b05066
......@@ -397,6 +397,26 @@ void DeclarationBuilder::visitClassStatement(ClassStatementAst *node)
DeclarationBuilderBase::visitClassStatement(node);
importTraitMethods(node);
} else if (node->constsSequence) {
if (node->modifiers) {
m_currentModifers = node->modifiers->modifiers;
if (m_reportErrors) {
// have to report the errors here to get a good problem range
if (m_currentModifers & ModifierFinal) {
reportError(i18n("Cannot use 'final' as constant modifier"), node->modifiers);
}
if (m_currentModifers & ModifierStatic) {
reportError(i18n("Cannot use 'static' as constant modifier"), node->modifiers);
}
if (m_currentModifers & ModifierAbstract) {
reportError(i18n("Cannot use 'abstract' as constant modifier"), node->modifiers);
}
}
} else {
m_currentModifers = 0;
}
DeclarationBuilderBase::visitClassStatement(node);
m_currentModifers = 0;
} else {
if (node->modifiers) {
m_currentModifers = node->modifiers->modifiers;
......@@ -665,7 +685,13 @@ void DeclarationBuilder::visitClassConstantDeclaration(ClassConstantDeclarationA
}
}
ClassMemberDeclaration* dec = openDefinition<ClassMemberDeclaration>(identifierForNode(node->identifier), m_editor->findRange(node->identifier));
dec->setAccessPolicy(Declaration::Public);
if (m_currentModifers & ModifierProtected) {
dec->setAccessPolicy(Declaration::Protected);
} else if (m_currentModifers & ModifierPrivate) {
dec->setAccessPolicy(Declaration::Private);
} else {
dec->setAccessPolicy(Declaration::Public);
}
dec->setStatic(true);
dec->setKind(Declaration::Instance);
lock.unlock();
......
......@@ -1696,6 +1696,56 @@ void TestDUChain::classConstWithTypeHint()
QVERIFY(type->modifiers() & AbstractType::ConstModifier);
}
void TestDUChain::classConstVisibility()
{
// 0 1 2 3 4 5 6 7
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
QByteArray method("<? class A { public const B = 1; protected const C = 1; private const D = 1; } ");
TopDUContext* top = parse(method, DumpNone);
DUChainReleaser releaseTop(top);
DUChainWriteLocker lock(DUChain::lock());
QCOMPARE(top->childContexts().count(), 1);
QCOMPARE(top->problems().count(), 0);
QList< Declaration* > decs = top->findDeclarations(QualifiedIdentifier("a::B"));
QCOMPARE(decs.count(), 1);
QCOMPARE(decs.first()->context(), top->childContexts().last());
IntegralType::Ptr type = decs.first()->abstractType().cast<IntegralType>();
QVERIFY(type);
QCOMPARE(type->dataType(), IntegralType::TypeInt);
QVERIFY(type->modifiers() & AbstractType::ConstModifier);
ClassMemberDeclaration* cmdec = dynamic_cast<ClassMemberDeclaration*>(decs.first());
QVERIFY(cmdec->accessPolicy() == Declaration::Public);
decs = top->findDeclarations(QualifiedIdentifier("a::C"));
QCOMPARE(decs.count(), 1);
QCOMPARE(decs.first()->context(), top->childContexts().last());
type = decs.first()->abstractType().cast<IntegralType>();
QVERIFY(type);
QCOMPARE(type->dataType(), IntegralType::TypeInt);
QVERIFY(type->modifiers() & AbstractType::ConstModifier);
cmdec = dynamic_cast<ClassMemberDeclaration*>(decs.first());
QVERIFY(cmdec->accessPolicy() == Declaration::Protected);
decs = top->findDeclarations(QualifiedIdentifier("a::D"));
QCOMPARE(decs.count(), 1);
QCOMPARE(decs.first()->context(), top->childContexts().last());
type = decs.first()->abstractType().cast<IntegralType>();
QVERIFY(type);
QCOMPARE(type->dataType(), IntegralType::TypeInt);
QVERIFY(type->modifiers() & AbstractType::ConstModifier);
cmdec = dynamic_cast<ClassMemberDeclaration*>(decs.first());
QVERIFY(cmdec->accessPolicy() == Declaration::Private);
}
void TestDUChain::semiReservedClassConst()
{
// 0 1 2 3 4 5 6 7
......@@ -1719,6 +1769,27 @@ void TestDUChain::semiReservedClassConst()
QCOMPARE(top->findDeclarations(QualifiedIdentifier("a::STRING")).first()->context(), top->childContexts().last());
}
void TestDUChain::illegalClassConst_data()
{
QTest::addColumn<QString>("code");
QTest::newRow("final const") << QStringLiteral("<? class A { final const C = 1; } ");
QTest::newRow("static const") << QStringLiteral("<? class A { static const C = 1; } ");
QTest::newRow("abstract const") << QStringLiteral("<? class A { abstract const C = 1; } ");
}
void TestDUChain::illegalClassConst()
{
QFETCH(QString, code);
TopDUContext* top = parse(code.toUtf8(), DumpNone);
QVERIFY(top);
DUChainReleaser releaseTop(top);
DUChainWriteLocker lock;
QCOMPARE(top->problems().count(), 1);
}
void TestDUChain::fileConst_data()
{
QTest::addColumn<QString>("code");
......
......@@ -87,7 +87,10 @@ private slots:
void classConst();
void classConst_data();
void classConstWithTypeHint();
void classConstVisibility();
void semiReservedClassConst();
void illegalClassConst();
void illegalClassConst_data();
void fileConst();
void fileConst_data();
void semiReservedFileConst();
......
......@@ -1026,13 +1026,13 @@ try/recover(#classStatements=classStatement)*
RBRACE [: rewind(tokenStream->index() - 2); :]
-> classBody ;;
CONST #consts=classConstantDeclaration @ COMMA SEMICOLON
| VAR variable=classVariableDeclaration SEMICOLON
VAR variable=classVariableDeclaration SEMICOLON
| modifiers=optionalModifiers
( variable=classVariableDeclaration SEMICOLON
| FUNCTION (BIT_AND | 0) methodName=semiReservedIdentifier LPAREN parameters=parameterList RPAREN
( COLON returnType=returnType | 0)
methodBody=methodBody
| CONST #consts=classConstantDeclaration @ COMMA SEMICOLON
)
| USE #traits=namespacedIdentifier @ COMMA (imports=traitAliasDeclaration|SEMICOLON)
-> classStatement ;;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment