public void Resolve(VBAParser.AsTypeClauseContext context)
        {
            var asType = context.type();

            if (asType == null)
            {
                return;
            }

            Declaration         type      = null;
            IdentifierReference reference = null;

            var baseType = asType.baseType();

            if (baseType != null)
            {
                var collection = baseType.COLLECTION();
                if (collection != null)
                {
                    type      = _declarations[collection.GetText()].SingleOrDefault(item => item.IsBuiltIn && item.DeclarationType == DeclarationType.Class);
                    reference = CreateReference(baseType, type);
                }
            }
            else
            {
                type      = ResolveType(asType.complexType());
                reference = CreateReference(asType.complexType(), type);
            }

            if (type != null)
            {
                type.AddReference(reference);
                _alreadyResolved.Add(reference.Context);
            }
        }
        public void EnterWithBlock(VBAParser.WithStmtContext context)
        {
            Declaration         qualifier = null;
            IdentifierReference reference = null;

            if (context.NEW() == null)
            {
                // with block is using an identifier declared elsewhere.
                var callee = ResolveInternal(context.implicitCallStmt_InStmt(), _currentScope, ContextAccessorType.GetValueOrReference);
                qualifier = ResolveType(callee);
            }
            else
            {
                // with block is using an anonymous declaration.
                // i.e. object variable reference is held by the with block itself.
                var typeContext     = context.type();
                var baseTypeContext = typeContext.baseType();
                if (baseTypeContext != null)
                {
                    var collectionContext = baseTypeContext.COLLECTION();
                    if (collectionContext != null)
                    {
                        // object variable is a built-in Collection class instance
                        qualifier = _declarations.Items.Single(item => item.IsBuiltIn &&
                                                               item.IdentifierName == collectionContext.GetText() &&
                                                               item.DeclarationType == DeclarationType.Class);
                        reference = CreateReference(baseTypeContext, qualifier);
                    }
                }
                else
                {
                    qualifier = ResolveType(typeContext.complexType());
                }
            }

            if (qualifier != null && reference != null)
            {
                qualifier.AddReference(reference);
                _alreadyResolved.Add(reference.Context);
            }
            _withBlockQualifiers.Push(qualifier); // note: pushes null if unresolved
        }
        private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declaration localScope, ContextAccessorType accessorType = ContextAccessorType.GetValueOrReference, VBAParser.DictionaryCallStmtContext fieldCall = null, bool hasExplicitLetStatement = false, bool isAssignmentTarget = false)
        {
            if (callSiteContext == null || _alreadyResolved.Contains(callSiteContext))
            {
                return(null);
            }

            if (!IdentifierContexts.Contains(callSiteContext.GetType()))
            {
                throw new ArgumentException("'" + callSiteContext.GetType().Name + "' is not an identifier context.", "callSiteContext");
            }

            if (localScope == null)
            {
                localScope = _currentScope;
            }

            var         parentContext  = callSiteContext.Parent;
            var         identifierName = callSiteContext.GetText();
            Declaration callee         = null;

            if (localScope.DeclarationType == DeclarationType.Variable)
            {
                // localScope is probably a UDT
                var udt = ResolveType(localScope);
                if (udt != null && udt.DeclarationType == DeclarationType.UserDefinedType)
                {
                    callee = _declarations[identifierName].SingleOrDefault(item => item.Context != null && item.Context.Parent == udt.Context);
                }
            }
            else
            {
                callee = FindLocalScopeDeclaration(identifierName, localScope, parentContext, isAssignmentTarget)
                         ?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
                         ?? FindModuleScopeDeclaration(identifierName, localScope)
                         ?? FindProjectScopeDeclaration(identifierName);
            }

            if (callee == null)
            {
                // calls inside With block can still refer to identifiers in _currentScope
                localScope     = _currentScope;
                identifierName = callSiteContext.GetText();
                callee         = FindLocalScopeDeclaration(identifierName, localScope, parentContext, isAssignmentTarget)
                                 ?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
                                 ?? FindModuleScopeDeclaration(identifierName, localScope)
                                 ?? FindProjectScopeDeclaration(identifierName);
            }

            if (callee == null)
            {
                return(null);
            }

            var reference = CreateReference(callSiteContext, callee, isAssignmentTarget, hasExplicitLetStatement);

            callee.AddReference(reference);
            _alreadyResolved.Add(reference.Context);
            _alreadyResolved.Add(callSiteContext);

            if (fieldCall != null)
            {
                return(ResolveInternal(fieldCall, callee));
            }

            return(callee);
        }