static void RecursivelyLookupContractsForProperties(InheritanceTracker @this) { Contract.Requires(@this != null); #region Dequeue if (@this._propertiesNeedingContractLookup.Count < 1) { return; } var propertyPair = @this._propertiesNeedingContractLookup.Dequeue(); var property = propertyPair.Value; var tagTuple = propertyPair.Key; #endregion try { var comp = @this._textViewTracker.LatestCompilation; if (comp == null) { ContractsPackageAccessor.Current.Logger.WriteToLog("No LatestCompilation, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } #region Get semantic property from syntactic property CSharpMember semanticProperty = null; semanticProperty = comp.GetMemberForPropertyDeclaration(property); if (semanticProperty == null) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 3) { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get semantic property from syntactic property, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get semantic property from syntactic property. Too many semantic models have already been fetched, skipping this property..."); goto Continue; } } #endregion #region Try get the property that this property is inherited from CSharpMember inheritedFromProperty; if (!TryGetIheritedFromMember(semanticProperty, property.Parent as TypeDeclarationNode, out inheritedFromProperty)) { goto Continue; } #endregion #region Uninstantiated property semanticProperty = semanticProperty.Uninstantiate(); #endregion #region Get our tool tip var toolTip = ""; if (!semanticProperty.IsAbstract && !semanticProperty.ContainingType.IsInterface) { toolTip = String.Format("Contracts inherited from {0}.", inheritedFromProperty.ContainingType.Name.Text); } #endregion #region Try get accessor contracts and update adornment IMethodReference getterReference = null; IMethodReference setterReference = null; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetPropertyAccessorReferences(inheritedFromProperty, out getterReference, out setterReference)) { if (tagTuple.Item1 != null && getterReference != null) { IMethodContract getterContracts; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetMethodContract(getterReference, out getterContracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tagTuple.Item1); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(getterContracts, toolTip); } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping getter..."); } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment not found, skipping getter..."); } } } if (tagTuple.Item2 != null && setterReference != null) { IMethodContract setterContracts; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetMethodContract(setterReference, out setterContracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tagTuple.Item2); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(setterContracts, toolTip); } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping setter..."); } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment not found, skipping setter..."); } } } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get CCI reference for: " + inheritedFromProperty.Name.Text); } #endregion } #region Exception handeling catch (IllFormedSemanticModelException e) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 2) { ContractsPackageAccessor.Current.Logger.WriteToLog("Error: An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Asking for a new semantic model..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Too many semantic models have been fetched, skipping this property..."); goto Continue; } } catch (InvalidOperationException e) { if (e.Message.Contains(ContractsPackageAccessor.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this property..."); goto Continue; } } else { throw e; } } catch (COMException e) { if (e.Message.Contains(ContractsPackageAccessor.COMExceptionMessage_BindingFailed)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this property..."); goto Continue; } } else { throw e; } } #endregion Continue: ContractsPackageAccessor.Current.QueueWorkItem(() => RecursivelyLookupContractsForProperties(@this)); return; RequeueAndAbort: @this._propertiesNeedingContractLookup.Enqueue(propertyPair); return; }
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 || !parseTree.IsModelReady()) { @this._textViewTracker.IsLatestSourceFileStale = true; Utilities.Delay(() => ContractsPackageAccessor.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))); ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new methods.", newKeys.Count)); //Update our method keys @this._methodKeys.Clear(); @this._methodKeys.AddAll(methods.Keys); ContractsPackageAccessor.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) { ContractsPackageAccessor.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); ContractsPackageAccessor.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 ContractsPackageAccessor.Current.QueueWorkItem(() => { foreach (var key in newKeys) { MethodDeclarationNode method; if (methods.TryGetValue(key, out method)) { ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.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(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer), DelayAfterMembersRevalutation); //Ask for the new VS model so we can look up contracts Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.Current.AskForNewVSModel), DelayAfterMembersRevalutation); }
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 || !parseTree.IsModelReady()) { @this._textViewTracker.IsLatestSourceFileStale = true; Utilities.Delay(() => ContractsPackageAccessor.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); } } ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new properties.", newTuples.Count)); //Update our property keys @this._propertyKeys.Clear(); @this._propertyKeys.AddAll(keys); ContractsPackageAccessor.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) { ContractsPackageAccessor.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); ContractsPackageAccessor.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 ContractsPackageAccessor.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 ContractsPackageAccessor.Current.Logger.WriteToLog("Skipping adornments for " + property.GetName(workingSnapshot) + " because get and set are on same line"); } else { ContractsPackageAccessor.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 ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item1); #endregion } if (tuple.Item2 != null) { #region Create setter placeholder adornment ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.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(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation); //Ask for the new VS model so we can look up contracts Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.Current.AskForNewVSModel, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation); }
static void RecursivelyLookupContractsForMethods(InheritanceTracker @this) { Contract.Requires(@this != null); #region Dequeue if (@this._methodsNeedingContractLookup.Count < 1) { return; } var methodPair = @this._methodsNeedingContractLookup.Dequeue(); var method = methodPair.Value; var tag = methodPair.Key; #endregion try { VSServiceProvider.Current.Logger.WriteToLog(String.Format("Attempting to lookup contracts for '{0}'", tag.ToString())); var comp = @this._textViewTracker.LatestCompilation; if (comp == null) { VSServiceProvider.Current.Logger.WriteToLog("No LatestCompilation, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } #region Get semantic method from syntactic method CSharpMember semanticMethod = null; semanticMethod = comp.GetMemberForMethodDeclaration(method); if (semanticMethod == null) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 3) { VSServiceProvider.Current.Logger.WriteToLog("Failed to get semantic method from syntactic method, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("Failed to get semantic method from syntactic method. Too many semantic models have already been fetched, skipping this method..."); goto Continue; } } #endregion #region Try get the method that this method is inherited from CSharpMember inheritedFromMethod; if (!TryGetIheritedFromMember(semanticMethod, method.Parent as TypeDeclarationNode, out inheritedFromMethod)) { goto Continue; } #endregion #region Uninstantiated method semanticMethod = semanticMethod.Uninstantiate(); #endregion #region Get our tool tip var toolTip = ""; if (!semanticMethod.IsAbstract && !semanticMethod.ContainingType.IsInterface) { toolTip = String.Format("Contracts inherited from {0}.", inheritedFromMethod.ContainingType.Name.Text); } #endregion #region Try get method contracts and update adornment IMethodContract contracts = null; if (@this._textViewTracker.ProjectTracker.ContractsProvider.TryGetMethodContract(inheritedFromMethod, out contracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tag); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(contracts, toolTip); } else { VSServiceProvider.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping method..."); } } else { VSServiceProvider.Current.Logger.WriteToLog("Placeholder adornment not found, skipping method..."); } } #endregion } #region Exception handeling catch (IllFormedSemanticModelException e) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 2) { VSServiceProvider.Current.Logger.WriteToLog("Error: An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Asking for a new semantic model..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Too many semantic models have been fetched, skipping this method..."); goto Continue; } } catch (InvalidOperationException e) { if (e.Message.Contains(VSServiceProvider.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this method..."); goto Continue; } } else { throw e; } } catch (COMException e) { if (e.Message.Contains(VSServiceProvider.COMExceptionMessage_BindingFailed)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this method..."); goto Continue; } } else { throw e; } } #endregion Continue: VSServiceProvider.Current.QueueWorkItem(() => RecursivelyLookupContractsForMethods(@this)); return; RequeueAndAbort: @this._methodsNeedingContractLookup.Enqueue(methodPair); return; }
static void RecursivelyLookupContractsForProperties(InheritanceTracker @this) { Contract.Requires(@this != null); #region Dequeue if (@this._propertiesNeedingContractLookup.Count < 1) return; var propertyPair = @this._propertiesNeedingContractLookup.Dequeue(); var property = propertyPair.Value; var tagTuple = propertyPair.Key; #endregion try { var comp = @this._textViewTracker.LatestCompilation; if (comp == null) { ContractsPackageAccessor.Current.Logger.WriteToLog("No LatestCompilation, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } #region Get semantic property from syntactic property CSharpMember semanticProperty = null; semanticProperty = comp.GetMemberForPropertyDeclaration(property); if (semanticProperty == null) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 3) { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get semantic property from syntactic property, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get semantic property from syntactic property. Too many semantic models have already been fetched, skipping this property..."); goto Continue; } } #endregion #region Try get the property that this property is inherited from CSharpMember inheritedFromProperty; if (!TryGetIheritedFromMember(semanticProperty, property.Parent as TypeDeclarationNode, out inheritedFromProperty)) { goto Continue; } #endregion #region Uninstantiated property semanticProperty = semanticProperty.Uninstantiate(); #endregion #region Get our tool tip var toolTip = ""; if (!semanticProperty.IsAbstract && !semanticProperty.ContainingType.IsInterface) toolTip = String.Format("Contracts inherited from {0}.", inheritedFromProperty.ContainingType.Name.Text); #endregion #region Try get accessor contracts and update adornment IMethodReference getterReference = null; IMethodReference setterReference = null; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetPropertyAccessorReferences(inheritedFromProperty, out getterReference, out setterReference)) { if (tagTuple.Item1 != null && getterReference != null) { IMethodContract getterContracts; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetMethodContract(getterReference, out getterContracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tagTuple.Item1); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(getterContracts, toolTip); } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping getter..."); } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment not found, skipping getter..."); } } } if (tagTuple.Item2 != null && setterReference != null) { IMethodContract setterContracts; if (((ContractsProvider)@this._textViewTracker.ProjectTracker.ContractsProvider).TryGetMethodContract(setterReference, out setterContracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tagTuple.Item2); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(setterContracts, toolTip); } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping setter..."); } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Placeholder adornment not found, skipping setter..."); } } } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to get CCI reference for: " + inheritedFromProperty.Name.Text); } #endregion } #region Exception handeling catch (IllFormedSemanticModelException e) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 2) { ContractsPackageAccessor.Current.Logger.WriteToLog("Error: An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Asking for a new semantic model..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Too many semantic models have been fetched, skipping this property..."); goto Continue; } } catch (InvalidOperationException e) { if (e.Message.Contains(ContractsPackageAccessor.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this property..."); goto Continue; } } else throw e; } catch (COMException e) { if (e.Message.Contains(ContractsPackageAccessor.COMExceptionMessage_BindingFailed)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; ContractsPackageAccessor.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { ContractsPackageAccessor.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this property..."); goto Continue; } } else throw e; } #endregion Continue: ContractsPackageAccessor.Current.QueueWorkItem(() => RecursivelyLookupContractsForProperties(@this)); return; RequeueAndAbort: @this._propertiesNeedingContractLookup.Enqueue(propertyPair); return; }
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 || !parseTree.IsModelReady()) { @this._textViewTracker.IsLatestSourceFileStale = true; Utilities.Delay(() => ContractsPackageAccessor.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); } ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new properties.", newTuples.Count)); //Update our property keys @this._propertyKeys.Clear(); @this._propertyKeys.AddAll(keys); ContractsPackageAccessor.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) { ContractsPackageAccessor.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); ContractsPackageAccessor.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 ContractsPackageAccessor.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 ContractsPackageAccessor.Current.Logger.WriteToLog("Skipping adornments for " + property.GetName(workingSnapshot) + " because get and set are on same line"); } else { ContractsPackageAccessor.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 ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item1); #endregion } if (tuple.Item2 != null) { #region Create setter placeholder adornment ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.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(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation); //Ask for the new VS model so we can look up contracts Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.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 || !parseTree.IsModelReady()) { @this._textViewTracker.IsLatestSourceFileStale = true; Utilities.Delay(() => ContractsPackageAccessor.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))); ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new methods.", newKeys.Count)); //Update our method keys @this._methodKeys.Clear(); @this._methodKeys.AddAll(methods.Keys); ContractsPackageAccessor.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) { ContractsPackageAccessor.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); ContractsPackageAccessor.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 ContractsPackageAccessor.Current.QueueWorkItem(() => { foreach (var key in newKeys) { MethodDeclarationNode method; if (methods.TryGetValue(key, out method)) { ContractsPackageAccessor.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(ContractsPackageAccessor.Current.VSOptionsPage); @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.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(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer), DelayAfterMembersRevalutation); //Ask for the new VS model so we can look up contracts Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.Current.AskForNewVSModel), DelayAfterMembersRevalutation); }
static void RecursivelyLookupContractsForMethods(InheritanceTracker @this) { Contract.Requires(@this != null); #region Dequeue if (@this._methodsNeedingContractLookup.Count < 1) return; var methodPair = @this._methodsNeedingContractLookup.Dequeue(); var method = methodPair.Value; var tag = methodPair.Key; #endregion try { VSServiceProvider.Current.Logger.WriteToLog(String.Format("Attempting to lookup contracts for '{0}'", tag.ToString())); var comp = @this._textViewTracker.LatestCompilation; if (comp == null) { VSServiceProvider.Current.Logger.WriteToLog("No LatestCompilation, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } #region Get semantic method from syntactic method CSharpMember semanticMethod = null; semanticMethod = comp.GetMemberForMethodDeclaration(method); if (semanticMethod == null) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 3) { VSServiceProvider.Current.Logger.WriteToLog("Failed to get semantic method from syntactic method, waiting for a new semantic model."); @this._textViewTracker.IsLatestCompilationStale = true; Utilities.Delay(() => VSServiceProvider.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("Failed to get semantic method from syntactic method. Too many semantic models have already been fetched, skipping this method..."); goto Continue; } } #endregion #region Try get the method that this method is inherited from CSharpMember inheritedFromMethod; if (!TryGetIheritedFromMember(semanticMethod, method.Parent as TypeDeclarationNode, out inheritedFromMethod)) { goto Continue; } #endregion #region Uninstantiated method semanticMethod = semanticMethod.Uninstantiate(); #endregion #region Get our tool tip var toolTip = ""; if (!semanticMethod.IsAbstract && !semanticMethod.ContainingType.IsInterface) toolTip = String.Format("Contracts inherited from {0}.", inheritedFromMethod.ContainingType.Name.Text); #endregion #region Try get method contracts and update adornment IMethodContract contracts = null; if (@this._textViewTracker.ProjectTracker.ContractsProvider.TryGetMethodContract(inheritedFromMethod, out contracts)) { var possibleAdornment = @this._adornmentManager.GetAdornment(tag); if (possibleAdornment != null) { var adornment = possibleAdornment as ContractAdornment; if (adornment != null) { adornment.SetContracts(contracts, toolTip); } else { VSServiceProvider.Current.Logger.WriteToLog("Placeholder adornment isn't a ContractAdornment (not good!), skipping method..."); } } else { VSServiceProvider.Current.Logger.WriteToLog("Placeholder adornment not found, skipping method..."); } } #endregion } #region Exception handeling catch (IllFormedSemanticModelException e) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 2) { VSServiceProvider.Current.Logger.WriteToLog("Error: An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Asking for a new semantic model..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("An 'IllFormedSemanticModelException' occured: '" + e.Message + "' Too many semantic models have been fetched, skipping this method..."); goto Continue; } } catch (InvalidOperationException e) { if (e.Message.Contains(VSServiceProvider.InvalidOperationExceptionMessage_TheSnapshotIsOutOfDate)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this method..."); goto Continue; } } else throw e; } catch (COMException e) { if (e.Message.Contains(VSServiceProvider.COMExceptionMessage_BindingFailed)) { if (@this.trackingNumberOfFetchedSemanticModels && @this.semanticModelsFetchedCounter <= 5) { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts, getting new compilation..."); @this._textViewTracker.IsLatestCompilationStale = true; VSServiceProvider.Current.AskForNewVSModel(); @this.semanticModelsFetchedCounter++; goto RequeueAndAbort; } else { VSServiceProvider.Current.Logger.WriteToLog("The Visual Studio Semantic/Syntactic model threw an exception (it's snapshot is out of date) while looking up contracts. Too many compilations have already been fetched, skipping this method..."); goto Continue; } } else throw e; } #endregion Continue: VSServiceProvider.Current.QueueWorkItem(() => RecursivelyLookupContractsForMethods(@this)); return; RequeueAndAbort: @this._methodsNeedingContractLookup.Enqueue(methodPair); return; }