private static void AnalyzePositionalArgumentsAndParameters( SymbolAnalysisContext context, AttributeData attribute, ImmutableArray <TypedConstant> attributePositionalArguments, ImmutableArray <IParameterSymbol> methodParameters) { for (var i = 0; i < attributePositionalArguments.Length; i++) { var attributeArgument = attributePositionalArguments[i]; var(methodParameterType, methodParameterName, methodParameterParamsType) = TestCaseUsageAnalyzer.GetParameterType(methodParameters, i); if (methodParameterType.IsTypeParameterAndDeclaredOnMethod()) { continue; } ITypeSymbol?argumentType = attributeArgument.Type; var argumentTypeMatchesParameterType = attributeArgument.CanAssignTo( methodParameterType, context.Compilation, allowImplicitConversion: true, allowEnumToUnderlyingTypeConversion: true); if (methodParameterParamsType == null && argumentTypeMatchesParameterType) { continue; } if (methodParameterParamsType != null) { var argumentTypeMatchesElementType = attributeArgument.CanAssignTo( methodParameterParamsType, context.Compilation, allowImplicitConversion: true, allowEnumToUnderlyingTypeConversion: true); if (argumentTypeMatchesElementType || (argumentTypeMatchesParameterType && (argumentType != null || !methodParameterParamsType.IsValueType))) { continue; } } var attributeArgumentSyntax = attribute.GetConstructorArgumentSyntax(i, context.CancellationToken); if (attributeArgumentSyntax is null) { continue; } context.ReportDiagnostic(Diagnostic.Create(parameterTypeMismatch, attributeArgumentSyntax.GetLocation(), i, argumentType?.ToDisplayString() ?? "<null>", methodParameterName, methodParameterType)); context.CancellationToken.ThrowIfCancellationRequested(); } }
public static bool IsAbstractClass([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.TypeKind == TypeKind.Class && symbol.IsAbstract;
public static bool IsNullable([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T;
// Is a protected symbol inside "originalContainingType" accessible from within "within", // which much be a named type or an assembly. private static bool IsProtectedSymbolAccessible( INamedTypeSymbol?withinType, IAssemblySymbol withinAssembly, ITypeSymbol?throughType, INamedTypeSymbol originalContainingType, out bool failedThroughTypeCheck) { failedThroughTypeCheck = false; // It is not an error to define protected member in a sealed Script class, // it's just a warning. The member behaves like a private one - it is visible // in all subsequent submissions. if (withinAssembly.IsInteractive && originalContainingType.IsScriptClass) { return(true); } if (withinType == null) { // If we're not within a type, we can't access a protected symbol return(false); } // A protected symbol is accessible if we're (optionally nested) inside the type that it // was defined in. // NOTE(ericli): It is helpful to consider 'protected' as *increasing* the // accessibility domain of a private member, rather than *decreasing* that of a public // member. Members are naturally private; the protected, internal and public access // modifiers all increase the accessibility domain. Since private members are accessible // to nested types, so are protected members. // NOTE(cyrusn): We do this check up front as it is very fast and easy to do. if (IsNestedWithinOriginalContainingType(withinType, originalContainingType)) { return(true); } // Protected is really confusing. Check out 3.5.3 of the language spec "protected access // for instance members" to see how it works. I actually got the code for this from // LangCompiler::CheckAccessCore { var current = withinType.OriginalDefinition; var originalThroughType = throughType?.OriginalDefinition; while (current != null) { Debug.Assert(current.IsDefinition); if (current.InheritsFromOrImplementsOrEqualsIgnoringConstruction(originalContainingType)) { // NOTE(cyrusn): We're continually walking up the 'throughType's inheritance // chain. We could compute it up front and cache it in a set. However, i // don't want to allocate memory in this function. Also, in practice // inheritance chains should be very short. As such, it might actually be // slower to create and check inside the set versus just walking the // inheritance chain. if (originalThroughType == null || originalThroughType.InheritsFromOrImplementsOrEqualsIgnoringConstruction(current)) { return(true); } else { failedThroughTypeCheck = true; } } // NOTE(cyrusn): The container of an original type is always original. current = current.ContainingType; } } return(false); }
public IEnumerable <MethodInfo> GetNotImplementedMessages(Accessibility?accessibility = null, ITypeSymbol?returnType = null) { foreach (var message in GetMessages()) { if (IsImplemented(message)) { continue; } if (accessibility.HasValue && !AccessibilityMatch(message, accessibility.Value)) { continue; } if (returnType != null && !returnType.Matches(message.ReturnType)) { continue; } yield return(message); } }
protected abstract bool IsAssignableTo( [NotNullWhen(returnValue: true)] ITypeSymbol?fromSymbol, [NotNullWhen(returnValue: true)] ITypeSymbol?toSymbol, Compilation compilation);
public bool TryCreate(IOperation operation, [NotNullWhen(returnValue: true)] out AnalysisEntity?analysisEntity) { if (_analysisEntityMap.TryGetValue(operation, out analysisEntity)) { return(analysisEntity != null); } analysisEntity = null; ISymbol?symbol = null; ImmutableArray <AbstractIndex> indices = ImmutableArray <AbstractIndex> .Empty; IOperation? instance = null; ITypeSymbol?type = operation.Type; switch (operation) { case ILocalReferenceOperation localReference: symbol = localReference.Local; break; case IParameterReferenceOperation parameterReference: symbol = parameterReference.Parameter; break; case IMemberReferenceOperation memberReference: instance = memberReference.Instance; GetSymbolAndIndicesForMemberReference(memberReference, ref symbol, ref indices); // Workaround for https://github.com/dotnet/roslyn/issues/22736 (IPropertyReferenceExpressions in IAnonymousObjectCreationExpression are missing a receiver). if (instance == null && symbol != null && memberReference is IPropertyReferenceOperation propertyReference) { instance = propertyReference.GetAnonymousObjectCreation(); } break; case IArrayElementReferenceOperation arrayElementReference: instance = arrayElementReference.ArrayReference; indices = CreateAbstractIndices(arrayElementReference.Indices); break; case IDynamicIndexerAccessOperation dynamicIndexerAccess: instance = dynamicIndexerAccess.Operation; indices = CreateAbstractIndices(dynamicIndexerAccess.Arguments); break; case IConditionalAccessInstanceOperation conditionalAccessInstance: IConditionalAccessOperation?conditionalAccess = conditionalAccessInstance.GetConditionalAccess(); instance = conditionalAccess?.Operation; if (conditionalAccessInstance.Parent is IMemberReferenceOperation memberReferenceParent) { GetSymbolAndIndicesForMemberReference(memberReferenceParent, ref symbol, ref indices); } break; case IInstanceReferenceOperation instanceReference: if (_getPointsToAbstractValue != null) { instance = instanceReference.GetInstance(_getIsInsideAnonymousObjectInitializer()); if (instance == null) { // Reference to this or base instance. analysisEntity = _interproceduralCallStack != null && _interproceduralCallStack.Peek().DescendantsAndSelf().Contains(instanceReference) ? _interproceduralThisOrMeInstanceForCaller : ThisOrMeInstance; } else { var instanceLocation = _getPointsToAbstractValue(instanceReference); analysisEntity = AnalysisEntity.Create(instanceReference, instanceLocation); } } break; case IConversionOperation conversion: return(TryCreate(conversion.Operand, out analysisEntity)); case IParenthesizedOperation parenthesized: return(TryCreate(parenthesized.Operand, out analysisEntity)); case IArgumentOperation argument: return(TryCreate(argument.Value, out analysisEntity)); case IFlowCaptureOperation flowCapture: var isLvalueFlowCapture = _getIsLValueFlowCapture(flowCapture); analysisEntity = GetOrCreateForFlowCapture(flowCapture.Id, flowCapture.Value.Type, flowCapture, isLvalueFlowCapture); // Store flow capture copy values for simple flow captures of non-flow captured entity. // This enables pseudo copy-analysis of values of these two entities in absence of true copy analysis, which is expensive. if (!isLvalueFlowCapture && TryCreate(flowCapture.Value, out var capturedEntity) && capturedEntity.CaptureId == null && !_captureIdCopyValueMap.ContainsKey(flowCapture.Id) && analysisEntity.Type.IsValueType == capturedEntity.Type.IsValueType) { // Skip flow capture for conversions unless we know the points to value // for conversion and operand is identical. if (flowCapture.Value is IConversionOperation conversion) { if (_getPointsToAbstractValue == null || _getPointsToAbstractValue(conversion) != _getPointsToAbstractValue(conversion.Operand)) { break; } } var kind = capturedEntity.Type.IsValueType ? CopyAbstractValueKind.KnownValueCopy : CopyAbstractValueKind.KnownReferenceCopy; var copyValue = new CopyAbstractValue(ImmutableHashSet.Create(analysisEntity, capturedEntity), kind); _captureIdCopyValueMap.Add(flowCapture.Id, copyValue); } break; case IFlowCaptureReferenceOperation flowCaptureReference: analysisEntity = GetOrCreateForFlowCapture(flowCaptureReference.Id, flowCaptureReference.Type, flowCaptureReference, flowCaptureReference.IsLValueFlowCaptureReference()); break; case IDeclarationExpressionOperation declarationExpression: switch (declarationExpression.Expression) { case ILocalReferenceOperation localReference: return(TryCreateForSymbolDeclaration(localReference.Local, out analysisEntity)); case ITupleOperation tupleOperation: return(TryCreate(tupleOperation, out analysisEntity)); } break; case IVariableDeclaratorOperation variableDeclarator: symbol = variableDeclarator.Symbol; type = variableDeclarator.Symbol.Type; break; case IDeclarationPatternOperation declarationPattern: var declaredLocal = declarationPattern.DeclaredSymbol as ILocalSymbol; symbol = declaredLocal; type = declaredLocal?.Type; break; default: break; } if (symbol != null || !indices.IsEmpty) { TryCreate(symbol, indices, type !, instance, out analysisEntity); } _analysisEntityMap[operation] = analysisEntity; return(analysisEntity != null); }
public static bool IsObjectType(this ITypeSymbol?type) { return(type == null || type.SpecialType == SpecialType.System_Object); }
public ActualApiResponseMetadata(IReturnOperation returnExpression, int statusCode, ITypeSymbol?returnType) { ReturnOperation = returnExpression; _statusCode = statusCode; ReturnType = returnType; }
private static bool IsWrongType(BackingFieldOrProperty fieldOrProperty, ArgumentSyntax argument, SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out ITypeSymbol?registeredType) { if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out registeredType) && !PropertyMetadata.IsValueValidForRegisteredType(argument.Expression, registeredType, context.SemanticModel, context.CancellationToken)) { if (context.SemanticModel.TryGetType(argument.Expression, context.CancellationToken, out var type)) { if (type == KnownSymbols.Object) { return(false); } if (registeredType.IsAssignableTo(KnownSymbols.Freezable, context.Compilation) && type.IsAssignableTo(KnownSymbols.Freezable, context.Compilation)) { return(false); } } return(true); } return(false); }
private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var invocation = (TInvocationExpressionSyntax)context.Node; SemanticModel semanticModel = context.SemanticModel; ISymbol symbol = semanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol; if (symbol == null || symbol.Kind != SymbolKind.Method || !symbol.Name.StartsWith("Register", StringComparison.Ordinal)) { return; } var method = (IMethodSymbol)symbol; NoteRegisterActionInvocation(method, invocation, semanticModel, context.CancellationToken); bool isRegisterSymbolAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterSymbolActionName, method, _analysisContext, _compilationStartAnalysisContext); bool isRegisterSyntaxNodeAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterSyntaxNodeActionName, method, _analysisContext, _compilationStartAnalysisContext, _codeBlockStartAnalysisContext); bool isRegisterCodeBlockStartAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterCodeBlockStartActionName, method, _analysisContext, _compilationStartAnalysisContext); bool isRegisterOperationAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterOperationActionName, method, _analysisContext, _compilationStartAnalysisContext, _operationBlockStartAnalysisContext); if (isRegisterSymbolAction || isRegisterSyntaxNodeAction || isRegisterOperationAction) { if (method.Parameters.Length == 2 && method.Parameters[1].IsParams) { IEnumerable <SyntaxNode>?arguments = GetArgumentExpressions(invocation); if (arguments != null) { int argumentCount = arguments.Count(); if (argumentCount >= 1) { ITypeSymbol type = semanticModel.GetTypeInfo(arguments.First(), context.CancellationToken).ConvertedType; if (type == null || type.Name.Equals(nameof(Action), StringComparison.Ordinal)) { if (argumentCount == 1) { DiagnosticDescriptor rule; if (isRegisterSymbolAction) { rule = MissingSymbolKindArgumentRule; } else if (isRegisterOperationAction) { rule = MissingOperationKindArgumentRule; } else { rule = MissingSyntaxKindArgumentRule; } SyntaxNode invocationExpression = GetInvocationExpression(invocation); Diagnostic diagnostic = Diagnostic.Create(rule, invocationExpression.GetLocation()); context.ReportDiagnostic(diagnostic); } else if (isRegisterSymbolAction) { foreach (SyntaxNode argument in arguments.Skip(1)) { symbol = semanticModel.GetSymbolInfo(argument, context.CancellationToken).Symbol; if (symbol != null && symbol.Kind == SymbolKind.Field && _symbolKind.Equals(symbol.ContainingType) && !s_supportedSymbolKinds.Contains(symbol.Name)) { Diagnostic diagnostic = Diagnostic.Create(UnsupportedSymbolKindArgumentRule, argument.GetLocation(), symbol.Name); context.ReportDiagnostic(diagnostic); } } } } } } } } if (!method.TypeParameters.IsEmpty && (isRegisterSyntaxNodeAction || isRegisterCodeBlockStartAction)) { ITypeSymbol?typeArgument = null; if (method.TypeParameters.Length == 1) { if (method.TypeParameters[0].Name == DiagnosticWellKnownNames.TLanguageKindEnumName) { typeArgument = method.TypeArguments[0]; } } else { ITypeParameterSymbol typeParam = method.TypeParameters.FirstOrDefault(t => t.Name == DiagnosticWellKnownNames.TLanguageKindEnumName); if (typeParam != null) { int index = method.TypeParameters.IndexOf(typeParam); typeArgument = method.TypeArguments[index]; } } if (typeArgument != null && typeArgument.TypeKind != TypeKind.TypeParameter && typeArgument.TypeKind != TypeKind.Error && !IsSyntaxKind(typeArgument)) { Location location = typeArgument.Locations[0]; if (!location.IsInSource) { SyntaxNode invocationExpression = GetInvocationExpression(invocation); location = invocationExpression.GetLocation(); } Diagnostic diagnostic = Diagnostic.Create(InvalidSyntaxKindTypeArgumentRule, location, typeArgument.Name, DiagnosticWellKnownNames.TLanguageKindEnumName, method.Name); context.ReportDiagnostic(diagnostic); } } }
public static bool IsImplementationOfInterfaceMethod(this IMethodSymbol method, ITypeSymbol?typeArgument, [NotNullWhen(returnValue: true)] INamedTypeSymbol?interfaceType, string interfaceMethodName) { INamedTypeSymbol?constructedInterface = typeArgument != null?interfaceType?.Construct(typeArgument) : interfaceType; return(constructedInterface?.GetMembers(interfaceMethodName).FirstOrDefault() is IMethodSymbol interfaceMethod && method.Equals(method.ContainingType.FindImplementationForInterfaceMember(interfaceMethod))); }
public static bool IsModuleType([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) { return(symbol?.TypeKind == TypeKind.Module); }
public static bool CanAddNullCheck([NotNullWhen(returnValue: true)] this ITypeSymbol?type) => type != null && (type.IsReferenceType || type.IsNullable());
internal static bool IsEqualToOrDerivedFrom(ITypeSymbol?type, ITypeSymbol expectedType) { return(EqualityComparer <ITypeSymbol?> .Default.Equals(type?.OriginalDefinition, expectedType) || IsDerivedFrom(type, expectedType)); }
private static void AddMissingMembersToStatefulMarshaller(DocumentEditor editor, SyntaxNode declaringSyntax, INamedTypeSymbol marshallerType, ITypeSymbol managedType, HashSet <string> missingMemberNames, bool isLinearCollectionMarshaller) { SyntaxGenerator gen = editor.Generator; // Get the methods of the shape so we can use them to determine what types to use in signatures that are not obvious. var(_, methods) = StatefulMarshallerShapeHelper.GetShapeForType(marshallerType, managedType, isLinearCollectionMarshaller, editor.SemanticModel.Compilation); INamedTypeSymbol spanOfT = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_Span_Metadata) !; INamedTypeSymbol readOnlySpanOfT = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata) !; var(typeParameters, _) = marshallerType.GetAllTypeArgumentsIncludingInContainingTypes(); // Use a lazy factory for the type syntaxes to avoid re-checking the various methods and reconstructing the syntax. Lazy <SyntaxNode> unmanagedTypeSyntax = new(CreateUnmanagedTypeSyntax, isThreadSafe : false); Lazy <ITypeSymbol> managedElementTypeSymbol = new(CreateManagedElementTypeSymbol, isThreadSafe : false); List <SyntaxNode> newMembers = new(); if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromManaged)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.Value.Stateful.FromManaged, parameters: new[] { gen.ParameterDeclaration("managed", gen.TypeExpression(managedType)) }, accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToUnmanaged)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.Value.Stateful.ToUnmanaged, returnType: unmanagedTypeSyntax.Value, accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromUnmanaged)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.Value.Stateful.FromUnmanaged, parameters: new[] { gen.ParameterDeclaration("unmanaged", unmanagedTypeSyntax.Value) }, accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToManaged)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.Value.Stateful.ToManaged, returnType: gen.TypeExpression(managedType), accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.BufferSize)) { newMembers.Add( gen.WithAccessorDeclarations( gen.PropertyDeclaration(ShapeMemberNames.BufferSize, gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_Int32)), Accessibility.Public, DeclarationModifiers.Static), gen.GetAccessorDeclaration(statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }))); } if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource, returnType: gen.TypeExpression(readOnlySpanOfT.Construct(managedElementTypeSymbol.Value)), accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination, returnType: gen.TypeExpression(spanOfT.Construct(typeParameters[typeParameters.Length - 1])), accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource, parameters: new[] { gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32)) }, returnType: gen.TypeExpression(readOnlySpanOfT.Construct(typeParameters[typeParameters.Length - 1])), accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination, parameters: new[] { gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32)) }, returnType: gen.TypeExpression(spanOfT.Construct(managedElementTypeSymbol.Value)), accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } if (missingMemberNames.Contains(ShapeMemberNames.Free)) { newMembers.Add( gen.MethodDeclaration( ShapeMemberNames.Value.Stateful.Free, accessibility: Accessibility.Public, statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })); } editor.ReplaceNode(declaringSyntax, (declaringSyntax, gen) => gen.AddMembers(declaringSyntax, newMembers)); SyntaxNode CreateUnmanagedTypeSyntax() { ITypeSymbol?unmanagedType = null; if (methods.ToUnmanaged is not null) { unmanagedType = methods.ToUnmanaged.ReturnType; } else if (methods.FromUnmanaged is not null) { unmanagedType = methods.FromUnmanaged.Parameters[0].Type; } else if (methods.UnmanagedValuesSource is not null) { unmanagedType = methods.UnmanagedValuesSource.Parameters[0].Type; } else if (methods.UnmanagedValuesDestination is not null) { unmanagedType = methods.UnmanagedValuesDestination.Parameters[0].Type; } if (unmanagedType is not null) { return(gen.TypeExpression(unmanagedType)); } return(gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr))); } ITypeSymbol CreateManagedElementTypeSymbol() { if (methods.ManagedValuesSource is not null) { return(((INamedTypeSymbol)methods.ManagedValuesSource.ReturnType).TypeArguments[0]); } if (methods.ManagedValuesDestination is not null) { return(((INamedTypeSymbol)methods.ManagedValuesDestination.ReturnType).TypeArguments[0]); } return(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr)); } }
internal static bool IsTask([NotNullWhen(true)] ITypeSymbol?typeSymbol) => typeSymbol?.Name == nameof(Task) && typeSymbol.BelongsToNamespace(Namespaces.SystemThreadingTasks);
public static bool IsExact([NotNullWhen(true)] this ITypeSymbol?type, string ns0, string name, int arity) => type is INamedTypeSymbol nt && nt.Name == name && nt.Arity == arity &&
public bool TryCreate(IOperation operation, [NotNullWhen(returnValue: true)] out AnalysisEntity?analysisEntity) { if (_analysisEntityMap.TryGetValue(operation, out analysisEntity)) { return(analysisEntity != null); } analysisEntity = null; ISymbol?symbol = null; ImmutableArray <AbstractIndex> indices = ImmutableArray <AbstractIndex> .Empty; IOperation? instance = null; ITypeSymbol?type = operation.Type; switch (operation) { case ILocalReferenceOperation localReference: symbol = localReference.Local; break; case IParameterReferenceOperation parameterReference: symbol = parameterReference.Parameter; break; case IMemberReferenceOperation memberReference: instance = memberReference.Instance; GetSymbolAndIndicesForMemberReference(memberReference, ref symbol, ref indices); // Workaround for https://github.com/dotnet/roslyn/issues/22736 (IPropertyReferenceExpressions in IAnonymousObjectCreationExpression are missing a receiver). if (instance == null && symbol != null && memberReference is IPropertyReferenceOperation propertyReference) { instance = propertyReference.GetAnonymousObjectCreation(); } break; case IArrayElementReferenceOperation arrayElementReference: instance = arrayElementReference.ArrayReference; indices = CreateAbstractIndices(arrayElementReference.Indices); break; case IDynamicIndexerAccessOperation dynamicIndexerAccess: instance = dynamicIndexerAccess.Operation; indices = CreateAbstractIndices(dynamicIndexerAccess.Arguments); break; case IConditionalAccessInstanceOperation conditionalAccessInstance: IConditionalAccessOperation?conditionalAccess = conditionalAccessInstance.GetConditionalAccess(); instance = conditionalAccess?.Operation; if (conditionalAccessInstance.Parent is IMemberReferenceOperation memberReferenceParent) { GetSymbolAndIndicesForMemberReference(memberReferenceParent, ref symbol, ref indices); } break; case IInstanceReferenceOperation instanceReference: if (_getPointsToAbstractValue != null) { instance = instanceReference.GetInstance(_getIsInsideAnonymousObjectInitializer()); if (instance == null) { // Reference to this or base instance. analysisEntity = _interproceduralCallStack != null && _interproceduralCallStack.Peek().DescendantsAndSelf().Contains(instanceReference) ? _interproceduralThisOrMeInstanceForCaller : ThisOrMeInstance; } else { var instanceLocation = _getPointsToAbstractValue(instanceReference); analysisEntity = AnalysisEntity.Create(instanceReference, instanceLocation); } } break; case IConversionOperation conversion: return(TryCreate(conversion.Operand, out analysisEntity)); case IParenthesizedOperation parenthesized: return(TryCreate(parenthesized.Operand, out analysisEntity)); case IArgumentOperation argument: return(TryCreate(argument.Value, out analysisEntity)); case IFlowCaptureOperation flowCapture: analysisEntity = GetOrCreateForFlowCapture(flowCapture.Id, flowCapture.Value.Type, flowCapture, _getIsLValueFlowCapture(flowCapture)); break; case IFlowCaptureReferenceOperation flowCaptureReference: analysisEntity = GetOrCreateForFlowCapture(flowCaptureReference.Id, flowCaptureReference.Type, flowCaptureReference, flowCaptureReference.IsLValueFlowCaptureReference()); break; case IDeclarationExpressionOperation declarationExpression: switch (declarationExpression.Expression) { case ILocalReferenceOperation localReference: return(TryCreateForSymbolDeclaration(localReference.Local, out analysisEntity)); case ITupleOperation tupleOperation: return(TryCreate(tupleOperation, out analysisEntity)); } break; case IVariableDeclaratorOperation variableDeclarator: symbol = variableDeclarator.Symbol; type = variableDeclarator.Symbol.Type; break; case IDeclarationPatternOperation declarationPattern: var declaredLocal = declarationPattern.DeclaredSymbol as ILocalSymbol; symbol = declaredLocal; type = declaredLocal?.Type; break; default: break; } if (symbol != null || !indices.IsEmpty) { TryCreate(symbol, indices, type !, instance, out analysisEntity); } _analysisEntityMap[operation] = analysisEntity; return(analysisEntity != null); }
internal static ExpectedAlternateMethodGroup?GetExpectedAlternateMethodGroup(string operatorName, ITypeSymbol returnType, ITypeSymbol?parameterType) {
// Is a member with declared accessibility "declaredAccessibility" accessible from within // "within", which must be a named type or an assembly. private static bool IsMemberAccessible( INamedTypeSymbol containingType, Accessibility declaredAccessibility, ISymbol within, ITypeSymbol?throughType, out bool failedThroughTypeCheck) { Debug.Assert(within is INamedTypeSymbol || within is IAssemblySymbol); Contract.ThrowIfNull(containingType); failedThroughTypeCheck = false; var originalContainingType = containingType.OriginalDefinition; var withinNamedType = within as INamedTypeSymbol; var withinAssembly = (within as IAssemblySymbol) ?? ((INamedTypeSymbol)within).ContainingAssembly; // A nested symbol is only accessible to us if its container is accessible as well. if (!IsNamedTypeAccessible(containingType, within)) { return(false); } switch (declaredAccessibility) { case Accessibility.NotApplicable: // TODO(cyrusn): Is this the right thing to do here? Should the caller ever be // asking about the accessibility of a symbol that has "NotApplicable" as its // value? For now, I'm preserving the behavior of the existing code. But perhaps // we should fail here and require the caller to not do this? return(true); case Accessibility.Public: // Public symbols are always accessible from any context return(true); case Accessibility.Private: // All expressions in the current submission (top-level or nested in a method or // type) can access previous submission's private top-level members. Previous // submissions are treated like outer classes for the current submission - the // inner class can access private members of the outer class. if (withinAssembly.IsInteractive && containingType.IsScriptClass) { return(true); } // private members never accessible from outside a type. return(withinNamedType != null && IsPrivateSymbolAccessible(withinNamedType, originalContainingType)); case Accessibility.Internal: // An internal type is accessible if we're in the same assembly or we have // friend access to the assembly it was defined in. return(withinAssembly.IsSameAssemblyOrHasFriendAccessTo(containingType.ContainingAssembly)); case Accessibility.ProtectedAndInternal: if (!withinAssembly.IsSameAssemblyOrHasFriendAccessTo(containingType.ContainingAssembly)) { // We require internal access. If we don't have it, then this symbol is // definitely not accessible to us. return(false); } // We had internal access. Also have to make sure we have protected access. return(IsProtectedSymbolAccessible(withinNamedType, withinAssembly, throughType, originalContainingType, out failedThroughTypeCheck)); case Accessibility.ProtectedOrInternal: if (withinAssembly.IsSameAssemblyOrHasFriendAccessTo(containingType.ContainingAssembly)) { // If we have internal access to this symbol, then that's sufficient. no // need to do the complicated protected case. return(true); } // We don't have internal access. But if we have protected access then that's // sufficient. return(IsProtectedSymbolAccessible(withinNamedType, withinAssembly, throughType, originalContainingType, out failedThroughTypeCheck)); case Accessibility.Protected: return(IsProtectedSymbolAccessible(withinNamedType, withinAssembly, throughType, originalContainingType, out failedThroughTypeCheck)); default: throw ExceptionUtilities.UnexpectedValue(declaredAccessibility); } }
public static bool IsDisposable([NotNullWhen(returnValue: true)] this ITypeSymbol?type, [NotNullWhen(returnValue: true)] ITypeSymbol?iDisposableType) => iDisposableType != null && (Equals(iDisposableType, type) || type?.AllInterfaces.Contains(iDisposableType) == true);
/// <summary> /// Checks if 'symbol' is accessible from within 'within', which must be a INamedTypeSymbol /// or an IAssemblySymbol. If 'symbol' is accessed off of an expression then /// 'throughTypeOpt' is the type of that expression. This is needed to properly do protected /// access checks. Sets "failedThroughTypeCheck" to true if this protected check failed. /// </summary> //// NOTE(cyrusn): I expect this function to be called a lot. As such, I do not do any memory //// allocations in the function itself (including not making any iterators). This does mean //// that certain helper functions that we'd like to call are inlined in this method to //// prevent the overhead of returning collections or enumerators. private static bool IsSymbolAccessibleCore( ISymbol symbol, ISymbol within, // must be assembly or named type symbol ITypeSymbol?throughType, out bool failedThroughTypeCheck) { Contract.ThrowIfNull(symbol); Contract.ThrowIfNull(within); Debug.Assert(within is INamedTypeSymbol || within is IAssemblySymbol); failedThroughTypeCheck = false; switch (symbol.Kind) { case SymbolKind.Alias: return(IsSymbolAccessibleCore(((IAliasSymbol)symbol).Target, within, throughType, out failedThroughTypeCheck)); case SymbolKind.ArrayType: return(IsSymbolAccessibleCore(((IArrayTypeSymbol)symbol).ElementType, within, null, out failedThroughTypeCheck)); case SymbolKind.PointerType: return(IsSymbolAccessibleCore(((IPointerTypeSymbol)symbol).PointedAtType, within, null, out failedThroughTypeCheck)); case SymbolKind.FunctionPointerType: var funcPtrSignature = ((IFunctionPointerTypeSymbol)symbol).Signature; if (!IsSymbolAccessibleCore(funcPtrSignature.ReturnType, within, null, out failedThroughTypeCheck)) { return(false); } foreach (var param in funcPtrSignature.Parameters) { if (!IsSymbolAccessibleCore(param.Type, within, null, out failedThroughTypeCheck)) { return(false); } } return(true); case SymbolKind.NamedType: return(IsNamedTypeAccessible((INamedTypeSymbol)symbol, within)); case SymbolKind.ErrorType: case SymbolKind.Discard: return(true); case SymbolKind.TypeParameter: case SymbolKind.Parameter: case SymbolKind.Local: case SymbolKind.Label: case SymbolKind.Namespace: case SymbolKind.DynamicType: case SymbolKind.Assembly: case SymbolKind.NetModule: case SymbolKind.RangeVariable: // These types of symbols are always accessible (if visible). return(true); case SymbolKind.Method: case SymbolKind.Property: case SymbolKind.Field: case SymbolKind.Event: if (symbol.IsStatic) { // static members aren't accessed "through" an "instance" of any type. So we // null out the "through" instance here. This ensures that we'll understand // accessing protected statics properly. throughType = null; } // If this is a synthesized operator of dynamic, it's always accessible. if (symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.DynamicType)) { return(true); } // If it's a synthesized operator on a pointer, use the pointer's PointedAtType. // Note: there are currently no synthesized operators on function pointer types. If that // ever changes, updated the below assert and fix the code Debug.Assert(!(symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.FunctionPointerType))); if (symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.PointerType)) { return(IsSymbolAccessibleCore(((IPointerTypeSymbol)symbol.ContainingSymbol).PointedAtType, within, null, out failedThroughTypeCheck)); } return(IsMemberAccessible(symbol.ContainingType, symbol.DeclaredAccessibility, within, throughType, out failedThroughTypeCheck)); default: throw ExceptionUtilities.UnexpectedValue(symbol.Kind); } }
public static bool IsInterfaceType([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.TypeKind == TypeKind.Interface;
public static async Task <ImmutableArray <SymbolAndProjectId> > FindImplementationsForInterfaceMemberAsync( this SymbolAndProjectId <ITypeSymbol> typeSymbolAndProjectId, SymbolAndProjectId interfaceMemberAndProjectId, Solution solution, CancellationToken cancellationToken) { // This method can return multiple results. Consider the case of: // // interface IGoo<X> { void Goo(X x); } // // class C : IGoo<int>, IGoo<string> { void Goo(int x); void Goo(string x); } // // If you're looking for the implementations of IGoo<X>.Goo then you want to find both // results in C. var arrBuilder = ArrayBuilder <SymbolAndProjectId> .GetInstance(); var interfaceMember = interfaceMemberAndProjectId.Symbol; // TODO(cyrusn): Implement this using the actual code for // TypeSymbol.FindImplementationForInterfaceMember var typeSymbol = typeSymbolAndProjectId.Symbol; if (typeSymbol == null || interfaceMember == null) { return(arrBuilder.ToImmutableAndFree()); } if (interfaceMember.Kind != SymbolKind.Event && interfaceMember.Kind != SymbolKind.Method && interfaceMember.Kind != SymbolKind.Property) { return(arrBuilder.ToImmutableAndFree()); } // WorkItem(4843) // // 'typeSymbol' has to at least implement the interface containing the member. note: // this just means that the interface shows up *somewhere* in the inheritance chain of // this type. However, this type may not actually say that it implements it. For // example: // // interface I { void Goo(); } // // class B { } // // class C : B, I { } // // class D : C { } // // D does implement I transitively through C. However, even if D has a "Goo" method, it // won't be an implementation of I.Goo. The implementation of I.Goo must be from a type // that actually has I in it's direct interface chain, or a type that's a base type of // that. in this case, that means only classes C or B. var interfaceType = interfaceMember.ContainingType; if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType)) { return(arrBuilder.ToImmutableAndFree()); } // We've ascertained that the type T implements some constructed type of the form I<X>. // However, we're not precisely sure which constructions of I<X> are being used. For // example, a type C might implement I<int> and I<string>. If we're searching for a // method from I<X> we might need to find several methods that implement different // instantiations of that method. var originalInterfaceType = interfaceMember.ContainingType.OriginalDefinition; var originalInterfaceMember = interfaceMember.OriginalDefinition; var constructedInterfaces = typeSymbol.AllInterfaces.Where(i => SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType)); // Try to get the compilation for the symbol we're searching for, // which can help identify matches with the call to SymbolFinder.OriginalSymbolsMatch. // OriginalSymbolMatch allows types to be matched across different assemblies // if they are considered to be the same type, which provides a more accurate // implementations list for interfaces. var typeSymbolProject = solution.GetProject(typeSymbolAndProjectId.ProjectId); var interfaceMemberProject = solution.GetProject(interfaceMemberAndProjectId.ProjectId); var typeSymbolCompilation = await GetCompilationOrNullAsync(typeSymbolProject, cancellationToken).ConfigureAwait(false); var interfaceMemberCompilation = await GetCompilationOrNullAsync(interfaceMemberProject, cancellationToken).ConfigureAwait(false); foreach (var constructedInterface in constructedInterfaces) { cancellationToken.ThrowIfCancellationRequested(); var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(typeSymbol => SymbolFinder.OriginalSymbolsMatch( typeSymbol, interfaceMember, solution, typeSymbolCompilation, interfaceMemberCompilation, cancellationToken)); if (constructedInterfaceMember == null) { continue; } // Now we need to walk the base type chain, but we start at the first type that actually // has the interface directly in its interface hierarchy. var seenTypeDeclaringInterface = false; for (ITypeSymbol?currentType = typeSymbol; currentType != null; currentType = currentType.BaseType) { seenTypeDeclaringInterface = seenTypeDeclaringInterface || currentType.GetOriginalInterfacesAndTheirBaseInterfaces().Contains(interfaceType.OriginalDefinition); if (seenTypeDeclaringInterface) { var result = currentType.FindImplementations(constructedInterfaceMember, solution.Workspace); if (result != null) { arrBuilder.Add(typeSymbolAndProjectId.WithSymbol(result)); break; } } } } return(arrBuilder.ToImmutableAndFree());
public static bool IsDelegateType([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.TypeKind == TypeKind.Delegate;
public static bool IsSystemVoid([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.SpecialType == SpecialType.System_Void;
public static bool IsStructType([NotNullWhen(returnValue: true)] this ITypeSymbol?symbol) => symbol?.TypeKind == TypeKind.Struct;
public static bool IsEnumType([NotNullWhen(true)] this ITypeSymbol?type) => IsEnumType(type, out _);
private static bool IsTypeAnObjectArray(ITypeSymbol?typeSymbol) { return(typeSymbol != null && typeSymbol.TypeKind == TypeKind.Array && ((IArrayTypeSymbol)typeSymbol).ElementType.SpecialType == SpecialType.System_Object); }