diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index bc0772fd..f7682d36 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -361,6 +361,11 @@ void BfStructuralVisitor::Visit(BfOffsetOfExpression* offsetOfExpr) Visit(offsetOfExpr->ToBase()); } +void BfStructuralVisitor::Visit(BfNameOfExpression* nameOfExpr) +{ + Visit(nameOfExpr->ToBase()); +} + void BfStructuralVisitor::Visit(BfIsConstExpression* isConstExpr) { Visit(isConstExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index ef5e3050..0522edd1 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -381,6 +381,7 @@ class BfTypeAttrExpression; class BfSizeOfExpression; class BfAlignOfExpression; class BfOffsetOfExpression; +class BfNameOfExpression; class BfStrideOfExpression; class BfIsConstExpression; class BfDefaultExpression; @@ -508,6 +509,7 @@ public: virtual void Visit(BfAlignOfExpression* alignOfExpr); virtual void Visit(BfStrideOfExpression* strideOfExpr); virtual void Visit(BfOffsetOfExpression* offsetOfExpr); + virtual void Visit(BfNameOfExpression* nameOfExpr); virtual void Visit(BfIsConstExpression* isConstExpr); virtual void Visit(BfDefaultExpression* defaultExpr); virtual void Visit(BfUninitializedExpression* uninitializedExpr); @@ -2728,6 +2730,16 @@ public: BfIdentifierNode* mMemberName; }; BF_AST_DECL(BfOffsetOfExpression, BfTypeAttrExpression); +class BfNameOfExpression : public BfExpression +{ +public: + BF_AST_TYPE(BfNameOfExpression, BfExpression); + BfTokenNode* mToken; + BfTokenNode* mOpenParen; + BfAstNode* mTarget; + BfTokenNode* mCloseParen; +}; BF_AST_DECL(BfNameOfExpression, BfExpression); + class BfIsConstExpression : public BfExpression { public: diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index e12e253f..34886f31 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -689,7 +689,13 @@ void BfAutoComplete::AddTypeDef(BfTypeDef* typeDef, const StringImpl& filter, bo } bool BfAutoComplete::CheckProtection(BfProtection protection, BfTypeDef* typeDef, bool allowProtected, bool allowPrivate) -{ +{ + if (mResolveType == BfResolveType_GetSymbolInfo) + { + // This is needed for nameof on private inner types + return true; + } + if ((protection == BfProtection_Internal) && (typeDef != NULL)) { return mModule->CheckProtection(protection, typeDef, allowProtected, allowPrivate); diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index bd088c9b..e977e1d9 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -519,6 +519,8 @@ void BfElementVisitor::Visit(BfTypeAttrExpression* typeAttrExpr) void BfElementVisitor::Visit(BfOffsetOfExpression* offsetOfExpr) { + Visit(offsetOfExpr->ToBase()); + VisitChild(offsetOfExpr->mToken); VisitChild(offsetOfExpr->mOpenParen); VisitChild(offsetOfExpr->mTypeRef); @@ -527,6 +529,16 @@ void BfElementVisitor::Visit(BfOffsetOfExpression* offsetOfExpr) VisitChild(offsetOfExpr->mCloseParen); } +void BfElementVisitor::Visit(BfNameOfExpression* nameOfExpr) +{ + Visit(nameOfExpr->ToBase()); + + VisitChild(nameOfExpr->mToken); + VisitChild(nameOfExpr->mOpenParen); + VisitChild(nameOfExpr->mTarget); + VisitChild(nameOfExpr->mCloseParen); +} + void BfElementVisitor::Visit(BfDefaultExpression* defaultExpr) { Visit(defaultExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index 992a5b88..c71ab888 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -72,6 +72,7 @@ public: virtual void Visit(BfParameterDeclaration* paramDecl); virtual void Visit(BfTypeAttrExpression* typeAttrExpr); virtual void Visit(BfOffsetOfExpression* offsetOfExpr); + virtual void Visit(BfNameOfExpression* nameOfExpr); virtual void Visit(BfDefaultExpression* defaultExpr); virtual void Visit(BfIsConstExpression* isConstExpr); virtual void Visit(BfUninitializedExpression* uninitializedExpr); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 20fdfaca..3f7119ab 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -3762,6 +3762,49 @@ static bool IsCharType(BfTypeCode typeCode) } } +bool BfExprEvaluator::CheckForMethodName(BfAstNode* refNode, BfTypeInstance* typeInst, const StringImpl& findName) +{ + BF_ASSERT((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0); + + auto autoComplete = GetAutoComplete(); + + while (typeInst != NULL) + { + auto typeDef = typeInst->mTypeDef; + typeDef->PopulateMemberSets(); + + BfMemberSetEntry* memberSetEntry; + if (typeDef->mMethodSet.TryGetWith(findName, &memberSetEntry)) + { + if (mModule->mCompiler->mResolvePassData != NULL) + mModule->mCompiler->mResolvePassData->HandleMethodReference(refNode, typeDef, (BfMethodDef*)memberSetEntry->mMemberDef); + + if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(refNode))) + { + autoComplete->SetDefinitionLocation(((BfMethodDef*)memberSetEntry->mMemberDef)->GetRefNode()); + if ((autoComplete->mResolveType == BfResolveType_GetSymbolInfo) && (autoComplete->mDefType == NULL)) + { + autoComplete->mDefType = typeDef; + autoComplete->mDefMethod = (BfMethodDef*)memberSetEntry->mMemberDef; + } + } + + if (mModule->mCompiler->mResolvePassData != NULL) + { + if (auto sourceClassifier = mModule->mCompiler->mResolvePassData->GetSourceClassifier(refNode)) + sourceClassifier->SetElementType(refNode, BfSourceElementType_Method); + } + + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NameOfSuccess); + return true; + } + + typeInst = typeInst->mBaseType; + } + + return false; +} + bool BfExprEvaluator::IsVar(BfType* type, bool forceIgnoreWrites) { if (type->IsVar()) @@ -4591,6 +4634,9 @@ void BfExprEvaluator::Visit(BfIdentifierNode* identifierNode) } } + if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) && (mModule->mCurTypeInstance != NULL) && (CheckForMethodName(identifierNode, mModule->mCurTypeInstance, identifierNode->ToString()))) + return; + if ((mBfEvalExprFlags & BfEvalExprFlags_NoLookupError) == 0) mModule->Fail("Identifier not found", identifierNode); } @@ -5063,7 +5109,7 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe } else if (!target) { - if (mModule->PreFail()) + if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) == 0) && (mModule->PreFail())) { if ((flags & BfLookupFieldFlag_CheckingOuter) != 0) mModule->Fail(StrFormat("An instance reference is required to reference non-static outer field '%s.%s'", mModule->TypeToString(typeInstance).c_str(), fieldDef->mName.c_str()), @@ -5530,7 +5576,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar auto prop = nextProp; nextProp = nextProp->mNextWithSameName; - if ((!isFailurePass) && (!mModule->CheckProtection(protectionCheckFlags, curCheckType, prop->mDeclaringType->mProject, prop->mProtection, startCheckType))) + if ((!isFailurePass) && ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) == 0) && (!mModule->CheckProtection(protectionCheckFlags, curCheckType, prop->mDeclaringType->mProject, prop->mProtection, startCheckType))) { continue; } @@ -5543,7 +5589,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar continue; } - if ((!target.IsStatic()) || (prop->mIsStatic)) + if ((!target.IsStatic()) || (prop->mIsStatic) || ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0)) { if (!mModule->IsInSpecializedSection()) { @@ -10864,6 +10910,10 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode* { FixitAddMember(typeInst, mExpectingType, nameRight->ToString(), false); } + + if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) && (typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, fieldName))) + return; + mModule->Fail(StrFormat("Unable to find member '%s' in '%s'", fieldName.c_str(), mModule->TypeToString(lookupType).c_str()), nameRight); } @@ -11013,6 +11063,13 @@ void BfExprEvaluator::LookupQualifiedStaticField(BfAstNode* nameNode, BfIdentifi } } + if ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) + { + auto typeInst = lookupType.mType->ToTypeInstance(); + if ((typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, findName))) + return; + } + if ((mBfEvalExprFlags & BfEvalExprFlags_NoLookupError) == 0) mModule->Fail("Field not found", nameRight); return; @@ -11885,6 +11942,135 @@ void BfExprEvaluator::Visit(BfOffsetOfExpression* offsetOfExpr) DoTypeIntAttr(offsetOfExpr->mTypeRef, offsetOfExpr->mCommaToken, offsetOfExpr->mMemberName, BfToken_OffsetOf); } +void BfExprEvaluator::Visit(BfNameOfExpression* nameOfExpr) +{ + String name; + + if (mModule->IsInSpecializedGeneric()) + { + if (auto identifierNode = BfNodeDynCastExact(nameOfExpr->mTarget)) + { + // This is necessary so we don't resolve 'T' to the actual generic argument type + name = identifierNode->ToString(); + } + } + + if (name.IsEmpty()) + { + auto type = mModule->ResolveTypeRef(nameOfExpr->mTarget, {}, BfPopulateType_IdentityNoRemapAlias, + (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_AllowUnboundGeneric | BfResolveTypeRefFlag_IgnoreLookupError | BfResolveTypeRefFlag_IgnoreProtection)); + if (type != NULL) + { + auto typeInst = type->ToTypeInstance(); + if (typeInst != NULL) + name = typeInst->mTypeDef->mName->ToString(); + else + name = mModule->TypeToString(type); + + mModule->AddDependency(type, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference); + + // Just do this for autocomplete + SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); + VisitChild(nameOfExpr->mTarget); + } + } + + if (name.IsEmpty()) + { + if (auto identifer = BfNodeDynCast(nameOfExpr->mTarget)) + { + String targetStr = nameOfExpr->mTarget->ToString(); + BfAtomComposite targetComposite; + bool isValid = mModule->mSystem->ParseAtomComposite(targetStr, targetComposite); + bool namespaceExists = false; + + BfProject* bfProject = NULL; + auto activeTypeDef = mModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + bfProject = activeTypeDef->mProject; + auto _CheckProject = [&](BfProject* project) + { + if ((isValid) && (project->mNamespaces.ContainsKey(targetComposite))) + namespaceExists = true; + }; + + if (bfProject != NULL) + { + for (int depIdx = -1; depIdx < (int)bfProject->mDependencies.size(); depIdx++) + { + BfProject* depProject = (depIdx == -1) ? bfProject : bfProject->mDependencies[depIdx]; + _CheckProject(depProject); + } + } + else + { + for (auto project : mModule->mSystem->mProjects) + _CheckProject(project); + } + + if (namespaceExists) + { + if (mModule->mCompiler->mResolvePassData != NULL) + { + if (auto sourceClassifier = mModule->mCompiler->mResolvePassData->GetSourceClassifier(nameOfExpr->mTarget)) + { + BfAstNode* checkIdentifier = identifer; + while (true) + { + auto qualifiedIdentifier = BfNodeDynCast(checkIdentifier); + if (qualifiedIdentifier == NULL) + break; + sourceClassifier->SetElementType(qualifiedIdentifier->mRight, BfSourceElementType_Namespace); + checkIdentifier = qualifiedIdentifier->mLeft; + } + + sourceClassifier->SetElementType(checkIdentifier, BfSourceElementType_Namespace); + } + } + + name = targetComposite.mParts[targetComposite.mSize - 1]->ToString(); + } + } + } + + if (name.IsEmpty()) + { + SetAndRestoreValue prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NameOf)); + VisitChild(nameOfExpr->mTarget); + + if ((mBfEvalExprFlags & BfEvalExprFlags_NameOfSuccess) != 0) + { + BfAstNode* nameNode = nameOfExpr->mTarget; + if (auto attributedIdentifierNode = BfNodeDynCast(nameNode)) + nameNode = attributedIdentifierNode->mIdentifier; + if (auto memberReferenceExpr = BfNodeDynCast(nameNode)) + nameNode = memberReferenceExpr->mMemberName; + if (auto qualifiedNameNode = BfNodeDynCast(nameNode)) + nameNode = qualifiedNameNode->mRight; + name = nameNode->ToString(); + } + else if (mResultFieldInstance != NULL) + { + auto fieldDef = mResultFieldInstance->GetFieldDef(); + if (fieldDef != NULL) + name = fieldDef->mName; + } + else if (mResultLocalVar != NULL) + { + name = mResultLocalVar->mName; + } + else if (mPropDef != NULL) + { + name = mPropDef->mName; + } + } + + if ((name.IsEmpty()) && (nameOfExpr->mTarget != NULL)) + mModule->Fail("Expression does not have a name", nameOfExpr->mTarget); + + mResult = BfTypedValue(mModule->GetStringObjectValue(name), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); +} + void BfExprEvaluator::Visit(BfIsConstExpression* isConstExpr) { if (isConstExpr->mExpression == NULL) @@ -21142,6 +21328,13 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx { if (auto targetIdentifier = BfNodeDynCast(memberRefExpr->mMemberName)) { + if ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) + { + auto typeInst = thisValue.mType->ToTypeInstance(); + if ((typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, findName))) + return; + } + mResult.mType = mModule->ResolveInnerType(thisValue.mType, targetIdentifier, BfPopulateType_Declaration); } } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 12492037..035acb0f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -273,8 +273,6 @@ public: bool IsVarCall(BfType*& outReturnType); }; - - class BfBaseClassWalker { public: @@ -432,6 +430,7 @@ public: BfExprEvaluator(BfModule* module); ~BfExprEvaluator(); + bool CheckForMethodName(BfAstNode* refNode, BfTypeInstance* typeInst, const StringImpl& findName); bool IsVar(BfType* type, bool forceIgnoreWrites = false); void GetLiteral(BfAstNode* refNode, const BfVariant& variant); void FinishExpressionResult(); @@ -559,6 +558,7 @@ public: virtual void Visit(BfAlignOfExpression* alignOfExpr) override; virtual void Visit(BfStrideOfExpression* strideOfExpr) override; virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override; + virtual void Visit(BfNameOfExpression* nameOfExpr) override; virtual void Visit(BfIsConstExpression* isConstExpr) override; virtual void Visit(BfDefaultExpression* defaultExpr) override; virtual void Visit(BfUninitializedExpression* uninitialziedExpr) override; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index f76d5d03..982e9a0d 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -54,7 +54,7 @@ enum BfPopulateType BfPopulateType_Full_Force }; -enum BfEvalExprFlags +enum BfEvalExprFlags : int64 { BfEvalExprFlags_None = 0, BfEvalExprFlags_ExplicitCast = 1, @@ -89,6 +89,8 @@ enum BfEvalExprFlags BfEvalExprFlags_AllowGenericConstValue = 0x20000000, BfEvalExprFlags_IsExpressionBody = 0x40000000, BfEvalExprFlags_AppendFieldInitializer = 0x80000000, + BfEvalExprFlags_NameOf = 0x100000000LL, + BfEvalExprFlags_NameOfSuccess = 0x200000000LL, BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType }; @@ -1947,7 +1949,7 @@ public: BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); BfType* ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); BfType* ResolveTypeDef(BfTypeDef* typeDef, const BfTypeVector& genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); - BfType* ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0); + BfType* ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); BfTypeDef* GetCombinedPartialTypeDef(BfTypeDef* type); BfTypeInstance* GetOuterType(BfType* type); bool IsInnerType(BfType* checkInnerType, BfType* checkOuterType); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 21e9c105..77e6c732 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -8029,7 +8029,7 @@ void BfModule::HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDe mCompiler->mResolvePassData->HandleMethodGenericParam(refNode, typeDef, methodDef, methodGenericParamIdx); } -BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType, bool ignoreErrors, int numGenericArgs) +BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType, bool ignoreErrors, int numGenericArgs, BfResolveTypeRefFlags resolveFlags) { BfTypeDef* nestedTypeDef = NULL; @@ -8092,7 +8092,8 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu { auto latestCheckType = checkType->GetLatest(); - if ((!isFailurePass) && (!CheckProtection(latestCheckType->mProtection, latestCheckType, allowProtected, allowPrivate))) + if ((!isFailurePass) && ((resolveFlags & BfResolveTypeRefFlag_IgnoreProtection) == 0) && + (!CheckProtection(latestCheckType->mProtection, latestCheckType, allowProtected, allowPrivate))) continue; if (checkType->mProject != checkOuterType->mTypeDef->mProject) @@ -8135,7 +8136,7 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu if (nestedTypeDef == NULL) { - if (!mIgnoreErrors && !ignoreErrors) + if ((!mIgnoreErrors) && (!ignoreErrors) && ((resolveFlags & BfResolveTypeRefFlag_IgnoreLookupError) == 0)) { StringT<64> name; name.Append(findName); @@ -11020,7 +11021,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } } - auto resolvedType = ResolveInnerType(leftType, qualifiedTypeRef->mRight, populateType, false, numGenericArgs); + auto resolvedType = ResolveInnerType(leftType, qualifiedTypeRef->mRight, populateType, false, numGenericArgs, resolveFlags); if ((resolvedType != NULL) && (mCurTypeInstance != NULL)) AddDependency(leftType, mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference); return ResolveTypeResult(typeRef, resolvedType, populateType, resolveFlags); diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index a204f437..7eecb9e5 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -3174,6 +3174,8 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro case TOKEN_HASH('n', 'a', 'm', 'e'): if (SrcPtrHasToken("namespace")) mToken = BfToken_Namespace; + else if (SrcPtrHasToken("nameof")) + mToken = BfToken_NameOf; break; case TOKEN_HASH('n', 'e', 'w', 0): if (SrcPtrHasToken("new")) diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 9eedbf12..ce8fad0b 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -2352,6 +2352,41 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat exprLeft = CreateMemberReferenceExpression(typeRef); } } + else if (tokenNode->GetToken() == BfToken_NameOf) + { + BfNameOfExpression* nameOfExpr = mAlloc->Alloc(); + ReplaceNode(tokenNode, nameOfExpr); + nameOfExpr->mToken = tokenNode; + tokenNode = ExpectTokenAfter(nameOfExpr, BfToken_LParen); + MEMBER_SET_CHECKED(nameOfExpr, mOpenParen, tokenNode); + + mVisitorPos.MoveNext(); + int outEndNode = -1; + bool isTypeRef = IsTypeReference(mVisitorPos.GetCurrent(), BfToken_RParen, -1, &outEndNode); + mVisitorPos.mReadPos--; + + if ((isTypeRef) && (outEndNode > 0)) + { + if (auto tokenNode = BfNodeDynCast(mVisitorPos.Get(outEndNode - 1))) + { + if ((tokenNode->mToken == BfToken_RChevron) || (tokenNode->mToken == BfToken_RDblChevron)) + { + // Can ONLY be a type reference + auto typeRef = CreateTypeRefAfter(nameOfExpr); + MEMBER_SET_CHECKED(nameOfExpr, mTarget, typeRef); + } + } + } + + if (nameOfExpr->mTarget == NULL) + { + auto expr = CreateExpressionAfter(nameOfExpr); + MEMBER_SET_CHECKED(nameOfExpr, mTarget, expr); + } + tokenNode = ExpectTokenAfter(nameOfExpr, BfToken_RParen); + MEMBER_SET_CHECKED(nameOfExpr, mCloseParen, tokenNode); + exprLeft = nameOfExpr; + } if (exprLeft == NULL) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 21e0510e..18c22ee2 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -40,7 +40,8 @@ enum BfResolveTypeRefFlags BfResolveTypeRefFlag_AllowGlobalsSelf = 0x10000, BfResolveTypeRefFlag_AllowImplicitConstExpr = 0x20000, BfResolveTypeRefFlag_AllowUnboundGeneric = 0x40000, - BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000 + BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000, + BfResolveTypeRefFlag_IgnoreProtection = 0x100000 }; enum BfTypeNameFlags : uint16 diff --git a/IDEHelper/Tests/src/Expressions.bf b/IDEHelper/Tests/src/Expressions.bf index 4a397103..8c212e32 100644 --- a/IDEHelper/Tests/src/Expressions.bf +++ b/IDEHelper/Tests/src/Expressions.bf @@ -1,6 +1,8 @@ #pragma warning disable 168 using System; +using System.Interop; +using System.Collections; namespace Tests { @@ -24,5 +26,27 @@ namespace Tests inStr.Length > 1 || 2 == 3 }; } + + static void GetName(String str) + { + str.Append(nameof(T)); + } + + [Test] + public static void TestNameof() + { + var point = (x: 3, y: 4); + + Test.Assert(nameof(System) == "System"); + Test.Assert(nameof(System.Collections) == "Collections"); + Test.Assert(nameof(point) == "point"); + Test.Assert(nameof(point.x) == "x"); + Test.Assert(nameof(Tests.Expressions) == "Expressions"); + Test.Assert(nameof(c_int) == "c_int"); + Test.Assert(nameof(List) == "List"); + Test.Assert(nameof(List.Add) == "Add"); + Test.Assert(nameof(TestBasics) == "TestBasics"); + Test.Assert(GetName(.. scope .()) == "T"); + } } }