public static TextLookupRanges GetRanges([NotNull] this CodeCompletionContext context, [NotNull] ITreeNode node) { TokenNodeType tokenType = node.GetTokenType(); // completion has been triggered by space or quote, insert/replace at the caret (just after the space/quote) if (tokenType == T4TokenNodeTypes.WHITE_SPACE || tokenType == T4TokenNodeTypes.QUOTE) { var range = new DocumentRange(context.CaretDocumentOffset, context.CaretDocumentOffset); return(new TextLookupRanges(range, range)); } // completion has been triggered by a letter/number, determine which characters are before and after the caret // replace only those before in insert mode, replace before and after in replace mode TextRange nodeRange = node.GetDocumentRange().TextRange; var beforeCaretRange = new DocumentRange(new DocumentOffset(context.Document, nodeRange.StartOffset), context.CaretDocumentOffset); var afterCaretRange = new DocumentRange(context.CaretDocumentOffset, new DocumentOffset(context.Document, nodeRange.EndOffset)); return(new TextLookupRanges(beforeCaretRange, beforeCaretRange.Join(afterCaretRange))); }
private static MemberGenerationContext TryBuildMemberGenerationContext( [NotNull] CSharpCodeCompletionContext context) { var identifier = context.TerminatedContext.TreeNode as ICSharpIdentifier; if (identifier == null) { return(null); } // override int __ var fieldDeclaration = FieldDeclarationNavigator.GetByNameIdentifier(identifier); if (fieldDeclaration != null) { var fieldTypeUsage = fieldDeclaration.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments() as ITypeUsage; if (fieldTypeUsage == null) { return(null); } if (!CheckNodesBeforeTypeUsage(fieldTypeUsage, out var modifiersList)) { return(null); } var memberReplaceRanges = ComputeMemberReplaceRanges(TreeOffset.InvalidOffset); if (memberReplaceRanges == null) { return(null); } var typeDeclaration = GetPhysicalNonStaticTypeDeclaration(); if (typeDeclaration == null) { return(null); } if (modifiersList.ContainsPreprocessorDirectiveChildren()) { return(null); } return(new MemberGenerationContext(typeDeclaration, modifiersList, fieldTypeUsage, memberReplaceRanges)); } // override __; var referenceName = ReferenceNameNavigator.GetByNameIdentifier(identifier); var userTypeUsage = UserTypeUsageNavigator.GetByScalarTypeName(referenceName); var methodDeclaration = MethodDeclarationNavigator.GetByTypeUsage(userTypeUsage); if (methodDeclaration != null) { if (!CheckNodesBeforeTypeUsage(userTypeUsage, out var modifiersList)) { return(null); } var methodStartRange = context.TerminatedContext.ToOriginalTreeRange( new TreeTextRange(methodDeclaration.GetTreeStartOffset())); var memberReplaceRanges = ComputeMemberReplaceRanges(methodStartRange.StartOffset); if (memberReplaceRanges == null) { return(null); } var typeDeclaration = GetPhysicalNonStaticTypeDeclaration(); if (typeDeclaration == null) { return(null); } if (modifiersList.ContainsPreprocessorDirectiveChildren()) { return(null); } return(new MemberGenerationContext(typeDeclaration, modifiersList, expectedReturnTypeUsage: null, memberReplaceRanges)); } return(null); bool CheckNodesBeforeTypeUsage(ITypeUsage typeUsage, out IModifiersList modifiersList) { var previousSibling = typeUsage.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments(); modifiersList = previousSibling as IModifiersList; if (previousSibling is IModifiersList) { previousSibling = previousSibling.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments(); } if (previousSibling is IAttributeSectionList) { previousSibling = previousSibling.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments(); } if (previousSibling is IDocCommentBlock) { previousSibling = previousSibling.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments(); } return(previousSibling == null); } bool IsDeclarationToReplace(ITreeNode declaration) { switch (declaration) { case IMultipleFieldDeclaration _: case IMethodDeclaration _: case IPropertyDeclaration _: case IIndexerDeclaration _: return(true); default: return(false); } } TextLookupRanges ComputeMemberReplaceRanges(TreeOffset startOffset) { foreach (var treeNode in context.NodeInFile.ContainingNodes(returnThis: true)) { if (IsDeclarationToReplace(treeNode)) { return(RangesForDeclaration(treeNode)); } if (treeNode.IsFiltered()) { var prevMeaningfulSibling = treeNode.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments(); if (prevMeaningfulSibling != null && IsDeclarationToReplace(prevMeaningfulSibling) && (!startOffset.IsValid() || prevMeaningfulSibling.GetTreeStartOffset() >= startOffset)) { return(RangesForDeclaration(prevMeaningfulSibling)); } var nextMeaningfulSibling = treeNode.GetNextMeaningfulSibling(); if (nextMeaningfulSibling != null && IsDeclarationToReplace(nextMeaningfulSibling)) { return(RangesForDeclaration(nextMeaningfulSibling)); } } if (treeNode is IFieldDeclaration field) { var range = context.CompletionRanges.ReplaceRange; if (field.GetPreviousMeaningfulSibling() is ITypeUsage typeUsage) { range = range.SetStartTo(typeUsage.GetDocumentStartOffset()); } return(new TextLookupRanges(range, range)); } if (treeNode is ICSharpTypeMemberDeclaration) { return(context.CompletionRanges); } } return(null); TextLookupRanges RangesForDeclaration(ITreeNode treeNode) { var elementRange = ComputeReplaceRangeForDeclaration(treeNode); if (!elementRange.IsValid()) { return(null); } return(CodeCompletionContextProviderBase.GetTextLookupRanges(context.BasicContext, elementRange)); } DocumentRange ComputeReplaceRangeForDeclaration(ITreeNode declaration) { var startOffsetRange = new DocumentRange(GetDeclarationStartDocumentOffset(declaration)); var selectedRange = context.BasicContext.SelectedRange; var anchorDeclaration = GetAnchorDeclaration(declaration); var elementRange = startOffsetRange.Join(selectedRange) .JoinRight(new DocumentRange(anchorDeclaration.GetDocumentEndOffset())); if (!elementRange.IsValid()) { elementRange = startOffsetRange.Join(selectedRange); } if (!elementRange.IsValid()) { return(DocumentRange.InvalidRange); } var anchorDeclarationNameRange = GetDeclarationNameRange(anchorDeclaration); var declarationNameLine = anchorDeclarationNameRange.StartOffset.ToDocumentCoords().Line; var selectionLine = selectedRange.EndOffset.ToDocumentCoords().Line; if (declarationNameLine != selectionLine) { return(elementRange.SetEndTo(selectedRange.EndOffset)); } return(elementRange); } DocumentOffset GetDeclarationStartDocumentOffset(ITreeNode declaration) { // note: do not include attributes into member range var firstChild = declaration.GetNextMeaningfulChild(null); if (firstChild is IDocCommentBlock) { firstChild = firstChild.GetNextMeaningfulSibling(); } if (firstChild is IAttributeSectionList) { firstChild = firstChild.GetNextMeaningfulSibling(); } return((firstChild ?? declaration).GetDocumentStartOffset()); } ITreeNode GetAnchorDeclaration(ITreeNode declaration) { if (declaration is IMethodDeclaration unfinishedMethod && unfinishedMethod.NameIdentifier == null && unfinishedMethod.LPar == null && unfinishedMethod.ModifiersList == null && unfinishedMethod.TypeUsage != null) { var nextDeclaration = unfinishedMethod.GetNextMeaningfulSibling(); if (IsDeclarationToReplace(nextDeclaration)) { return(nextDeclaration); } } return(declaration); } DocumentRange GetDeclarationNameRange(ITreeNode declaration) { switch (declaration) { case IMultipleFieldDeclaration fieldDecl: return(fieldDecl.DeclaratorsEnumerable.FirstOrDefault().GetDocumentRange()); case IDeclaration decl: return(decl.GetNameDocumentRange()); default: return(declaration.GetDocumentRange()); } } } ITypeDeclaration GetPhysicalNonStaticTypeDeclaration() { foreach (var typeDeclaration in context.NodeInFile.ContainingNodes <ITypeDeclaration>()) { if (typeDeclaration.GetNameRange().EndOffset > context.BasicContext.CaretTreeOffset) { continue; } switch (typeDeclaration) { case IClassDeclaration classDeclaration when !classDeclaration.IsStatic: return(classDeclaration); case IStructDeclaration structDeclaration: return(structDeclaration); default: return(null); } } return(null); } }