/// <summary>
        /// Sets VSSeriviceProvider.Current.
        /// </summary>
        public VSServiceProvider()
        {
            current    = this;
            _startTime = DateTime.Now;

#if false
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debugger.Launch();
            }
#endif
            this.logger = new Logger(PublicEntryException, QueueWorkItem,
                                     (s) => {
                if (_outputPane != null)
                {
                    var elapsed      = DateTime.Now - _startTime;
                    var outputString = s + " " + (int)elapsed.TotalMinutes + ":" + elapsed.Seconds + "." + elapsed.Milliseconds;
                    _outputPane.OutputString(outputString + "\n");
                }
            },
                                     (s) => {
                Debug.WriteLine(s);
            },
                                     (s) => {
                if (_outputStream != null)
                {
                    var elapsed      = DateTime.Now - _startTime;
                    var outputString = s + " " + (int)elapsed.TotalMinutes + ":" + elapsed.Seconds + "." + elapsed.Milliseconds;
                    _outputStream.WriteLine(outputString);
                }
            });
            this._projectTrackers = new Dictionary <string, ProjectTracker>();
        }
        static void RevaluatePropertyInheritanceAdornments(InheritanceTracker @this)
        {
            Contract.Requires(@this != null);

            var workingSnapshot = @this._textViewTracker.TextView.TextSnapshot; //Save the current snapshot so it doesn't change while you work, we assume that the snapshot is the same as the source file.

            //Check if model is ready
            var parseTree = @this._textViewTracker.LatestSourceFile == null ? null : @this._textViewTracker.LatestSourceFile.GetParseTree();

            if (parseTree == null || !VSServiceProvider.IsModelReady(parseTree))
            {
                @this._textViewTracker.IsLatestSourceFileStale = true;
                Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain);
                return;
            }

            //Collect all the properties in this text view
            var propertyCollector = new PropertyCollector(workingSnapshot);

            propertyCollector.Visit(parseTree.RootNode);
            var properties = propertyCollector.GetProperties();

            //Get our property keys
            var keys      = new List <object>();
            var newTuples = new List <Tuple <object, object> >();

            foreach (var tuple in properties.Keys)
            {
                if (tuple.Item1 != null)
                {
                    keys.Add(tuple.Item1);
                }
                if (tuple.Item2 != null)
                {
                    keys.Add(tuple.Item2);
                }
                if (!(@this._propertyKeys.Contains(tuple.Item1) && @this._propertyKeys.Contains(tuple.Item1)))
                {
                    newTuples.Add(tuple);
                }
            }

            VSServiceProvider.Current.Logger.WriteToLog(String.Format("Found {0} new properties.", newTuples.Count));

            //Update our property keys
            @this._propertyKeys.Clear();
            @this._propertyKeys.AddAll(keys);

            VSServiceProvider.Current.QueueWorkItem(() => {
                if (@this._textViewTracker.TextView.IsClosed)
                {
                    return;
                }
                var adornmentKeys = new List <object>(@this._adornmentManager.Adornments.Keys);
                foreach (var key in adornmentKeys)
                {
                    var keyAsString = key as string;
                    if (keyAsString == null)
                    {
                        VSServiceProvider.Current.Logger.WriteToLog("Unexpected: A key in the AdornmentManager wasn't a string! key: " + key.ToString());
                        continue;
                    }
                    if (!@this._propertyKeys.Contains(key) && keyAsString.EndsWith(PropertyCollector.PropertyTagSuffix))
                    {
                        @this._adornmentManager.RemoveAdornment(key);
                        VSServiceProvider.Current.Logger.WriteToLog("Removing obsolete property adornment with tag: " + keyAsString);
                    }
                }
            }, () => @this._textViewTracker.TextView.IsClosed || @this._textViewTracker.TextView.HasAggregateFocus);

            //Create placeholder adornments for our new properties and queue them for contract lookup
            VSServiceProvider.Current.QueueWorkItem(() => {
                foreach (var tuple in newTuples)
                {
                    PropertyDeclarationNode property;
                    if (properties.TryGetValue(tuple, out property))
                    {
                        if (tuple.Item1 != null && tuple.Item2 != null &&
                            property.GetAccessorDeclaration.GetSpan().Start.Line == property.SetAccessorDeclaration.GetSpan().Start.Line)
                        {
                            // set and get on same line, don't add adornment
                            VSServiceProvider.Current.Logger.WriteToLog("Skipping adornments for " + property.GetName(workingSnapshot) + " because get and set are on same line");
                        }
                        else
                        {
                            VSServiceProvider.Current.Logger.WriteToLog("Creating placeholder adornment and enqueueing for future contract lookup for: " + property.GetName(workingSnapshot));
                            if (tuple.Item1 != null)
                            {
                                #region Create getter placeholder adornment
                                VSServiceProvider.Current.Logger.WriteToLog(String.Format("\t(Creating getter placeholder with tag {0})", tuple.Item1));
                                //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                                var snapshotSpan = new SnapshotSpan(property.GetAccessorDeclaration.GetSpan().Convert(workingSnapshot).Start, 1);
                                var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                                var ops          = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage);
                                @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, VSServiceProvider.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item1);
                                #endregion
                            }
                            if (tuple.Item2 != null)
                            {
                                #region Create setter placeholder adornment
                                VSServiceProvider.Current.Logger.WriteToLog(String.Format("\t(Creating setter placeholder with tag {0})", tuple.Item2));
                                //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                                var snapshotSpan = new SnapshotSpan(property.SetAccessorDeclaration.GetSpan().Convert(workingSnapshot).Start, 1);
                                var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                                var ops          = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage);
                                @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, VSServiceProvider.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item2);
                                #endregion
                            }
                            @this._propertiesNeedingContractLookup.Enqueue(new KeyValuePair <Tuple <object, object>, PropertyDeclarationNode>(tuple, property));
                        }
                    }
                }
            });

            //Most likely we've changed something (and this is a pretty cheap call), so let's ask for a refresh
            Utilities.Delay(() => VSServiceProvider.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation);

            //Ask for the new VS model so we can look up contracts
            Utilities.Delay(() => VSServiceProvider.Current.QueueWorkItem(VSServiceProvider.Current.AskForNewVSModel, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation);
        }
        static void RevaluateMethodInheritanceAdornments(InheritanceTracker @this)
        {
            Contract.Requires(@this != null);

            var workingSnapshot = @this._textViewTracker.TextView.TextSnapshot; //Save the current snapshot so it doesn't change while you work, we assume that the snapshot is the same as the source file.

            //Check if model is ready
            var parseTree = @this._textViewTracker.LatestSourceFile == null ? null : @this._textViewTracker.LatestSourceFile.GetParseTree();

            if (parseTree == null || !VSServiceProvider.IsModelReady(parseTree))
            {
                @this._textViewTracker.IsLatestSourceFileStale = true;
                Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain);
                return;
            }

            //Collect all the methods in this text view
            var methodCollector = new MethodCollector(workingSnapshot);

            methodCollector.Visit(parseTree.RootNode);
            var methods = methodCollector.GetMethods();

            //Calculate which methods are new
            var newKeys = new List <object>(methods.Keys.Where((k) => !@this._methodKeys.Contains(k)));

            VSServiceProvider.Current.Logger.WriteToLog(String.Format("Found {0} new methods.", newKeys.Count));

            //Update our method keys
            @this._methodKeys.Clear();
            @this._methodKeys.AddAll(methods.Keys);

            VSServiceProvider.Current.QueueWorkItem(() => {
                if (@this._textViewTracker.TextView.IsClosed)
                {
                    return;
                }
                var adornmentKeys = new List <object>(@this._adornmentManager.Adornments.Keys);
                foreach (var key in adornmentKeys)
                {
                    var keyAsString = key as string;
                    if (keyAsString == null)
                    {
                        VSServiceProvider.Current.Logger.WriteToLog("Unexpected: A key in the AdornmentManager wasn't a string! key: " + key.ToString());
                        continue;
                    }
                    if (!@this._methodKeys.Contains(key) && keyAsString.EndsWith(MethodCollector.MethodTagSuffix))
                    {
                        @this._adornmentManager.RemoveAdornment(key);
                        VSServiceProvider.Current.Logger.WriteToLog("Removing obsolete method adornment with tag: " + keyAsString);
                    }
                }
            }, () => @this._textViewTracker.TextView.IsClosed || @this._textViewTracker.TextView.HasAggregateFocus);

            //Create placeholder adornments for our new methods and queue them for contract lookup
            VSServiceProvider.Current.QueueWorkItem(() => {
                foreach (var key in newKeys)
                {
                    MethodDeclarationNode method;
                    if (methods.TryGetValue(key, out method))
                    {
                        VSServiceProvider.Current.Logger.WriteToLog("Creating placeholder adornment and enqueueing for future contract lookup for: " + key.ToString());
                        #region Create placeholder adornment
                        //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                        var snapshotSpan = new SnapshotSpan(method.GetSpan().Convert(workingSnapshot).Start, 1);
                        var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                        var ops          = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage);
                        @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, VSServiceProvider.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), key);
                        #endregion
                        @this._methodsNeedingContractLookup.Enqueue(new KeyValuePair <object, MethodDeclarationNode>(key, method));
                    }
                }
            });

            //Most likely we've changed something (and this is a pretty cheap call), so let's ask for a refresh
            Utilities.Delay(() => VSServiceProvider.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer), DelayAfterMembersRevalutation);

            //Ask for the new VS model so we can look up contracts
            Utilities.Delay(() => VSServiceProvider.Current.QueueWorkItem(VSServiceProvider.Current.AskForNewVSModel), DelayAfterMembersRevalutation);
        }
        public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan)
        {
            if (session == null)
            {
                applicableToSpan = null;
                return;
            }

            var span = applicableToSpan = session.ApplicableToSpan;

            if (quickInfoContent == null)
            {
                return;
            }

            //Wrap our method body in a safty net that checks for exceptions
            VSServiceProvider.Current.Logger.PublicEntry(() => {
                //Record our start time for preformance considerations
                var startTime = DateTime.Now;

                //Is our session valid?
                if (session == null)
                {
                    return;
                }

                //Can we get our trigger point?
                var triggerPoint = session.GetTriggerPoint(_textBuffer);
                if (triggerPoint == null)
                {
                    return;
                }

                //Can we get our snapshot?
                var workingSnapshot = _textBuffer.CurrentSnapshot;
                if (workingSnapshot == null)
                {
                    return;
                }

                //Can we get our SourceFile?
                var sourceFile = _textViewTracker.LatestSourceFile;
                if (sourceFile == null)
                {
                    return;
                }

                //Can we get our ParseTree?
                var parseTree = sourceFile.GetParseTree();
                if (parseTree == null)
                {
                    return;
                }

                //Can we get our compilation?
                var comp = _textViewTracker.LatestCompilation;
                if (comp == null)
                {
                    return;
                }

                //Is the model ready?
                if (!VSServiceProvider.IsModelReady(parseTree) || _textViewTracker.IsLatestCompilationStale || _textViewTracker.IsLatestSourceFileStale)
                {
                    //Ask for a new model
                    VSServiceProvider.Current.AskForNewVSModel();

                    //Return a message saying we aren't ready yet
                    VSServiceProvider.Current.Logger.WriteToLog("The VS model is out of date! Aborting contract lookup.");
                    return;//"(VS isn't ready for possible contract lookup yet. Please try again in a few seconds.)";
                }

                //Proceed cautiously
                string formattedContracts;
                try {
                    //Can we get a call node?
                    var targetNode = IntellisenseContractsHelper.GetTargetAtTriggerPoint(triggerPoint, workingSnapshot, parseTree);
                    if (targetNode == null)
                    {
                        return;
                    }

                    //Can we get our semantic member?
                    var semanticMember = IntellisenseContractsHelper.GetSemanticMember(targetNode, comp, sourceFile);
                    if (semanticMember == null)
                    {
                        return;
                    }

                    //Can we get our contracts?
                    formattedContracts = GetFormattedContracts(semanticMember);
                    if (formattedContracts == null)
                    {
                        return;
                    }

                    if (span == null)
                    {
                        span = workingSnapshot.CreateTrackingSpan(triggerPoint.GetPosition(workingSnapshot), 1, SpanTrackingMode.EdgeInclusive);
                    }
                    //Give up on our contracts if we get an exception
                } catch (IllFormedSemanticModelException) {
                    return;
                } catch (InvalidOperationException e) {
                    if (!e.Message.Contains(VSServiceProvider.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate))
                    {
                        throw e;
                    }
                    else
                    {
                        this._textViewTracker.IsLatestCompilationStale = true;
                        return;
                    }
                } catch (System.Runtime.InteropServices.COMException e) {
                    // various reasons for ComExceptions:
                    //  - binding failed
                    //  - project unavailable
                    if (e.Message.EndsWith("out of date"))
                    {
                        this._textViewTracker.IsLatestCompilationStale = true;
                    }
                    return;
                }

                //Append our formatted contract info
                quickInfoContent.Add(formattedContracts);
                //Print our elapsed time for preformance considerations
                var elapseTime = DateTime.Now - startTime;
                VSServiceProvider.Current.Logger.WriteToLog("Time to compute quickinfo: " + elapseTime.Milliseconds + "ms");
            }, "AugmentQuickInfoSession");

            if (span != null)
            {
                applicableToSpan = span;
            }
        }
Beispiel #5
0
        public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList <ISignature> signatures)
        {
            VSServiceProvider.Current.Logger.PublicEntry(() => {
                //Record our start time for preformance considerations
                var startTime = DateTime.Now;

                //Do we have signatures?
                if (signatures == null || signatures.Count < 1)
                {
                    return;
                }

                //Do we have a well-formed session?
                if (session == null || session.TextView == null || session.TextView.TextBuffer == null)
                {
                    return;
                }

                //Can we get our trigger point?
                var triggerPoint = session.GetTriggerPoint(_textBuffer);
                if (triggerPoint == null)
                {
                    return;
                }

                //Can we get our snapshot?
                var workingSnapshot = _textBuffer.CurrentSnapshot;
                if (workingSnapshot == null)
                {
                    return;
                }

                //Can we get our SourceFile?
                var sourceFile = _textViewTracker.LatestSourceFile;
                if (sourceFile == null)
                {
                    return;
                }

                //Can we get our ParseTree?
                var parseTree = sourceFile.GetParseTree();
                if (parseTree == null)
                {
                    return;
                }

                //Can we get our compilation?
                var comp = _textViewTracker.LatestCompilation;
                if (comp == null)
                {
                    return;
                }

                //Is the model ready?
                if (!VSServiceProvider.IsModelReady(parseTree) || _textViewTracker.IsLatestCompilationStale || _textViewTracker.IsLatestSourceFileStale)
                {
                    //Ask for a new model
                    VSServiceProvider.Current.AskForNewVSModel();

                    //Return a message saying we aren't ready yet
                    VSServiceProvider.Current.Logger.WriteToLog("The VS model is out of date! Aborting contract lookup.");
                    return;//"(VS isn't ready for possible contract lookup yet. Please try again in a few seconds.)";
                }

                string[] contractContents = null;

                //Proceed cautiously
                try
                {
                    //Can we get a call node?
                    var callNode = IntellisenseContractsHelper.GetAnyCallNodeAboveTriggerPoint(triggerPoint, workingSnapshot, parseTree);
                    if (callNode == null || comp == null || sourceFile == null)
                    {
                        return;
                    }

                    //Can we get our semantic member?
                    var semanticMember = IntellisenseContractsHelper.GetSemanticMember(callNode, comp, sourceFile);
                    if (semanticMember == null)
                    {
                        return;
                    }

                    var declType = semanticMember.ContainingType;
                    // find all members of the same name (virt/non-virt)

                    var overloads = GetSignatureOverloads(declType, signatures, semanticMember);

                    contractContents = GetContractsForOverloads(overloads);


                    //Give up on our contracts if we get an exception
                }
                catch (IllFormedSemanticModelException)
                {
                    return;
                }
                catch (InvalidOperationException e)
                {
                    if (!e.Message.Contains(VSServiceProvider.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate))
                    {
                        throw e;
                    }
                    else
                    {
                        this._textViewTracker.IsLatestCompilationStale = true;
                        return;
                    }
                }
                catch (System.Runtime.InteropServices.COMException)
                {
                    // various reasons for COMException
                    // - binding failed
                    // - project unavailable
                    // - ...
                    return;
                }

                //Enumerate the signatures and append our custom content
                for (int i = 0; i < signatures.Count; i++)
                {
                    var sig = signatures[i];

                    if (contractContents != null && !String.IsNullOrEmpty(contractContents[i]))
                    {
                        signatures[i] = new SignatureWithContracts(sig, contractContents[i]);
                    }
                }

                //Print our elapsed time for preformance considerations
                var elapseTime = DateTime.Now - startTime;
                VSServiceProvider.Current.Logger.WriteToLog("Time to compute quickinfo: " + elapseTime.Milliseconds + "ms");
            }, "AugmentSignatureHelpSession");
        }