private static bool CanReplaceWithReducedName(
            this MemberAccessExpressionSyntax memberAccess,
            ExpressionSyntax reducedName,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (!IsThisOrTypeOrNamespace(memberAccess, semanticModel))
            {
                return false;
            }

            var speculationAnalyzer = new SpeculationAnalyzer(memberAccess, reducedName, semanticModel, cancellationToken);
            if (!speculationAnalyzer.SymbolsForOriginalAndReplacedNodesAreCompatible() ||
                speculationAnalyzer.ReplacementChangesSemantics())
            {
                return false;
            }

            if (WillConflictWithExistingLocal(memberAccess, reducedName))
            {
                return false;
            }

            if (IsMemberAccessADynamicInvocation(memberAccess, semanticModel))
            {
                return false;
            }

            if (memberAccess.AccessMethodWithDynamicArgumentInsideStructConstructor(semanticModel))
            {
                return false;
            }

            if (memberAccess.Expression.Kind() == SyntaxKind.BaseExpression)
            {
                var enclosingNamedType = semanticModel.GetEnclosingNamedType(memberAccess.SpanStart, cancellationToken);
                var symbol = semanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken).Symbol;
                if (enclosingNamedType != null &&
                    !enclosingNamedType.IsSealed &&
                    symbol != null &&
                    symbol.IsOverridable())
                {
                    return false;
                }
            }

            var invalidTransformation1 = ParserWouldTreatExpressionAsCast(reducedName, memberAccess);

            return !invalidTransformation1;
        }
예제 #2
0
 protected override INamedTypeSymbol DetermineTypeToGenerateIn(SemanticModel semanticModel, SimpleNameSyntax simpleName, CancellationToken cancellationToken)
 {
     return(semanticModel.GetEnclosingNamedType(simpleName.SpanStart, cancellationToken));
 }
예제 #3
0
        public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node)
        {
            if (!ValidateNode(node, context.Span))
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken);

            if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol)))
            {
                return;
            }

            TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false);

            if (declaration == null)
            {
                return;
            }

            for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent)
            {
                if (object.ReferenceEquals(declaration, parent))
                {
                    return;
                }
            }

            (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration);

            SyntaxNode nodeIncludingConditionalAccess = node.WalkUp(f => f.IsKind(SyntaxKind.ConditionalAccessExpression));

            if (expression != null ||
                (statements.Any() && nodeIncludingConditionalAccess.IsParentKind(SyntaxKind.ExpressionStatement)))
            {
                ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol);

                if (parameterInfos.IsDefault)
                {
                    return;
                }

                INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken);

                SemanticModel declarationSemanticModel = semanticModel;

                if (node.SyntaxTree != declaration.SyntaxTree)
                {
                    Document document = context.Solution.GetDocument(declaration.SyntaxTree);

                    // https://github.com/dotnet/roslyn/issues/5260
                    if (document == null)
                    {
                        return;
                    }

                    declarationSemanticModel = await document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
                }

                InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, nodeIncludingConditionalAccess, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken);

                string title = CSharpFacts.GetTitle(declaration);

                if (expression != null)
                {
                    context.RegisterRefactoring($"Inline {title}", ct => refactoring.InlineAsync(nodeIncludingConditionalAccess, expression, ct), GetDescriptor());

                    context.RegisterRefactoring($"Inline and remove {title}", ct => refactoring.InlineAndRemoveAsync(nodeIncludingConditionalAccess, expression, ct), GetDescriptor(), "Remove");
                }
                else
                {
                    var expressionStatement = (ExpressionStatementSyntax)nodeIncludingConditionalAccess.Parent;

                    context.RegisterRefactoring($"Inline {title}", ct => refactoring.InlineAsync(expressionStatement, statements, ct), GetDescriptor());

                    context.RegisterRefactoring($"Inline and remove {title}", ct => refactoring.InlineAndRemoveAsync(expressionStatement, statements, ct), GetDescriptor(), "Remove");
                }
            }
        }
예제 #4
0
            private ExpressionSyntax VisitSimpleName(SimpleNameSyntax rewrittenSimpleName, SimpleNameSyntax originalSimpleName)
            {
                _cancellationToken.ThrowIfCancellationRequested();

                // if this is "var", then do not process further
                if (originalSimpleName.IsVar)
                {
                    return(rewrittenSimpleName);
                }

                var identifier           = rewrittenSimpleName.Identifier;
                ExpressionSyntax newNode = rewrittenSimpleName;

                var isInsideCref = originalSimpleName.AncestorsAndSelf(ascendOutOfTrivia: true).Any(n => n is CrefSyntax);

                ////
                //// 1. if this identifier is an alias, we'll expand it here and replace the node completely.
                ////
                if (!SyntaxFacts.IsAliasQualifier(originalSimpleName))
                {
                    var aliasInfo = _semanticModel.GetAliasInfo(originalSimpleName, _cancellationToken);
                    if (aliasInfo != null)
                    {
                        var aliasTarget = aliasInfo.Target;

                        if (aliasTarget.IsNamespace() && ((INamespaceSymbol)aliasTarget).IsGlobalNamespace)
                        {
                            return(rewrittenSimpleName);
                        }

                        // if the enclosing expression is a typeof expression that already contains open type we cannot
                        // we need to insert an open type as well.
                        var typeOfExpression = originalSimpleName.GetAncestor <TypeOfExpressionSyntax>();
                        if (typeOfExpression != null && IsTypeOfUnboundGenericType(_semanticModel, typeOfExpression))
                        {
                            aliasTarget = ((INamedTypeSymbol)aliasTarget).ConstructUnboundGenericType();
                        }

                        // the expanded form replaces the current identifier name.
                        var replacement = FullyQualifyIdentifierName(
                            aliasTarget,
                            newNode,
                            originalSimpleName,
                            replaceNode: true,
                            isInsideCref: isInsideCref,
                            omitLeftHandSide: false)
                                          .WithAdditionalAnnotations(Simplifier.Annotation);

                        // We replace the simple name completely, so we can't continue and rename the token
                        // with a RenameLocationAnnotation.
                        // There's also no way of removing annotations, so we just add a DoNotRenameAnnotation.
                        if (replacement.Kind() == SyntaxKind.AliasQualifiedName)
                        {
                            var qualifiedReplacement = (AliasQualifiedNameSyntax)replacement;

                            var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Name.Identifier);

                            if (_annotationForReplacedAliasIdentifier != null)
                            {
                                newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier);
                            }

                            var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name);

                            newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo);

                            replacement = replacement.ReplaceNode(
                                qualifiedReplacement.Name,
                                qualifiedReplacement.Name.WithIdentifier(newIdentifier));

                            replacement = newNode.CopyAnnotationsTo(replacement);

                            var         firstReplacementToken = replacement.GetFirstToken(true, false, true, true);
                            var         firstOriginalToken    = originalSimpleName.GetFirstToken(true, false, true, true);
                            SyntaxToken tokenWithLeadingWhitespace;
                            if (TryAddLeadingElasticTriviaIfNecessary(firstReplacementToken, firstOriginalToken, out tokenWithLeadingWhitespace))
                            {
                                replacement = replacement.ReplaceToken(firstOriginalToken, tokenWithLeadingWhitespace);
                            }

                            replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName);

                            return(replacement);
                        }

                        if (replacement.Kind() == SyntaxKind.QualifiedName)
                        {
                            var qualifiedReplacement = (QualifiedNameSyntax)replacement;

                            var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Right.Identifier);

                            if (_annotationForReplacedAliasIdentifier != null)
                            {
                                newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier);
                            }

                            var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name);

                            newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo);

                            replacement = replacement.ReplaceNode(
                                qualifiedReplacement.Right,
                                qualifiedReplacement.Right.WithIdentifier(newIdentifier));

                            replacement = newNode.CopyAnnotationsTo(replacement);

                            replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName);

                            return(replacement);
                        }

                        throw new NotImplementedException();
                    }
                }

                var symbol = _semanticModel.GetSymbolInfo(originalSimpleName.Identifier).Symbol;

                if (symbol == null)
                {
                    return(newNode);
                }

                var typeArgumentSymbols      = TypeArgumentSymbolsPresentInName(originalSimpleName);
                var omitLeftSideOfExpression = false;

                // Check to see if the type Arguments in the resultant Symbol is recursively defined.
                if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: true))
                {
                    if (symbol.ContainingSymbol.Equals(symbol.OriginalDefinition.ContainingSymbol) &&
                        symbol.Kind == SymbolKind.Method &&
                        ((IMethodSymbol)symbol).IsStatic)
                    {
                        if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: false))
                        {
                            return(newNode);
                        }
                        else
                        {
                            omitLeftSideOfExpression = true;
                        }
                    }
                    else
                    {
                        return(newNode);
                    }
                }

                if (IsInvocationWithDynamicArguments(originalSimpleName, _semanticModel))
                {
                    return(newNode);
                }

                ////
                //// 2. If it's an attribute, make sure the identifier matches the attribute's class name.
                ////
                if (originalSimpleName.GetAncestor <AttributeSyntax>() != null)
                {
                    if (symbol.IsConstructor() && symbol.ContainingType?.IsAttribute() == true)
                    {
                        symbol = symbol.ContainingType;
                        var name = symbol.Name;

                        Debug.Assert(name.StartsWith(originalSimpleName.Identifier.ValueText, StringComparison.Ordinal));

                        // if the user already used the Attribute suffix in the attribute, we'll maintain it.
                        if (identifier.ValueText == name && name.EndsWith("Attribute", StringComparison.Ordinal))
                        {
                            identifier = identifier.WithAdditionalAnnotations(SimplificationHelpers.DontSimplifyAnnotation);
                        }

                        identifier = identifier.CopyAnnotationsTo(SyntaxFactory.VerbatimIdentifier(identifier.LeadingTrivia, name, name, identifier.TrailingTrivia));
                    }
                }

                ////
                //// 3. Always try to escape keyword identifiers
                ////
                identifier = TryEscapeIdentifierToken(identifier, originalSimpleName, _semanticModel).WithAdditionalAnnotations(Simplifier.Annotation);
                if (identifier != rewrittenSimpleName.Identifier)
                {
                    switch (newNode.Kind())
                    {
                    case SyntaxKind.IdentifierName:
                    case SyntaxKind.GenericName:
                        newNode = ((SimpleNameSyntax)newNode).WithIdentifier(identifier);
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }

                var parent = originalSimpleName.Parent;

                // do not complexify further for location where only simple names are allowed
                if (parent is MemberDeclarationSyntax ||
                    parent is MemberBindingExpressionSyntax ||
                    originalSimpleName.GetAncestor <NameEqualsSyntax>() != null ||
                    (parent is MemberAccessExpressionSyntax && parent.Kind() != SyntaxKind.SimpleMemberAccessExpression) ||
                    ((parent.Kind() == SyntaxKind.SimpleMemberAccessExpression || parent.Kind() == SyntaxKind.NameMemberCref) && originalSimpleName.IsRightSideOfDot()) ||
                    (parent.Kind() == SyntaxKind.QualifiedName && originalSimpleName.IsRightSideOfQualifiedName()) ||
                    (parent.Kind() == SyntaxKind.AliasQualifiedName))
                {
                    return(TryAddTypeArgumentToIdentifierName(newNode, symbol));
                }

                ////
                //// 4. If this is a standalone identifier or the left side of a qualified name or member access try to fully qualify it
                ////

                // we need to treat the constructor as type name, so just get the containing type.
                if (symbol.IsConstructor() && (parent.Kind() == SyntaxKind.ObjectCreationExpression || parent.Kind() == SyntaxKind.NameMemberCref))
                {
                    symbol = symbol.ContainingType;
                }

                // if it's a namespace or type name, fully qualify it.
                if (symbol.Kind == SymbolKind.NamedType ||
                    symbol.Kind == SymbolKind.Namespace)
                {
                    var replacement = FullyQualifyIdentifierName(
                        (INamespaceOrTypeSymbol)symbol,
                        newNode,
                        originalSimpleName,
                        replaceNode: false,
                        isInsideCref: isInsideCref,
                        omitLeftHandSide: omitLeftSideOfExpression)
                                      .WithAdditionalAnnotations(Simplifier.Annotation);

                    replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName);

                    return(replacement);
                }

                // if it's a member access, we're fully qualifying the left side and make it a member access.
                if (symbol.Kind == SymbolKind.Method ||
                    symbol.Kind == SymbolKind.Field ||
                    symbol.Kind == SymbolKind.Property)
                {
                    if (symbol.IsStatic ||
                        originalSimpleName.IsParentKind(SyntaxKind.NameMemberCref) ||
                        _semanticModel.SyntaxTree.IsNameOfContext(originalSimpleName.SpanStart, _semanticModel, _cancellationToken))
                    {
                        newNode = FullyQualifyIdentifierName(
                            symbol,
                            newNode,
                            originalSimpleName,
                            replaceNode: false,
                            isInsideCref: isInsideCref,
                            omitLeftHandSide: omitLeftSideOfExpression);
                    }
                    else
                    {
                        if (!IsPropertyNameOfObjectInitializer(originalSimpleName))
                        {
                            ExpressionSyntax left;

                            // Assumption here is, if the enclosing and containing types are different then there is Inheritence relationship
                            if (_semanticModel.GetEnclosingNamedType(originalSimpleName.SpanStart, _cancellationToken) != symbol.ContainingType)
                            {
                                left = SyntaxFactory.BaseExpression();
                            }
                            else
                            {
                                left = SyntaxFactory.ThisExpression();
                            }

                            var identifiersLeadingTrivia = newNode.GetLeadingTrivia();
                            newNode = TryAddTypeArgumentToIdentifierName(newNode, symbol);

                            newNode = newNode.CopyAnnotationsTo(
                                SyntaxFactory.MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    left,
                                    (SimpleNameSyntax)newNode.WithLeadingTrivia(null))
                                .WithLeadingTrivia(identifiersLeadingTrivia));
                        }
                    }
                }

                var result = newNode.WithAdditionalAnnotations(Simplifier.Annotation);

                result = AppendElasticTriviaIfNecessary(result, originalSimpleName);

                return(result);
            }
        private static async Task HandleSingleTypeAsync(CompletionContext context, SemanticModel semanticModel, SyntaxToken token, ITypeSymbol type, CancellationToken cancellationToken)
        {
            // If we have a Nullable<T>, unwrap it.
            if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
            {
                var typeArg = type.GetTypeArguments().FirstOrDefault();
                if (typeArg == null)
                {
                    return;
                }

                type = typeArg;
            }

            // When true, this completion provider shows both the type (e.g. DayOfWeek) and its qualified members (e.g.
            // DayOfWeek.Friday). We set this to false for enum-like cases (static members of structs and classes) so we
            // only show the qualified members in these cases.
            var showType           = true;
            var position           = context.Position;
            var enclosingNamedType = semanticModel.GetEnclosingNamedType(position, cancellationToken);

            if (type.TypeKind != TypeKind.Enum)
            {
                var enumType = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ??
                               TryGetCompletionListType(type, enclosingNamedType, semanticModel.Compilation);

                if (enumType == null)
                {
                    if (context.Trigger.Kind == CompletionTriggerKind.Insertion && s_triggerCharacters.Contains(context.Trigger.Character))
                    {
                        // This completion provider understands static members of matching types, but doesn't
                        // proactively trigger completion for them to avoid interfering with common typing patterns.
                        return;
                    }

                    // If this isn't an enum or marked with completionlist, also check if it contains static members of
                    // a matching type. These 'enum-like' types have similar characteristics to enum completion, but do
                    // not show the containing type as a separate item in completion.
                    showType = false;
                    enumType = TryGetTypeWithStaticMembers(type);
                    if (enumType == null)
                    {
                        return;
                    }
                }

                type = enumType;
            }

            var hideAdvancedMembers = context.CompletionOptions.HideAdvancedMembers;

            if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
            {
                return;
            }

            // Does type have any aliases?
            var alias = await type.FindApplicableAliasAsync(position, semanticModel, cancellationToken).ConfigureAwait(false);

            var displayText = alias != null
                ? alias.Name
                : type.ToMinimalDisplayString(semanticModel, position);

            // Add the enum itself.
            var symbol   = alias ?? type;
            var sortText = symbol.Name;

            if (showType)
            {
                context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                    displayText,
                                    displayTextSuffix: "",
                                    symbols: ImmutableArray.Create(symbol),
                                    rules: s_enumTypeRules,
                                    contextPosition: position,
                                    sortText: sortText));
            }

            // And now all the accessible members of the enum.
            if (type.TypeKind == TypeKind.Enum)
            {
                // We'll want to build a list of the actual enum members and all accessible instances of that enum, too
                var index = 0;

                var fields = type.GetMembers().OfType <IFieldSymbol>().Where(f => f.IsConst).Where(f => f.HasConstantValue);
                foreach (var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue)))
                {
                    index++;
                    if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                    {
                        continue;
                    }

                    var memberDisplayName = $"{displayText}.{field.Name}";
                    context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                                        displayText: memberDisplayName,
                                        displayTextSuffix: "",
                                        symbols: ImmutableArray.Create <ISymbol>(field),
                                        rules: CompletionItemRules.Default,
                                        contextPosition: position,
                                        sortText: $"{sortText}_{index:0000}",
                                        filterText: memberDisplayName));
                }
            }
            else if (enclosingNamedType is not null)
            {
                // Build a list of the members with the same type as the target
                foreach (var member in type.GetMembers())
                {
                    ISymbol     staticSymbol;
                    ITypeSymbol symbolType;
                    if (member is IFieldSymbol {
                        IsStatic: true
                    } field)
                    {
                        staticSymbol = field;
                        symbolType   = field.Type;
                    }
                    else if (member is IPropertySymbol {
                        IsStatic: true, IsIndexer: false
                    } property)
                    {
                        staticSymbol = property;
                        symbolType   = property.Type;
                    }
예제 #6
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation)
        {
            if (CheckSpan(invocation, context.Span))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                IMethodSymbol methodSymbol = GetMethodSymbol(invocation, semanticModel, context.CancellationToken);

                if (methodSymbol != null)
                {
                    MethodDeclarationSyntax methodDeclaration = await GetMethodDeclarationAsync(methodSymbol, context.CancellationToken).ConfigureAwait(false);

                    if (methodDeclaration != null &&
                        !invocation.Ancestors().Any(f => f == methodDeclaration))
                    {
                        ExpressionSyntax expression = GetMethodExpression(methodDeclaration);

                        if (expression != null)
                        {
                            List <ParameterInfo> parameterInfos = GetParameterInfos(invocation, methodSymbol, semanticModel, context.CancellationToken);

                            if (parameterInfos != null)
                            {
                                INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(invocation.SpanStart, context.CancellationToken);

                                SemanticModel declarationSemanticModel = (invocation.SyntaxTree == methodDeclaration.SyntaxTree)
                                    ? semanticModel
                                    : await context.Solution.GetDocument(methodDeclaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                                var refactoring = new InlineMethodExpressionRefactoring(context.Document, invocation, enclosingType, methodSymbol, methodDeclaration, parameterInfos.ToArray(), semanticModel, declarationSemanticModel, context.CancellationToken);

                                context.RegisterRefactoring("Inline method", c => refactoring.InlineMethodAsync(invocation, expression));

                                context.RegisterRefactoring("Inline and remove method", c => refactoring.InlineAndRemoveMethodAsync(invocation, expression));
                            }
                        }
                        else if (methodSymbol.ReturnsVoid &&
                                 invocation.IsParentKind(SyntaxKind.ExpressionStatement))
                        {
                            BlockSyntax body = methodDeclaration.Body;

                            if (body != null)
                            {
                                SyntaxList <StatementSyntax> statements = body.Statements;

                                if (statements.Any())
                                {
                                    List <ParameterInfo> parameterInfos = GetParameterInfos(invocation, methodSymbol, semanticModel, context.CancellationToken);

                                    if (parameterInfos != null)
                                    {
                                        var expressionStatement = (ExpressionStatementSyntax)invocation.Parent;

                                        INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(invocation.SpanStart, context.CancellationToken);

                                        SemanticModel declarationSemanticModel = (invocation.SyntaxTree == methodDeclaration.SyntaxTree)
                                            ? semanticModel
                                            : await context.Solution.GetDocument(methodDeclaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                                        var refactoring = new InlineMethodStatementsRefactoring(context.Document, invocation, enclosingType, methodSymbol, methodDeclaration, parameterInfos.ToArray(), semanticModel, declarationSemanticModel, context.CancellationToken);

                                        context.RegisterRefactoring("Inline method", c => refactoring.InlineMethodAsync(expressionStatement, statements));

                                        context.RegisterRefactoring("Inline and remove method", c => refactoring.InlineAndRemoveMethodAsync(expressionStatement, statements));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        private static async Task HandleSingleTypeAsync(CompletionContext context, SemanticModel semanticModel, SyntaxToken token, ITypeSymbol type, CancellationToken cancellationToken)
        {
            // If we have a Nullable<T>, unwrap it.
            if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
            {
                var typeArg = type.GetTypeArguments().FirstOrDefault();
                if (typeArg == null)
                    return;

                type = typeArg;
            }

            var position = context.Position;
            if (type.TypeKind != TypeKind.Enum)
            {
                var enumType = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ??
                               TryGetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation);

                if (enumType == null)
                    return;

                type = enumType;
            }

            var options = context.Options;
            var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language);
            if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                return;

            // Does type have any aliases?
            var alias = await type.FindApplicableAliasAsync(position, semanticModel, cancellationToken).ConfigureAwait(false);

            var displayText = alias != null
                ? alias.Name
                : type.ToMinimalDisplayString(semanticModel, position);

            // Add the enum itself.
            var symbol = alias ?? type;
            var sortText = symbol.Name;

            context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                displayText,
                displayTextSuffix: "",
                symbols: ImmutableArray.Create(symbol),
                rules: s_enumTypeRules,
                contextPosition: position,
                sortText: sortText));

            // And now all the accessible members of the enum.
            if (type.TypeKind == TypeKind.Enum)
            {
                // We'll want to build a list of the actual enum members and all accessible instances of that enum, too
                var index = 0;

                var fields = type.GetMembers().OfType<IFieldSymbol>().Where(f => f.IsConst).Where(f => f.HasConstantValue);
                foreach (var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue)))
                {
                    index++;
                    if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation))
                        continue;

                    var memberDisplayName = $"{displayText}.{field.Name}";
                    context.AddItem(SymbolCompletionItem.CreateWithSymbolId(
                        displayText: memberDisplayName,
                        displayTextSuffix: "",
                        symbols: ImmutableArray.Create<ISymbol>(field),
                        rules: CompletionItemRules.Default,
                        contextPosition: position,
                        sortText: $"{sortText}_{index:0000}",
                        filterText: memberDisplayName));
                }
            }
        }
예제 #8
0
        public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node)
        {
            if (!CheckNode(node, context.Span))
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken);

            if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol)))
            {
                return;
            }

            TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false);

            if (declaration == null)
            {
                return;
            }

            for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent)
            {
                if (object.ReferenceEquals(declaration, parent))
                {
                    return;
                }
            }

            (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration);

            if (expression != null ||
                (statements.Any() && node.IsParentKind(SyntaxKind.ExpressionStatement)))
            {
                ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol);

                if (parameterInfos.IsDefault)
                {
                    return;
                }

                INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken);

                SemanticModel declarationSemanticModel = (node.SyntaxTree == declaration.SyntaxTree)
                    ? semanticModel
                    : await context.Solution.GetDocument(declaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, node, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken);

                string title = declaration.GetTitle();

                if (expression != null)
                {
                    context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(node, expression, cancellationToken));

                    context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(node, expression, cancellationToken));
                }
                else
                {
                    var expressionStatement = (ExpressionStatementSyntax)node.Parent;

                    context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(expressionStatement, statements, cancellationToken));

                    context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(expressionStatement, statements, cancellationToken));
                }
            }
        }