소스 검색

Fixed extension initializers and dtors. [NoExtension]. Extension warning

Brian Fiete 4 년 전
부모
커밋
b6db69d2b0

+ 6 - 0
BeefLibs/corlib/src/Attribute.bf

@@ -149,6 +149,12 @@ namespace System
 	    
 	}
 
+	[AttributeUsage(.MemberAccess)]
+	public struct NoExtensionAttribute : Attribute
+	{
+	    
+	}
+
 	[AttributeUsage(.Block)]
 	public struct IgnoreErrorsAttribute : Attribute
 	{

+ 1 - 1
IDEHelper/Compiler/BfAst.h

@@ -2949,7 +2949,7 @@ public:
 	BfTokenNode* mThisToken;
 	
 	BfTokenNode* mInitializerColonToken;
-	BfInvocationExpression* mInitializer;
+	BfExpression* mInitializer;
 	
 };	BF_AST_DECL(BfConstructorDeclaration, BfMethodDeclaration);
 

+ 5 - 3
IDEHelper/Compiler/BfCompiler.cpp

@@ -395,6 +395,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 	mActionTypeDef = NULL;
 	mEnumTypeDef = NULL;
 	mFriendAttributeTypeDef = NULL;
+	mNoExtensionAttributeTypeDef = NULL;
 	mCheckedAttributeTypeDef = NULL;
 	mUncheckedAttributeTypeDef = NULL;
 	mFunctionTypeDef = NULL;
@@ -6491,14 +6492,14 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 		return typeDef;
 	};
 
-	mArray1TypeDef = _GetRequiredType("System.Array1", 1);	
-	mArray2TypeDef = _GetRequiredType("System.Array2", 1);	
+	mArray1TypeDef = _GetRequiredType("System.Array1", 1);
+	mArray2TypeDef = _GetRequiredType("System.Array2", 1);
 	mArray3TypeDef = _GetRequiredType("System.Array3", 1);
 	mArray4TypeDef = _GetRequiredType("System.Array4", 1);
 	mSpanTypeDef = _GetRequiredType("System.Span", 1);
 	mAttributeTypeDef = _GetRequiredType("System.Attribute");
 	mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute");
-	mBfObjectTypeDef = _GetRequiredType("System.Object");	
+	mBfObjectTypeDef = _GetRequiredType("System.Object");
 	mClassVDataTypeDef = _GetRequiredType("System.ClassVData");
 	mCLinkAttributeTypeDef = _GetRequiredType("System.CLinkAttribute");
 	mImportAttributeTypeDef = _GetRequiredType("System.ImportAttribute");
@@ -6516,6 +6517,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mActionTypeDef = _GetRequiredType("System.Action");
 	mEnumTypeDef = _GetRequiredType("System.Enum");
 	mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
+	mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute");
 	mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
 	mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
 	mResultTypeDef = _GetRequiredType("System.Result", 1);

+ 1 - 0
IDEHelper/Compiler/BfCompiler.h

@@ -394,6 +394,7 @@ public:
 	BfTypeDef* mDisableChecksAttributeTypeDef;
 	BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
 	BfTypeDef* mFriendAttributeTypeDef;
+	BfTypeDef* mNoExtensionAttributeTypeDef;
 	BfTypeDef* mCheckedAttributeTypeDef;
 	BfTypeDef* mUncheckedAttributeTypeDef;	
 	BfTypeDef* mStaticInitAfterAttributeTypeDef;

+ 3 - 1
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -2008,8 +2008,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 
 	if (mCurTypeDef->mTypeCode == BfTypeCode_TypeAlias)
 		needsDefaultCtor = false;
+	if (mCurTypeDef->mTypeCode == BfTypeCode_Extension)
+		needsDefaultCtor = false;
 
-	if ((needsDefaultCtor) && (!hasDefaultCtor))
+	if ((needsDefaultCtor) && ((!hasDefaultCtor)))
 	{
 		BfProtection prot = hasCtor ? BfProtection_Hidden : BfProtection_Public;
 		if (mCurTypeDef->mName == mSystem->mEmptyAtom)

+ 15 - 1
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -2167,6 +2167,13 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
 // 			if (checkMethod->mName != mMethodName)
 // 				continue;			
 
+			if ((checkMethod->mDeclaringType->IsExtension()) && (mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) &&
+				(mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoExtensionAttributeTypeDef)))
+			{
+				mModule->mAttributeState->mUsed = true;
+				continue;
+			}
+
 			if (!isDelegate)
 			{				
 				if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) ||
@@ -6408,8 +6415,15 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou
 			if (checkMethod->mIsStatic)
 				continue;
 
-			if (!mModule->IsInSpecializedSection())
+			if ((checkMethod->mDeclaringType->IsExtension()) && (mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) &&
+				(mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoExtensionAttributeTypeDef)))
 			{
+				mModule->mAttributeState->mUsed = true;
+				continue;
+			}
+
+			if (!mModule->IsInSpecializedSection())
+			{				
 				if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) ||
 					(!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, visibleProjectSet)))
 					continue;

+ 105 - 43
IDEHelper/Compiler/BfModule.cpp

@@ -14592,14 +14592,28 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly)
 {
 	// Any errors should only be shown in the actual CTOR call
 	SetAndRestoreValue<bool> prevIgnoreWrites(mIgnoreErrors, true);
-
+	
 	auto methodDef = mCurMethodInstance->mMethodDef;
 	BF_ASSERT((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorCalcAppend));
 	auto ctorDeclaration = (BfConstructorDeclaration*)methodDef->mMethodDeclaration;	
+
+	BfCustomAttributes* customAttributes = NULL;
+	defer(delete customAttributes);
+	BfInvocationExpression* ctorInvocation = NULL;
+	if (ctorDeclaration != NULL)
+	{
+		ctorInvocation = BfNodeDynCast<BfInvocationExpression>(ctorDeclaration->mInitializer);
+		if (auto attributedExpr = BfNodeDynCast<BfAttributedExpression>(ctorDeclaration->mInitializer))
+		{
+			ctorInvocation = BfNodeDynCast<BfInvocationExpression>(attributedExpr->mExpression);
+			customAttributes = GetCustomAttributes(attributedExpr->mAttributes, BfAttributeTargets_MemberAccess);
+		}
+	}
+
 	BfTypeInstance* targetType = NULL;
-	if (ctorDeclaration->mInitializer != NULL)
+	if (ctorInvocation != NULL)
 	{
-		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorDeclaration->mInitializer->mTarget);
+		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorInvocation->mTarget);
 		targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType;
 	}
 	else
@@ -14614,9 +14628,9 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly)
 		
 	BfExprEvaluator exprEvaluator(this);
 	BfResolvedArgs argValues;
-	if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL))
+	if ((ctorDeclaration != NULL) && (ctorInvocation != NULL))
 	{
-		argValues.Init(&ctorDeclaration->mInitializer->mArguments);
+		argValues.Init(&ctorInvocation->mArguments);
 	}
 	
 	//
@@ -14670,7 +14684,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly)
 	{
 		// Do it again, but without mIgnoreWrites set
 		BfResolvedArgs argValues;
-		argValues.Init(&ctorDeclaration->mInitializer->mArguments);
+		argValues.Init(&ctorInvocation->mArguments);
 		exprEvaluator.ResolveArgValues(argValues, BfResolveArgFlag_DeferParamEval);
 
 		BfFunctionBindResult bindResult;
@@ -15445,13 +15459,31 @@ void BfModule::EmitCtorBody(bool& skipBody)
 	auto ctorDeclaration = (BfConstructorDeclaration*)methodDef->mMethodDeclaration;
 	auto typeDef = mCurTypeInstance->mTypeDef;
 
+	BfCustomAttributes* customAttributes = NULL;
+	defer(delete customAttributes);
+	BfInvocationExpression* ctorInvocation = NULL;
+
+	BfAttributeState attributeState;
+	attributeState.mTarget = BfAttributeTargets_MemberAccess;
+	if (ctorDeclaration != NULL)
+	{
+		ctorInvocation = BfNodeDynCast<BfInvocationExpression>(ctorDeclaration->mInitializer);
+		if (auto attributedExpr = BfNodeDynCast<BfAttributedExpression>(ctorDeclaration->mInitializer))
+		{
+			ctorInvocation = BfNodeDynCast<BfInvocationExpression>(attributedExpr->mExpression);
+			attributeState.mCustomAttributes = GetCustomAttributes(attributedExpr->mAttributes, attributeState.mTarget);
+		}
+	}
+
+	SetAndRestoreValue<BfAttributeState*> prevAttributeState(mAttributeState, &attributeState);
+
 	// Prologue
 	mBfIRBuilder->ClearDebugLocation();
 
 	bool hadThisInitializer = false;	
-	if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL))
+	if ((ctorDeclaration != NULL) && (ctorInvocation != NULL))
 	{
-		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorDeclaration->mInitializer->mTarget);
+		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorInvocation->mTarget);
 		auto targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType;
 		if (targetToken->GetToken() == BfToken_This)
 		{
@@ -15480,8 +15512,8 @@ void BfModule::EmitCtorBody(bool& skipBody)
 	}
 
 	BfAstNode* baseCtorNode = NULL;
-	if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL) && (ctorDeclaration->mInitializer->mTarget != NULL))
-		baseCtorNode = ctorDeclaration->mInitializer->mTarget;
+	if ((ctorDeclaration != NULL) && (ctorInvocation != NULL) && (ctorInvocation->mTarget != NULL))
+		baseCtorNode = ctorInvocation->mTarget;
 	else if (methodDef->mBody != NULL)
 		baseCtorNode = methodDef->mBody;
 	else if (ctorDeclaration != NULL)
@@ -15493,10 +15525,12 @@ void BfModule::EmitCtorBody(bool& skipBody)
 	else
 		baseCtorNode = mContext->mBfObjectType->mTypeDef->mTypeDeclaration;
 
-	if ((!mCurTypeInstance->IsBoxed()) && (methodDef->mMethodType == BfMethodType_Ctor))
+	bool calledCtorNoBody = false;
+	
+	if ((!mCurTypeInstance->IsBoxed()) && (methodDef->mMethodType == BfMethodType_Ctor) && (!hadThisInitializer))
 	{		
-		// Call the root type's default ctor (with no body) to initialize its fields and call the chained ctors
-		if (methodDef->mDeclaringType->mTypeCode == BfTypeCode_Extension)
+		// Call the root type's default ctor (with no body) to initialize its fields and call the chained ctors		
+		if (mCurTypeInstance->mTypeDef->mHasCtorNoBody)
 		{
 			BfMethodDef* defaultCtor = NULL;
 
@@ -15520,6 +15554,8 @@ void BfModule::EmitCtorBody(bool& skipBody)
 				SizedArray<BfIRValue, 1> irArgs;
 				exprEvaluator.PushThis(NULL, GetThis(), moduleMethodInstance.mMethodInstance, irArgs);
 				exprEvaluator.CreateCall(moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, irArgs);
+
+				calledCtorNoBody = true;
 			}
 		}		
 	}
@@ -15533,7 +15569,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
 	{
 		// Field initializers occur in CtorNoBody methods for extensions
 	}
-	else if (!hadThisInitializer)
+	else if ((!hadThisInitializer) && (!calledCtorNoBody))
 	{
 		// If we had a 'this' initializer, that other ctor will have initialized our fields
 
@@ -15711,9 +15747,9 @@ void BfModule::EmitCtorBody(bool& skipBody)
 		if (methodDef->mBody == NULL)
 			SetIllegalSrcPos();
 	}
-	if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL))
+	if ((ctorDeclaration != NULL) && (ctorInvocation != NULL))
 	{
-		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorDeclaration->mInitializer->mTarget);
+		auto targetToken = BfNodeDynCast<BfTokenNode>(ctorInvocation->mTarget);
 		targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType;
 	}
 	else if ((mCurTypeInstance->mBaseType != NULL) && (!mCurTypeInstance->IsUnspecializedType()))
@@ -15801,9 +15837,9 @@ void BfModule::EmitCtorBody(bool& skipBody)
 		mCurMethodState->mCurAppendAlign = methodInstance->mAppendAllocAlign;
 	}
 
-	if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL) && (ctorDeclaration->mInitializer->mArguments.size() == 1) && (targetType != NULL))
+	if ((ctorDeclaration != NULL) && (ctorInvocation != NULL) && (ctorInvocation->mArguments.size() == 1) && (targetType != NULL))
 	{
-		if (auto tokenNode = BfNodeDynCast<BfUninitializedExpression>(ctorDeclaration->mInitializer->mArguments[0]))
+		if (auto tokenNode = BfNodeDynCast<BfUninitializedExpression>(ctorInvocation->mArguments[0]))
 		{
 			if (targetType == mCurTypeInstance)
 			{
@@ -15829,9 +15865,9 @@ void BfModule::EmitCtorBody(bool& skipBody)
 
 		auto autoComplete = mCompiler->GetAutoComplete();
 		auto wasCapturingMethodInfo = (autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo);
-		if ((autoComplete != NULL) && (ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL))
+		if ((autoComplete != NULL) && (ctorDeclaration != NULL) && (ctorInvocation != NULL))
 		{
-			auto invocationExpr = ctorDeclaration->mInitializer;
+			auto invocationExpr = ctorInvocation;
 			autoComplete->CheckInvocation(invocationExpr, invocationExpr->mOpenParen, invocationExpr->mCloseParen, invocationExpr->mCommas);
 		}
 
@@ -15839,9 +15875,9 @@ void BfModule::EmitCtorBody(bool& skipBody)
 		auto target = Cast(targetRefNode, GetThis(), targetThisType);
 		BfExprEvaluator exprEvaluator(this);
 		BfResolvedArgs argValues;
-		if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL))
+		if ((ctorDeclaration != NULL) && (ctorInvocation != NULL))
 		{			
-			argValues.Init(&ctorDeclaration->mInitializer->mArguments);
+			argValues.Init(&ctorInvocation->mArguments);
 			if (gDebugStuff)
 			{
 				OutputDebugStrF("Expr: %@  %d\n", argValues.mArguments->mVals, argValues.mArguments->mSize);
@@ -21367,6 +21403,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 		Fail("Interfaces cannot contain constructors", methodDeclaration);
 	}
 
+	bool foundHiddenMethod = false;
+
 	// Don't compare specialized generic methods against normal methods
 	if ((((mCurMethodInstance->mIsUnspecialized) || (mCurMethodInstance->mMethodDef->mGenericParams.size() == 0))) &&
 		(!methodDef->mIsLocalMethod))
@@ -21436,7 +21474,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 							if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType))
 								continue;
 														
-							bool silentlyAllow = false;							
+							bool silentlyAllow = false;
+							bool extensionWarn = false;
 							if (checkMethod->mDeclaringType != methodDef->mDeclaringType)
 							{								
 								if (typeInstance->IsInterface())
@@ -21445,7 +21484,21 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 										silentlyAllow = true;
 								}
 								else
-									silentlyAllow = true;
+								{
+									if ((methodDef->mDeclaringType->mProject != checkMethod->mDeclaringType->mProject) &&
+										(!checkMethod->mDeclaringType->IsExtension()))
+									{
+										foundHiddenMethod = true;
+										if ((methodDef->mMethodType == BfMethodType_Ctor) && (methodDef->mIsStatic))
+											silentlyAllow = true;
+										else if (methodDef->mIsNew)
+											silentlyAllow = true;
+										else
+											extensionWarn = true;
+									}
+									else
+										silentlyAllow = true;
+								}
 							}
 
 							if ((checkMethod->mCommutableKind == BfCommutableKind_Reverse) || (methodDef->mCommutableKind == BfCommutableKind_Reverse))
@@ -21456,7 +21509,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 								if ((!methodDef->mName.IsEmpty()) || (checkMethodInstance->mMethodDef->mIsOperator))
 								{
 									auto refNode = methodDef->GetRefNode();
-									auto bfError = Fail("Method already declared with the same parameter types", refNode, true);
+									BfError* bfError;
+									if (extensionWarn)
+										bfError = Warn(BfWarning_CS0114_MethodHidesInherited, 
+											StrFormat("This method hides a method in the root type definition. Use the 'new' keyword if the hiding was intentional. Note that this method is not callable from project '%s'.", 
+												checkMethod->mDeclaringType->mProject->mName.c_str()), refNode);
+									else
+										bfError = Fail("Method already declared with the same parameter types", refNode, true);
 									if (bfError != NULL)
 										mCompiler->mPassInstance->MoreInfo("First declaration", checkMethod->GetRefNode());
 								}
@@ -21472,8 +21531,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 			(!methodDef->mIsLocalMethod) &&
 			(!methodInstance->mIsForeignMethodDef) && (typeInstance->mBaseType != NULL) && 
 			(methodDef->mMethodType == BfMethodType_Normal) && (methodDef->mMethodDeclaration != NULL))
-		{
-			bool foundHiddenMethod = false;
+		{			
 			auto baseType = typeInstance->mBaseType;
 			while (baseType != NULL)
 			{					
@@ -21623,12 +21681,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
 
 	if (mCurTypeInstance->IsUnspecializedTypeVariation())
 		return false;
-
-	if ((mCurTypeInstance->mTypeDef->mName->ToString() == "Zornk") && (methodInstance->mMethodDef->mName == "GCMarkMembers"))
-	{
-		NOP;
-	}
-
+	
 	auto _AddVirtualDecl = [&](BfMethodInstance* declMethodInstance)
 	{
 		if (!mCompiler->mOptions.mAllowHotSwapping)
@@ -21956,13 +22009,17 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
 				{
 					methodInstance->mVirtualTableIdx = virtualMethodMatchIdx;
 
+					bool preferRootDefinition = (methodDef->mName == BF_METHODNAME_MARKMEMBERS) || (methodDef->mMethodType == BfMethodType_Dtor);
+
+					BfMethodInstance* setMethodInstance = methodInstance;
+					bool doOverride = false;
+
 					auto& overridenRef = typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod;
 					if (overridenRef.mKind != BfMethodRefKind_AmbiguousRef)
 					{
 						methodOverriden = overridenRef;
 
-						BfMethodInstance* setMethodInstance = methodInstance;
-						bool doOverride = true;
+						doOverride = true;
 						if (methodOverriden->GetOwner() == methodInstance->GetOwner())
 						{
 							bool isBetter = false;
@@ -21990,7 +22047,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
 
 								if ((isBetter) && (methodInstance->GetOwner() == methodOverriden->GetOwner()))
 								{
-									if (methodDef->mName == BF_METHODNAME_MARKMEMBERS)
+									if (preferRootDefinition)
 									{
 										// Leave the master GCMarkMember
 										isBetter = false;
@@ -22001,14 +22058,19 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
 								doOverride = isBetter;
 							}
 						}
+					}
+					else if ((preferRootDefinition) && (!methodDef->mDeclaringType->IsExtension()))
+					{
+						methodOverriden = overridenRef;
+						doOverride = true;
+					}
 
-						if (doOverride)
-						{							
-							auto declMethodInstance = (BfMethodInstance*)typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mDeclaringMethod;
-							_AddVirtualDecl(declMethodInstance);
-							setMethodInstance->mVirtualTableIdx = virtualMethodMatchIdx;
-							typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod = setMethodInstance;							
-						}
+					if (doOverride)
+					{
+						auto declMethodInstance = (BfMethodInstance*)typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mDeclaringMethod;
+						_AddVirtualDecl(declMethodInstance);
+						setMethodInstance->mVirtualTableIdx = virtualMethodMatchIdx;
+						typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod = setMethodInstance;
 					}
 				}
 

+ 28 - 1
IDEHelper/Compiler/BfReducer.cpp

@@ -9147,8 +9147,23 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 			MEMBER_SET(ctorDecl, mInitializerColonToken, endToken);
 			mVisitorPos.MoveNext();
 
+			BfAstNode* invokeAfter = ctorDecl;
 			auto nextNode = mVisitorPos.GetNext();
-			endToken = ExpectTokenAfter(ctorDecl, BfToken_This, BfToken_Base);
+
+			BfAttributeDirective* attributeDirective = NULL;
+			if (auto nextToken = BfNodeDynCast<BfTokenNode>(nextNode))
+			{
+				if (nextToken->mToken == BfToken_LBracket)
+				{
+					mVisitorPos.MoveNext();
+					attributeDirective = CreateAttributeDirective(nextToken);
+					nextNode = mVisitorPos.GetNext();
+					if (attributeDirective != NULL)
+						invokeAfter = attributeDirective;
+				}
+			}
+
+			endToken = ExpectTokenAfter(invokeAfter, BfToken_This, BfToken_Base);
 			if (endToken != NULL)
 			{
 				auto invocationExpr = CreateInvocationExpression(endToken);
@@ -9162,6 +9177,18 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 				// In process of typing - just eat identifier so we don't error out on whole method
 				MoveNode(identifierAfter, ctorDecl);
 			}
+
+			if (attributeDirective != NULL)
+			{
+				BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();
+				ReplaceNode(attributeDirective, attribExpr);
+				attribExpr->mAttributes = attributeDirective;
+				if (ctorDecl->mInitializer != NULL)
+				{
+					MEMBER_SET(attribExpr, mExpression, ctorDecl->mInitializer);
+				}				
+				MEMBER_SET(ctorDecl, mInitializer, attribExpr);
+			}
 		}
 
 		endToken = NULL;

+ 6 - 1
IDEHelper/Compiler/BfSystem.cpp

@@ -2640,6 +2640,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
 	typeDef->mIsConcrete = nextTypeDef->mIsConcrete;
 	typeDef->mIsStatic = nextTypeDef->mIsStatic;
 	typeDef->mHasAppendCtor = nextTypeDef->mHasAppendCtor;
+	typeDef->mHasCtorNoBody = nextTypeDef->mHasCtorNoBody;
 	typeDef->mHasOverrideMethods = nextTypeDef->mHasOverrideMethods;
 	typeDef->mHasExtensionMethods = nextTypeDef->mHasExtensionMethods;
 	typeDef->mIsOpaque = nextTypeDef->mIsOpaque;
@@ -2744,6 +2745,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
 		typeDef->mIsConcrete = partialTypeDef->mIsConcrete;
 		typeDef->mIsStatic = partialTypeDef->mIsStatic;
 		typeDef->mHasAppendCtor = partialTypeDef->mHasAppendCtor;		
+		typeDef->mHasCtorNoBody = partialTypeDef->mHasCtorNoBody;
 		typeDef->mHasExtensionMethods = partialTypeDef->mHasExtensionMethods;
 		typeDef->mHasOverrideMethods = partialTypeDef->mHasOverrideMethods;
 
@@ -2780,7 +2782,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
 	typeDef->mIsAbstract |= partialTypeDef->mIsAbstract;
 	typeDef->mIsConcrete |= partialTypeDef->mIsConcrete;
 	typeDef->mIsStatic |= partialTypeDef->mIsStatic;
-	typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor;
+	typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor;	
 	typeDef->mHasExtensionMethods |= partialTypeDef->mHasExtensionMethods;
 	typeDef->mHasOverrideMethods |= partialTypeDef->mHasOverrideMethods;
 	typeDef->mProtection = BF_MIN(typeDef->mProtection, partialTypeDef->mProtection);	
@@ -2956,6 +2958,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef)
 			anyHasFieldInitializers = true;			
 			if (!isExtension)
 				primaryHasFieldInitializers = true;				
+			nextRevision->mHasCtorNoBody = true;
 			auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_CtorNoBody, BfProtection_Protected, false, "");
 			methodDef->mDeclaringType = partialTypeDef;
 			methodDef->mIsMutating = true;
@@ -2964,6 +2967,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef)
 
 	if ((anyHasFieldInitializers) && (!primaryHasFieldInitializers))
 	{
+		nextRevision->mHasCtorNoBody = true;
 		auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_CtorNoBody, BfProtection_Protected, false, "");
 		methodDef->mDeclaringType = primaryDef;
 		methodDef->mIsMutating = true;
@@ -2991,6 +2995,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef)
 
 	if ((allHasMethods[0][0].mDtor == 0) && (allHasMethods[1][0].mDtor > 1))
 	{
+		nextRevision->mDtorDef = NULL;
 		auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_Dtor, BfProtection_Public, false, "");
 		methodDef->mDeclaringType = primaryDef;
 	}

+ 2 - 0
IDEHelper/Compiler/BfSystem.h

@@ -919,6 +919,7 @@ public:
 	bool mIsConcrete;
 	bool mIsStatic;	
 	bool mHasAppendCtor;
+	bool mHasCtorNoBody;
 	bool mHasExtensionMethods;
 	bool mHasOverrideMethods;	
 	bool mIsOpaque;
@@ -956,6 +957,7 @@ public:
 		mIsClosure = false;
 		mIsStatic = false;
 		mHasAppendCtor = false;
+		mHasCtorNoBody = false;
 		mHasExtensionMethods = false;
 		mHasOverrideMethods = false;
 		mIsOpaque = false;

+ 23 - 4
IDEHelper/Tests/LibA/src/LibA0.bf

@@ -1,5 +1,6 @@
 using System;
 using System.Collections;
+using System.Diagnostics;
 
 namespace LibA
 {
@@ -90,11 +91,18 @@ namespace LibA
 
 class LibClassA
 {
-	public int32 mA = GetVal(7, "LibA.LibClassA.mA");
+	public int32 mA = GetVal(7, 10, "LibA.LibClassA.mA");
+
+	public static int32 sMagic = 1;
+
+	public static this()
+	{
+		sMagic += 10;
+	}
 
 	public this()
 	{
-		PrintF("LibA.LibClassA()\n");
+		Debug.WriteLine("LibA.LibClassA()\n");
 		mA += 100;
 	}
 
@@ -103,9 +111,15 @@ class LibClassA
 		mA += a;
 	}
 
-	public static int32 GetVal(int32 val, String str)
+	public ~this()
+	{
+		sMagic += 20;
+	}
+
+	public static int32 GetVal(int32 val, int32 magic, String str)
 	{
-		PrintF("GetVal: %s\n", str.CStr());
+		Debug.WriteLine("GetVal: {}", str);
+		sMagic += magic;
 		return val;
 	}
 
@@ -118,6 +132,11 @@ class LibClassA
 	{
 		return 30;
 	}
+
+	public static LibClassA Create()
+	{
+		return new LibClassA();
+	}
 }
 
 class LibClassB

+ 13 - 3
IDEHelper/Tests/LibB/src/LibB0.bf

@@ -14,15 +14,25 @@ namespace LibB
 
 extension LibClassA
 {
-	public int32 mB = GetVal(8, "LibB.LibClassA.mB");
+	public int32 mB = GetVal(8, 100, "LibB.LibClassA.mB");
 
-	public this()
+	public static this()
+	{
+		sMagic += 100;
+	}
+
+	public ~this()
+	{
+		sMagic += 200;
+	}
+
+	public new this() : [NoExtension]this()
 	{
 		PrintF("LibB.LibClassA()\n");
 		mB += 100;
 	}
 
-	public this(int32 a)
+	public new this(int32 a)
 	{
 		PrintF("LibB.LibClassA(int32)\n");
 		mB += 1000;

+ 11 - 1
IDEHelper/Tests/LibC/src/LibC0.bf

@@ -12,7 +12,17 @@ namespace LibC
 
 extension LibClassA
 {
-	public int32 mB = GetVal(13, "LibC.LibClassA.mB");
+	public int32 mB = GetVal(13, 1000, "LibC.LibClassA.mB");
+
+	public static this()
+	{
+		sMagic += 1000;
+	}
+
+	public ~this()
+	{
+		sMagic += 2000;
+	}
 
 	public this(int8 i8)
 	{

+ 3 - 3
IDEHelper/Tests/TestsB/src/TestsB0.bf

@@ -2,15 +2,15 @@ using System;
 
 extension LibClassA
 {
-	public int32 mC = GetVal(9, "TestsB.LibClassA.mC");
+	public int32 mC = GetVal(9, 10000, "TestsB.LibClassA.mC");
 
-	public this()
+	public new this()
 	{
 		PrintF("TestB.LibClassA()\n");
 		mB += 10000;
 	}
 
-	public int GetVal2()
+	public new int GetVal2()
 	{
 		return 11;
 	}

+ 12 - 1
IDEHelper/Tests/src/Extensions.bf

@@ -227,21 +227,32 @@ namespace Tests
 		[Test]
 		public static void TestSharedData()
 		{
+			Test.Assert(LibClassA.sMagic == 1111);
+
 			LibClassA ca = scope LibClassA();
-			Test.Assert(ca.mA == 7);
+			Test.Assert(LibClassA.sMagic == 2221);
+			Test.Assert(ca.mA == 107);
 			Test.Assert(ca.LibB_GetB() == 108);
 			Test.Assert(ca.LibC_GetB() == 13);
 			Test.Assert(ca.GetVal2() == 9);
 
 			ca = scope LibClassA(12345);
+			Test.Assert(LibClassA.sMagic == 3331);
 			Test.Assert(ca.mA == 7);
 			Test.Assert(ca.LibB_GetB() == 1008);
 			Test.Assert(ca.LibC_GetB() == 13);
 
 			ca = scope LibClassA((int8)2);
+			Test.Assert(LibClassA.sMagic == 4441);
 			Test.Assert(ca.mA == 7);
 			Test.Assert(ca.LibB_GetB() == 8);
 			Test.Assert(ca.LibC_GetB() == 30013);
+
+			ca = LibClassA.Create();
+			Test.Assert(LibClassA.sMagic == 5551);
+			Test.Assert(ca.mA == 107);
+			delete ca;
+			Test.Assert(LibClassA.sMagic == 7771);
 		}
 
 		[Test]