protected override int GetAdjustedContextPoint(int contextPoint, Document document) { // Determine the position in the buffer at which to end the tracking span representing // the part of the imaginary buffer before the text in the view. var tree = document.GetSyntaxTreeSynchronously(CancellationToken.None); var token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None); // Special case to handle class designer because it asks for debugger IntelliSense using // spans between members. if (contextPoint > token.Span.End && token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Block) && token.Parent.Parent is MemberDeclarationSyntax) { return contextPoint; } if (token.IsKindOrHasMatchingText(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Block)) { return token.SpanStart; } return token.FullSpan.End; }
public static string CreateUniqueEventName( Document document, string className, string objectName, string nameOfEvent, CancellationToken cancellationToken) { var type = document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetTypeByMetadataName(className); var name = objectName + "_" + nameOfEvent; var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken); var tree = document.GetSyntaxTreeSynchronously(cancellationToken); var typeNode = type.DeclaringSyntaxReferences.Where(r => r.SyntaxTree == tree).Select(r => r.GetSyntax(cancellationToken)).First(); var codeModel = document.Project.LanguageServices.GetService<ICodeModelNavigationPointService>(); var point = codeModel.GetStartPoint(typeNode, EnvDTE.vsCMPart.vsCMPartBody); var reservedNames = semanticModel.LookupSymbols(point.Value.Position, type).Select(m => m.Name); return NameGenerator.EnsureUniqueness(name, reservedNames, document.Project.LanguageServices.GetService<ISyntaxFactsService>().IsCaseSensitive); }
protected override int GetContainingClassName(Document document, SnapshotSpan fieldSpan, CancellationToken cancellationToken, ref string value, ref int hasDefaultValue) { // Find the nearest enclosing type declaration and use its name var syntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken); var type = syntaxTree.FindTokenOnLeftOfPosition(fieldSpan.Start.Position, cancellationToken).GetAncestor<TypeDeclarationSyntax>(); if (type != null) { value = type.Identifier.ToString(); if (!string.IsNullOrWhiteSpace(value)) { hasDefaultValue = 1; } } return VSConstants.S_OK; }
private static ISymbol GetEventSymbol( Document document, string objectTypeName, string nameOfEvent, INamedTypeSymbol type, CancellationToken cancellationToken) { var compilation = document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken); var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken); var objectType = compilation.GetTypeByMetadataName(objectTypeName); if (objectType == null) { throw new InvalidOperationException(); } var containingTree = document.GetSyntaxTreeSynchronously(cancellationToken); var typeLocation = type.Locations.FirstOrDefault(d => d.SourceTree == containingTree); if (typeLocation == null) { throw new InvalidOperationException(); } return semanticModel.LookupSymbols(typeLocation.SourceSpan.Start, objectType, nameOfEvent).SingleOrDefault(m => m.Kind == SymbolKind.Event); }
/// <summary> /// Ensure that an event handler exists for a given event. /// </summary> /// <param name="thisDocument">The document corresponding to this operation.</param> /// <param name="targetDocument">The document to generate the event handler in if it doesn't /// exist.</param> /// <param name="className">The name of the type to generate the event handler in.</param> /// <param name="objectName">The name of the event member (if <paramref /// name="useHandlesClause"/> is true)</param> /// <param name="objectTypeName">The name of the type containing the event.</param> /// <param name="nameOfEvent">The name of the event member in <paramref /// name="objectTypeName"/></param> /// <param name="eventHandlerName">The name of the method to be hooked up to the /// event.</param> /// <param name="itemidInsertionPoint">The VS itemid of the file to generate the event /// handler in.</param> /// <param name="useHandlesClause">If true, a vb "Handles" clause will be generated for the /// handler.</param> /// <param name="additionalFormattingRule">An additional formatting rule that can be used to /// format the newly inserted method</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>Either the unique id of the method if it already exists, or the unique id of /// the to be generated method, the text of the to be generated method, and the position in /// <paramref name="itemidInsertionPoint"/> where the text should be inserted.</returns> public static Tuple<string, string, VsTextSpan> EnsureEventHandler( Document thisDocument, Document targetDocument, string className, string objectName, string objectTypeName, string nameOfEvent, string eventHandlerName, uint itemidInsertionPoint, bool useHandlesClause, IFormattingRule additionalFormattingRule, CancellationToken cancellationToken) { var thisCompilation = thisDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken); var type = thisCompilation.GetTypeByMetadataName(className); var existingEventHandlers = GetCompatibleEventHandlers(targetDocument, className, objectTypeName, nameOfEvent, cancellationToken); var existingHandler = existingEventHandlers.SingleOrDefault(e => e.Item1 == eventHandlerName); if (existingHandler != null) { return Tuple.Create(existingHandler.Item2, (string)null, default(VsTextSpan)); } // Okay, it doesn't exist yet. Let's create it. var codeGenerationService = targetDocument.GetLanguageService<ICodeGenerationService>(); var syntaxFactory = targetDocument.GetLanguageService<SyntaxGenerator>(); var eventMember = GetEventSymbol(thisDocument, objectTypeName, nameOfEvent, type, cancellationToken); if (eventMember == null) { throw new InvalidOperationException(); } var eventType = ((IEventSymbol)eventMember).Type; if (eventType.Kind != SymbolKind.NamedType || ((INamedTypeSymbol)eventType).DelegateInvokeMethod == null) { throw new InvalidOperationException(ServicesVSResources.Event_type_is_invalid); } var handlesExpressions = useHandlesClause ? new[] { syntaxFactory.MemberAccessExpression( objectName != null ? syntaxFactory.IdentifierName(objectName) : syntaxFactory.ThisExpression(), syntaxFactory.IdentifierName(nameOfEvent)) } : null; var invokeMethod = ((INamedTypeSymbol)eventType).DelegateInvokeMethod; var newMethod = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: null, accessibility: Accessibility.Protected, modifiers: new DeclarationModifiers(), returnType: targetDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSpecialType(SpecialType.System_Void), explicitInterfaceSymbol: null, name: eventHandlerName, typeParameters: null, parameters: invokeMethod.Parameters.ToArray(), statements: null, handlesExpressions: handlesExpressions); var annotation = new SyntaxAnnotation(); newMethod = annotation.AddAnnotationToSymbol(newMethod); var codeModel = targetDocument.Project.LanguageServices.GetService<ICodeModelNavigationPointService>(); var syntaxFacts = targetDocument.Project.LanguageServices.GetService<ISyntaxFactsService>(); var targetSyntaxTree = targetDocument.GetSyntaxTreeSynchronously(cancellationToken); var position = type.Locations.First(loc => loc.SourceTree == targetSyntaxTree).SourceSpan.Start; var destinationType = syntaxFacts.GetContainingTypeDeclaration(targetSyntaxTree.GetRoot(cancellationToken), position); var insertionPoint = codeModel.GetEndPoint(destinationType, EnvDTE.vsCMPart.vsCMPartBody); if (insertionPoint == null) { throw new InvalidOperationException(ServicesVSResources.Can_t_find_where_to_insert_member); } var newType = codeGenerationService.AddMethod(destinationType, newMethod, new CodeGenerationOptions(autoInsertionLocation: false), cancellationToken); var newRoot = targetSyntaxTree.GetRoot(cancellationToken).ReplaceNode(destinationType, newType); newRoot = Simplifier.ReduceAsync( targetDocument.WithSyntaxRoot(newRoot), Simplifier.Annotation, null, cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSyntaxRootSynchronously(cancellationToken); var formattingRules = additionalFormattingRule.Concat(Formatter.GetDefaultFormattingRules(targetDocument)); newRoot = Formatter.FormatAsync( newRoot, Formatter.Annotation, targetDocument.Project.Solution.Workspace, targetDocument.Options, formattingRules, cancellationToken).WaitAndGetResult_Venus(cancellationToken); var newMember = newRoot.GetAnnotatedNodesAndTokens(annotation).Single(); var newMemberText = newMember.ToFullString(); // In VB, the final newline is likely a statement terminator in the parent - just add // one on so that things don't get messed. if (!newMemberText.EndsWith(Environment.NewLine, StringComparison.Ordinal)) { newMemberText += Environment.NewLine; } return Tuple.Create(ConstructMemberId(newMethod), newMemberText, insertionPoint.Value.ToVsTextSpan()); }