/// <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; } }
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"); }