internal void UpdateCodeElementNodeKey(AbstractKeyedCodeElement keyedElement, SyntaxNodeKey oldNodeKey, SyntaxNodeKey newNodeKey) { if (!_codeElementTable.TryGetValue(oldNodeKey, out var codeElement)) { throw new InvalidOperationException($"Could not find {oldNodeKey} in Code Model element table."); } _codeElementTable.Remove(oldNodeKey); var managedElement = ComAggregate.GetManagedObject <AbstractKeyedCodeElement>(codeElement); if (!object.Equals(managedElement, keyedElement)) { throw new InvalidOperationException($"Unexpected failure in Code Model while updating node keys {oldNodeKey} -> {newNodeKey}"); } // If we're updating this element with the same node key as an element that's already in the table, // just remove the old element. The old element will continue to function (through its node key), but // the new element will replace it in the cache. if (_codeElementTable.ContainsKey(newNodeKey)) { _codeElementTable.Remove(newNodeKey); } _codeElementTable.Add(newNodeKey, codeElement); }
public void Add(SyntaxNodeKey key, EnvDTE.CodeElement element) { // This code deals with a weird case of interaction with WinForms: The same // element can be added multiple times. What we have to do is bump // the conflicting element to a free [KeyName, Ordinal] slot // by incrementing [Ordinal] // Elements with the same node path can also be added multiple times in // normal editing scenarios, e.g. when a code element is changing preserving its name // (e.g. a class becomes an interface) or user just removes a block of code and // then readds it back before code elements for removed code were garbage collected. CodeElementWeakComAggregateHandle existingElementHandle; if (_elementWeakComHandles.TryGetValue(key, out existingElementHandle)) { int newOrdinal = key.Ordinal; while (true) { newOrdinal++; var currentKey = new SyntaxNodeKey(key.Name, newOrdinal); if (!_elementWeakComHandles.ContainsKey(currentKey)) { // We found a free "slot": use it and release the previous one AbstractKeyedCodeElement existingElement = null; EnvDTE.CodeElement existingElementManagedObject; if (existingElementHandle.TryGetManagedObjectWithoutCaringWhetherNativeObjectIsAlive(out existingElementManagedObject)) { existingElement = existingElementManagedObject as AbstractKeyedCodeElement; } _elementWeakComHandles.Remove(key); if (existingElementHandle.ComAggregateObject == null) { // The native object has already been released. // There's no need to re-add this handle. break; } Debug.Assert(existingElement != null, "The ComAggregate is alive. Why isn't the actual managed object?"); _elementWeakComHandles.Add(currentKey, existingElementHandle); existingElement.NodeKey = currentKey; break; } } } Debug.Assert(!_elementWeakComHandles.ContainsKey(key), "All right, we got it wrong. We should ahve a free entry in the table!"); _elementWeakComHandles.Add(key, new CodeElementWeakComAggregateHandle(element)); }
internal void UpdateCodeElementNodeKey(AbstractKeyedCodeElement keyedElement, SyntaxNodeKey oldNodeKey, SyntaxNodeKey newNodeKey) { var codeElement = _codeElementTable.Remove(oldNodeKey); var managedElement = ComAggregate.GetManagedObject <AbstractKeyedCodeElement>(codeElement); if (!object.Equals(managedElement, keyedElement)) { throw new InvalidOperationException($"Unexpected failure in Code Model while updating node keys {oldNodeKey} -> {newNodeKey}"); } _codeElementTable.Add(newNodeKey, codeElement); }
/// <summary> /// This function re-adds a code element to the table, taking care not to duplicate /// an element (i.e., making sure that no two elements with the same key-ordinal /// appear in the same element chain in the table). To resolve any conflict, each /// node with the given key is examined positionally, and the existing order is /// maintained as closely as possible -- but it is still possible the code element /// references to duplicate elements can get "bumped" by odd edits -- nothing we /// can do about this. /// </summary> internal void ResetElementNodeKey(AbstractKeyedCodeElement element, SyntaxNodeKey nodeKey) { EnvDTE.CodeElement elementInTable; _elementTable.Remove(element.NodeKey, out elementInTable); var abstractElementInTable = ComAggregate.GetManagedObject <AbstractKeyedCodeElement>(elementInTable); if (!object.Equals(abstractElementInTable, element)) { Debug.Fail("Found a different element with the same key!"); throw new InvalidOperationException(); } abstractElementInTable.NodeKey = nodeKey; _elementTable.Add(nodeKey, elementInTable); }