From 958a1630aaeb54b68b6e3bea7cafac8d7b1e6351 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sun, 18 May 2025 12:13:15 +0200 Subject: [PATCH] Added support for global:: lookups --- IDEHelper/Compiler/BfAst.cpp | 2 ++ IDEHelper/Compiler/BfAst.h | 34 ++++++++++++++++++ IDEHelper/Compiler/BfAutoComplete.cpp | 14 ++++++-- IDEHelper/Compiler/BfExprEvaluator.cpp | 36 ++++++++++++++----- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 29 +++++++++++---- IDEHelper/Compiler/BfParser.cpp | 7 ++++ IDEHelper/Compiler/BfReducer.cpp | 44 ++++++++++++++++++++--- IDEHelper/Compiler/BfReducer.h | 2 +- IDEHelper/Compiler/BfResolvedTypeUtils.h | 5 +-- IDEHelper/Compiler/BfSourceClassifier.cpp | 8 ++++- IDEHelper/Compiler/BfStmtEvaluator.cpp | 6 ++-- IDEHelper/Tests/src/Lookups.bf | 41 +++++++++++++++++++++ 13 files changed, 202 insertions(+), 28 deletions(-) create mode 100644 IDEHelper/Tests/src/Lookups.bf diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index a4210268..b483feda 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -1611,6 +1611,8 @@ const char* Beefy::BfTokenToString(BfToken token) return ";"; case BfToken_Colon: return ":"; + case BfToken_ColonColon: + return "::"; case BfToken_Comma: return ","; case BfToken_Dot: diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 16e70c5c..45010fdd 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -304,6 +304,7 @@ enum BfToken : uint8 BfToken_RDblChevron, BfToken_Semicolon, BfToken_Colon, + BfToken_ColonColon, BfToken_Comma, BfToken_Dot, BfToken_DotDot, @@ -2014,6 +2015,13 @@ public: BfTokenNode* mColonToken; BfAstNode* mTargetNode; // . : or identifier BfAttributeDirective* mAttributes; + + BfAstNode* GetTargetNode() + { + if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon)) + return mColonToken; + return mTargetNode; + } }; BF_AST_DECL(BfScopeNode, BfAstNode); class BfNewNode : public BfAstNode @@ -2108,6 +2116,12 @@ public: ASTREF(BfIdentifierNode*) mLeft; ASTREF(BfTokenNode*) mDot; ASTREF(BfIdentifierNode*) mRight; + + bool IsGlobalLookup() + { + return (mDot != NULL) && (mDot->mToken == BfToken_ColonColon); + } + }; BF_AST_DECL(BfQualifiedNameNode, BfIdentifierNode); class BfUsingDirective : public BfStatement @@ -2599,6 +2613,12 @@ public: ASTREF(BfTypeReference*) mLeft; ASTREF(BfTokenNode*) mDot; ASTREF(BfTypeReference*) mRight; + + bool IsGlobalLookup() + { + return (mDot != NULL) && (mDot->mToken == BfToken_ColonColon); + } + }; BF_AST_DECL(BfQualifiedTypeReference, BfTypeReference); class BfResolvedTypeReference : public BfTypeReference @@ -3036,6 +3056,13 @@ public: BfAstNode* mTargetNode; + BfAstNode* GetScopeNameNode() + { + if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon)) + return mColonToken; + return mScopeName; + } + // virtual bool IsMissingSemicolon() override // { // return BfNodeDynCastExact(mTargetNode) == NULL; @@ -3059,6 +3086,13 @@ public: BfAstNode* mTarget; BfTokenNode* mColonToken; BfAstNode* mScopeName; // :, mixin, or identifier + + BfAstNode* GetScopeNameNode() + { + if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon)) + return mColonToken; + return mScopeName; + } }; BF_AST_DECL(BfScopedInvocationTarget, BfAstNode); class BfInvocationExpression : public BfMethodBoundExpression diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 515eaa97..951da61e 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -1853,7 +1853,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress { "alignof", "append", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "const", "default", "defer", "delegate", "delete", "do", "else", "false", "finally", - "fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "not", "null", + "fixed", "for", "function", "global", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "not", "null", "offsetof", "out", "params", "readonly", "ref", "rettype", "return", "sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked", "using", "var", "virtual", "volatile", "where", "while", @@ -1873,7 +1873,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress const char* tokens[] = { "abstract", "append", "base", "class", "concrete", "const", - "delegate", "extern", "enum", "explicit", "extension", "function", + "delegate", "extern", "enum", "explicit", "extension", "function", "global", "interface", "in", "implicit", "internal", "mixin", "namespace", "new", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return", "scope", "sealed", "static", "struct", "this", "typealias", @@ -1926,6 +1926,16 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken if (!WantsEntries()) return false; + bool isGlobalLookup = true; + if (auto dotTokenNode = BfNodeDynCast(dotToken)) + { + if (dotTokenNode->mToken == BfToken_ColonColon) + { + CheckNode(memberName, false, false); + return false; + } + } + BfAttributedIdentifierNode* attrIdentifier = NULL; bool isAutocompletingName = false; if ((attrIdentifier = BfNodeDynCast(memberName))) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index f956425b..386e0bc3 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -17223,8 +17223,8 @@ void BfExprEvaluator::ResolveAllocTarget(BfAllocTarget& allocTarget, BfAstNode* { if (auto scopeNode = BfNodeDynCast(allocNode)) { - newToken = scopeNode->mScopeToken; - allocTarget.mScopeData = mModule->FindScope(scopeNode->mTargetNode, true); + newToken = scopeNode->mScopeToken; + allocTarget.mScopeData = mModule->FindScope(scopeNode->GetTargetNode(), true); if (autoComplete != NULL) { @@ -17799,7 +17799,9 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo } auto targetNameNode = targetSrc; if (scopedInvocationTarget != NULL) - targetNameNode = scopedInvocationTarget->mTarget; + { + targetNameNode = scopedInvocationTarget->GetScopeNameNode(); + } while (true) { @@ -18214,7 +18216,7 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo auto checkNode = origTargetSrc; if (scopedInvocationTarget != NULL) { - auto targetScope = mModule->FindScope(scopedInvocationTarget->mScopeName, curMethodState->mMixinState); + auto targetScope = mModule->FindScope(scopedInvocationTarget->GetScopeNameNode(), curMethodState->mMixinState); if (targetScope != NULL) { mixinState->mTargetScope = targetScope; @@ -19106,7 +19108,20 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if (GetAutoComplete() != NULL) GetAutoComplete()->CheckMemberReference(qualifiedName->mLeft, qualifiedName->mDot, qualifiedName->mRight); - if (qualifiedName->mLeft->GetSrcLength() == 4) + bool isGlobalLookup = false; + if (auto qualifiedNameNode = BfNodeDynCast(target)) + { + if (qualifiedNameNode->IsGlobalLookup()) + { + if (auto subQualifiedNameNode = BfNodeDynCast(qualifiedNameNode->mRight)) + { + qualifiedName = subQualifiedNameNode; + isGlobalLookup = true; + } + } + } + + if ((!isGlobalLookup) && (qualifiedName->mLeft->GetSrcLength() == 4)) { if (CheckIsBase(qualifiedName->mLeft)) bypassVirtual = true; @@ -19127,7 +19142,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m targetFunctionName = qualifiedName->mRight->ToString(); bool hadError = false; - thisValue = LookupIdentifier(qualifiedName->mLeft, true, &hadError); + if (!isGlobalLookup) + thisValue = LookupIdentifier(qualifiedName->mLeft, true, &hadError); CheckResultForReading(thisValue); if (mPropDef != NULL) @@ -19141,18 +19157,22 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if ((!thisValue) && (mPropDef == NULL)) { + auto typeLookupFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError); + if (isGlobalLookup) + typeLookupFlags = (BfResolveTypeRefFlags)(typeLookupFlags | BfResolveTypeRefFlag_GlobalLookup); + // Identifier not found. Static method? Just check speculatively don't throw error BfType* type; { //SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); - type = mModule->ResolveTypeRef(qualifiedName->mLeft, NULL, BfPopulateType_DataAndMethods, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError)); + type = mModule->ResolveTypeRef(qualifiedName->mLeft, NULL, BfPopulateType_DataAndMethods, typeLookupFlags); } if (type == NULL) { //SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); - type = mModule->ResolveTypeRef(qualifiedName, methodGenericArguments, BfPopulateType_DataAndMethods, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError)); + type = mModule->ResolveTypeRef(qualifiedName, methodGenericArguments, BfPopulateType_DataAndMethods, typeLookupFlags); if (type != NULL) { // This is a CTOR call, treat it as such diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index a591c739..3290988e 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -16568,7 +16568,7 @@ BfScopeData* BfModule::FindScope(BfAstNode* scopeName, BfMixinState* fromMixinSt if (auto tokenNode = BfNodeDynCast(scopeName)) { - if (tokenNode->GetToken() == BfToken_Colon) + if ((tokenNode->GetToken() == BfToken_Colon) || (tokenNode->GetToken() == BfToken_ColonColon)) { if ((!allowAcrossDeferredBlock) && (mCurMethodState->mInDeferredBlock)) { diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 89df7450..c751bb49 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -10519,12 +10519,15 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene if (mSystem->mTypeDefs.TryGet(findName, NULL)) mSystem->FindTypeDef(findName, numGenericArgs, useProject, BfAtomComposite(), allowPrivate, &lookupCtx); - for (auto& checkNamespace : useTypeDef->mNamespaceSearch) + if ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) == 0) { - BfAtom* atom = findName.mParts[0]; - BfAtom* prevAtom = checkNamespace.mParts[checkNamespace.mSize - 1]; - if (atom->mPrevNamesMap.ContainsKey(prevAtom)) - mSystem->FindTypeDef(findName, numGenericArgs, useProject, checkNamespace, allowPrivate, &lookupCtx); + for (auto& checkNamespace : useTypeDef->mNamespaceSearch) + { + BfAtom* atom = findName.mParts[0]; + BfAtom* prevAtom = checkNamespace.mParts[checkNamespace.mSize - 1]; + if (atom->mPrevNamesMap.ContainsKey(prevAtom)) + mSystem->FindTypeDef(findName, numGenericArgs, useProject, checkNamespace, allowPrivate, &lookupCtx); + } } } @@ -10550,7 +10553,7 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene } } - if ((!lookupCtx.HasValidMatch()) && (typeInstance == NULL)) + if ((!lookupCtx.HasValidMatch()) && (typeInstance == NULL) && ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) == 0)) { if (useTypeDef->mOuterType != NULL) return FindTypeDefRaw(findName, numGenericArgs, typeInstance, useTypeDef->mOuterType, error); @@ -10591,6 +10594,12 @@ BfTypeDef* BfModule::FindTypeDef(const BfAtomComposite& findName, int numGeneric if (useTypeDef != NULL) useTypeDef = useTypeDef->GetDefinition(); + if ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) != 0) + { + // No need to cache + return FindTypeDefRaw(findName, numGenericArgs, typeInstance, useTypeDef, error, NULL, resolveFlags); + } + if ((typeInstance == NULL) && (useTypeDef == NULL)) { BfProject* project = NULL; @@ -10648,7 +10657,7 @@ BfTypeDef* BfModule::FindTypeDef(const BfAtomComposite& findName, int numGeneric BfTypeLookupEntry typeLookupEntry; typeLookupEntry.mName.Reference(findName); typeLookupEntry.mNumGenericParams = numGenericArgs; - typeLookupEntry.mFlags = ((resolveFlags & BfResolveTypeRefFlag_SpecializedProject) != 0) ? BfTypeLookupEntry::Flags_SpecializedProject : BfTypeLookupEntry::Flags_None; + typeLookupEntry.mFlags = ((resolveFlags & BfResolveTypeRefFlag_SpecializedProject) != 0) ? BfTypeLookupEntry::Flags_SpecializedProject : BfTypeLookupEntry::Flags_None; typeLookupEntry.mUseTypeDef = useTypeDef; BfTypeLookupEntry* typeLookupEntryPtr = NULL; @@ -11589,6 +11598,12 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po if (auto qualifiedTypeRef = BfNodeDynCast(typeRef)) { + if (qualifiedTypeRef->IsGlobalLookup()) + { + resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_GlobalLookup); + return ResolveTypeRef_Ref(qualifiedTypeRef->mRight, populateType, resolveFlags, numGenericArgs); + } + //TODO: Determine why we had this prevIgnoreErrors set here. It causes things like IEnumerator> not fail // properly on INVALIDNAME SetAndRestoreValue prevIgnoreErrors(mIgnoreErrors, /*true*/mIgnoreErrors); diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index f20fd95f..c2e3a6fa 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -2630,6 +2630,13 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro mToken = BfToken_Dot; mSyntaxToken = BfSyntaxToken_Token; } + else if (mSrc[mSrcIdx] == ':') + { + mSrcIdx++; + mTokenEnd = mSrcIdx; + mToken = BfToken_ColonColon; + mSyntaxToken = BfSyntaxToken_Token; + } else { mToken = BfToken_Colon; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 0d14a95e..9d3014b6 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -4248,6 +4248,11 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS FailAfter("Expected scope name", deferStmt); } } + else if (nextTokenNode->GetToken() == BfToken_ColonColon) + { + MEMBER_SET(deferStmt, mColonToken, nextTokenNode); + mVisitorPos.MoveNext(); + } else if (nextTokenNode->GetToken() == BfToken_LParen) { mPassInstance->Warn(0, "Syntax deprecated", nextTokenNode); @@ -5868,7 +5873,7 @@ BfTypeReference* BfReducer::CreateRefTypeRef(BfTypeReference* elementType, BfTok return refTypeRef; } -BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) +BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode, bool allowGlobalLookup) { AssertCurrentNode(leftNode); @@ -5879,9 +5884,15 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) auto leftIdentifier = (BfIdentifierNode*)leftNode; while (true) { + bool isGlobalLookup = false; + auto nextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 1); auto tokenNode = BfNodeDynCast(nextToken); - if ((tokenNode == NULL) || ((tokenNode->GetToken() != BfToken_Dot) /*&& (tokenNode->GetToken() != BfToken_QuestionDot)*/)) + if ((tokenNode != NULL) && (tokenNode->mToken == BfToken_ColonColon) && (leftNode->IsExact()) && (leftNode->Equals("global")) && (allowGlobalLookup)) + { + isGlobalLookup = true; + } + else if ((tokenNode == NULL) || ((tokenNode->GetToken() != BfToken_Dot) /*&& (tokenNode->GetToken() != BfToken_QuestionDot)*/)) return leftIdentifier; auto nextNextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 2); @@ -5906,6 +5917,22 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) return leftIdentifier; } + if (isGlobalLookup) + { + // For 'global::', we put 'global' on the left and the rest on the right which is different from normal + mVisitorPos.MoveNext(); // past . + mVisitorPos.MoveNext(); // past right + auto rightSide = CompactQualifiedName(rightIdentifier, false); + + auto qualifiedNameNode = mAlloc->Alloc(); + ReplaceNode(leftIdentifier, qualifiedNameNode); + qualifiedNameNode->mLeft = leftIdentifier; + MEMBER_SET(qualifiedNameNode, mDot, tokenNode); + MEMBER_SET(qualifiedNameNode, mRight, rightSide); + + return qualifiedNameNode; + } + // If the previous dotted span failed (IE: had chevrons) then don't insert qualified names in the middle of it auto prevNodeToken = BfNodeDynCast(prevNode); if ((prevNodeToken != NULL) && @@ -7935,7 +7962,7 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target, if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { - if (nextToken->GetToken() == BfToken_Colon) + if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_ColonColon)) { auto scopedInvocationTarget = CreateScopedInvocationTarget(invocationExpr->mTarget, nextToken); invocationExpr->SetSrcEnd(scopedInvocationTarget->GetSrcEnd()); @@ -8317,6 +8344,10 @@ BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& ta MEMBER_SET(scopedInvocationTarget, mColonToken, colonToken); mVisitorPos.MoveNext(); + + if (colonToken->mToken == BfToken_ColonColon) + return scopedInvocationTarget; + if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) @@ -8473,7 +8504,7 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); if (nextToken == NULL) return allocToken; - if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_LBracket)) + if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_ColonColon) && (nextToken->mToken != BfToken_LBracket)) return allocToken; auto scopeNode = mAlloc->Alloc(); @@ -8504,6 +8535,11 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) FailAfter("Expected scope name", scopeNode); } } + else if (nextToken->mToken == BfToken_ColonColon) + { + MEMBER_SET(scopeNode, mColonToken, nextToken); + mVisitorPos.MoveNext(); + } nextToken = BfNodeDynCast(mVisitorPos.GetNext()); if (nextToken == NULL) diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index c5349549..af5ceb42 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -231,7 +231,7 @@ public: void ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, BfBlock* block); BfAstNode* ReadTypeMember(BfTokenNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL); BfAstNode* ReadTypeMember(BfAstNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL); - BfIdentifierNode* CompactQualifiedName(BfAstNode* leftNode); + BfIdentifierNode* CompactQualifiedName(BfAstNode* leftNode, bool allowGlobalLookup = true); void TryIdentifierConvert(int readPos); void CreateQualifiedNames(BfAstNode* node); BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 6d6e679a..d972ed08 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -42,7 +42,8 @@ enum BfResolveTypeRefFlags BfResolveTypeRefFlag_AllowUnboundGeneric = 0x40000, BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000, BfResolveTypeRefFlag_IgnoreProtection = 0x100000, - BfResolveTypeRefFlag_SpecializedProject = 0x200000 + BfResolveTypeRefFlag_SpecializedProject = 0x200000, + BfResolveTypeRefFlag_GlobalLookup = 0x400000 }; enum BfTypeNameFlags : uint16 @@ -1735,7 +1736,7 @@ struct BfTypeLookupEntry enum Flags : uint8 { Flags_None, - Flags_SpecializedProject + Flags_SpecializedProject, }; BfAtomComposite mName; diff --git a/IDEHelper/Compiler/BfSourceClassifier.cpp b/IDEHelper/Compiler/BfSourceClassifier.cpp index 74b92df5..c4e3d0ce 100644 --- a/IDEHelper/Compiler/BfSourceClassifier.cpp +++ b/IDEHelper/Compiler/BfSourceClassifier.cpp @@ -283,8 +283,10 @@ void BfSourceClassifier::Visit(BfIdentifierNode* identifier) void BfSourceClassifier::Visit(BfQualifiedNameNode* qualifiedName) { Visit((BfAstNode*)qualifiedName); - + VisitChild(qualifiedName->mLeft); + if (qualifiedName->IsGlobalLookup()) + SetElementType(qualifiedName->mLeft, BfSourceElementType_Namespace); VisitChild(qualifiedName->mDot); VisitChild(qualifiedName->mRight); if (BfNodeIsExact(qualifiedName->mRight)) @@ -350,6 +352,8 @@ void BfSourceClassifier::Visit(BfQualifiedTypeReference* qualifiedType) Visit((BfAstNode*)qualifiedType); VisitChild(qualifiedType->mLeft); + if (qualifiedType->IsGlobalLookup()) + SetElementType(qualifiedType->mLeft, BfSourceElementType_Namespace); VisitChild(qualifiedType->mDot); VisitChild(qualifiedType->mRight); } @@ -495,6 +499,8 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr) if (auto qualifiedName = BfNodeDynCast(target)) { VisitChild(qualifiedName->mLeft); + if (qualifiedName->IsGlobalLookup()) + SetElementType(qualifiedName->mLeft, BfSourceElementType_Namespace); VisitChild(qualifiedName->mDot); VisitChild(qualifiedName->mRight); identifier = qualifiedName->mRight; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 4117d70f..d18d015d 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -7387,6 +7387,8 @@ void BfModule::Visit(BfDeferStatement* deferStmt) BfScopeData* scope = NULL; + auto scopeNameNode = deferStmt->GetScopeNameNode(); + if (deferStmt->mScopeToken != NULL) { if (deferStmt->mScopeToken->GetToken() == BfToken_Scope) @@ -7394,9 +7396,9 @@ void BfModule::Visit(BfDeferStatement* deferStmt) else scope = &mCurMethodState->mHeadScope; } - else if (deferStmt->mScopeName != NULL) + else if (scopeNameNode != NULL) { - scope = FindScope(deferStmt->mScopeName, true); + scope = FindScope(scopeNameNode, true); if (scope == NULL) { diff --git a/IDEHelper/Tests/src/Lookups.bf b/IDEHelper/Tests/src/Lookups.bf new file mode 100644 index 00000000..cdeb5913 --- /dev/null +++ b/IDEHelper/Tests/src/Lookups.bf @@ -0,0 +1,41 @@ +#pragma warning disable 168 + +namespace Tests; + +namespace A.B +{ + class Zonk + { + public static int sVal = 123; + } + + static + { + public static void Main() + { + global::B.Init(); + global::A.B.Zonk.sVal = 234; + global::B.MethodT(); + global::System.String str = null; + } + } +} + +namespace B +{ + static + { + public static void Init() + { + } + + public static void MethodT() + { + } + } +} + +class Lookups +{ + +} \ No newline at end of file