Merge pull request from melex750/dev

Implicit cast and null when passing arguments
dev-new-models
krzys_h 2016-09-24 17:13:17 +02:00 committed by GitHub
commit 89bf0da30c
19 changed files with 440 additions and 75 deletions

View File

@ -1730,6 +1730,9 @@ msgstr ""
msgid "Expression expected after ="
msgstr ""
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Dividing by zero"
msgstr ""

View File

@ -86,6 +86,9 @@ msgstr "Trägt schon etwas"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr ""
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Analysis already performed"
msgstr "Analyse schon durchgeführt"

View File

@ -81,6 +81,9 @@ msgstr "Porte déjà quelque chose"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr ""
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Analysis already performed"
msgstr "Analyse déjà effectuée"

View File

@ -84,6 +84,9 @@ msgstr "Nie można nieść więcej przedmiotów"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr "Alternatywny tryb kamery\\Poruszaj na boki zamiast obracać (w kamerze swobodnej)"
msgid "Ambiguous call to overloaded function"
msgstr "Niejednoznaczne wywołanie przeciążonej funkcji"
msgid "Analysis already performed"
msgstr "Analiza została już wykonana"

View File

@ -84,6 +84,9 @@ msgstr "Уже что-то несу"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr "Альтернативный режим камеры\\Движение в стороны вместо поворачивания (в режиме свободной камеры)"
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Analysis already performed"
msgstr "Анализ уже выполнен"

View File

@ -639,7 +639,6 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
{
// return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
CBotFunction* prev = nullptr;
CBotToken* ppp = p;
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
CBotDefParam* params = CBotDefParam::Compile(p, pStk );
@ -648,7 +647,6 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while ( pf != nullptr ) // search by name and parameters
{
if (pf->GetName() == pp && pf->CheckParam( params )) break;
prev = pf;
pf = pf->Next();
}
@ -684,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();
}
@ -693,18 +692,12 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
// compiles a method
p = pBase;
CBotFunction* f =
CBotFunction::Compile(p, pile, nullptr/*, false*/);
CBotFunction::Compile(p, pile, pf/*, false*/);
if ( f != nullptr )
{
f->m_pProg = pStack->GetProgram();
f->m_bSynchro = bSynchro;
// replaces the element in the chain
f->m_next = pf->m_next;
pf->m_next = nullptr;
delete pf;
if (prev == nullptr) m_pMethod = f;
else prev->m_next = f;
}
pStack->Return(nullptr, pile);
}

View File

@ -236,6 +236,7 @@ enum CBotError : int
CBotErrPrivate = 5041, //!< protected item
CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after =
CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -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::CheckProtectionError(pStk, preVar, var))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -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::CheckProtectionError(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::CheckProtectionError(pStk, preVar, var, privat))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -134,4 +134,57 @@ std::string CBotFieldExpr::GetDebugData()
return ss.str();
}
////////////////////////////////////////////////////////////////////////////////
bool CBotFieldExpr::CheckProtectionError(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

View File

@ -65,6 +65,21 @@ public:
*/
void RestoreStateVar(CBotStack* &pj, bool bMain) override;
/*!
* \brief Check if access to a variable is allowed or not depending on public/private/protected setting
*
* If this function returns true, the caller is responsible for failing the compilation with ::CBotErrPrivate error.
* This function doesn't set the error flag itself.
*
* \param pStack Current compilation stack frame
* \param pPrev Class instance which variable to check is part of, or nullptr if not part of a class
* \param pVar Variable to check
* \param privat CBotVar::ProtectionLevel::ReadOnly if requesting read-only access, anything else otherwise
* \return true if pVar is inaccessible in the current context, false if access should be allowed
*/
static bool CheckProtectionError(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;

View File

@ -224,10 +224,6 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken();
if ( pStk->IsOk() )
{
if ( func->m_bPublic ) // public function, return known for all
{
CBotFunction::AddPublic(func);
}
return pStack->ReturnFunc(func, pStk);
}
}
@ -466,8 +462,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
if ( name.empty() ) return nullptr;
int delta = 99999; // seeks the lowest signature
CBotFunction* pFunc = nullptr; // the best function found
std::map<CBotFunction*, int> funcMap;
if ( this != nullptr )
{
@ -482,44 +477,48 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
CBotVar* pw = ppVars[i++]; // provided list parameter
while ( pv != nullptr && pw != nullptr)
{
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(paramType, argType))
{
if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
break;
}
if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
{
CBotClass* c1 = paramType.GetClass();
CBotClass* c2 = argType.GetClass();
while (c2 != c1 && c2 != nullptr) // implicit cast
{
alpha += 10;
c2 = c2->GetParent();
}
}
else
{
int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
}
pv = pv->GetNext();
pw = ppVars[i++];
}
if ( pw != nullptr )
{
if ( pFunc != nullptr ) continue;
if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // too many parameters
}
if ( pv != nullptr )
{
if ( pFunc != nullptr ) continue;
if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
continue; // not enough parameters
}
if (alpha == 0) // perfect signature
{
nIdent = pt->m_nFuncIdent;
TypeOrError = pt->m_retTyp;
return pt;
}
if ( alpha < delta ) // a better signature?
{
pFunc = pt;
delta = alpha;
}
funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
}
}
}
@ -537,50 +536,72 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
CBotVar* pw = ppVars[i++]; // list of provided parameters
while ( pv != nullptr && pw != nullptr)
{
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(paramType, argType))
{
if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
break;
}
if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
{
CBotClass* c1 = paramType.GetClass();
CBotClass* c2 = argType.GetClass();
while (c2 != c1 && c2 != nullptr) // implicit cast
{
alpha += 10;
c2 = c2->GetParent();
}
}
else
{
int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
}
pv = pv->GetNext();
pw = ppVars[i++];
}
if ( pw != nullptr )
{
if ( pFunc != nullptr ) continue;
if ( !funcMap.empty() ) continue; // previous useable function
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // to many parameters
}
if ( pv != nullptr )
{
if ( pFunc != nullptr ) continue;
if ( !funcMap.empty() ) continue; // previous useable function
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
continue; // not enough parameters
}
if (alpha == 0) // perfect signature
{
nIdent = pt->m_nFuncIdent;
TypeOrError = pt->m_retTyp;
return pt;
}
if ( alpha < delta ) // a better signature?
{
pFunc = pt;
delta = alpha;
}
funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
}
}
}
if ( pFunc != nullptr )
if ( !funcMap.empty() )
{
auto it = funcMap.begin();
CBotFunction* pFunc = it->first; // the best function found
signed int delta = it->second; // seeks the lowest signature
for (++it ; it != funcMap.end() ; it++)
{
if (it->second < delta) // a better signature?
{
TypeOrError.SetType(CBotNoErr);
pFunc = it->first;
delta = it->second;
continue;
}
if (it->second == delta) TypeOrError.SetType(CBotErrAmbiguousCall);
}
if (TypeOrError.Eq(CBotErrAmbiguousCall)) return nullptr;
nIdent = pFunc->m_nFuncIdent;
TypeOrError = pFunc->m_retTyp;
return pFunc;

View File

@ -149,12 +149,20 @@ bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2)
if (max >= CBotTypBoolean)
{
if (t1 == CBotTypPointer && t2 == CBotTypNullPointer) return true;
if (t2 != t1) return false;
if (max == CBotTypPointer)
{
CBotClass* c1 = type1.GetClass();
CBotClass* c2 = type2.GetClass();
return c2->IsChildOf(c1);
}
if (max == CBotTypArrayPointer)
return TypesCompatibles(type1.GetTypElem(), type2.GetTypElem());
if (max == CBotTypClass || max == CBotTypPointer)
if (max == CBotTypClass)
return type1.GetClass() == type2.GetClass() ;
return true ;

View File

@ -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::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@ -125,11 +124,12 @@ 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::CheckProtectionError(pStk, preVar, var,
CBotVar::ProtectionLevel::ReadOnly))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -124,14 +124,13 @@ 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);
next->m_pProg = this; // keeps pointers to the module
next = next->Next();
}

View File

@ -332,13 +332,6 @@ public:
*/
CBotFunction* GetFunctions();
/**
* \brief true while compiling class
*
* TODO: refactor this
*/
bool m_bCompileClass;
/**
* \brief Returns static list of all registered external calls
*/

View File

@ -106,7 +106,7 @@ public:
/**
* \brief Returns ::CBotType or ::CBotError stored in this object
* \param mode Mode, see ::GetTypeMode enum
* \param mode Mode, see GetTypeMode enum
*/
int GetType(GetTypeMode mode = GetTypeMode::NORMAL) const;

View File

@ -717,6 +717,7 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrPrivate] = TR("Private element");
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after =");
stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

@ -1786,3 +1786,270 @@ TEST_F(CBotUT, ClassNewConstructorMethodChain)
"}\n"
);
}
TEST_F(CBotUT, PassNullAsArgument)
{
auto publicProgram = ExecuteTest(
"public class BaseClass {}\n"
"public class SubClass extends BaseClass {}\n"
);
ExecuteTest(
"bool Test(BaseClass b) {\n"
" return (b == null);\n"
"}\n"
"extern void PassNullAsArgument() {\n"
" ASSERT(true == Test(null));\n"
"}\n"
);
ExecuteTest(
"void Test(BaseClass b) {}\n"
"void Test(SubClass s) {}\n"
"\n"
"extern void AmbiguousCallArgumentNull() {\n"
" Test(null);\n"
"}\n",
CBotErrAmbiguousCall
);
}
TEST_F(CBotUT, ClassImplicitCastArguments)
{
auto publicProgram = ExecuteTest(
"public class BaseClass { int a = 360; }\n"
"public class SubClass extends BaseClass {}\n"
);
ExecuteTest(
"bool Test(BaseClass b) {\n"
" SubClass s = b;\n"
" return (360 == s.a);\n"
"}\n"
"extern void UpcastPassingArguments() {\n"
" ASSERT(true == Test(new SubClass()));\n"
"}\n"
);
ExecuteTest(
"void Test(BaseClass b, SubClass s) {}\n"
"void Test(SubClass s, BaseClass b) {}\n"
"\n"
"extern void UpcastAmbiguousCall() {\n"
" Test(new SubClass(), new SubClass());\n"
"}\n",
CBotErrAmbiguousCall
);
ExecuteTest(
"bool Test(BaseClass b, SubClass s) { return false; }\n"
"bool Test(SubClass s, BaseClass b) { return false; }\n"
"bool Test(SubClass s, SubClass s2) { return true; }\n"
"\n"
"extern void NoErrorMoreSpecific() {\n"
" ASSERT(true == Test(new SubClass(), new SubClass()));\n"
"}\n"
);
}
TEST_F(CBotUT, AmbiguousCallWithNumbers)
{
ExecuteTest(
"void Test(int i, float f) {}\n"
"void Test(float f, int i) {}\n"
"\n"
"extern void AmbiguousCallNumbers() {\n"
" Test(1, 2);\n"
"}\n",
CBotErrAmbiguousCall
);
ExecuteTest(
"bool Test(int i, float f) { return false; }\n"
"bool Test(float f, int i) { return false; }\n"
"bool Test(int i, int ii) { return true; }\n"
"\n"
"extern void NoErrorMoreSpecific() {\n"
" ASSERT(true == Test(1, 2));\n"
"}\n"
);
}
TEST_F(CBotUT, ClassMethodWithPublicKeyword)
{
auto publicProgram = ExecuteTest(
"public class TestClass {\n"
" public int Test() { return 1; }\n"
"}\n"
);
ExecuteTest(
"int Test() { return 2; }\n"
"\n"
"extern void DontCallMethodInTestClass()\n"
"{\n"
" ASSERT(2 == Test());\n"
"}\n"
);
ExecuteTest(
"int Test() { return 2; }\n"
"\n"
"public class OtherClass {}\n"
"\n"
"extern void OtherClass::TestCallWithThis()\n"
"{\n"
" this.Test();\n"
"}\n",
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
);
}