Beispiel #1
0
        // Returns true if this looks like a possible type name that is on it's own (i.e. not after
        // a dot).  This function is not exhaustive and additional checks may be added if they are
        // beleived to be valuable.
        public static bool LooksLikeStandaloneTypeName(this SimpleNameSyntax simpleName)
        {
            if (simpleName == null)
            {
                return(false);
            }

            // Isn't stand-alone if it's on the right of a dot/arrow
            if (simpleName.IsRightSideOfDotOrArrow())
            {
                return(false);
            }

            // type names can't be invoked.
            if (simpleName.IsParentKind(SyntaxKind.InvocationExpression) &&
                ((InvocationExpressionSyntax)simpleName.Parent).Expression == simpleName)
            {
                return(false);
            }

            // type names can't be indexed into.
            if (simpleName.IsParentKind(SyntaxKind.ElementAccessExpression) &&
                ((ElementAccessExpressionSyntax)simpleName.Parent).Expression == simpleName)
            {
                return(false);
            }

            // Looks good.  However, feel free to add additional checks if this funciton is too
            // lenient in some circumstances.
            return(true);
        }
        public static bool LooksLikeStandaloneTypeName(this SimpleNameSyntax simpleName)
        {
            if (simpleName == null)
            {
                return(false);
            }

            // Isn't stand-alone if it's on the right of a dot/arrow
            if (simpleName.IsRightSideOfDotOrArrow())
            {
                return(false);
            }

            // type names can't be invoked.
            if (
                simpleName.IsParentKind(
                    SyntaxKind.InvocationExpression,
                    out InvocationExpressionSyntax invocation
                    ) &&
                invocation.Expression == simpleName
                )
            {
                return(false);
            }

            // type names can't be indexed into.
            if (
                simpleName.IsParentKind(
                    SyntaxKind.ElementAccessExpression,
                    out ElementAccessExpressionSyntax elementAccess
                    ) &&
                elementAccess.Expression == simpleName
                )
            {
                return(false);
            }

            if (simpleName.Identifier.CouldBeKeyword())
            {
                // Something that looks like a keyword is almost certainly not intended to be a
                // "Standalone type name".
                //
                // 1. Users are not going to name types the same name as C# keywords (contextual or otherwise).
                // 2. Types in .NET are virtually always start with a Uppercase. While keywords are lowercase)
                //
                // Having a lowercase identifier which matches a c# keyword is enough of a signal
                // to just not treat this as a standalone type name (even though for some identifiers
                // it could be according to the language).
                return(false);
            }

            // Looks good.  However, feel free to add additional checks if this function is too
            // lenient in some circumstances.
            return(true);
        }
 public static ExpressionSyntax GetLeftSideOfDot(this SimpleNameSyntax name)
 {
     Debug.Assert(
         name.IsSimpleMemberAccessExpressionName() ||
         name.IsMemberBindingExpressionName() ||
         name.IsRightSideOfQualifiedName() ||
         name.IsParentKind(SyntaxKind.NameMemberCref)
         );
     if (name.IsSimpleMemberAccessExpressionName())
     {
         return(((MemberAccessExpressionSyntax)name.Parent).Expression);
     }
     else if (name.IsMemberBindingExpressionName())
     {
         return(name.GetParentConditionalAccessExpression().Expression);
     }
     else if (name.IsRightSideOfQualifiedName())
     {
         return(((QualifiedNameSyntax)name.Parent).Left);
     }
     else
     {
         return(((QualifiedCrefSyntax)name.Parent.Parent).Container);
     }
 }
Beispiel #4
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            SimpleNameSyntax simpleName = root
                                          .FindNode(context.Span, getInnermostNodeForTie: true)?
                                          .FirstAncestorOrSelf <SimpleNameSyntax>();

            Debug.Assert(simpleName != null, $"{nameof(simpleName)} is null");

            if (simpleName == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotConvertMethodGroupToNonDelegateType:
                {
                    if (!simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                    {
                        break;
                    }

                    var memberAccess = (MemberAccessExpressionSyntax)simpleName.Parent;

                    CodeAction codeAction = CodeAction.Create(
                        "Add argument list",
                        cancellationToken =>
                        {
                            InvocationExpressionSyntax invocationExpression = InvocationExpression(
                                memberAccess.WithoutTrailingTrivia(),
                                ArgumentList().WithTrailingTrivia(memberAccess.GetTrailingTrivia()));

                            return(context.Document.ReplaceNodeAsync(memberAccess, invocationExpression, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Beispiel #5
0
 public static ExpressionSyntax GetLeftSideOfDot(this SimpleNameSyntax name)
 {
     Contract.Requires(name.IsMemberAccessExpressionName() || name.IsRightSideOfQualifiedName() || name.IsParentKind(SyntaxKind.NameMemberCref));
     if (name.IsMemberAccessExpressionName())
     {
         var conditionalAccess = name.GetParentConditionalAccessExpression();
         if (conditionalAccess != null)
         {
             return(conditionalAccess.Expression);
         }
         else
         {
             return(((MemberAccessExpressionSyntax)name.Parent).Expression);
         }
     }
     else if (name.IsRightSideOfQualifiedName())
     {
         return(((QualifiedNameSyntax)name.Parent).Left);
     }
     else
     {
         return(((QualifiedCrefSyntax)name.Parent.Parent).Container);
     }
 }
 private static bool IsQualified(SimpleNameSyntax identifierName)
 {
     return(identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression));
 }
Beispiel #7
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);
            }