Exemple #1
0
        private static ulong?GetConstantValueForBitwiseOrCheck(IOperation operation)
        {
            // We might have a nullable conversion on top of an integer constant. But only dig out
            // one level.

#if !CODE_STYLE
            if (operation is IConversionOperation conversion &&
                conversion.Conversion.IsImplicit &&
                conversion.Conversion.IsNullable)
            {
                operation = conversion.Operand;
            }
#endif

            var constantValue = operation.ConstantValue;
            if (!constantValue.HasValue || constantValue.Value == null)
            {
                return(null);
            }

            if (!operation.Type.SpecialType.IsIntegralType())
            {
                return(null);
            }

            return(IntegerUtilities.ToUInt64(constantValue.Value));
        }
Exemple #2
0
        private static bool TryGetAllEnumMembers(
            ITypeSymbol enumType,
            Dictionary <long, ISymbol> enumValues)
        {
            foreach (var member in enumType.GetMembers())
            {
                // skip `.ctor` and `__value`
                var fieldSymbol = member as IFieldSymbol;
                if (fieldSymbol == null || fieldSymbol.Type.SpecialType != SpecialType.None)
                {
                    continue;
                }

                if (fieldSymbol.ConstantValue == null)
                {
                    // We have an enum that has problems with it (i.e. non-const members).  We won't
                    // be able to determine properly if the switch is complete.  Assume it is so we
                    // don't offer to do anything.
                    return(false);
                }

                // Multiple enum members may have the same value.  Only consider the first one
                // we run int.
                var enumValue = IntegerUtilities.ToInt64(fieldSymbol.ConstantValue);
                if (!enumValues.ContainsKey(enumValue))
                {
                    enumValues.Add(enumValue, fieldSymbol);
                }
            }

            return(true);
        }
        private static ExpressionSyntax GenerateIntegralLiteralExpression(
            ITypeSymbol type, object value, string suffix, bool canUseFieldReference)
        {
            // If it's the constant value 0, and the type of the value matches the type we want for
            // this context, then we can just emit the literal 0 here.  We don't want to emit things
            // like UInteger.MinValue.
            if (value != null && IntegerUtilities.ToUInt64(value) == 0 && TypesMatch(type, value))
            {
                return(GenerateLiteralExpression(0, "0"));
            }

            var constants = value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static).Where(f => f.IsLiteral);

            return(GenerateLiteralExpression(type, value, constants, null, suffix, canUseFieldReference));
        }
        public FindLiteralsSearchEngine(
            Solution solution,
            IStreamingFindLiteralReferencesProgress progress,
            object value,
            CancellationToken cancellationToken
            )
        {
            _solution          = solution;
            _progress          = progress;
            _progressTracker   = progress.ProgressTracker;
            _value             = value;
            _cancellationToken = cancellationToken;

            switch (value)
            {
            case string s:
                _stringValue = s;
                _searchKind  = SearchKind.StringLiterals;
                break;

            case double d:
                _longValue  = BitConverter.DoubleToInt64Bits(d);
                _searchKind = SearchKind.NumericLiterals;
                break;

            case float f:
                _longValue  = BitConverter.DoubleToInt64Bits(f);
                _searchKind = SearchKind.NumericLiterals;
                break;

            case decimal _:     // unsupported
                _searchKind = SearchKind.None;
                break;

            case char _:
                _longValue  = IntegerUtilities.ToInt64(value);
                _searchKind = SearchKind.CharacterLiterals;
                break;

            default:
                _longValue  = IntegerUtilities.ToInt64(value);
                _searchKind = SearchKind.NumericLiterals;
                break;
            }
        }
Exemple #5
0
        private static bool TryRemoveExistingEnumMembers(
            ISwitchOperation switchStatement,
            Dictionary <long, ISymbol> enumValues
            )
        {
            foreach (var switchCase in switchStatement.Cases)
            {
                foreach (var clause in switchCase.Clauses)
                {
                    switch (clause.CaseKind)
                    {
                    default:
                    case CaseKind.None:
                    case CaseKind.Relational:
                    case CaseKind.Range:
                        // This was some sort of complex switch.  For now just ignore
                        // these and assume that they're complete.
                        return(false);

                    case CaseKind.Default:
                        // ignore the 'default/else' clause.
                        continue;

                    case CaseKind.SingleValue:
                        var value = ((ISingleValueCaseClauseOperation)clause).Value;
                        if (value == null || !value.ConstantValue.HasValue)
                        {
                            // We had a case which didn't resolve properly.
                            // Assume the switch is complete.
                            return(false);
                        }

                        var caseValue = IntegerUtilities.ToInt64(value.ConstantValue.Value);
                        enumValues.Remove(caseValue);
                        break;
                    }
                }
            }

            return(true);
        }
Exemple #6
0
        private static bool TryRemoveExistingEnumMembers(
            ISwitchExpressionOperation operation, Dictionary <long, ISymbol> enumMembers)
        {
            foreach (var arm in operation.Arms)
            {
                if (arm.Pattern is IConstantPatternOperation constantPattern)
                {
                    var constantValue = constantPattern.Value.ConstantValue;
                    if (!constantValue.HasValue)
                    {
                        // We had a case which didn't resolve properly.
                        // Assume the switch is complete.
                        return(false);
                    }

                    enumMembers.Remove(IntegerUtilities.ToInt64(constantValue.Value));
                }
            }

            return(true);
        }
Exemple #7
0
        private static ExpressionSyntax CreateEnumMemberValue(EnumDeclarationSyntax destinationOpt, IFieldSymbol enumMember)
        {
            if (!enumMember.HasConstantValue)
            {
                return(null);
            }

            if (enumMember.ConstantValue is not byte and
                not sbyte and
                not ushort and
                not short and
                not int and
                not uint and
                not long and
                not ulong)
            {
                return(null);
            }

            var value = IntegerUtilities.ToInt64(enumMember.ConstantValue);

            if (destinationOpt != null)
            {
                if (destinationOpt.Members.Count == 0)
                {
                    if (value == 0)
                    {
                        return(null);
                    }
                }
                else
                {
                    // Don't generate an initializer if no other members have them, and our value
                    // would be correctly inferred from our position.
                    if (destinationOpt.Members.Count == value &&
                        destinationOpt.Members.All(m => m.EqualsValue == null))
                    {
                        return(null);
                    }

                    // Existing members, try to stay consistent with their style.
                    var lastMember = destinationOpt.Members.LastOrDefault(m => m.EqualsValue != null);
                    if (lastMember != null)
                    {
                        var lastExpression = lastMember.EqualsValue.Value;
                        if (lastExpression.Kind() == SyntaxKind.LeftShiftExpression &&
                            IntegerUtilities.HasOneBitSet(value))
                        {
                            var binaryExpression = (BinaryExpressionSyntax)lastExpression;
                            if (binaryExpression.Left.Kind() == SyntaxKind.NumericLiteralExpression)
                            {
                                var numericLiteral = (LiteralExpressionSyntax)binaryExpression.Left;
                                if (numericLiteral.Token.ValueText == "1")
                                {
                                    // The user is left shifting ones, stick with that pattern
                                    var shiftValue = IntegerUtilities.LogBase2(value);

                                    // Re-use the numericLiteral text so type suffixes match too
                                    return(SyntaxFactory.BinaryExpression(
                                               SyntaxKind.LeftShiftExpression,
                                               SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(numericLiteral.Token.Text, 1)),
                                               SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(shiftValue.ToString(), shiftValue))));
                                }
                            }
                        }
                        else if (lastExpression.IsKind(SyntaxKind.NumericLiteralExpression, out LiteralExpressionSyntax numericLiteral))
                        {
                            var numericToken = numericLiteral.Token;
                            var numericText  = numericToken.ToString();

                            if (numericText.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
                            {
                                // Hex
                                return(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
                                                                       SyntaxFactory.Literal(numericText.Substring(0, 2) + value.ToString("X"), value)));
                            }
                            else if (numericText.StartsWith("0b", StringComparison.OrdinalIgnoreCase))
                            {
                                return(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
                                                                       SyntaxFactory.Literal(numericText.Substring(0, 2) + Convert.ToString(value, 2), value)));
                            }
                        }
                    }
                }
            }

            var namedType      = enumMember.Type as INamedTypeSymbol;
            var underlyingType = namedType?.EnumUnderlyingType;

            return(ExpressionGenerator.GenerateNonEnumValueExpression(
                       underlyingType,
                       enumMember.ConstantValue,
                       canUseFieldReference: true));
        }
Exemple #8
0
        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 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;

            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;
                    }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var numericToken = await GetNumericTokenAsync(context).ConfigureAwait(false);

            if (numericToken == default || numericToken.ContainsDiagnostics)
            {
                return;
            }

            var syntaxNode    = numericToken.GetRequiredParent();
            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = semanticModel.GetTypeInfo(syntaxNode, cancellationToken).Type;

            if (symbol == null)
            {
                return;
            }

            if (!IsIntegral(symbol.SpecialType))
            {
                return;
            }

            var valueOpt = semanticModel.GetConstantValue(syntaxNode);

            if (!valueOpt.HasValue)
            {
                return;
            }

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var value       = IntegerUtilities.ToInt64(valueOpt.Value);
            var numericText = numericToken.ToString();

            var(hexPrefix, binaryPrefix) = GetNumericLiteralPrefixes();
            var(prefix, number, suffix)  = GetNumericLiteralParts(numericText, hexPrefix, binaryPrefix);
            var kind = string.IsNullOrEmpty(prefix) ? NumericKind.Decimal
                : prefix.Equals(hexPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Hexadecimal
                : prefix.Equals(binaryPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Binary
                : NumericKind.Unknown;

            if (kind == NumericKind.Unknown)
            {
                return;
            }

            if (kind != NumericKind.Decimal)
            {
                RegisterRefactoringWithResult(value.ToString(), FeaturesResources.Convert_to_decimal);
            }

            if (kind != NumericKind.Binary)
            {
                RegisterRefactoringWithResult(binaryPrefix + Convert.ToString(value, toBase: 2), FeaturesResources.Convert_to_binary);
            }

            if (kind != NumericKind.Hexadecimal)
            {
                RegisterRefactoringWithResult(hexPrefix + value.ToString("X"), FeaturesResources.Convert_to_hex);
            }

            const string DigitSeparator = "_";

            if (numericText.Contains(DigitSeparator))
            {
                RegisterRefactoringWithResult(prefix + number.Replace(DigitSeparator, string.Empty), FeaturesResources.Remove_separators);
            }
            else
            {
                switch (kind)
                {
                case NumericKind.Decimal when number.Length > 3:
                    RegisterRefactoringWithResult(AddSeparators(number, interval: 3), FeaturesResources.Separate_thousands);
                    break;

                case NumericKind.Hexadecimal when number.Length > 4:
                    RegisterRefactoringWithResult(hexPrefix + AddSeparators(number, interval: 4), FeaturesResources.Separate_words);
                    break;

                case NumericKind.Binary when number.Length > 4:
                    RegisterRefactoringWithResult(binaryPrefix + AddSeparators(number, interval: 4), FeaturesResources.Separate_nibbles);
                    break;
                }
            }

            void RegisterRefactoringWithResult(string text, string title)
            {
                context.RegisterRefactoring(
                    new MyCodeAction(title, c => ReplaceTokenAsync(document, root, numericToken, value, text, suffix)),
                    numericToken.Span);
            }
        }
Exemple #10
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var cancellationToken = context.CancellationToken;
            var syntaxFacts       = document.GetLanguageService <ISyntaxFactsService>();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var numericToken = await root.SyntaxTree.GetTouchingTokenAsync(context.Span.Start,
                                                                           token => syntaxFacts.IsNumericLiteralExpression(token.Parent), cancellationToken).ConfigureAwait(false);

            if (numericToken == default)
            {
                return;
            }

            if (numericToken.ContainsDiagnostics)
            {
                return;
            }

            if (context.Span.Length > 0 &&
                context.Span != numericToken.Span)
            {
                return;
            }

            var syntaxNode    = numericToken.Parent;
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = semanticModel.GetTypeInfo(syntaxNode, cancellationToken).Type;

            if (symbol == null)
            {
                return;
            }

            if (!IsIntegral(symbol.SpecialType))
            {
                return;
            }

            var valueOpt = semanticModel.GetConstantValue(syntaxNode);

            if (!valueOpt.HasValue)
            {
                return;
            }

            var value       = IntegerUtilities.ToInt64(valueOpt.Value);
            var numericText = numericToken.ToString();

            var(hexPrefix, binaryPrefix) = GetNumericLiteralPrefixes();
            var(prefix, number, suffix)  = GetNumericLiteralParts(numericText, hexPrefix, binaryPrefix);
            var kind = string.IsNullOrEmpty(prefix) ? NumericKind.Decimal
                : prefix.Equals(hexPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Hexadecimal
                : prefix.Equals(binaryPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Binary
                : NumericKind.Unknown;

            if (kind == NumericKind.Unknown)
            {
                return;
            }

            if (kind != NumericKind.Decimal)
            {
                RegisterRefactoringWithResult(value.ToString(), FeaturesResources.Convert_to_decimal);
            }

            if (kind != NumericKind.Binary)
            {
                RegisterRefactoringWithResult(binaryPrefix + Convert.ToString(value, 2), FeaturesResources.Convert_to_binary);
            }

            if (kind != NumericKind.Hexadecimal)
            {
                RegisterRefactoringWithResult(hexPrefix + value.ToString("X"), FeaturesResources.Convert_to_hex);
            }

            const string DigitSeparator = "_";

            if (numericText.Contains(DigitSeparator))
            {
                RegisterRefactoringWithResult(prefix + number.Replace(DigitSeparator, string.Empty), FeaturesResources.Remove_separators);
            }
            else
            {
                switch (kind)
                {
                case NumericKind.Decimal when number.Length > 3:
                    RegisterRefactoringWithResult(AddSeparators(number, 3), FeaturesResources.Separate_thousands);
                    break;

                case NumericKind.Hexadecimal when number.Length > 4:
                    RegisterRefactoringWithResult(hexPrefix + AddSeparators(number, 4), FeaturesResources.Separate_words);
                    break;

                case NumericKind.Binary when number.Length > 4:
                    RegisterRefactoringWithResult(binaryPrefix + AddSeparators(number, 4), FeaturesResources.Separate_nibbles);
                    break;
                }
            }

            void RegisterRefactoringWithResult(string text, string title)
            {
                context.RegisterRefactoring(new MyCodeAction(title, c =>
                {
                    var generator    = SyntaxGenerator.GetGenerator(document);
                    var updatedToken = generator.NumericLiteralToken(text + suffix, (ulong)value)
                                       .WithTriviaFrom(numericToken);
                    var updatedRoot = root.ReplaceToken(numericToken, updatedToken);
                    return(Task.FromResult(document.WithSyntaxRoot(updatedRoot)));
                }));
            }
        }
        private static async Task <SyntaxTreeIndex> CreateIndexAsync(
            Document document, Checksum checksum, CancellationToken cancellationToken)
        {
            var project     = document.Project;
            var stringTable = GetStringTable(project);

            var syntaxFacts     = document.GetLanguageService <ISyntaxFactsService>();
            var infoFactory     = document.GetLanguageService <IDeclaredSymbolInfoFactoryService>();
            var ignoreCase      = syntaxFacts != null && !syntaxFacts.IsCaseSensitive;
            var isCaseSensitive = !ignoreCase;

            GetIdentifierSet(ignoreCase, out var identifiers, out var escapedIdentifiers);

            var stringLiterals = StringLiteralHashSetPool.Allocate();
            var longLiterals   = LongLiteralHashSetPool.Allocate();

            try
            {
                var containsForEachStatement           = false;
                var containsLockStatement              = false;
                var containsUsingStatement             = false;
                var containsQueryExpression            = false;
                var containsThisConstructorInitializer = false;
                var containsBaseConstructorInitializer = false;
                var containsElementAccess              = false;
                var containsIndexerMemberCref          = false;
                var containsDeconstruction             = false;
                var containsAwait = false;

                var predefinedTypes     = (int)PredefinedType.None;
                var predefinedOperators = (int)PredefinedOperator.None;

                var declaredSymbolInfos = ArrayBuilder <DeclaredSymbolInfo> .GetInstance();

                if (syntaxFacts != null)
                {
                    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    foreach (var current in root.DescendantNodesAndTokensAndSelf(descendIntoTrivia: true))
                    {
                        if (current.IsNode)
                        {
                            var node = (SyntaxNode)current;

                            containsForEachStatement  = containsForEachStatement || syntaxFacts.IsForEachStatement(node);
                            containsLockStatement     = containsLockStatement || syntaxFacts.IsLockStatement(node);
                            containsUsingStatement    = containsUsingStatement || syntaxFacts.IsUsingStatement(node);
                            containsQueryExpression   = containsQueryExpression || syntaxFacts.IsQueryExpression(node);
                            containsElementAccess     = containsElementAccess || syntaxFacts.IsElementAccessExpression(node);
                            containsIndexerMemberCref = containsIndexerMemberCref || syntaxFacts.IsIndexerMemberCRef(node);

                            containsDeconstruction = containsDeconstruction || syntaxFacts.IsDeconstructionAssignment(node) ||
                                                     syntaxFacts.IsDeconstructionForEachStatement(node);

                            containsAwait = containsAwait || syntaxFacts.IsAwaitExpression(node);

                            // We've received a number of error reports where DeclaredSymbolInfo.GetSymbolAsync() will
                            // crash because the document's syntax root doesn't contain the span of the node returned
                            // by TryGetDeclaredSymbolInfo().  There are two possibilities for this crash:
                            //   1) syntaxFacts.TryGetDeclaredSymbolInfo() is returning a bad span, or
                            //   2) Document.GetSyntaxRootAsync() (called from DeclaredSymbolInfo.GetSymbolAsync) is
                            //      returning a bad syntax root that doesn't represent the original parsed document.
                            // By adding the `root.FullSpan.Contains()` check below, if we get similar crash reports in
                            // the future then we know the problem lies in (2).  If, however, the problem is really in
                            // TryGetDeclaredSymbolInfo, then this will at least prevent us from returning bad spans
                            // and will prevent the crash from occurring.
                            if (infoFactory.TryGetDeclaredSymbolInfo(stringTable, node, out var declaredSymbolInfo))
                            {
                                if (root.FullSpan.Contains(declaredSymbolInfo.Span))
                                {
                                    declaredSymbolInfos.Add(declaredSymbolInfo);
                                }
                                else
                                {
                                    var message =
                                        $@"Invalid span in {nameof(declaredSymbolInfo)}.
{nameof(declaredSymbolInfo.Span)} = {declaredSymbolInfo.Span}
{nameof(root.FullSpan)} = {root.FullSpan}";

                                    FatalError.ReportWithoutCrash(new InvalidOperationException(message));
                                }
                            }
                        }
                        else
                        {
                            var token = (SyntaxToken)current;

                            containsThisConstructorInitializer = containsThisConstructorInitializer || syntaxFacts.IsThisConstructorInitializer(token);
                            containsBaseConstructorInitializer = containsBaseConstructorInitializer || syntaxFacts.IsBaseConstructorInitializer(token);

                            if (syntaxFacts.IsIdentifier(token) ||
                                syntaxFacts.IsGlobalNamespaceKeyword(token))
                            {
                                var valueText = token.ValueText;

                                identifiers.Add(valueText);
                                if (valueText.Length != token.Width())
                                {
                                    escapedIdentifiers.Add(valueText);
                                }
                            }

                            if (syntaxFacts.TryGetPredefinedType(token, out var predefinedType))
                            {
                                predefinedTypes |= (int)predefinedType;
                            }

                            if (syntaxFacts.TryGetPredefinedOperator(token, out var predefinedOperator))
                            {
                                predefinedOperators |= (int)predefinedOperator;
                            }

                            if (syntaxFacts.IsStringLiteral(token))
                            {
                                stringLiterals.Add(token.ValueText);
                            }

                            if (syntaxFacts.IsCharacterLiteral(token))
                            {
                                longLiterals.Add((char)token.Value);
                            }

                            if (syntaxFacts.IsNumericLiteral(token))
                            {
                                var value = token.Value;
                                switch (value)
                                {
                                case decimal d:
                                    // not supported for now.
                                    break;

                                case double d:
                                    longLiterals.Add(BitConverter.DoubleToInt64Bits(d));
                                    break;

                                case float f:
                                    longLiterals.Add(BitConverter.DoubleToInt64Bits(f));
                                    break;

                                default:
                                    longLiterals.Add(IntegerUtilities.ToInt64(token.Value));
                                    break;
                                }
                            }
                        }
                    }
                }

                return(new SyntaxTreeIndex(
                           checksum,
                           new LiteralInfo(
                               new BloomFilter(FalsePositiveProbability, stringLiterals, longLiterals)),
                           new IdentifierInfo(
                               new BloomFilter(FalsePositiveProbability, isCaseSensitive, identifiers),
                               new BloomFilter(FalsePositiveProbability, isCaseSensitive, escapedIdentifiers)),
                           new ContextInfo(
                               predefinedTypes,
                               predefinedOperators,
                               containsForEachStatement,
                               containsLockStatement,
                               containsUsingStatement,
                               containsQueryExpression,
                               containsThisConstructorInitializer,
                               containsBaseConstructorInitializer,
                               containsElementAccess,
                               containsIndexerMemberCref,
                               containsDeconstruction,
                               containsAwait),
                           new DeclarationInfo(
                               declaredSymbolInfos.ToImmutableAndFree())));
            }
            finally
            {
                Free(ignoreCase, identifiers, escapedIdentifiers);
                StringLiteralHashSetPool.ClearAndFree(stringLiterals);
                LongLiteralHashSetPool.ClearAndFree(longLiterals);
            }
        }
Exemple #12
0
        private static ExpressionSyntax CreateEnumMemberValue(EnumDeclarationSyntax destinationOpt, IFieldSymbol enumMember)
        {
            var valueOpt = enumMember.ConstantValue is IConvertible
                ? (long?)IntegerUtilities.ToInt64(enumMember.ConstantValue)
                : null;

            if (valueOpt == null)
            {
                return(null);
            }

            var value = valueOpt.Value;

            if (destinationOpt != null)
            {
                if (destinationOpt.Members.Count == 0)
                {
                    if (value == 0)
                    {
                        return(null);
                    }
                }
                else
                {
                    // Don't generate an initializer if no other members have them, and our value
                    // would be correctly inferred from our position.
                    if (destinationOpt.Members.Count == value &&
                        destinationOpt.Members.All(m => m.EqualsValue == null))
                    {
                        return(null);
                    }

                    // Existing members, try to stay consistent with their style.
                    var lastMember = destinationOpt.Members.LastOrDefault(m => m.EqualsValue != null);
                    if (lastMember != null)
                    {
                        var lastExpression = lastMember.EqualsValue.Value;
                        if (lastExpression.CSharpKind() == SyntaxKind.LeftShiftExpression &&
                            IntegerUtilities.HasOneBitSet(value))
                        {
                            var binaryExpression = (BinaryExpressionSyntax)lastExpression;
                            if (binaryExpression.Left.CSharpKind() == SyntaxKind.NumericLiteralExpression)
                            {
                                var numericLiteral = (LiteralExpressionSyntax)binaryExpression.Left;
                                if (numericLiteral.Token.ValueText == "1")
                                {
                                    // The user is left shifting ones, stick with that pattern
                                    var shiftValue = IntegerUtilities.LogBase2(value);
                                    return(SyntaxFactory.BinaryExpression(
                                               SyntaxKind.LeftShiftExpression,
                                               SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("1", 1)),
                                               SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(shiftValue.ToString(), shiftValue))));
                                }
                            }
                        }
                        else if (lastExpression.CSharpKind() == SyntaxKind.NumericLiteralExpression)
                        {
                            var numericLiteral = (LiteralExpressionSyntax)lastExpression;
                            var numericToken   = numericLiteral.Token;
                            var numericText    = numericToken.ToString();

                            if (numericText.StartsWith("0x") || numericText.StartsWith("0X"))
                            {
                                // Hex
                                return(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
                                                                       SyntaxFactory.Literal(numericText.Substring(0, 2) + value.ToString("X"), value)));
                            }
                        }
                    }
                }
            }

            var namedType      = enumMember.Type as INamedTypeSymbol;
            var underlyingType = namedType != null ? namedType.EnumUnderlyingType : null;

            return(ExpressionGenerator.GenerateNonEnumValueExpression(
                       underlyingType,
                       enumMember.ConstantValue,
                       canUseFieldReference: true));
        }
        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));
                }
            }
        }