private void CheckForAttributeWithArrayArgument(Symbol symbol) { System.Diagnostics.Debug.Assert(IsTrue(GetDeclaredOrInheritedCompliance(symbol)), "Only call on compliant symbols"); CheckForAttributeWithArrayArgumentInternal(symbol.GetAttributes()); if (symbol.Kind == SymbolKind.Method) { CheckForAttributeWithArrayArgumentInternal(((MethodSymbol)symbol).GetReturnTypeAttributes()); } }
internal static void ReportDiagnosticsIfObsolete( DiagnosticBag diagnostics, Symbol symbol, SyntaxNodeOrToken node, bool hasBaseReceiver, Symbol containingMember, NamedTypeSymbol containingType, BinderFlags location) { Debug.Assert((object)symbol != null); Debug.Assert(symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Event || symbol.Kind == SymbolKind.Property); // Dev11 also reports on the unconstructed method. It would be nice to report on // the constructed method, but then we wouldn't be able to walk the override chain. if (symbol.Kind == SymbolKind.Method) { symbol = ((MethodSymbol)symbol).ConstructedFrom; } // There are two reasons to walk up to the least-overridden member: // 1) That's the method to which we will actually emit a call. // 2) We don't know what virtual dispatch will do at runtime so an // overriding member is basically a shot in the dark. Better to // just be consistent and always use the least-overridden member. Symbol leastOverriddenSymbol = symbol.GetLeastOverriddenMember(containingType); bool checkOverridingSymbol = hasBaseReceiver && !ReferenceEquals(symbol, leastOverriddenSymbol); if (checkOverridingSymbol) { // If we have a base receiver, we must be done with declaration binding, so it should // be safe to decode diagnostics. We want to do this since reporting for the overriding // member is conditional on reporting for the overridden member (i.e. we need a definite // answer so we don't double-report). You might think that double reporting just results // in cascading diagnostics, but it's possible that the second diagnostic is an error // while the first is merely a warning. leastOverriddenSymbol.GetAttributes(); } var diagnosticKind = ReportDiagnosticsIfObsoleteInternal(diagnostics, leastOverriddenSymbol, node, containingMember, location); // CONSIDER: In place of hasBaseReceiver, dev11 also accepts cases where symbol.ContainingType is a "simple type" (e.g. int) // or a special by-ref type (e.g. ArgumentHandle). These cases are probably more important for other checks performed by // ExpressionBinder::PostBindMethod, but they do appear to ObsoleteAttribute as well. We're skipping them because they // don't make much sense for ObsoleteAttribute (e.g. this would seem to address the case where int.ToString has been made // obsolete but object.ToString has not). // If the overridden member was not definitely obsolete and this is a (non-virtual) base member // access, then check the overriding symbol as well. switch (diagnosticKind) { case ObsoleteDiagnosticKind.NotObsolete: case ObsoleteDiagnosticKind.Lazy: if (checkOverridingSymbol) { Debug.Assert(diagnosticKind != ObsoleteDiagnosticKind.Lazy, "We forced attribute binding above."); ReportDiagnosticsIfObsoleteInternal(diagnostics, symbol, node, containingMember, location); } break; } }
/// <remarks> /// As in dev11, we ignore the fact that CLSCompliantAttribute is inherited (i.e. from the base type) /// (see CSemanticChecker::CheckSymForCLS). This should only affect types where the syntactic parent /// and the inheritance parent disagree. /// </remarks> private bool? GetDeclaredCompliance(Symbol symbol, out Location attributeLocation) { attributeLocation = null; foreach (CSharpAttributeData data in symbol.GetAttributes()) { // Check signature before HasErrors to avoid realizing symbols for other attributes. if (data.IsTargetAttribute(symbol, AttributeDescription.CLSCompliantAttribute)) { NamedTypeSymbol attributeClass = data.AttributeClass; if ((object)attributeClass != null) { DiagnosticInfo info = attributeClass.GetUseSiteDiagnostic(); if (info != null) { Location location = symbol.Locations.IsEmpty ? NoLocation.Singleton : symbol.Locations[0]; _diagnostics.Enqueue(new CSDiagnostic(info, location)); if (info.Severity >= DiagnosticSeverity.Error) { continue; } } } if (!data.HasErrors) { if (!TryGetAttributeWarningLocation(data, out attributeLocation)) { attributeLocation = null; } ImmutableArray<TypedConstant> args = data.CommonConstructorArguments; System.Diagnostics.Debug.Assert(args.Length == 1, "We already checked the signature and HasErrors."); // Duplicates are reported elsewhere - we only care about the first (error-free) occurrence. return (bool)args[0].Value; } } } return null; }