diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index d24d5620..5d663e1e 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -55,6 +55,7 @@ enum BfProtection : uint8 BfProtection_Private, BfProtection_Internal, BfProtection_Protected, + BfProtection_ProtectedInternal, BfProtection_Public }; @@ -2271,7 +2272,7 @@ public: BfAttributeDirective* mAttributes; BfTokenNode* mAbstractSpecifier; BfTokenNode* mSealedSpecifier; - BfTokenNode* mProtectionSpecifier; + BfAstNode* mProtectionSpecifier; BfTokenNode* mStaticSpecifier; BfTokenNode* mPartialSpecifier; BfTokenNode* mTypeNode; @@ -2829,7 +2830,7 @@ public: BF_AST_TYPE(BfMemberDeclaration, BfAstNode); BfAttributeDirective* mAttributes; - BfTokenNode* mProtectionSpecifier; + BfAstNode* mProtectionSpecifier; BfTokenNode* mStaticSpecifier; BfTokenNode* mReadOnlySpecifier; // Also stores 'inline' }; BF_AST_DECL(BfMemberDeclaration, BfAstNode); @@ -3035,7 +3036,7 @@ public: BF_AST_TYPE(BfPropertyMethodDeclaration, BfAstNode); BfPropertyDeclaration* mPropertyDeclaration; BfAttributeDirective* mAttributes; - BfTokenNode* mProtectionSpecifier; + BfAstNode* mProtectionSpecifier; BfTokenNode* mMutSpecifier; BfIdentifierNode* mNameNode; BfTokenNode* mFatArrowToken; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 97040c6c..21066146 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -370,23 +370,27 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD } } -BfProtection BfDefBuilder::GetProtection(BfTokenNode* protectionToken) -{ - if (protectionToken == NULL) +BfProtection BfDefBuilder::GetProtection(BfAstNode* protectionNode) +{ + if (auto tokenPair = BfNodeDynCast(protectionNode)) { - if (mCurTypeDef->mTypeCode == BfTypeCode_Interface) - return BfProtection_Public; - else - return BfProtection_Private; + return BfProtection_ProtectedInternal; } - - if (protectionToken->GetToken() == BfToken_Public) - return BfProtection_Public; - if (protectionToken->GetToken() == BfToken_Protected) - return BfProtection_Protected; - if (protectionToken->GetToken() == BfToken_Internal) - return BfProtection_Internal; - return BfProtection_Private; + else if (auto protectionToken = BfNodeDynCast(protectionNode)) + { + if (protectionToken->GetToken() == BfToken_Public) + return BfProtection_Public; + if (protectionToken->GetToken() == BfToken_Protected) + return BfProtection_Protected; + if (protectionToken->GetToken() == BfToken_Internal) + return BfProtection_Internal; + return BfProtection_Private; + } + + if (mCurTypeDef->mTypeCode == BfTypeCode_Interface) + return BfProtection_Public; + else + return BfProtection_Private; } void BfDefBuilder::Visit(BfConstructorDeclaration* ctorDeclaration) diff --git a/IDEHelper/Compiler/BfDefBuilder.h b/IDEHelper/Compiler/BfDefBuilder.h index a638bf7d..a351ee78 100644 --- a/IDEHelper/Compiler/BfDefBuilder.h +++ b/IDEHelper/Compiler/BfDefBuilder.h @@ -28,7 +28,7 @@ public: public: void ParseGenericParams(BfGenericParamsDeclaration* genericParamsDecl, BfGenericConstraintsDeclaration* genericConstraints, Array& genericParams, Array* externConstraintDefs, int outerGenericSize, bool isInGeneric); - BfProtection GetProtection(BfTokenNode* protectionToken); + BfProtection GetProtection(BfAstNode* protectionNode); bool WantsNode(BfAstNode* wholeNode, BfAstNode* startNode = NULL, int addLen = 0); //static BfNamedTypeReference* AllocTypeReference(BfSource* bfSource, const StringImpl& typeName); //static BfResolvedTypeReference* AllocTypeReference(BfSource* bfSource, BfType* type); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c1d5e3d6..e2cb58a1 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -1228,7 +1228,9 @@ bool BfMethodMatcher::WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInst MatchFailKind matchFailKind = MatchFailKind_None; if (!mModule->CheckProtection(flags, checkTypeInstance, checkMethod->mDeclaringType->mProject, checkMethod->mProtection, startTypeInstance)) { - if ((mBypassVirtual) && (checkMethod->mProtection == BfProtection_Protected) && (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, startTypeInstance))) + if ((mBypassVirtual) && + ((checkMethod->mProtection == BfProtection_Protected) || (checkMethod->mProtection == BfProtection_ProtectedInternal)) && + (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, startTypeInstance))) { // Allow explicit 'base' call } @@ -2217,7 +2219,9 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe MatchFailKind matchFailKind = MatchFailKind_None; if (!mModule->CheckProtection(protectionCheckFlags, curTypeInst, checkMethod->mDeclaringType->mProject, checkMethod->mProtection, typeInstance)) { - if ((mBypassVirtual) && (checkMethod->mProtection == BfProtection_Protected) && (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, typeInstance))) + if ((mBypassVirtual) && + ((checkMethod->mProtection == BfProtection_Protected) || (checkMethod->mProtection == BfProtection_ProtectedInternal)) && + (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, typeInstance))) { // Allow explicit 'base' call } @@ -6688,7 +6692,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou } else { - if (checkProt == BfProtection_Protected) // Treat protected constructors as private + if ((checkProt == BfProtection_Protected) || (checkProt == BfProtection_ProtectedInternal)) // Treat protected constructors as private checkProt = BfProtection_Private; if (!mModule->CheckProtection(protectionCheckFlags, curTypeInst, checkMethod->mDeclaringType->mProject, checkProt, curTypeInst)) continue; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 77dde7c5..a182b341 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2519,7 +2519,7 @@ void BfModule::SetIllegalExprSrcPos(BfSrcPosFlags flags) bool BfModule::CheckProtection(BfProtection protection, BfTypeDef* checkType, bool allowProtected, bool allowPrivate) { if ((protection == BfProtection_Public) || - ((protection == BfProtection_Protected) && (allowProtected)) || + (((protection == BfProtection_Protected) || (protection == BfProtection_ProtectedInternal)) && (allowProtected)) || ((protection == BfProtection_Private) && (allowPrivate))) return true; if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef))) @@ -2527,7 +2527,7 @@ bool BfModule::CheckProtection(BfProtection protection, BfTypeDef* checkType, bo mAttributeState->mUsed = true; return true; } - if ((protection == BfProtection_Internal) && (checkType != NULL)) + if (((protection == BfProtection_Internal) || (protection == BfProtection_ProtectedInternal)) && (checkType != NULL)) { if (CheckInternalProtection(checkType)) return true; @@ -2571,7 +2571,7 @@ bool BfModule::CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* me } if ((flags & BfProtectionCheckFlag_AllowPrivate) != 0) return true; - if (memberProtection == BfProtection_Protected) + if ((memberProtection == BfProtection_Protected) || (memberProtection == BfProtection_ProtectedInternal)) { if ((flags & BfProtectionCheckFlag_CheckedProtected) == 0) { @@ -2658,7 +2658,7 @@ bool BfModule::CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* me return true; } - if ((memberProtection == BfProtection_Internal) && (memberOwner != NULL)) + if (((memberProtection == BfProtection_Internal) || (memberProtection == BfProtection_ProtectedInternal)) && (memberOwner != NULL)) { if (CheckInternalProtection(memberOwner->mTypeDef)) return true; @@ -7355,7 +7355,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS canAlloc = true; break; } - if (checkMethodDef->mProtection == BfProtection_Protected) + if ((checkMethodDef->mProtection == BfProtection_Protected) || (checkMethodDef->mProtection == BfProtection_ProtectedInternal)) hadProtected = true; checkMethodDef = checkMethodDef->mNextWithSameName; } @@ -21838,7 +21838,9 @@ genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var); else if (methodDef->mIsVirtual) { if ((methodDef->mProtection == BfProtection_Private) && (virtualToken != NULL)) - Fail("Virtual or abstract members cannot be private", virtualToken, true); + Fail("Virtual or abstract members cannot be 'private'", virtualToken, true); + if ((methodDef->mProtection == BfProtection_Internal) && (virtualToken != NULL)) + Fail("Virtual or abstract members cannot be 'internal'. Consider using the 'protected internal' access specifier.", virtualToken, true); } mCompiler->mStats.mMethodDeclarations++; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index bf4195ac..2e7d5836 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -1090,6 +1090,16 @@ void BfPrinter::Visit(BfTokenNode* tokenNode) } } +void BfPrinter::Visit(BfTokenPairNode* tokenPairNode) +{ + Visit(tokenPairNode->ToBase()); + + VisitChild(tokenPairNode->mLeft); + if ((tokenPairNode->mRight != NULL) && (tokenPairNode->mRight->mToken != BfToken_Star)) + ExpectSpace(); + VisitChild(tokenPairNode->mRight); +} + void BfPrinter::Visit(BfLiteralExpression* literalExpr) { Visit(literalExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index 8469cb77..043041d2 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -137,6 +137,7 @@ public: virtual void Visit(BfEmptyStatement* emptyStmt) override; virtual void Visit(BfTokenNode* tokenNode) override; + virtual void Visit(BfTokenPairNode* tokenPairNode) override; virtual void Visit(BfLiteralExpression* literalExpr) override; virtual void Visit(BfStringInterpolationExpression* stringInterpolationExpression) override; virtual void Visit(BfIdentifierNode* identifierNode) override; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 10cfbece..d5d26259 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -6074,12 +6074,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, int depth, BfAstNod (token == BfToken_Private) || (token == BfToken_Internal)) { - if (memberDecl->mProtectionSpecifier != NULL) - { - AddErrorNode(memberDecl->mProtectionSpecifier); - Fail("Protection already specified", memberDecl->mProtectionSpecifier); - } - MEMBER_SET(memberDecl, mProtectionSpecifier, tokenNode); + SetProtection(memberDecl, memberDecl->mProtectionSpecifier, tokenNode); return memberDecl; } @@ -6266,7 +6261,7 @@ void BfReducer::ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, Bf while (true) { - BfTokenNode* protectionSpecifier = NULL; + BfAstNode* protectionSpecifier = NULL; BfAttributeDirective* attributes = NULL; auto child = mVisitorPos.GetNext(); if (child == NULL) @@ -6297,11 +6292,7 @@ void BfReducer::ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, Bf (token == BfToken_Public) || (token == BfToken_Internal)) { - if (protectionSpecifier != NULL) - { - Fail("Protection already specified", protectionSpecifier); - } - protectionSpecifier = tokenNode; + SetProtection(NULL, protectionSpecifier, tokenNode); mVisitorPos.MoveNext(); child = mVisitorPos.GetCurrent(); } @@ -7382,6 +7373,43 @@ BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& ta return scopedInvocationTarget; } +bool BfReducer::SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode) +{ + bool failed = false; + + if (protectionNodeRef != NULL) + { + if (auto prevToken = BfNodeDynCast(protectionNodeRef)) + { + if (((prevToken->mToken == BfToken_Protected) && (tokenNode->mToken == BfToken_Internal)) || + ((prevToken->mToken == BfToken_Internal) && (tokenNode->mToken == BfToken_Protected))) + { + auto tokenPair = mAlloc->Alloc(); + ReplaceNode(protectionNodeRef, tokenPair); + MEMBER_SET(tokenPair, mLeft, prevToken); + MEMBER_SET(tokenPair, mRight, tokenNode); + + if (tokenPair->mLeft->mSrcStart > tokenPair->mRight->mSrcStart) + { + BF_SWAP(tokenPair->mLeft, tokenPair->mRight); + } + + protectionNodeRef = tokenPair; + if (parentNode != NULL) + MoveNode(tokenPair, parentNode); + return true; + } + } + + Fail("Protection already specified", protectionNodeRef); + } + protectionNodeRef = tokenNode; + if (parentNode != NULL) + MoveNode(tokenNode, parentNode); + + return !failed; +} + BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) { if (allocToken->GetToken() == BfToken_Scope) @@ -8153,11 +8181,7 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi (token == BfToken_Private) || (token == BfToken_Internal)) { - if (typeDeclaration->mProtectionSpecifier != NULL) - { - Fail("Protection already specified", tokenNode); - } - MEMBER_SET(typeDeclaration, mProtectionSpecifier, tokenNode); + SetProtection(typeDeclaration, typeDeclaration->mProtectionSpecifier, tokenNode); } if (token == BfToken_Static) diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index cf414a89..7b9fafb6 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -176,6 +176,7 @@ public: void MoveNode(BfAstNode* srcNode, BfAstNode* newOwner); void ReplaceNode(BfAstNode* prevNode, BfAstNode* newNode); + bool SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode); BfAstNode* CreateAllocNode(BfTokenNode* newNode); BfAstNode* ReplaceTokenStarter(BfAstNode* astNode, int idx = -1); BfEnumCaseBindExpression* CreateEnumCaseBindExpression(BfTokenNode* bindToken);