private void ResetElementKey(GlobalNodeKey globalNodeKey) { // Failure to find the element is not an error -- it just means the code // element didn't exist... if (_codeElementTable.TryGetValue(globalNodeKey.NodeKey, out var element)) { var keyedElement = ComAggregate.GetManagedObject <AbstractKeyedCodeElement>(element); if (keyedElement != null) { keyedElement.ReacquireNodeKey(globalNodeKey.Path, default); } } }
public void Remove(object element) { var codeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>(element); codeElement ??= ComAggregate.TryGetManagedObject <AbstractCodeElement>(this.Members.Item(element)); if (codeElement == null) { throw new ArgumentException(ServicesVSResources.Element_is_not_valid, nameof(element)); } codeElement.Delete(); }
internal static EnvDTE.CodeEnum Create( CodeModelState state, FileCodeModel fileCodeModel, SyntaxNodeKey nodeKey, int?nodeKind) { var element = new CodeEnum(state, fileCodeModel, nodeKey, nodeKind); var result = (EnvDTE.CodeEnum)ComAggregate.CreateAggregatedObject(element); fileCodeModel.OnCodeElementCreated(nodeKey, (EnvDTE.CodeElement)result); return(result); }
internal static new EnvDTE.CodeFunction Create( CodeModelState state, FileCodeModel fileCodeModel, SyntaxNodeKey nodeKey, int?nodeKind) { var element = new CodeFunctionWithEventHandler(state, fileCodeModel, nodeKey, nodeKind); var result = (EnvDTE.CodeFunction)ComAggregate.CreateAggregatedObject(element); fileCodeModel.OnCodeElementCreated(nodeKey, (EnvDTE.CodeElement)result); return(result); }
protected EnvDTE.CodeElements GetCollection <T>(object parentObject) { var parentInstance = ComAggregate.GetManagedObject <object>(parentObject); Debug.Assert(!Marshal.IsComObject(parentInstance), "We should have a pure managed object!"); if (parentInstance is ICodeElementContainer <T> container) { return(container.GetCollection()); } throw Exceptions.ThrowEFail(); }
internal static IEnumerator Create( CodeModelState state, ProjectId projectId, SymbolKey namespaceSymbolId ) { var newEnumerator = new ExternalNamespaceEnumerator( state, projectId, namespaceSymbolId ); return((IEnumerator)ComAggregate.CreateAggregatedObject(newEnumerator)); }
private EnvDTE.CodeElement CreateInternalCodeMember(CodeModelState state, FileCodeModel fileCodeModel, SyntaxNode node) { var element = CodeModelService.CreateInternalCodeElement(state, fileCodeModel, node); if (IsBatchOpen) { var codeElement = ComAggregate.TryGetManagedObject <AbstractKeyedCodeElement>(element); if (codeElement != null) { _batchElements.Add(codeElement); } } return(element); }
internal static EnvDTE.CodeElements Create( CodeModelState state, object parent, ProjectId projectId, INamespaceSymbol namespaceSymbol ) { var collection = new ExternalNamespaceCollection( state, parent, projectId, namespaceSymbol ); return((EnvDTE.CodeElements)ComAggregate.CreateAggregatedObject(collection)); }
public void Remove(object element) { var codeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>(element); if (codeElement == null) { codeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>(this.CodeElements.Item(element)); } if (codeElement == null) { throw new ArgumentException(ServicesVSResources.ElementIsNotValid, "element"); } codeElement.Delete(); }
internal static EnvDTE.CodeElements Create( CodeModelState state, object parent, FileCodeModel fileCodeModel, SyntaxNodeKey nodeKey ) { var collection = new InheritsImplementsCollection( state, parent, fileCodeModel, nodeKey ); return((EnvDTE.CodeElements)ComAggregate.CreateAggregatedObject(collection)); }
internal EnvDTE.CodeParameter AddParameter( EnvDTE.CodeElement parent, SyntaxNode containerNode, string name, object type, object position ) { var typeSymbol = CodeModelService.GetTypeSymbol( type, this.GetSemanticModel(), containerNode.SpanStart ); var typeName = typeSymbol.GetEscapedFullName(); var parameterNode = CodeModelService.CreateParameterNode( CodeModelService.GetUnescapedName(name), typeName ); var insertionIndex = CodeModelService.PositionVariantToParameterInsertionIndex( position, containerNode, fileCodeModel: this ); var newNode = InsertParameter(containerNode, parameterNode, insertionIndex); // Since parameters form part of the NodeKey for functions, delegates, and indexers, // creating a CodeParameter hooked up to the correct parent is a little tricky. After // the call to InsertParameter, the syntax tree has been updated, but not the NodeKey // map or the NodeKey in the parent CodeParameter. If we delegate the creation of the // CodeParameter to CodeModelService.CreateInternalCodeElement, it will attempt to // look up an element in the NodeKey map based on the new syntax tree. This will fail, // causing it to create a new, duplicate element for the parent. Later, when we // reacquire the NodeKeys, the original element will get the proper NodeKey, while the // duplicate will be updated to a meaningless NodeKey. Since the duplicate is the one // being used by the CodeParameter, most operations on it will then fail. // Instead, we need to have the parent passed in to us. var parentObj = ComAggregate.GetManagedObject <AbstractCodeMember>(parent); return(CodeParameter.Create( this.State, parentObj, CodeModelService.GetParameterName(newNode) )); }
/// <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); }
public void RenameNoUI( EnvDTE.CodeElement element, string newName, bool fPreview, bool fSearchComments, bool fOverloads ) { // TODO: Support options var codeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>(element); if (codeElement != null) { codeElement.RenameSymbol(newName); } }
internal T CreateCodeElement <T>(SyntaxNode node) { var nodeKey = CodeModelService.TryGetNodeKey(node); if (!nodeKey.IsEmpty) { // Check if the node exists in the parse tree. // Note that in designer spew the nodes don't get created right away so we skip this check. if (!IsBatchOpen && CodeModelService.LookupNode(nodeKey, GetSyntaxTree()) == null) { throw Exceptions.ThrowEFail(); } // See if the element exists. var previousElement = _elementTable.TryGetValue(nodeKey); // Here's our element... possibly. It must be valid -- if it isn't, // we need to remove it. if (previousElement != null) { var previousElementImpl = ComAggregate.TryGetManagedObject <AbstractCodeElement>(previousElement); if (previousElementImpl.IsValidNode()) { if (previousElement is T) { return((T)previousElement); } else { Debug.Fail("Called asked for the wrong type!"); throw new InvalidOperationException(); } } else { // This guy is no longer valid, so yank it out. No sense // continuing to look for a match, either. RemoveElement(nodeKey); } } } return((T)CodeModelService.CreateInternalCodeElement(this.State, this, node)); }
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}"); } _codeElementTable.Add(newNodeKey, codeElement); }
private ImmutableArray <EnvDTE.CodeElement> GetParts() { // Retrieving the parts is potentially very expensive because it can force multiple FileCodeModels to be instantiated. // Here, we cache the result to avoid having to perform these calculations each time GetParts() is called. // This *could* be an issue because it means that a PartialTypeCollection will not necessarily reflect the // current state of the user's code. However, because a new PartialTypeCollection is created every time the Parts // property is accessed on CodeClass, CodeStruct or CodeInterface, consumers would hit this behavior rarely. if (_parts == null) { var partsBuilder = ArrayBuilder <EnvDTE.CodeElement> .GetInstance(); var solution = this.Workspace.CurrentSolution; var symbol = ParentType.LookupSymbol(); foreach (var location in symbol.Locations.Where(l => l.IsInSource)) { var document = solution.GetDocument(location.SourceTree); if (document != null) { var fileCodeModelObject = this.Workspace.GetFileCodeModel(document.Id); if (fileCodeModelObject != null) { var fileCodeModel = ComAggregate.GetManagedObject <FileCodeModel>( fileCodeModelObject ); var element = fileCodeModel.CodeElementFromPosition( location.SourceSpan.Start, ParentType.Kind ); if (element != null) { partsBuilder.Add(element); } } } } _parts = partsBuilder.ToImmutableAndFree(); } return(_parts); }
internal List <GlobalNodeKey> GetCurrentNodeKeys() { var currentNodeKeys = new List <GlobalNodeKey>(); foreach (var element in _codeElementTable.Values) { var keyedElement = ComAggregate.TryGetManagedObject <AbstractKeyedCodeElement>(element); if (keyedElement == null) { continue; } if (keyedElement.TryLookupNode(out var node)) { var nodeKey = keyedElement.NodeKey; currentNodeKeys.Add(new GlobalNodeKey(nodeKey, new SyntaxPath(node))); } } return(currentNodeKeys); }
internal void OnBeforeCodeElementCreated(SyntaxNode node) { // It's conceivable that a consumer is creating a code element with the same node key as a "dead" element // that hasn't been removed from the cache yet. For example, the element could have been "deleted" by // simply replacing its text in the underlying buffer. To handle this situation, we test to see if the // element is "dead" by checking whether it's underlying node is invalid (that is, it can't be found by // its node key). If the element is "dead", we'll go ahead and remove it from the cache here to avoid a // collision with the new element. var nodeKey = CodeModelService.TryGetNodeKey(node); EnvDTE.CodeElement codeElement; if (!nodeKey.IsEmpty && _codeElementTable.TryGetValue(nodeKey, out codeElement)) { var managedElement = ComAggregate.GetManagedObject <AbstractKeyedCodeElement>(codeElement); if (managedElement?.IsValidNode() != true) { _codeElementTable.Remove(nodeKey); } } }
private ImmutableArray<EnvDTE.CodeElement> EnumerateOverloads() { var symbol = (IMethodSymbol)ParentElement.LookupSymbol(); // Only methods and constructors can be overloaded. However, all functions // can successfully return a collection of overloaded functions; if not // really overloaded, the collection contains just the original function. if (symbol.MethodKind != MethodKind.Ordinary && symbol.MethodKind != MethodKind.Constructor) { return ImmutableArray.Create((EnvDTE.CodeElement)Parent); } var overloadsBuilder = ImmutableArray.CreateBuilder<EnvDTE.CodeElement>(); foreach (var method in symbol.ContainingType.GetMembers(symbol.Name)) { if (method.Kind != SymbolKind.Method) { continue; } var location = method.Locations.FirstOrDefault(l => l.IsInSource); if (location != null) { var tree = location.SourceTree; var document = this.Workspace.CurrentSolution.GetDocument(tree); var fileCodeModelObject = this.Workspace.GetFileCodeModel(document.Id); var fileCodeModel = ComAggregate.GetManagedObject<FileCodeModel>(fileCodeModelObject); var element = fileCodeModel.CodeElementFromPosition(location.SourceSpan.Start, EnvDTE.vsCMElement.vsCMElementFunction); if (element != null) { overloadsBuilder.Add(element); } } } return overloadsBuilder.ToImmutable(); }
public void RemoveMember(object element) { // Is this an EnvDTE.CodeElement that we created? If so, try to get the underlying code element object. var abstractCodeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>( element ); if (abstractCodeElement == null) { if (element is EnvDTE.CodeElement codeElement) { // Is at least an EnvDTE.CodeElement? If so, try to retrieve it from the Members collection by name. // Note: This might throw an ArgumentException if the name isn't found in the collection. abstractCodeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>( this.Members.Item(codeElement.Name) ); } else if (element is string || element is int) { // Is this a string or int? If so, try to retrieve it from the Members collection. Again, this will // throw an ArgumentException if the name or index isn't found in the collection. abstractCodeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>( this.Members.Item(element) ); } } if (abstractCodeElement == null) { throw new ArgumentException( ServicesVSResources.Element_is_not_valid, nameof(element) ); } abstractCodeElement.Delete(); }
private ImmutableArray <EnvDTE.CodeElement> GetParts() { var partsBuilder = ImmutableArray.CreateBuilder <EnvDTE.CodeElement>(); var symbol = ParentType.LookupSymbol(); foreach (var location in symbol.Locations.Where(l => l.IsInSource)) { var tree = location.SourceTree; var document = this.Workspace.CurrentSolution.GetDocument(tree); var fileCodeModelObject = this.Workspace.GetFileCodeModel(document.Id); var fileCodeModel = ComAggregate.GetManagedObject <FileCodeModel>(fileCodeModelObject); var element = fileCodeModel.CodeElementFromPosition(location.SourceSpan.Start, ParentType.Kind); if (element != null) { partsBuilder.Add(element); } } return(partsBuilder.ToImmutable()); }
public void RemoveParameter(object element) { FileCodeModel.EnsureEditor(() => { // The parameters are part of the node key, so we need to update it // after removing a parameter. var node = LookupNode(); var nodePath = new SyntaxPath(node); var codeElement = ComAggregate.TryGetManagedObject <AbstractCodeElement>(element); codeElement ??= ComAggregate.TryGetManagedObject <AbstractCodeElement>(this.Parameters.Item(element)); if (codeElement == null) { throw new ArgumentException(ServicesVSResources.Element_is_not_valid, nameof(element)); } codeElement.Delete(); ReacquireNodeKey(nodePath, CancellationToken.None); }); }
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); }
private EnvDTE.CodeElement GetParameterElementForCodeModelEvent(CodeModelEvent codeModelEvent, EnvDTE.CodeElements parentParameters, object parentElement) { if (parentParameters == null) { return(null); } var parameterName = this.CodeModelService.GetName(codeModelEvent.Node); if (codeModelEvent.Type == CodeModelEventType.Remove) { var parentCodeElement = ComAggregate.TryGetManagedObject <AbstractCodeMember>(parentElement); if (parentCodeElement != null) { return((EnvDTE.CodeElement)CodeParameter.Create(this.State, parentCodeElement, parameterName)); } } else { return(parentParameters.Item(parameterName)); } return(null); }
internal T GetOrCreateCodeElement <T>(SyntaxNode node) { var nodeKey = CodeModelService.TryGetNodeKey(node); if (!nodeKey.IsEmpty) { // Since the node already has a key, check to see if a code element already // exists for it. If so, return that element it it's still valid; otherwise, // remove it from the table. if (_codeElementTable.TryGetValue(nodeKey, out var codeElement)) { if (codeElement != null) { var element = ComAggregate.TryGetManagedObject <AbstractCodeElement>( codeElement ); if (element.IsValidNode()) { if (codeElement is T tcodeElement) { return(tcodeElement); } throw new InvalidOperationException( $"Found a valid code element for {nodeKey}, but it is not of type, {typeof(T).ToString()}" ); } } } // Go ahead and remove the nodeKey from the table. At this point, we'll be creating a new one. _codeElementTable.Remove(nodeKey); } return((T)CodeModelService.CreateInternalCodeElement(this.State, this, node)); }
private EnvDTE.CodeElement GetAttributeArgumentForCodeModelEvent(CodeModelEvent codeModelEvent, EnvDTE.CodeElements parentAttributeArguments, object parentElement) { if (parentAttributeArguments == null) { return(null); } CodeModelService.GetAttributeArgumentParentAndIndex(codeModelEvent.Node, out var attributeNode, out var ordinal); if (codeModelEvent.Type == CodeModelEventType.Remove) { var parentCodeElement = ComAggregate.TryGetManagedObject <CodeAttribute>(parentElement); if (parentCodeElement != null) { return((EnvDTE.CodeElement)CodeAttributeArgument.Create(this.State, parentCodeElement, ordinal)); } } else { return(parentAttributeArguments.Item(ordinal + 1)); // Needs to be 1-based to call back into code model } return(null); }
internal static EnvDTE.CodeParameter Create(CodeModelState state, ProjectId projectId, IParameterSymbol symbol, AbstractExternalCodeMember parent) { var element = new ExternalCodeParameter(state, projectId, symbol, parent); return((EnvDTE.CodeParameter)ComAggregate.CreateAggregatedObject(element)); }
internal static EnvDTE.CodeFunction Create(CodeModelState state, AbstractCodeMember parent, MethodKind kind) { var newElement = new CodeAccessorFunction(state, parent, kind); return((EnvDTE.CodeFunction)ComAggregate.CreateAggregatedObject(newElement)); }
internal ComHandle <THandle, TObject> GetComHandle <THandle, TObject>() where THandle : class where TObject : ApartmentSensitiveComObject, THandle { return(new ComHandle <THandle, TObject>((THandle)ComAggregate.CreateAggregatedObject((TObject)this), (TObject)this)); }
internal static ICSCodeTypeLocation Create(string externalLocation) { var result = new CodeTypeLocationExtender(externalLocation); return((ICSCodeTypeLocation)ComAggregate.CreateAggregatedObject(result)); }