diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index c62622f0..2313e8bd 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -236,6 +236,11 @@ void BfStructuralVisitor::Visit(BfTypeReference* typeRef) Visit(typeRef->ToBase()); } +void BfStructuralVisitor::Visit(BfInlineTypeReference* typeRef) +{ + Visit(typeRef->ToBase()); +} + void BfStructuralVisitor::Visit(BfNamedTypeReference* typeRef) { Visit(typeRef->ToBase()); @@ -1233,14 +1238,21 @@ void BfBlock::SetSize(int wantSize) ////////////////////////////////////////////////////////////////////////// +bool BfTypeDeclaration::IsAnonymous() +{ + return (mAnonymousName != NULL); +} + +////////////////////////////////////////////////////////////////////////// + bool BfTypeReference::IsNamedTypeReference() { - return IsA() || IsA(); + return IsA() || IsA() || IsA(); } bool BfTypeReference::IsTypeDefTypeReference() { - return IsA() || IsA() || IsA(); + return IsA() || IsA() || IsA() || IsA(); } String BfTypeReference::ToCleanAttributeString() @@ -1657,6 +1669,11 @@ bool Beefy::BfTokenIsKeyword(BfToken token) return (token >= BfToken_Abstract) && (token <= BfToken_Yield); } +bool Beefy::BfTokenIsTypeDecl(BfToken token) +{ + return (token == BfToken_Struct) || (token == BfToken_Class) || (token == BfToken_Interface) || (token == BfToken_Enum); +} + BfBinaryOp Beefy::BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp) { switch (assignmentOp) diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index a9a87f23..5b24e794 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -381,6 +381,7 @@ class BfReturnStatement; class BfYieldStatement; class BfUnaryOperatorExpression; class BfBinaryOperatorExpression; +class BfInlineTypeReference; class BfArrayTypeRef; class BfPointerTypeRef; class BfDotTypeReference; @@ -549,6 +550,7 @@ public: virtual void Visit(BfInitializerExpression* collectionInitExpr); virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr); virtual void Visit(BfTypeReference* typeRef); + virtual void Visit(BfInlineTypeReference* typeRef); virtual void Visit(BfNamedTypeReference* typeRef); virtual void Visit(BfQualifiedTypeReference* qualifiedType); virtual void Visit(BfDotTypeReference* typeRef); @@ -2147,6 +2149,7 @@ public: ASTREF(BfTokenNode*) mCtorCloseParen; BfSizedArray mArguments; BfSizedArray mCommas; + bool mIsMultiUse; // For anonymous types and also another use like a field decl ASTREF(BfAttributeDirective*) mNextAttribute; @@ -2442,10 +2445,15 @@ public: BfGenericParamsDeclaration* mGenericParams; BfGenericConstraintsDeclaration* mGenericConstraintsDeclaration; bool mIgnoreDeclaration; + char* mAnonymousName; BfTokenNode* mColonToken; BfSizedArray mBaseClasses; BfSizedArray mBaseClassCommas; + BfSizedArray mAnonymousTypes; + + bool IsAnonymous(); + }; BF_AST_DECL(BfTypeDeclaration, BfAstNode); class BfTypeAliasDeclaration : public BfTypeDeclaration @@ -2468,6 +2476,14 @@ public: String ToCleanAttributeString(); }; BF_AST_DECL(BfTypeReference, BfAstNode); +class BfInlineTypeReference : public BfTypeReference +{ +public: + BF_AST_TYPE(BfInlineTypeReference, BfTypeReference); + + BfTypeDeclaration* mTypeDeclaration; +}; BF_AST_DECL(BfInlineTypeReference, BfTypeReference); + class BfDirectTypeReference : public BfTypeReference { public: @@ -3568,6 +3584,7 @@ public: const char* BfTokenToString(BfToken token); bool BfTokenIsKeyword(BfToken token); +bool BfTokenIsTypeDecl(BfToken token); BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp); BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp); BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp); diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 372f9829..8a5f4902 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -223,6 +223,7 @@ BfAutoComplete::BfAutoComplete(BfResolveType resolveType, bool doFuzzyAutoComple BfAutoComplete::~BfAutoComplete() { Clear(); + RemoveMethodMatchInfo(); } void BfAutoComplete::SetModule(BfModule* module) diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 79c71ada..c0e7a8d8 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -795,10 +795,16 @@ void BfDefBuilder::Visit(BfMethodDeclaration* methodDeclaration) } } -void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef) +void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef, bool checkReturnType) { - while (attributes != NULL) + if (checkReturnType) { + if (auto inlineTypeRef = BfNodeDynCast(methodDef->mReturnTypeRef)) + ParseAttributes(inlineTypeRef->mTypeDeclaration->mAttributes, methodDef, false); + } + + while (attributes != NULL) + { if (attributes->mAttributeTypeRef != NULL) { auto typeRefName = attributes->mAttributeTypeRef->ToCleanAttributeString(); @@ -1434,13 +1440,11 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) } BF_ASSERT(typeDeclaration->GetSourceData() == mCurSource->mSourceData); - - if ((typeDeclaration->mTypeNode != NULL) && (typeDeclaration->mNameNode == NULL)) - return; - + /*if (typeDeclaration->mNameNode != NULL) OutputDebugStrF("Decl: %s\n", typeDeclaration->mNameNode->ToString().c_str());*/ + bool isAnonymous = typeDeclaration->IsAnonymous(); bool isAutoCompleteTempType = false; if (mResolvePassData != NULL) { @@ -1511,10 +1515,17 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) } if (typeDeclaration->mNameNode == NULL) { - // Global - mCurTypeDef->mName = mSystem->mGlobalsAtom; - mCurTypeDef->mName->Ref(); - BF_ASSERT(mCurTypeDef->mSystem != NULL); + if (typeDeclaration->mStaticSpecifier != NULL) + { + // Global + mCurTypeDef->mName = mSystem->mGlobalsAtom; + mCurTypeDef->mName->Ref(); + BF_ASSERT(mCurTypeDef->mSystem != NULL); + } + else + { + mCurTypeDef->mName = mSystem->GetAtom(typeDeclaration->mAnonymousName); + } } else { @@ -1527,7 +1538,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) BfLogSys(mCurSource->mSystem, "DefBuilder %p %p TypeDecl:%s\n", mCurTypeDef, mCurSource, mCurTypeDef->mName->ToString().mPtr); - mCurTypeDef->mProtection = (outerTypeDef == NULL) ? BfProtection_Public : BfProtection_Private; + mCurTypeDef->mProtection = ((outerTypeDef == NULL) || (isAnonymous)) ? BfProtection_Public : BfProtection_Private; if (typeDeclaration->mProtectionSpecifier != NULL) { if ((outerTypeDef == NULL) && @@ -1956,6 +1967,11 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) } } + for (auto& anonTypeDecl : typeDeclaration->mAnonymousTypes) + { + VisitChildNoRef(anonTypeDecl); + } + FinishTypeDef(mCurTypeDef->mTypeCode == BfTypeCode_Enum); // Map methods into the correct index from previous revision diff --git a/IDEHelper/Compiler/BfDefBuilder.h b/IDEHelper/Compiler/BfDefBuilder.h index 15ef96e1..24566890 100644 --- a/IDEHelper/Compiler/BfDefBuilder.h +++ b/IDEHelper/Compiler/BfDefBuilder.h @@ -56,7 +56,7 @@ public: static void AddParam(BfMethodDef* methodDef, BfTypeReference* typeRef, const StringImpl& paramName); BfTypeDef* ComparePrevTypeDef(BfTypeDef* prevTypeDef, BfTypeDef* checkTypeDef); void FinishTypeDef(bool wantsToString); - void ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef); + void ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef, bool checkReturnType = true); void ParseAttributes(BfAttributeDirective* attributes, BfTypeDef* typeDef); BfMethodDef* CreateMethodDef(BfMethodDeclaration* methodDecl, BfMethodDef* outerMethodDef = NULL); BfError* Fail(const StringImpl& errorStr, BfAstNode* refNode); diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index 8a18b5e5..7bd8ec07 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -325,6 +325,13 @@ void BfElementVisitor::Visit(BfTypeReference* typeRef) Visit(typeRef->ToBase()); } +void BfElementVisitor::Visit(BfInlineTypeReference* typeRef) +{ + Visit(typeRef->ToBase()); + + VisitChild(typeRef->mTypeDeclaration); +} + void BfElementVisitor::Visit(BfNamedTypeReference* typeRef) { Visit(typeRef->ToBase()); diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index 948e260d..3802caa8 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -51,6 +51,7 @@ public: virtual void Visit(BfInitializerExpression* initExpr); virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr); virtual void Visit(BfTypeReference* typeRef); + virtual void Visit(BfInlineTypeReference* typeRef); virtual void Visit(BfNamedTypeReference* typeRef); virtual void Visit(BfQualifiedTypeReference* qualifiedType); virtual void Visit(BfDotTypeReference* typeRef); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 2d68e7c2..86dcd5d1 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2350,7 +2350,7 @@ bool BfModule::TryLocalVariableInit(BfLocalVariable* localVar) void BfModule::LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit) { BfAstNode* localNameNode = localVar->mNameNode; - if (localVar->mIsThis) + if ((localVar->mIsThis) && (mCurMethodInstance != NULL)) { localNameNode = mCurMethodInstance->mMethodDef->GetRefNode(); } @@ -12137,7 +12137,7 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con return mBfIRBuilder->CreateConst(constant, constHolder); } -void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget) +void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget, bool force) { if (attrTarget == BfAttributeTargets_SkipValidate) return; @@ -12149,6 +12149,9 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf if ((customAttribute.mType->mAttributeData->mAttributeTargets & attrTarget) == 0) { + if ((customAttribute.mIsMultiUse) && (!force)) + continue; + Fail(StrFormat("Attribute '%s' is not valid on this declaration type. It is only valid on %s.", customAttribute.GetRefNode()->ToString().c_str(), GetAttributesTargetListString(customAttribute.mType->mAttributeData->mAttributeTargets).c_str()), customAttribute.mRef->mAttributeTypeRef); // CS0592 } @@ -12222,6 +12225,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri customAttribute.mAwaitingValidation = true; customAttribute.mDeclaringType = activeTypeDef; customAttribute.mRef = attributesDirective; + customAttribute.mIsMultiUse = attributesDirective->mIsMultiUse; if (attributesDirective->mAttrOpenToken != NULL) targetOverride = (BfAttributeTargets)0; @@ -23430,7 +23434,7 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) auto typeInstance = methodInstance->GetOwner(); if (typeInstance->IsInstanceOf(mCompiler->mValueTypeTypeDef)) - return; + return; BfTypeState typeState(typeInstance); SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); @@ -23458,7 +23462,7 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) if ((methodInstance == methodInstance->mMethodInstanceGroup->mDefault) && (methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes != NULL)) { - // Take over prevoiusly-generated custom attributes + // Take over previously-generated custom attributes methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes = methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes; methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes = NULL; } @@ -23479,7 +23483,55 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) } } - customAttributes = methodInstance->GetCustomAttributes(); + if (methodDeclaration != NULL) + { + if (auto inlineTypeRef = BfNodeDynCast(methodDeclaration->mReturnType)) + { + if (inlineTypeRef->mTypeDeclaration->mAttributes != NULL) + { + // Apply multiuse attributes from anonymous return type + auto returnType = ResolveTypeRef(inlineTypeRef); + if ((returnType != NULL) && (returnType->ToTypeInstance())) + { + auto returnTypeInst = returnType->ToTypeInstance(); + if ((returnTypeInst->IsAnonymous()) && (returnTypeInst->mCustomAttributes != NULL)) + { + bool hasPendingAttributes = false; + for (const auto& customAttribute : returnTypeInst->mCustomAttributes->mAttributes) + { + if (customAttribute.mAwaitingValidation) + { + hasPendingAttributes = true; + break; + } + } + + if (hasPendingAttributes) + { + if (methodInstance->GetMethodInfoEx()->mMethodCustomAttributes == NULL) + methodInstance->mMethodInfoEx->mMethodCustomAttributes = new BfMethodCustomAttributes(); + + if (methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes == NULL) + methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes = new BfCustomAttributes(); + + for (const auto& customAttribute : returnTypeInst->mCustomAttributes->mAttributes) + { + if (!customAttribute.mAwaitingValidation) + continue; + + BfCustomAttribute copiedCustomAttribute = customAttribute; + copiedCustomAttribute.mIsMultiUse = false; + methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes->mAttributes.Add(copiedCustomAttribute); + } + ValidateCustomAttributes(methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes, attrTarget); + } + } + } + } + } + } + + customAttributes = methodInstance->GetCustomAttributes(); if (customAttributes == NULL) { auto owner = methodInstance->GetOwner(); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 8e96ec9a..c0f7a98e 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1676,7 +1676,7 @@ public: bool HasUnactializedConstant(BfConstant* constant, BfIRConstHolder* constHolder); BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false); - void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget); + void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget, bool force = false); void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 7e2c63a4..36a7956a 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -5077,10 +5077,13 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy // Handled elsewhere } else - { + { SetAndRestoreValue prevTypeRef(mContext->mCurTypeState->mCurFieldDef, fieldDef); + fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->GetFieldDeclaration()->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field); + } - fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->GetFieldDeclaration()->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field); + if (fieldInstance->mCustomAttributes != NULL) + { for (auto customAttr : fieldInstance->mCustomAttributes->mAttributes) { if (TypeToString(customAttr.mType) == "System.ThreadStaticAttribute") @@ -5094,6 +5097,38 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } + if ((fieldInstance->mResolvedType != NULL) && (fieldInstance->mResolvedType->IsTypeInstance()) && (fieldInstance->mResolvedType->ToTypeInstance()->IsAnonymous())) + { + auto fieldTypeInst = fieldInstance->mResolvedType->ToTypeInstance(); + if ((fieldTypeInst->IsAnonymous()) && (fieldTypeInst->mCustomAttributes != NULL)) + { + bool hasPendingAttributes = false; + for (const auto& customAttribute : fieldTypeInst->mCustomAttributes->mAttributes) + { + if (customAttribute.mAwaitingValidation) + { + hasPendingAttributes = true; + break; + } + } + + if (hasPendingAttributes) + { + fieldInstance->mCustomAttributes = new BfCustomAttributes(); + for (const auto& customAttribute : fieldTypeInst->mCustomAttributes->mAttributes) + { + if (!customAttribute.mAwaitingValidation) + continue; + + BfCustomAttribute copiedCustomAttribute = customAttribute; + copiedCustomAttribute.mIsMultiUse = false; + fieldInstance->mCustomAttributes->mAttributes.Add(copiedCustomAttribute); + } + ValidateCustomAttributes(fieldInstance->mCustomAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field); + } + } + } + if (resolvedFieldType == NULL) { if ((underlyingType != NULL) || (typeInstance->IsPayloadEnum())) @@ -8445,6 +8480,7 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu BfNamedTypeReference* namedTypeRef = NULL; BfGenericInstanceTypeRef* genericTypeRef = NULL; BfDirectStrTypeReference* directStrTypeRef = NULL; + BfInlineTypeReference* inlineTypeRef = NULL; BfIdentifierNode* identifierNode = NULL; if ((namedTypeRef = BfNodeDynCast(typeRef))) { @@ -8463,17 +8499,24 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu { // } + else if ((inlineTypeRef = BfNodeDynCastExact(typeRef))) + { + // + } - BF_ASSERT((identifierNode != NULL) || (namedTypeRef != NULL) || (directStrTypeRef != NULL)); + BF_ASSERT((identifierNode != NULL) || (namedTypeRef != NULL) || (directStrTypeRef != NULL) || (inlineTypeRef != NULL)); auto usedOuterType = outerType; if (nestedTypeDef == NULL) { + String tempStr; StringView findName; if (namedTypeRef != NULL) findName = namedTypeRef->mNameNode->ToStringView(); else if (identifierNode != NULL) findName = identifierNode->ToStringView(); + else if (inlineTypeRef != NULL) + findName = inlineTypeRef->mTypeDeclaration->mAnonymousName; else findName = directStrTypeRef->mTypeName; @@ -10468,17 +10511,18 @@ BfTypeDef* BfModule::FindTypeDef(BfTypeReference* typeRef, BfTypeInstance* typeI if (auto elementedType = BfNodeDynCast(typeRef)) return FindTypeDef(elementedType->mElementType, typeInstanceOverride, error); - BF_ASSERT(typeRef->IsA() || typeRef->IsA() || typeRef->IsA()); + BF_ASSERT(typeRef->IsA() || typeRef->IsA() || typeRef->IsA() || typeRef->IsA()); auto namedTypeRef = BfNodeDynCast(typeRef); StringView findNameStr; if (namedTypeRef != NULL) findNameStr = namedTypeRef->mNameNode->ToStringView(); else - { - auto directStrTypeDef = BfNodeDynCastExact(typeRef); - if (directStrTypeDef != NULL) + { + if (auto directStrTypeDef = BfNodeDynCastExact(typeRef)) findNameStr = directStrTypeDef->mTypeName; + else if (auto inlineTypeRef = BfNodeDynCastExact(typeRef)) + findNameStr = inlineTypeRef->mTypeDeclaration->mAnonymousName; else BFMODULE_FATAL(this, "Error?"); } @@ -10943,7 +10987,7 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po { Fail("Invalid use of 'var ref'. Generally references are generated with a 'var' declaration with 'ref' applied to the initializer", typeRef); return NULL; - } + } if (mNoResolveGenericParams) resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_NoResolveGenericParam); @@ -10989,13 +11033,16 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po // Check generics first auto namedTypeRef = BfNodeDynCastExact(typeRef); auto directStrTypeRef = BfNodeDynCastExact(typeRef); - if (((namedTypeRef != NULL) && (namedTypeRef->mNameNode != NULL)) || (directStrTypeRef != NULL)) + auto inlineStrTypeRef = BfNodeDynCastExact(typeRef); + if (((namedTypeRef != NULL) && (namedTypeRef->mNameNode != NULL)) || (directStrTypeRef != NULL) || (inlineStrTypeRef != NULL)) { StringView findName; if (namedTypeRef != NULL) findName = namedTypeRef->mNameNode->ToStringView(); - else + else if (directStrTypeRef != NULL) findName = directStrTypeRef->mTypeName; + else + findName = inlineStrTypeRef->mTypeDeclaration->mAnonymousName; if (findName == "Self") { BfType* selfType = mCurTypeInstance; diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index f6cc7d92..164ec548 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -105,6 +105,38 @@ return 0; ////////////////////////////////////////////////////////////////////////// +static CritSect gParseFileDataCrit; +static Array gFreeIds; +static int gCurFreeId; + +int BfParseFileData::GetUniqueId(int idx) +{ + AutoCrit autoCrit(gParseFileDataCrit); + while (idx >= mUniqueIDList.size()) + { + if (!gFreeIds.IsEmpty()) + { + mUniqueIDList.Add(gFreeIds.back()); + gFreeIds.pop_back(); + } + else + mUniqueIDList.Add(gCurFreeId++); + } + return mUniqueIDList[idx]; +} + +BfParseFileData::~BfParseFileData() +{ + if (!mUniqueIDList.IsEmpty()) + { + AutoCrit autoCrit(gParseFileDataCrit); + for (auto id : mUniqueIDList) + gFreeIds.Add(id); + } +} + +////////////////////////////////////////////////////////////////////////// + BfParserCache* Beefy::gBfParserCache = NULL; bool BfParserCache::DataEntry::operator==(const LookupEntry& lookup) const @@ -201,14 +233,39 @@ BfParserData::BfParserData() mCharIdData = NULL; mUniqueParser = NULL; mDidReduce = false; + mParseFileData = NULL; } BfParserData::~BfParserData() { + if (mParseFileData != NULL) + { + BF_ASSERT(mParseFileData->mRefCount >= 0); + mParseFileData->mRefCount--; + if (mParseFileData->mRefCount == 0) + { + delete mParseFileData; + gBfParserCache->mParseFileDataMap.Remove(mFileName); + } + } + delete[] mJumpTable; delete[] mCharIdData; } +void BfParserData::InitFileData() +{ + BF_ASSERT(mParseFileData == NULL); + + BfParseFileData** valuePtr = NULL; + if (gBfParserCache->mParseFileDataMap.TryAdd(mFileName, NULL, &valuePtr)) + { + *valuePtr = new BfParseFileData(); + } + mParseFileData = *valuePtr; + mParseFileData->mRefCount++; +} + int BfParserData::GetCharIdAtIndex(int findIndex) { if (mCharIdData == NULL) @@ -328,7 +385,7 @@ void BfParserData::Deref() mRefCount--; BF_ASSERT(mRefCount >= 0); if (mRefCount == 0) - { + { AutoCrit autoCrit(gBfParserCache->mCritSect); BfParserCache::DataEntry dataEntry; dataEntry.mParserData = this; @@ -413,6 +470,8 @@ BfParser::~BfParser() } else if (mParserData->mRefCount == 0) { + + // Just never got added to the cache delete mParserData; } @@ -510,6 +569,7 @@ void BfParser::Init(uint64 cacheHash) mParserData = new BfParserData(); mSourceData = mParserData; mParserData->mFileName = mFileName; + mParserData->InitFileData(); if (mDataId != -1) mParserData->mDataId = mDataId; else diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index cab5bb04..c01f9cd2 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -62,6 +62,22 @@ enum MaybeBool MaybeBool_True = 1, }; +class BfParseFileData +{ +public: + Array mUniqueIDList; + int mRefCount; + +public: + BfParseFileData() + { + mRefCount = 0; + } + ~BfParseFileData(); + + int GetUniqueId(int idx); +}; + class BfParserData : public BfSourceData { public: @@ -81,8 +97,9 @@ public: OwnedVector mStringLiterals; Dictionary mWarningEnabledChanges; std::set mUnwarns; + BfParseFileData* mParseFileData; bool mFailed; // Don't cache if there's a warning or an error - bool mDidReduce; + bool mDidReduce; public: BfParserData(); @@ -94,6 +111,7 @@ public: return this; } + void InitFileData(); virtual BfParser* ToParser() override; int GetCharIdAtIndex(int findIndex); void GetLineCharAtIdx(int idx, int& line, int& lineChar); @@ -130,6 +148,7 @@ public: int mRefCount; BfAstAllocManager mAstAllocManager; HashSet mEntries; + Dictionary mParseFileDataMap; public: BfParserCache(); diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 200202a6..603cf882 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -47,6 +47,7 @@ BfReducer::BfReducer() mSystem = NULL; mResolvePassData = NULL; mMethodDepth = 0; + mCurUniqueIdx = 0; mDocumentCheckIdx = 0; mTypeMemberNodeStart = NULL; } @@ -403,6 +404,39 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int mVisitorPos.mReadPos = startNode; return true; } + else if ((checkToken == BfToken_Struct) || (checkToken == BfToken_Class) || (checkToken == BfToken_Interface) || (checkToken == BfToken_Enum)) + { + checkIdx++; + auto nextNode = mVisitorPos.Get(checkIdx); + if (auto block = BfNodeDynCast(nextNode)) + { + if (outEndNode != NULL) + *outEndNode = checkIdx; + return true; + } + + if (auto tokenNode = BfNodeDynCast(nextNode)) + { + if (tokenNode->mToken == BfToken_Colon) + { + while (true) + { + checkIdx++; + auto checkNode = mVisitorPos.Get(checkIdx); + if (checkNode == NULL) + return false; + if (auto block = BfNodeDynCast(checkNode)) + { + if (outEndNode != NULL) + *outEndNode = checkIdx; + return true; + } + } + } + } + + return false; + } else return false; } @@ -4360,6 +4394,7 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS ReplaceNode(typeRef, methodDecl); methodDecl->mDocumentation = FindDocumentation(methodDecl); methodDecl->mReturnType = typeRef; + CheckMultiuseAttributeTypeRef(methodDecl->mReturnType); BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); @@ -5105,6 +5140,71 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF if ((createTypeRefFlags & CreateTypeRefFlags_EarlyExit) != 0) return delegateTypeRef; } + else if ((BfTokenIsTypeDecl(token)) || (token == BfToken_LBracket)) + { + BfAttributeDirective* attributes = NULL; + if (token == BfToken_LBracket) + { + attributes = CreateAttributeDirective(tokenNode); + if (attributes == NULL) + return NULL; + mVisitorPos.MoveNext(); + bool isValid = false; + + auto nextNode = mVisitorPos.GetCurrent(); + tokenNode = BfNodeDynCast(nextNode); + if (tokenNode != NULL) + { + token = tokenNode->mToken; + if (BfTokenIsTypeDecl(token)) + isValid = true; + } + if (!isValid) + { + AddErrorNode(attributes); + return NULL; + } + } + + bool attribsApply = false; + if ((mTypeMemberNodeStart != NULL) && (mTypeMemberNodeStart->mSrcEnd == tokenNode->mTriviaStart)) + attribsApply = true; + auto typeDeclNode = CreateTopLevelObject(tokenNode, attributes, attribsApply ? mTypeMemberNodeStart : NULL, true); + if (typeDeclNode == NULL) + { + if (attributes != NULL) + AddErrorNode(attributes); + return NULL; + } + + auto typeDecl = BfNodeDynCast(typeDeclNode); + if (typeDecl == NULL) + { + if (attributes != NULL) + AddErrorNode(attributes); + AddErrorNode(typeDeclNode); + return NULL; + } + + String name; + auto parserData = typeDecl->GetParserData(); + name = "Anon_"; + + auto parseFileData = parserData->mParseFileData; + int uniqueId = parseFileData->GetUniqueId(mCurUniqueIdx++); + name += StrFormat("%d", uniqueId); + + int len = (int)name.length() + 1; + typeDecl->mAnonymousName = (char*)mAlloc->AllocBytes(len); + memcpy(typeDecl->mAnonymousName, name.c_str(), len); + + if (mCurTypeState != NULL) + mCurTypeState->mAnonymousTypeDecls.Add(typeDecl); + auto typeRef = mAlloc->Alloc(); + ReplaceNode(typeDecl, typeRef); + typeRef->mTypeDeclaration = typeDecl; + return typeRef; + } else if ((token == BfToken_Comptype) || (token == BfToken_Decltype)) { auto declTypeRef = mAlloc->Alloc(); @@ -5881,6 +5981,12 @@ BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode, Create (checkNode->IsA()) || (checkNode->IsA())) { + if (auto varDecl = BfNodeDynCast(checkNode)) + { + if (CheckInlineTypeRefAttribute(varDecl->mTypeRef, attrib)) + return BfNodeDynCast(stmt); + } + BfAttributedStatement* attribStmt = mAlloc->Alloc(); ReplaceNode(attrib, attribStmt); attribStmt->mAttributes = attrib; @@ -6169,6 +6275,8 @@ BfFieldDeclaration* BfReducer::CreateFieldDeclaration(BfTokenNode* tokenNode, Bf MoveNode(fieldDeclaration->mNameNode, fieldDeclaration); //mVisitorPos.MoveNext(); } + CheckMultiuseAttributeTypeRef(fieldDeclaration->mTypeRef); + BfToken token = tokenNode->GetToken(); if (token == BfToken_AssignEquals) { @@ -6273,6 +6381,26 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i Fail("Invalid target for attributes", memberNode); return memberNode; } + + memberNode->mTriviaStart = attributes->mTriviaStart; + memberNode->mSrcStart = attributes->mSrcStart; + + if (auto fieldDecl = BfNodeDynCast(member)) + { + if (CheckInlineTypeRefAttribute(fieldDecl->mTypeRef, attributes)) + { + return member; + } + } + + if (auto methodDecl = BfNodeDynCast(member)) + { + if (CheckInlineTypeRefAttribute(methodDecl->mReturnType, attributes)) + { + return member; + } + } + ReplaceNode(attributes, member); member->mAttributes = attributes; @@ -6291,6 +6419,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i if (typeRef == NULL) return operatorDecl; MEMBER_SET_CHECKED(operatorDecl, mReturnType, typeRef); + CheckMultiuseAttributeTypeRef(operatorDecl->mReturnType); operatorDecl->mIsConvOperator = true; ParseMethod(operatorDecl, ¶ms, &commas); @@ -7061,10 +7190,19 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept } } + if ((token == BfToken_Struct) || (token == BfToken_Class) || (token == BfToken_Interface) || (token == BfToken_Enum)) + { + int endNodeIdx = -1; + if (IsTypeReference(node, BfToken_None, -1, &endNodeIdx)) + { + isTypeRef = true; + } + } + if ((token == BfToken_LBracket) && (depth > 0)) { - Fail("Unexpected custom attribute", node); - return NULL; + // The only valid option is an attributed type reference + isTypeRef = true; } if (isTypeRef) @@ -7218,6 +7356,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept ReplaceNode(nameIdentifier, methodDeclaration); methodDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart); MEMBER_SET(methodDeclaration, mReturnType, typeRef); + CheckMultiuseAttributeTypeRef(methodDeclaration->mReturnType); MEMBER_SET(methodDeclaration, mExplicitInterface, explicitInterface); MEMBER_SET(methodDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot); return methodDeclaration; @@ -7235,6 +7374,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept BfDeferredAstSizedArray commas(operatorDecl->mCommas, mAlloc); ReplaceNode(typeRef, operatorDecl); operatorDecl->mReturnType = typeRef; + CheckMultiuseAttributeTypeRef(operatorDecl->mReturnType); mVisitorPos.MoveNext(); MEMBER_SET(operatorDecl, mOperatorToken, nextToken); @@ -7394,6 +7534,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept ReplaceNode(typeRef, propDecl); propDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); propDecl->mTypeRef = typeRef; + CheckMultiuseAttributeTypeRef(propDecl->mTypeRef); if (explicitInterface != NULL) { @@ -7553,6 +7694,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept ReplaceNode(typeRef, fieldDecl); fieldDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); fieldDecl->mTypeRef = typeRef; + CheckMultiuseAttributeTypeRef(fieldDecl->mTypeRef); return fieldDecl; } } @@ -7584,6 +7726,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept } methodDeclaration->mReturnType = typeRef; + CheckMultiuseAttributeTypeRef(methodDeclaration->mReturnType); MEMBER_SET_CHECKED(methodDeclaration, mNameNode, nameIdentifier); mCurMethodDecl = methodDeclaration; ParseMethod(methodDeclaration, ¶ms, &commas); @@ -7990,6 +8133,47 @@ BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& ta return scopedInvocationTarget; } +bool BfReducer::CheckInlineTypeRefAttribute(BfAstNode* typeRef, BfAttributeDirective* attributes) +{ + if (attributes == NULL) + return false; + + if (auto inlineTypeRef = BfNodeDynCast(typeRef)) + { + auto checkAttribute = attributes; + while (checkAttribute != NULL) + { + checkAttribute->mIsMultiUse = true; + checkAttribute = checkAttribute->mNextAttribute; + } + + auto typeDecl = inlineTypeRef->mTypeDeclaration; + typeDecl->mTriviaStart = attributes->mTriviaStart; + typeDecl->mSrcStart = attributes->mSrcStart; + typeDecl->mAttributes = attributes; + + if ((typeDecl->mIgnoreDeclaration) && (IsNodeRelevant(typeDecl))) + typeDecl->mIgnoreDeclaration = false; + + return true; + } + + return false; +} + +void BfReducer::CheckMultiuseAttributeTypeRef(BfAstNode* typeRef) +{ + if (auto inlineTypeRef = BfNodeDynCast(typeRef)) + { + auto checkAttribute = inlineTypeRef->mTypeDeclaration->mAttributes; + while (checkAttribute != NULL) + { + checkAttribute->mIsMultiUse = true; + checkAttribute = checkAttribute->mNextAttribute; + } + } +} + bool BfReducer::SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode) { bool failed = false; @@ -8648,7 +8832,7 @@ BfAstNode* BfReducer::HandleTopLevel(BfBlock* node) return node; } -BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode) +BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode, bool isAnonymous) { AssertCurrentNode(tokenNode); @@ -8992,9 +9176,12 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi case BfToken_Delegate: case BfToken_Function: - { + { auto typeDeclaration = mAlloc->Alloc(); + SetAndRestoreValue prevTypeDecl(mCurTypeDecl, typeDeclaration); + CurTypeState curTypeState(typeDeclaration, mAlloc); + SetAndRestoreValue prevTypeState(mCurTypeState, &curTypeState); ReplaceNode(tokenNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); @@ -9006,6 +9193,7 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi auto methodDecl = mAlloc->Alloc(); MEMBER_SET(methodDecl, mReturnType, retType); + CheckMultiuseAttributeTypeRef(methodDecl->mReturnType); BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); methodDecl->mDocumentation = FindDocumentation(methodDecl); @@ -9121,11 +9309,16 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi if ((tokenNode->GetToken() == BfToken_Enum) && (isSimpleEnum)) break; - auto identifierNode = ExpectIdentifierAfter(tokenNode); - if (identifierNode == NULL) + BfIdentifierNode* identifierNode = NULL; + + if (!isAnonymous) { - AddErrorNode(tokenNode); - return NULL; + identifierNode = ExpectIdentifierAfter(tokenNode); + if (identifierNode == NULL) + { + AddErrorNode(tokenNode); + return NULL; + } } // We put extra effort in here to continue after failure, since 'return NULL' failure @@ -9138,7 +9331,8 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi typeDeclaration->mTypeNode = tokenNode; typeDeclaration->mNameNode = identifierNode; ReplaceNode(tokenNode, typeDeclaration); - MoveNode(identifierNode, typeDeclaration); + if (identifierNode != NULL) + MoveNode(identifierNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart); auto nextNode = mVisitorPos.GetNext(); @@ -10645,8 +10839,10 @@ void BfReducer::HandleBlock(BfBlock* block, bool allowEndingExpression) void BfReducer::HandleTypeDeclaration(BfTypeDeclaration* typeDecl, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode) { SetAndRestoreValue prevTypeDecl(mCurTypeDecl, typeDecl); + CurTypeState curTypeState(typeDecl, mAlloc); + SetAndRestoreValue prevTypeState(mCurTypeState, &curTypeState); SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(BfNodeDynCast(typeDecl->mDefineNode))); - + if (attributes != NULL) { MEMBER_SET(typeDecl, mAttributes, attributes); diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index 4a6a88eb..6bdd6f2c 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -129,6 +129,39 @@ public: } }; + struct CurTypeState + { + public: + BfTypeDeclaration* mTypeDeclaration; + BfAstAllocator* mAlloc; + Array mAnonymousTypeDecls; + + public: + CurTypeState() + { + mTypeDeclaration = NULL; + mAlloc = NULL; + } + + CurTypeState(BfTypeDeclaration* typeDecl, BfAstAllocator* alloc) + { + mTypeDeclaration = typeDecl; + mAlloc = alloc; + } + + ~CurTypeState() + { + if ((mTypeDeclaration != NULL) && (mAnonymousTypeDecls.mSize > 0)) + { + BF_ASSERT(mTypeDeclaration->mAnonymousTypes.mSize == 0); + mTypeDeclaration->mAnonymousTypes.mSize = (int)mAnonymousTypeDecls.size(); + mTypeDeclaration->mAnonymousTypes.mVals = (BfTypeDeclaration**)mAlloc->AllocBytes(mAnonymousTypeDecls.mSize * sizeof(BfTypeDeclaration*), sizeof(BfTypeDeclaration*)); + for (int i = 0; i < mAnonymousTypeDecls.mSize; i++) + mTypeDeclaration->mAnonymousTypes.mVals[i] = mAnonymousTypeDecls[i]; + } + } + }; + public: BfAstAllocator* mAlloc; BfSystem* mSystem; @@ -138,10 +171,12 @@ public: BfAstNode* mTypeMemberNodeStart; int mClassDepth; int mMethodDepth; + int mCurUniqueIdx; BfTypeDeclaration* mCurTypeDecl; + CurTypeState* mCurTypeState; BfTypeDeclaration* mLastTypeDecl; BfMethodDeclaration* mCurMethodDecl; - BfAstNode* mLastBlockNode; + BfAstNode* mLastBlockNode; bool mStmtHasError; bool mPrevStmtHadError; bool mCompatMode; // Does C++ compatible parsing @@ -179,7 +214,9 @@ public: bool IsNodeRelevant(BfAstNode* startNode, BfAstNode* endNode); void MoveNode(BfAstNode* srcNode, BfAstNode* newOwner); void ReplaceNode(BfAstNode* prevNode, BfAstNode* newNode); - + + bool CheckInlineTypeRefAttribute(BfAstNode* typeRef, BfAttributeDirective* attributes); + void CheckMultiuseAttributeTypeRef(BfAstNode* typeRef); bool SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode); BfAstNode* CreateAllocNode(BfTokenNode* newNode); BfAstNode* ReplaceTokenStarter(BfAstNode* astNode, int idx = -1, bool allowIn = false); @@ -238,7 +275,7 @@ public: BfWhileStatement* CreateWhileStatement(BfAstNode* node); BfDoStatement* CreateDoStatement(BfAstNode* node); BfRepeatStatement* CreateRepeatStatement(BfAstNode* node); - BfAstNode* CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode = NULL); + BfAstNode* CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode = NULL, bool isAnonymous = false); BfAstNode* HandleTopLevel(BfBlock* node); BfInlineAsmStatement* CreateInlineAsmStatement(BfAstNode* asmNode); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 61b88b63..82dca438 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2450,6 +2450,11 @@ bool BfTypeInstance::GetResultInfo(BfType*& valueType, int& okTagId) return false; } +bool BfTypeInstance::IsAnonymous() +{ + return (mTypeDef->mTypeDeclaration != NULL) && (mTypeDef->mTypeDeclaration->IsAnonymous()); +} + void BfTypeInstance::ReportMemory(MemReporter* memReporter) { if (mGenericTypeInfo != NULL) @@ -4249,6 +4254,13 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa } return nameHash ^ HASH_TAG; } +// else if (auto inlineTypeRef = BfNodeDynCastExact(typeRef)) +// { +// String name; +// inlineTypeRef->mTypeDeclaration->GetAnonymousName(name); +// int nameHash = (int)Hash64(name.c_str(), (int)name.length()); +// return nameHash ^ HASH_TAG; +// } else { BF_FATAL("Not handled"); @@ -5552,6 +5564,8 @@ String BfTypeUtils::TypeToString(BfAstNode* typeRefNode) } if (auto directStrTypeName = BfNodeDynCast(typeRef)) return directStrTypeName->mTypeName; + if (auto inlineTypeRef = BfNodeDynCast(typeRef)) + return inlineTypeRef->mTypeDeclaration->mAnonymousName; if (auto tupleTypeRef = BfNodeDynCast(typeRef)) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 8a2fd549..ac92cdfc 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -2205,6 +2205,7 @@ public: bool HasBeenInstantiated() { return mHasBeenInstantiated || ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_AssumeInstantiated) != 0); } bool IncludeAllMethods() { return ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_IncludeAllMethods) != 0); } bool DefineStateAllowsStaticMethods() { return mDefineState >= BfTypeDefineState_HasInterfaces_Direct; } + bool IsAnonymous(); virtual void ReportMemory(MemReporter* memReporter) override; }; @@ -2669,6 +2670,7 @@ public: Array mSetProperties; Array mSetField; bool mAwaitingValidation; + bool mIsMultiUse; BfAstNode* GetRefNode() { diff --git a/IDEHelper/Compiler/BfSourceClassifier.cpp b/IDEHelper/Compiler/BfSourceClassifier.cpp index fda1207a..c1055929 100644 --- a/IDEHelper/Compiler/BfSourceClassifier.cpp +++ b/IDEHelper/Compiler/BfSourceClassifier.cpp @@ -662,7 +662,7 @@ void BfSourceClassifier::Visit(BfTypeDeclaration* typeDeclaration) SetAndRestoreValue prevMember(mCurMember, typeDeclaration); - if (mSkipTypeDeclarations) + if ((mSkipTypeDeclarations) && (!typeDeclaration->IsAnonymous())) { if (auto defineBlock = BfNodeDynCast(typeDeclaration->mDefineNode)) { diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 1946d10f..4d37d542 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -1984,6 +1984,8 @@ BfSystem::BfSystem() gPerfManager = new PerfManager(); //gPerfManager->StartRecording(); + mAnonymousAtomCount = 0; + mCurUniqueId = 0; mAtomUpdateIdx = 0; mAtomCreateIdx = 0; mTypeMapVersion = 1; @@ -2094,7 +2096,7 @@ BfSystem::~BfSystem() typeDef->mHash = typeCode + 1000; \ mSystemTypeDefs[name] = typeDef; -BfAtom* BfSystem::GetAtom(const StringImpl& string) +BfAtom* BfSystem::GetAtom(const StringImpl& string, BfAtom::Kind kind) { StringView* stringPtr = NULL; BfAtom* atom = NULL; @@ -2111,6 +2113,7 @@ BfAtom* BfSystem::GetAtom(const StringImpl& string) } #endif mAtomCreateIdx++; + atom->mKind = kind; atom->mIsSystemType = false; atom->mAtomUpdateIdx = ++mAtomUpdateIdx; atom->mString = *stringPtr; @@ -2121,6 +2124,9 @@ BfAtom* BfSystem::GetAtom(const StringImpl& string) for (char c : string) atom->mHash = ((atom->mHash ^ c) << 5) - atom->mHash; + if (kind == BfAtom::Kind_Anon) + mAnonymousAtomCount++; + BfLogSys(this, "Atom Allocated %p %s\n", atom, string.c_str()); return atom; @@ -2152,6 +2158,12 @@ void BfSystem::ReleaseAtom(BfAtom* atom) { if (--atom->mRefCount == 0) { + if (atom->mKind == BfAtom::Kind_Anon) + { + mAnonymousAtomCount--; + BF_ASSERT(mAnonymousAtomCount >= 0); + } + mAtomGraveyard.push_back(atom); return; } diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index c3c4fa9c..c938ab75 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -48,8 +48,16 @@ typedef HashSet BfProjectSet; class BfAtom { +public: + enum Kind + { + Kind_Normal, + Kind_Anon + }; + public: StringView mString; + Kind mKind; int mRefCount; int mPendingDerefCount; int mHash; @@ -1783,6 +1791,8 @@ public: Array mAtomGraveyard; uint32 mAtomUpdateIdx; int32 mTypeMapVersion; // Increment when we add any new types or namespaces + int32 mAnonymousAtomCount; + int32 mCurUniqueId; OwnedVector mMethodGraveyard; OwnedVector mFieldGraveyard; @@ -1830,7 +1840,7 @@ public: BfSystem(); ~BfSystem(); - BfAtom* GetAtom(const StringImpl& string); + BfAtom* GetAtom(const StringImpl& string, BfAtom::Kind kind = BfAtom::Kind_Normal); BfAtom* FindAtom(const StringImpl& string); // Doesn't create a ref BfAtom* FindAtom(const StringView& string); // Doesn't create a ref void ReleaseAtom(BfAtom* atom); diff --git a/IDEHelper/Tests/src/Anonymous.bf b/IDEHelper/Tests/src/Anonymous.bf new file mode 100644 index 00000000..9a0d8b46 --- /dev/null +++ b/IDEHelper/Tests/src/Anonymous.bf @@ -0,0 +1,44 @@ +using System; +namespace Tests; + +class Anonymous +{ + struct StructA + { + public [Union] struct { public int mX, mY; } mVals; + + [CRepr, SkipCall] struct { public int mA, mB; } GetVals() + { + decltype(GetVals()) retVals; + retVals.mA = 1; + retVals.mB = 2; + return retVals; + } + } + + struct StructB + { + [Union] + public using struct + { + public int mX; + public int mY; + } mCoords; + } + + [Test] + public static void TestBasics() + { + StructA sa = default; + sa.mVals.mX = 123; + Test.Assert(sa.mVals.mY == 123); + + var val = sa.[Friend]GetVals(); + Test.Assert(val.mA == 0); + Test.Assert(val.mB == 0); + + StructB sb = default; + sb.mX = 345; + Test.Assert(sb.mY == 345); + } +} \ No newline at end of file