[colobot] 48/74: Fix access to protected and private variables
Didier Raboud
odyx at moszumanska.debian.org
Mon Nov 7 07:50:04 UTC 2016
This is an automated email from the git hooks/post-receive script.
odyx pushed a commit to branch debian/master
in repository colobot.
commit 9ab7f7d140d779ef23323d95f3a01569d997a889
Author: melex750 <melex750 at users.noreply.github.com>
Date: Sat Sep 17 08:00:34 2016 -0400
Fix access to protected and private variables
---
src/CBot/CBotClass.cpp | 1 +
src/CBot/CBotInstr/CBotExprRetVar.cpp | 4 +-
src/CBot/CBotInstr/CBotExprVar.cpp | 7 +-
src/CBot/CBotInstr/CBotFieldExpr.cpp | 53 ++++++++++++
src/CBot/CBotInstr/CBotFieldExpr.h | 11 +++
src/CBot/CBotInstr/CBotLeftExpr.cpp | 7 +-
src/CBot/CBotProgram.cpp | 2 -
src/CBot/CBotProgram.h | 7 --
test/unit/CBot/CBot_test.cpp | 149 ++++++++++++++++++++++++++++++++++
9 files changed, 222 insertions(+), 19 deletions(-)
diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp
index b342ab4..460ab9f 100644
--- a/src/CBot/CBotClass.cpp
+++ b/src/CBot/CBotClass.cpp
@@ -682,6 +682,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
initType = CBotVar::InitType::DEF;
pcopy->SetInit(initType);
pcopy->SetUniqNum(pv->GetUniqNum());
+ pcopy->SetPrivate(pv->GetPrivate());
pile->AddVar(pcopy);
pv = pv->GetNext();
}
diff --git a/src/CBot/CBotInstr/CBotExprRetVar.cpp b/src/CBot/CBotInstr/CBotExprRetVar.cpp
index 96ff03c..c0e0e18 100644
--- a/src/CBot/CBotInstr/CBotExprRetVar.cpp
+++ b/src/CBot/CBotInstr/CBotExprRetVar.cpp
@@ -105,12 +105,12 @@ CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bMeth
CBotFieldExpr* i = new CBotFieldExpr();
i->SetToken(pp);
inst->AddNext3(i);
+ CBotVar* preVar = var;
var = var->GetItem(p->GetString());
if (var != nullptr)
{
i->SetUniqNum(var->GetUniqNum());
- if ( var->IsPrivate() &&
- !pStk->GetProgram()->m_bCompileClass)
+ if (CBotFieldExpr::ProtectionError(pStk, preVar, var))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;
diff --git a/src/CBot/CBotInstr/CBotExprVar.cpp b/src/CBot/CBotInstr/CBotExprVar.cpp
index 3b774ca..1963d30 100644
--- a/src/CBot/CBotInstr/CBotExprVar.cpp
+++ b/src/CBot/CBotInstr/CBotExprVar.cpp
@@ -67,8 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (ident > 0 && ident < 9000)
{
- if ( var->IsPrivate(privat) &&
- !pStk->GetProgram()->m_bCompileClass)
+ if (CBotFieldExpr::ProtectionError(pStk, nullptr, var, privat))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@@ -133,12 +132,12 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
CBotFieldExpr* i = new CBotFieldExpr(); // new element
i->SetToken(pp); // keeps the name of the token
inst->AddNext3(i); // add after
+ CBotVar* preVar = var;
var = var->GetItem(p->GetString()); // get item correspondent
if (var != nullptr)
{
i->SetUniqNum(var->GetUniqNum());
- if ( var->IsPrivate() &&
- !pStk->GetProgram()->m_bCompileClass)
+ if (CBotFieldExpr::ProtectionError(pStk, preVar, var, privat))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;
diff --git a/src/CBot/CBotInstr/CBotFieldExpr.cpp b/src/CBot/CBotInstr/CBotFieldExpr.cpp
index 56ba987..1d12a65 100644
--- a/src/CBot/CBotInstr/CBotFieldExpr.cpp
+++ b/src/CBot/CBotInstr/CBotFieldExpr.cpp
@@ -134,4 +134,57 @@ std::string CBotFieldExpr::GetDebugData()
return ss.str();
}
+////////////////////////////////////////////////////////////////////////////////
+bool CBotFieldExpr::ProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
+ CBotVar::ProtectionLevel privat)
+{
+ CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
+
+ if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat)
+ return true;
+
+ if (varPriv == CBotVar::ProtectionLevel::Public) return false;
+
+ std::string prevName = (pPrev == nullptr) ? "" : pPrev->GetName();
+
+ // implicit 'this.'var, this.var, or super.var
+ if (pPrev == nullptr || prevName == "this" || prevName == "super") // member of the current class
+ {
+ if (varPriv == CBotVar::ProtectionLevel::Private) // var is private ?
+ {
+ CBotToken token("this");
+ CBotVar* pThis = pStack->FindVar(token);
+ CBotClass* pClass = pThis->GetClass(); // the current class
+
+ CBotVar* pVarList = pClass->GetVar();
+
+ int ident = pVar->GetUniqNum();
+ // check if var is inherited from a parent class
+ if (pVarList == nullptr || ident < pVarList->GetUniqNum())
+ return true;
+ }
+ }
+ else // any other context
+ {
+ if (pVar->IsPrivate()) // var is protected or private ?
+ {
+ CBotToken token("this");
+ CBotVar* pThis = pStack->FindVar(token);
+
+ if (pThis == nullptr) return true; // inside a function ?
+ if (pThis->GetType() != CBotTypPointer) return true;
+
+ CBotClass* pClass = pThis->GetClass(); // the current class
+
+ if (!pClass->IsChildOf(pPrev->GetClass())) // var is member of some other class ?
+ return true;
+
+ if (varPriv == CBotVar::ProtectionLevel::Private && // private member of a parent class
+ pClass != pPrev->GetClass()) return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace CBot
diff --git a/src/CBot/CBotInstr/CBotFieldExpr.h b/src/CBot/CBotInstr/CBotFieldExpr.h
index db48839..2ee2851 100644
--- a/src/CBot/CBotInstr/CBotFieldExpr.h
+++ b/src/CBot/CBotInstr/CBotFieldExpr.h
@@ -65,6 +65,17 @@ public:
*/
void RestoreStateVar(CBotStack* &pj, bool bMain) override;
+ /*!
+ * \brief ProtectionError Test if access to a variable is not allowed.
+ * \param pStack
+ * \param pPrev
+ * \param pVar
+ * \param privat
+ * \return True if pVar is protected in the current context.
+ */
+ static bool ProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
+ CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
+
protected:
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }
virtual std::string GetDebugData() override;
diff --git a/src/CBot/CBotInstr/CBotLeftExpr.cpp b/src/CBot/CBotInstr/CBotLeftExpr.cpp
index 3a9fe15..8201137 100644
--- a/src/CBot/CBotInstr/CBotLeftExpr.cpp
+++ b/src/CBot/CBotInstr/CBotLeftExpr.cpp
@@ -64,8 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
inst->m_nIdent = var->GetUniqNum();
if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
{
- if ( var->IsPrivate(CBotVar::ProtectionLevel::ReadOnly) &&
- !pStk->GetProgram()->m_bCompileClass)
+ if (CBotFieldExpr::ProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@@ -125,11 +124,11 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
if (p->GetType() == TokenTypVar) // must be a name
{
+ CBotVar* preVar = var;
var = var->GetItem(p->GetString()); // get item correspondent
if (var != nullptr)
{
- if ( var->IsPrivate(CBotVar::ProtectionLevel::ReadOnly) &&
- !pStk->GetProgram()->m_bCompileClass)
+ if (CBotFieldExpr::ProtectionError(pStk, preVar, var, CBotVar::ProtectionLevel::ReadOnly))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;
diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp
index c406a01..8100829 100644
--- a/src/CBot/CBotProgram.cpp
+++ b/src/CBot/CBotProgram.cpp
@@ -124,12 +124,10 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( p->GetType() == ID_CLASS ||
( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS ))
{
- m_bCompileClass = true;
CBotClass::Compile(p, pStack.get()); // completes the definition of the class
}
else
{
- m_bCompileClass = false;
CBotFunction::Compile(p, pStack.get(), next);
if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/);
if (next->IsPublic()) CBotFunction::AddPublic(next);
diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h
index 9f5cdc0..165defc 100644
--- a/src/CBot/CBotProgram.h
+++ b/src/CBot/CBotProgram.h
@@ -333,13 +333,6 @@ public:
CBotFunction* GetFunctions();
/**
- * \brief true while compiling class
- *
- * TODO: refactor this
- */
- bool m_bCompileClass;
-
- /**
* \brief Returns static list of all registered external calls
*/
static CBotExternalCallList* GetExternalCalls();
diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp
index fb63ed9..797a674 100644
--- a/test/unit/CBot/CBot_test.cpp
+++ b/test/unit/CBot/CBot_test.cpp
@@ -1904,3 +1904,152 @@ TEST_F(CBotUT, ClassMethodWithPublicKeyword)
CBotErrUndefCall
);
}
+
+TEST_F(CBotUT, ClassTestProtectedMember)
+{
+ auto publicProgram = ExecuteTest(
+ "public class BaseClass {\n"
+ " protected int a_protected = 1;\n"
+ " bool test() {\n"
+ " a_protected = 1;\n"
+ " int a = a_protected;\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
+ "extern void Test() {\n"
+ " BaseClass b();\n"
+ " ASSERT(true == b.test());\n"
+ "}\n"
+ );
+
+ ExecuteTest(
+ "public class SubClass extends BaseClass {\n"
+ " bool testProtected() {\n"
+ " a_protected = 1;\n"
+ " int a = a_protected;\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
+ "extern void TestSubClassAccessProtected() {\n"
+ " SubClass s();\n"
+ " ASSERT(true == s.test());\n"
+ " ASSERT(true == s.testProtected());\n"
+ "}\n"
+ );
+
+ ExecuteTest(
+ "extern void TestErrorProtected() {\n"
+ " BaseClass b();\n"
+ " int i = b.a_protected;\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "extern void ErrorProtectedAssignment() {\n"
+ " BaseClass b();\n"
+ " b.a_protected = 1;\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "public class SomeOtherClass {\n"
+ " void testErrorProtected() {\n"
+ " BaseClass b();\n"
+ " int i = b.a_protected;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "public class SomeOtherClass {\n"
+ " void testErrorProtectedAssignment() {\n"
+ " BaseClass b();\n"
+ " b.a_protected = 1;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+}
+
+TEST_F(CBotUT, ClassTestPrivateMember)
+{
+ auto publicProgram = ExecuteTest(
+ "public class BaseClass {\n"
+ " private int a_private = 2;\n"
+ "\n"
+ " bool test() {\n"
+ " a_private = 2;\n"
+ " int a = a_private;\n"
+ " return true;\n"
+ " }\n"
+ " bool NoErrorPrivateSameClass() {\n"
+ " BaseClass b = new BaseClass();\n"
+ " int a = b.a_private;\n"
+ " b.a_private = 2;\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
+ "extern void Test() {\n"
+ " BaseClass b();\n"
+ " ASSERT(true == b.test());\n"
+ " ASSERT(true == b.NoErrorPrivateSameClass());\n"
+ "}\n"
+ );
+
+ ExecuteTest(
+ "public class SubClass extends BaseClass {\n"
+ " void testErrorPrivate() {\n"
+ " int a = a_private;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "public class SubClass extends BaseClass {\n"
+ " void testErrorPrivateAssignment() {\n"
+ " a_private = 2;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "extern void TestErrorPrivate() {\n"
+ " BaseClass b();\n"
+ " int i = b.a_private;\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "extern void ErrorPrivateAssignment() {\n"
+ " BaseClass b();\n"
+ " b.a_private = 2;\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "public class SomeOtherClass {\n"
+ " void testErrorPrivate() {\n"
+ " BaseClass b();\n"
+ " int i = b.a_private;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+
+ ExecuteTest(
+ "public class SomeOtherClass {\n"
+ " void testErrorPrivateAssignment() {\n"
+ " BaseClass b();\n"
+ " b.a_private = 1;\n"
+ " }\n"
+ "}\n",
+ CBotErrPrivate
+ );
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git
More information about the Pkg-games-commits
mailing list