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 ((ISymbol)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 ((ISymbol)symbol).DeclaredAccessibility; } } return Accessibility.Private; }
protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken, out TextSpan issueSpan) { // If it is already var, return. if (typeName.IsTypeInferred(semanticModel)) { issueSpan = default(TextSpan); return false; } var candidateReplacementNode = SyntaxFactory.IdentifierName("var"); var candidateIssueSpan = typeName.Span; // If there exists a type named var, return. var conflict = semanticModel.GetSpeculativeSymbolInfo(typeName.SpanStart, candidateReplacementNode, SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol; if (conflict?.IsKind(SymbolKind.NamedType) == true) { issueSpan = default(TextSpan); return false; } if (typeName.Parent.IsKind(SyntaxKind.VariableDeclaration) && typeName.Parent.IsParentKind(SyntaxKind.LocalDeclarationStatement, SyntaxKind.ForStatement, SyntaxKind.UsingStatement)) { var variableDeclaration = (VariableDeclarationSyntax)typeName.Parent; // implicitly typed variables cannot be constants. if ((variableDeclaration.Parent as LocalDeclarationStatementSyntax)?.IsConst == true) { issueSpan = default(TextSpan); return false; } var variable = variableDeclaration.Variables.Single(); if (AssignmentSupportsStylePreference(variable.Identifier, typeName, variable.Initializer, semanticModel, optionSet, cancellationToken)) { issueSpan = candidateIssueSpan; return true; } } else if (typeName.IsParentKind(SyntaxKind.ForEachStatement)) { issueSpan = candidateIssueSpan; return true; } issueSpan = default(TextSpan); return false; }