Ejemplo n.º 1
0
        public static Accessibility DetermineAccessibilityConstraint(
            this SemanticModel semanticModel,
            TypeSyntax type,
            CancellationToken cancellationToken)
        {
            if (type == null)
            {
                return(Accessibility.Private);
            }

            type = GetOutermostType(type);

            // Interesting cases based on 3.5.4 Accessibility constraints in the language spec.
            // If any of the below hold, then we will override the default accessibility if the
            // constraint wants the type to be more accessible. i.e. if by default we generate
            // 'internal', but a constraint makes us 'public', then be public.

            // 1) The direct base class of a class type must be at least as accessible as the
            //    class type itself.
            //
            // 2) The explicit base interfaces of an interface type must be at least as accessible
            //    as the interface type itself.
            if (type != null)
            {
                if (type.Parent is BaseTypeSyntax && type.Parent.IsParentKind(SyntaxKind.BaseList) && ((BaseTypeSyntax)type.Parent).Type == type)
                {
                    var containingType = semanticModel.GetDeclaredSymbol(type.GetAncestor <BaseTypeDeclarationSyntax>(), cancellationToken) as INamedTypeSymbol;
                    if (containingType != null && containingType.TypeKind == TypeKind.Interface)
                    {
                        return(containingType.DeclaredAccessibility);
                    }
                    else if (((BaseListSyntax)type.Parent.Parent).Types[0] == type.Parent)
                    {
                        return(containingType.DeclaredAccessibility);
                    }
                }
            }

            // 4) The type of a constant must be at least as accessible as the constant itself.
            // 5) The type of a field must be at least as accessible as the field itself.
            if (type.IsParentKind(SyntaxKind.VariableDeclaration) &&
                type.Parent.IsParentKind(SyntaxKind.FieldDeclaration))
            {
                var variableDeclaration = (VariableDeclarationSyntax)type.Parent;
                return(semanticModel.GetDeclaredSymbol(
                           variableDeclaration.Variables[0], cancellationToken).DeclaredAccessibility);
            }

            // Also do the same check if we are in an object creation expression
            if (type.IsParentKind(SyntaxKind.ObjectCreationExpression) &&
                type.Parent.IsParentKind(SyntaxKind.EqualsValueClause) &&
                type.Parent.Parent.IsParentKind(SyntaxKind.VariableDeclarator) &&
                type.Parent.Parent.Parent.IsParentKind(SyntaxKind.VariableDeclaration) &&
                type.Parent.Parent.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration))
            {
                var variableDeclaration = (VariableDeclarationSyntax)type.Parent.Parent.Parent.Parent;
                return(semanticModel.GetDeclaredSymbol(
                           variableDeclaration.Variables[0], cancellationToken).DeclaredAccessibility);
            }

            // 3) The return type of a delegate type must be at least as accessible as the
            //    delegate type itself.
            // 6) The return type of a method must be at least as accessible as the method
            //    itself.
            // 7) The type of a property must be at least as accessible as the property itself.
            // 8) The type of an event must be at least as accessible as the event itself.
            // 9) The type of an indexer must be at least as accessible as the indexer itself.
            // 10) The return type of an operator must be at least as accessible as the operator
            //     itself.
            if (type.IsParentKind(SyntaxKind.DelegateDeclaration) ||
                type.IsParentKind(SyntaxKind.MethodDeclaration) ||
                type.IsParentKind(SyntaxKind.PropertyDeclaration) ||
                type.IsParentKind(SyntaxKind.EventDeclaration) ||
                type.IsParentKind(SyntaxKind.IndexerDeclaration) ||
                type.IsParentKind(SyntaxKind.OperatorDeclaration))
            {
                return(semanticModel.GetDeclaredSymbol(
                           type.Parent, cancellationToken).DeclaredAccessibility);
            }

            // 3) The parameter types of a delegate type must be at least as accessible as the
            //    delegate type itself.
            // 6) The parameter types of a method must be at least as accessible as the method
            //    itself.
            // 9) The parameter types of an indexer must be at least as accessible as the
            //    indexer itself.
            // 10) The parameter types of an operator must be at least as accessible as the
            //     operator itself.
            // 11) The parameter types of an instance constructor must be at least as accessible
            //     as the instance constructor itself.
            if (type.IsParentKind(SyntaxKind.Parameter) && type.Parent.IsParentKind(SyntaxKind.ParameterList))
            {
                if (type.Parent.Parent.IsParentKind(SyntaxKind.DelegateDeclaration) ||
                    type.Parent.Parent.IsParentKind(SyntaxKind.MethodDeclaration) ||
                    type.Parent.Parent.IsParentKind(SyntaxKind.IndexerDeclaration) ||
                    type.Parent.Parent.IsParentKind(SyntaxKind.OperatorDeclaration))
                {
                    return(semanticModel.GetDeclaredSymbol(
                               type.Parent.Parent.Parent, cancellationToken).DeclaredAccessibility);
                }

                if (type.Parent.Parent.IsParentKind(SyntaxKind.ConstructorDeclaration))
                {
                    var symbol = semanticModel.GetDeclaredSymbol(type.Parent.Parent.Parent, cancellationToken);
                    if (!symbol.IsStatic)
                    {
                        return(symbol.DeclaredAccessibility);
                    }
                }
            }

            // 8) The type of an event must be at least as accessible as the event itself.
            if (type.IsParentKind(SyntaxKind.VariableDeclaration) &&
                type.Parent.IsParentKind(SyntaxKind.EventFieldDeclaration))
            {
                var variableDeclaration = (VariableDeclarationSyntax)type.Parent;
                var symbol = semanticModel.GetDeclaredSymbol(variableDeclaration.Variables[0], cancellationToken);
                if (symbol != null)
                {
                    return(symbol.DeclaredAccessibility);
                }
            }

            return(Accessibility.Private);
        }