public override object TrackedVisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
        {
            // If we are in a property set region,
            // this may be the statement where the field value is assigned.
            if (this.associatedMember == null &&                // skip if already found to improve performance
                this.currentContext == VisitorContext.PropertySetRegion &&
                assignmentExpression.Op == AssignmentOperatorType.Assign && data != null)
            {
                // Resolve the expression.
                if (!FileUtility.IsEqualFileName(this.FileName, this.memberToFind.DeclaringType.CompilationUnit.FileName))
                {
                    throw new InvalidOperationException("The PropertyFieldAssociationVisitor does currently not support the case that the field is declared in a different file than the property.");
                }
                MemberResolveResult mrr = this.Resolve(assignmentExpression.Left) as MemberResolveResult;
                if (mrr != null && mrr.ResolvedMember is IField && !((IField)mrr.ResolvedMember).IsLocalVariable)
                {
                    PropertyDeclaration pd;

                                        #if DEBUG
                    LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, resolved field: " + mrr.ResolvedMember.ToString());
                                        #endif

                    if (data as bool? ?? false)
                    {
                        // We are looking for this property.
                                                #if DEBUG
                        LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, this property seems to reference field " + mrr.ResolvedMember.ToString());
                                                #endif
                        this.associatedMember = mrr.ResolvedMember;
                    }
                    else if ((pd = (data as PropertyDeclaration)) != null)
                    {
                        // We are looking for the field in this.memberToFind.
                        if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0)
                        {
                            // Resolve the property.
                            MemberResolveResult prr = NRefactoryAstCacheService.ResolveLowLevel(this.FileName, this.FileContent, pd.StartLocation.Y, pd.StartLocation.X + 1, null, pd.Name, ExpressionContext.Default) as MemberResolveResult;
                            if (prr != null)
                            {
                                                                #if DEBUG
                                LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, resolved property: " + prr.ResolvedMember.ToString());
                                                                #endif

                                if (prr.ResolvedMember is IProperty)
                                {
                                                                        #if DEBUG
                                    LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, property " + prr.ResolvedMember.ToString() + " seems to reference field " + mrr.ResolvedMember.ToString());
                                                                        #endif
                                    this.associatedMember = prr.ResolvedMember;
                                }
                            }
                        }
                    }
                }
            }

            return(base.TrackedVisitAssignmentExpression(assignmentExpression, data));
        }
        /// <summary>
        /// Resolves an expression in the current node's context.
        /// </summary>
        /// <param name="expression">The expression to be resolved.</param>
        /// <param name="context">The ExpressionContext.</param>
        public ResolveResult Resolve(Expression expression, ExpressionContext context)
        {
            if (!this.PositionAvailable)
            {
                LoggingService.Info("ResourceToolkit: PositionTrackingAstVisitor: Resolve failed due to position information being unavailable. Expression: " + expression.ToString());
                return(null);
            }

                        #if DEBUG
            LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Using this parent node for resolve: " + this.parentNodes.Peek().ToString());
                        #endif

            return(NRefactoryAstCacheService.ResolveLowLevel(this.fileName, this.fileContent, this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X + 1, this.compilationUnit, null, expression, context));
        }
        /// <summary>
        /// Tries to determine the resource set which is referenced by the
        /// resource manager which is assigned to the specified member.
        /// </summary>
        /// <param name="member">The referenced member to examine.</param>
        /// <returns>
        /// The ResourceSetReference, if successful, or a null reference, if the
        /// specified member is not a resource manager or if the
        /// resource file cannot be determined.
        /// </returns>
        static ResourceSetReference ResolveResourceSet(IMember member)
        {
            if (member != null && member.ReturnType != null &&
                member.DeclaringType != null && member.DeclaringType.CompilationUnit != null)
            {
                ResourceSetReference rsr;
                if (!NRefactoryAstCacheService.CacheEnabled || !cachedResourceSetReferenceMappings.TryGetValue(member, out rsr))
                {
                    string declaringFileName = member.DeclaringType.CompilationUnit.FileName;
                    if (declaringFileName != null)
                    {
                        if (IsResourceManager(member.ReturnType, declaringFileName))
                        {
                            SupportedLanguage?language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName);
                            if (language == null)
                            {
                                return(null);
                            }

                            CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName, ResourceResolverService.GetParsableFileContent(declaringFileName));
                            if (cu != null)
                            {
                                ResourceManagerInitializationFindVisitor visitor = new ResourceManagerInitializationFindVisitor(member);
                                cu.AcceptVisitor(visitor, null);
                                if (visitor.FoundResourceSet != null)
                                {
                                    rsr = visitor.FoundResourceSet;

                                    if (NRefactoryAstCacheService.CacheEnabled)
                                    {
                                        cachedResourceSetReferenceMappings.Add(member, rsr);
                                    }

                                    return(rsr);
                                }
                            }
                        }
                    }

                    return(null);
                }

                return(rsr);
            }
            return(null);
        }
        // ********************************************************************************************************************************

        /// <summary>
        /// Tries to resolve the resource reference using all available
        /// NRefactory resource resolvers.
        /// </summary>
        static ResourceResolveResult TryResolve(ExpressionResult result, Expression expr, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char?charTyped)
        {
            ResolveResult rr = NRefactoryAstCacheService.ResolveLowLevel(fileName, fileContent, caretLine + 1, caretColumn + 1, null, result.Expression, expr, result.Context);

            if (rr != null)
            {
                ResourceResolveResult rrr;
                foreach (INRefactoryResourceResolver resolver in Resolvers)
                {
                    if ((rrr = resolver.Resolve(result, expr, rr, caretLine, caretColumn, fileName, fileContent, expressionFinder, charTyped)) != null)
                    {
                        return(rrr);
                    }
                }
            }

            return(null);
        }
        public override object TrackedVisitReturnStatement(ReturnStatement returnStatement, object data)
        {
            // If we are in a property get region,
            // this may be the statement where the field value is returned.
            if (this.associatedMember == null &&                // skip if already found to improve performance
                this.currentContext == VisitorContext.PropertyGetRegion && data != null)
            {
                // Fix some type casting and parenthesized expressions
                Expression expr = returnStatement.Expression;
                while (true)
                {
                    CastExpression ce = expr as CastExpression;
                    if (ce != null)
                    {
                        expr = ce.Expression;
                        continue;
                    }
                    ParenthesizedExpression pe = expr as ParenthesizedExpression;
                    if (pe != null)
                    {
                        expr = pe.Expression;
                        continue;
                    }
                    break;
                }

                // Resolve the expression.
                if (!FileUtility.IsEqualFileName(this.FileName, this.memberToFind.DeclaringType.CompilationUnit.FileName))
                {
                    throw new InvalidOperationException("The PropertyFieldAssociationVisitor does currently not support the case that the field is declared in a different file than the property.");
                }
                MemberResolveResult mrr = this.Resolve(expr) as MemberResolveResult;
                if (mrr != null && mrr.ResolvedMember is IField)
                {
                    PropertyDeclaration pd;

                                        #if DEBUG
                    LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, resolved field: " + mrr.ResolvedMember.ToString());
                                        #endif

                    if (data as bool? ?? false)
                    {
                        // We are looking for this property.
                                                #if DEBUG
                        LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, this property seems to reference field " + mrr.ResolvedMember.ToString());
                                                #endif
                        this.associatedMember = mrr.ResolvedMember;
                    }
                    else if ((pd = (data as PropertyDeclaration)) != null)
                    {
                        // We are looking for the field in this.memberToFind.
                        if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0)
                        {
                            // Resolve the property.
                            MemberResolveResult prr = NRefactoryAstCacheService.ResolveLowLevel(this.FileName, this.FileContent, pd.StartLocation.Y, pd.StartLocation.X + 1, null, pd.Name, ExpressionContext.Default) as MemberResolveResult;
                            if (prr != null)
                            {
                                                                #if DEBUG
                                LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, resolved property: " + prr.ResolvedMember.ToString());
                                                                #endif

                                if (prr.ResolvedMember is IProperty)
                                {
                                                                        #if DEBUG
                                    LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, property " + prr.ResolvedMember.ToString() + " seems to reference field " + mrr.ResolvedMember.ToString());
                                                                        #endif
                                    this.associatedMember = prr.ResolvedMember;
                                }
                            }
                        }
                    }
                }
            }

            return(base.TrackedVisitReturnStatement(returnStatement, data));
        }
        // ********************************************************************************************************************************

        /// <summary>
        /// Attempts to resolve a reference to a resource.
        /// </summary>
        /// <param name="fileName">The name of the file that contains the expression to be resolved.</param>
        /// <param name="document">The document that contains the expression to be resolved.</param>
        /// <param name="caretLine">The 0-based line in the file that contains the expression to be resolved.</param>
        /// <param name="caretColumn">The 0-based column position of the expression to be resolved.</param>
        /// <param name="caretOffset">The offset of the position of the expression to be resolved.</param>
        /// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
        /// <returns>A <see cref="ResourceResolveResult"/> that describes which resource is referenced by the expression at the specified position in the specified file, or <c>null</c> if that expression does not reference a (known) resource.</returns>
        protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset, char?charTyped)
        {
            IExpressionFinder ef = ResourceResolverService.GetExpressionFinder(fileName);

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

            bool foundStringLiteral = false;

            while (true)
            {
                ExpressionResult result = ef.FindFullExpression(document.Text, caretOffset);

                if (result.Expression == null)
                {
                    // Try to find an expression to the left, but only
                    // in the same line.
                    if (foundStringLiteral || --caretOffset < 0)
                    {
                        return(null);
                    }
                    var line = document.GetLineForOffset(caretOffset);
                    if (line.LineNumber - 1 != caretLine)
                    {
                        return(null);
                    }
                    continue;
                }

                if (!result.Region.IsEmpty)
                {
                    caretLine   = result.Region.BeginLine - 1;
                    caretColumn = result.Region.BeginColumn - 1;
                }

                PrimitiveExpression pe;
                Expression          expr = NRefactoryAstCacheService.ParseExpression(fileName, result.Expression, caretLine + 1, caretColumn + 1);

                if (expr == null)
                {
                    return(null);
                }
                else if ((pe = expr as PrimitiveExpression) != null)
                {
                    if (pe.Value is string)
                    {
                        if (foundStringLiteral)
                        {
                            return(null);
                        }

                        // We are inside a string literal and need to find
                        // the next outer expression to decide
                        // whether it is a resource key.

                        if (!result.Region.IsEmpty)
                        {
                            // Go back to the start of the string literal - 2.
                            caretOffset = document.PositionToOffset(result.Region.BeginLine, result.Region.BeginColumn) - 2;
                            if (caretOffset < 0)
                            {
                                return(null);
                            }
                        }
                        else
                        {
                            LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver: Found string literal, but result region is empty. Trying to infer position from text.");
                            int newCaretOffset = document.GetText(0, Math.Min(document.TextLength, caretOffset + result.Expression.Length)).LastIndexOf(result.Expression);
                            if (newCaretOffset == -1)
                            {
                                LoggingService.Warn("ResourceToolkit: NRefactoryResourceResolver: Could not find resolved expression in text.");
                                --caretOffset;
                                continue;
                            }
                            else
                            {
                                caretOffset = newCaretOffset;
                            }
                        }

                        foundStringLiteral = true;
                        continue;
                    }
                    else
                    {
                        return(null);
                    }
                }

                return(TryResolve(result, expr, caretLine, caretColumn, fileName, document.Text, ef, charTyped));
            }
        }
        /// <summary>
        /// Tries to find a resource reference in the specified expression.
        /// </summary>
        /// <param name="expressionResult">The ExpressionResult for the expression.</param>
        /// <param name="expr">The AST representation of the full expression.</param>
        /// <param name="resolveResult">SharpDevelop's ResolveResult for the expression.</param>
        /// <param name="caretLine">The 0-based line where the expression is located.</param>
        /// <param name="caretColumn">The 0-based column where the expression is located.</param>
        /// <param name="fileName">The name of the source file where the expression is located.</param>
        /// <param name="fileContent">The content of the source file where the expression is located.</param>
        /// <param name="expressionFinder">The ExpressionFinder for the file.</param>
        /// <param name="charTyped">The character that has been typed at the caret position but is not yet in the buffer (this is used when invoked from code completion), or <c>null</c>.</param>
        /// <returns>A ResourceResolveResult describing the referenced resource, or <c>null</c>, if this expression does not reference a resource using the standard .NET framework classes.</returns>
        public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent, IExpressionFinder expressionFinder, char?charTyped)
        {
            /*
             * We need to catch the following cases here:
             *
             * Something.GetString(
             * Something.GetString("...")
             * Something.ApplyResources(obj, "...")
             * Something[
             * Something["..."]
             *
             */

            if (charTyped == '(')
            {
                // Something.GetString
                // This is a MethodResolveResult and we need the reference to "Something",
                // which is the next outer expression.
                // This is only valid when invoked from code completion
                // and the method invocation character ('(' in C# and VB)
                // has been typed.

                // This code is also reused when reducing a complete InvocationExpression
                // (MemberResolveResult) to the method reference by passing '(' as
                // charTyped explicitly.

                MethodGroupResolveResult methrr = resolveResult as MethodGroupResolveResult;
                if (methrr != null)
                {
                    if ((methrr.Name == "GetString" || methrr.Name == "GetObject" || methrr.Name == "GetStream" || methrr.Name == "ApplyResources") &&
                        (resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, fileContent, expressionFinder)) != null)
                    {
                        return(ResolveResource(resolveResult, expr));
                    }
                    else
                    {
                        return(null);
                    }
                }
            }

            // Do not use "else if" here.
            // '(' is also the IndexerExpressionStartToken for VB,
            // so the "else" block further down might still apply.

            if (charTyped == null)
            {
                // A MemberResolveResult with a complete expression
                // must only be considered a valid resource reference
                // when Resolve is not invoked from code completion
                // (i.e. charTyped == null) because this indicates
                // that the resource reference is already before the typed character
                // and we are not interested in the following expression.
                // This may happen when typing something like:
                // Something.GetString("...")[

                MemberResolveResult mrr = resolveResult as MemberResolveResult;
                if (mrr != null)
                {
                    if (mrr.ResolvedMember is IMethod &&
                        (mrr.ResolvedMember.Name == "GetString" || mrr.ResolvedMember.Name == "GetObject" || mrr.ResolvedMember.Name == "GetStream" || mrr.ResolvedMember.Name == "ApplyResources"))
                    {
                        // Something.GetString("...")
                        // This is a MemberResolveResult and we need the reference to "Something".
                        // The expression finder may only remove the string literal, so
                        // we have to call Resolve again in this case to resolve
                        // the method reference.

                        if ((resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, fileContent, expressionFinder)) != null)
                        {
                            if (resolveResult is MethodGroupResolveResult)
                            {
                                return(this.Resolve(expressionResult, expr, resolveResult, caretLine, caretColumn, fileName, fileContent, expressionFinder, '('));
                            }
                            else
                            {
                                return(ResolveResource(resolveResult, expr));
                            }
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    else if (expr is IndexerExpression &&
                             IsResourceManager(mrr.ResolvedMember.DeclaringType.DefaultReturnType, fileName))
                    {
                        // Something["..."] is an IndexerExpression.
                        // We need the reference to Something and this is
                        // the next outer expression.

                        if ((resolveResult = NRefactoryAstCacheService.ResolveNextOuterExpression(ref expressionResult, caretLine, caretColumn, fileName, fileContent, expressionFinder)) != null)
                        {
                            return(ResolveResource(resolveResult, expr));
                        }
                        else
                        {
                            return(null);
                        }
                    }
                }
            }
            else
            {
                // This request is triggered from code completion.
                // The only case that has not been caught above is:
                // Something[
                // The reference to "Something" is already in this expression.
                // So we have to test the trigger character against the
                // indexer expression start token of the file's language.

                LanguageProperties lp = NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName);
                if (lp != null &&
                    !String.IsNullOrEmpty(lp.IndexerExpressionStartToken) &&
                    lp.IndexerExpressionStartToken[0] == charTyped)
                {
                                        #if DEBUG
                    LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Indexer expression start typed, ResolveResult: " + resolveResult.ToString());
                    LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: -> Expression: " + expr.ToString());
                                        #endif

                    return(ResolveResource(resolveResult, expr));
                }
            }

            return(null);
        }