Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/uikit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8354,6 +8354,7 @@ interface UIButton : UIAccessibilityContentSizeCategoryImageAdjusting
[Export ("buttonWithType:")] [Static]
UIButton FromType (UIButtonType type);

[Appearance]
[Export ("contentEdgeInsets")]
UIEdgeInsets ContentEdgeInsets {get;set;}

Expand Down Expand Up @@ -8497,6 +8498,7 @@ interface UIButton : UIAccessibilityContentSizeCategoryImageAdjusting
[Export ("attributedTitleForState:")]
NSAttributedString GetAttributedTitle (UIControlState state);

[Appearance]
[Watch (6,0), TV (13,0), iOS (13,0)]
[Export ("setPreferredSymbolConfiguration:forImageInState:")]
void SetPreferredSymbolConfiguration ([NullAllowed] UIImageSymbolConfiguration configuration, UIControlState state);
Expand Down Expand Up @@ -9327,6 +9329,7 @@ interface UINavigationBar : UIBarPositioning, NSCoding {
[Export ("backgroundImageForBarPosition:barMetrics:")]
UIImage GetBackgroundImage (UIBarPosition barPosition, UIBarMetrics barMetrics);

[Appearance]
[NoTV]
[iOS (11,0)]
[Export ("prefersLargeTitles")]
Expand Down Expand Up @@ -11106,9 +11109,11 @@ interface UISearchBar : UIBarPositioning, UITextInputTraits
[NullAllowed]
UIImage ScopeBarBackgroundImage { get; set; }

[Appearance]
[Export ("searchFieldBackgroundPositionAdjustment")]
UIOffset SearchFieldBackgroundPositionAdjustment { get; set; }

[Appearance]
[Export ("searchTextPositionAdjustment")]
UIOffset SearchTextPositionAdjustment { get; set; }

Expand Down Expand Up @@ -11152,9 +11157,11 @@ interface UISearchBar : UIBarPositioning, UITextInputTraits
[Appearance]
NSDictionary _GetScopeBarButtonTitleTextAttributes (UIControlState state);

[Appearance]
[Export ("setPositionAdjustment:forSearchBarIcon:")]
void SetPositionAdjustmentforSearchBarIcon (UIOffset adjustment, UISearchBarIcon icon);

[Appearance]
[Export ("positionAdjustmentForSearchBarIcon:")]
UIOffset GetPositionAdjustmentForSearchBarIcon (UISearchBarIcon icon);

Expand Down Expand Up @@ -11564,6 +11571,7 @@ interface UISegmentedControl
[Export ("selectedSegmentIndex")]
nint SelectedSegment { get; set; }

[Appearance]
[iOS (13,0), TV (13,0), Watch (6,0)]
[NullAllowed, Export ("selectedSegmentTintColor", ArgumentSemantic.Strong)]
UIColor SelectedSegmentTintColor { get; set; }
Expand Down Expand Up @@ -11983,19 +11991,23 @@ interface UITabBar
[NullAllowed]
UIColor BarTintColor { get; set; }

[Appearance]
[NoTV]
[iOS (7,0)]
[Export ("itemPositioning")]
UITabBarItemPositioning ItemPositioning { get; set; }

[Appearance]
[iOS (7,0)]
[Export ("itemWidth")]
nfloat ItemWidth { get; set; }

[Appearance]
[iOS (7,0)]
[Export ("itemSpacing")]
nfloat ItemSpacing { get; set; }

[Appearance]
[NoTV]
[iOS (7,0)]
[Export ("barStyle")]
Expand All @@ -12005,6 +12017,7 @@ interface UITabBar
[Export ("translucent")]
bool Translucent { [Bind ("isTranslucent")] get; set; }

[Appearance]
[iOS (10,0), TV (10,0)]
[NullAllowed, Export ("unselectedItemTintColor", ArgumentSemantic.Copy)]
UIColor UnselectedItemTintColor { get; set; }
Expand Down Expand Up @@ -12206,10 +12219,12 @@ interface UITabBarItem : NSCoding
[Export ("selectedImage", ArgumentSemantic.Retain)][NullAllowed]
UIImage SelectedImage { get; set; }

[Appearance]
[iOS (10,0), TV (10,0)]
[NullAllowed, Export ("badgeColor", ArgumentSemantic.Copy)]
UIColor BadgeColor { get; set; }

[Appearance]
[iOS (10,0), TV (10,0)]
[Export ("setBadgeTextAttributes:forState:")]
[Internal]
Expand All @@ -12219,13 +12234,15 @@ interface UITabBarItem : NSCoding
[Wrap ("SetBadgeTextAttributes (textAttributes.GetDictionary (), state)")]
void SetBadgeTextAttributes (UIStringAttributes textAttributes, UIControlState state);

[Appearance]
[iOS (10,0), TV (10,0)]
[Export ("badgeTextAttributesForState:")]
[Internal]
NSDictionary<NSString, NSObject> _GetBadgeTextAttributes (UIControlState state);
[EditorBrowsable (EditorBrowsableState.Advanced)]
[return: NullAllowed]
NSDictionary<NSString, NSObject> GetBadgeTextAttributesDictionary (UIControlState state);

[iOS (10,0), TV (10,0)]
[Wrap ("new UIStringAttributes (_GetBadgeTextAttributes(state))")]
[Wrap ("new UIStringAttributes (GetBadgeTextAttributesDictionary(state))")]
UIStringAttributes GetBadgeTextAttributes (UIControlState state);

[Appearance]
Expand Down Expand Up @@ -12943,11 +12960,13 @@ interface UITableViewCell : NSCoding, UIGestureRecognizerDelegate {
[Export ("multipleSelectionBackgroundView", ArgumentSemantic.Retain), NullAllowed]
UIView MultipleSelectionBackgroundView { get; set; }

[Appearance]
[NoTV]
[iOS (7,0)]
[Export ("separatorInset")]
UIEdgeInsets SeparatorInset { get; set; }

[Appearance]
[iOS (9,0)] // introduced in Xcode 7.1 SDK (iOS 9.1 but hidden in 9.0)
[Export ("focusStyle", ArgumentSemantic.Assign)]
UITableViewCellFocusStyle FocusStyle { get; set; }
Expand Down Expand Up @@ -13676,12 +13695,14 @@ interface UIToolbar : UIBarPositioning {
[Export ("initWithFrame:")]
IntPtr Constructor (CGRect frame);

[Appearance]
[Export ("barStyle")]
UIBarStyle BarStyle { get; set; }

[Export ("items", ArgumentSemantic.Copy)][NullAllowed]
UIBarButtonItem [] Items { get; set; }

[Appearance]
[Export ("translucent", ArgumentSemantic.Assign)]
bool Translucent { [Bind ("isTranslucent")] get; set; }

Expand Down
1 change: 1 addition & 0 deletions tests/xtro-sharpie/Runner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public void Execute (string pchFile, IEnumerable<string> assemblyNames)
new RequiresSuperCheck (),
new DeprecatedCheck (),
new NullabilityCheck (),
new UIAppearanceCheck (),
// new ListNative (), // for debug
};
foreach (var assemblyName in assemblyNames) {
Expand Down
138 changes: 138 additions & 0 deletions tests/xtro-sharpie/UIAppearanceCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// The rule reports
//
// !missing-ui-appearance-support!
// when an API does not have a [Appearance] attribute while ObjC headers have a UI_APPEARANCE_SELECTOR
//
// !extra-ui-appearance-support!
// when an API is decorated with [Appearance] attribute but ObjC headers don't have a UI_APPEARANCE_SELECTOR
//

using System;
using System.Collections.Generic;

using Mono.Cecil;

using Clang.Ast;

namespace Extrospection {

public class UIAppearanceCheck : BaseVisitor {

static HashSet<TypeDefinition> appearance_types = new HashSet<TypeDefinition> ();
static HashSet<MethodDefinition> appearance_methods = new HashSet<MethodDefinition> ();
static Dictionary<string,MethodDefinition> methods = new Dictionary<string,MethodDefinition> ();

static MethodDefinition GetMethod (ObjCMethodDecl decl)
{
methods.TryGetValue (decl.GetName (), out var md);
return md;
}

public override void VisitManagedType (TypeDefinition type)
{
if (!type.HasNestedTypes)
return;

var tn = type.Name + "Appearance";
foreach (var nt in type.NestedTypes) {
if (nt.Name == tn)
appearance_types.Add (nt);
}
}

public override void VisitManagedMethod (MethodDefinition method)
{
var key = method.GetName ();
if (key != null)
methods [key] = method;
}

public override void VisitObjCPropertyDecl (ObjCPropertyDecl decl)
{
// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;

// does not look exposed, but part of the dump
if (decl.DumpToString ().IndexOf ("UI_APPEARANCE_SELECTOR", StringComparison.OrdinalIgnoreCase) < 0)
return;

var getter = decl.Getter;
if (getter != null)
VisitObjCMethodDecl (getter);
var setter = decl.Setter;
if (setter != null)
VisitObjCMethodDecl (setter);
}

public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind)
{
if (visitKind != VisitKind.Enter)
return;

// don't process methods (or types) that are unavailable for the current platform
if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ())
return;

// does not look exposed, but part of the dump
if (decl.DumpToString ().IndexOf ("UI_APPEARANCE_SELECTOR", StringComparison.OrdinalIgnoreCase) < 0)
return;

VisitObjCMethodDecl (decl);
}

void VisitObjCMethodDecl (ObjCMethodDecl decl)
{
var framework = Helpers.GetFramework (decl);
if (framework == null)
return;

var method = GetMethod (decl);
if (method == null)
return;

var dt = method.DeclaringType;
if (dt.HasNestedTypes) {
foreach (var nt in dt.NestedTypes) {
if (nt.Name != dt.Name + "Appearance")
continue;
// find matching method, including parameters (we have overloads)
var fn = method.FullName;
int ms = fn.IndexOf ("::");
fn = fn.Insert (ms, $"/{dt.Name}Appearance");
foreach (var m in nt.Methods) {
if (m.FullName != fn)
continue;
appearance_methods.Add (m); // legit one
return;
}
}
}

Log.On (framework).Add ($"!missing-ui-appearance-support! {method.GetName ()} is missing [Appearance]");
}

public override void End ()
{
// looking for extra [Appearance] attributes
foreach (var t in appearance_types) {
if (!t.HasMethods)
continue;
foreach (var m in t.Methods) {
if (m.IsConstructor)
continue;
if (appearance_methods.Contains (m))
continue;
var framework = Helpers.GetFramework (m);
var fn = m.FullName;
// don't report on the *Appearance type - but where the attribute was used
int ns = fn.IndexOf ('/');
int ms = fn.IndexOf ("::", ns);
fn = fn.Remove (ns, ms - ns);
Log.On (framework).Add ($"!extra-ui-appearance-support! {fn} should NOT be decorated with [Appearance]");
}
}
}
}
}
24 changes: 24 additions & 0 deletions tests/xtro-sharpie/common-UIKit.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,30 @@
!missing-protocol! UIResponderStandardEditActions not bound
!missing-protocol-conformance! UIResponder should conform to UIResponderStandardEditActions

## there's no UI_APPEARANCE_SELECTOR in headers - but they can (unofficially) work, YYMV
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIBarButtonItem::get_TintColor() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UIBarButtonItem::set_TintColor(UIKit.UIColor) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UIButton::SetImage(UIKit.UIImage,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIButton::get_CurrentTitleColor() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIButton::get_CurrentTitleShadowColor() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIButton::TitleColor(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIButton::TitleShadowColor(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UIButton::BackgroundImageForState(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UIButton::get_CurrentBackgroundImage() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UIButton::get_CurrentImage() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UIButton::ImageForState(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UIView::set_TintColor(UIKit.UIColor) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIColor UIKit.UIView::get_TintColor() should NOT be decorated with [Appearance]

## manually bound (better, stronger signature) on `[setS|s]copeBarButtonTitleTextAttributes:forState:` which is decorated with `UI_APPEARANCE_SELECTOR`
!extra-ui-appearance-support! System.Void UIKit.UISearchBar::SetScopeBarButtonTitle(UIKit.UITextAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UITextAttributes UIKit.UISearchBar::GetScopeBarButtonTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]

## [Wrap] over `[largeT|t]itleTextAttributes` which is decorated with `UI_APPEARANCE_SELECTOR`
!extra-ui-appearance-support! UIKit.UIStringAttributes UIKit.UINavigationBar::get_LargeTitleTextAttributes() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIStringAttributes UIKit.UINavigationBar::get_TitleTextAttributes() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UINavigationBar::set_LargeTitleTextAttributes(UIKit.UIStringAttributes) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UINavigationBar::set_TitleTextAttributes(UIKit.UIStringAttributes) should NOT be decorated with [Appearance]

## unsorted

Expand Down
21 changes: 20 additions & 1 deletion tests/xtro-sharpie/iOS-UIKit.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UIMotionEffect::ComputeKeyPathsAndRelativeValues(UIKit.UIOffset)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UISearchBar::_GetScopeBarButtonTitleTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UISegmentedControl::_GetTitleTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary`2<Foundation.NSString,Foundation.NSObject> UIKit.UITabBarItem::_GetBadgeTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSExtensionContext UIKit.UIViewController::get_ExtensionContext()' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSFileWrapper Foundation.NSAttributedString::GetFileWrapperFromRange(Foundation.NSRange,Foundation.NSDictionary,Foundation.NSError&)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSIndexPath UIKit.UICollectionView::IndexPathForCell(UIKit.UICollectionViewCell)' is missing an [NullAllowed] on return type
Expand Down Expand Up @@ -517,3 +516,23 @@
## These are inlined by protocol adoption so you can't really add such decoration
!missing-requires-super! UIControl::contextMenuInteraction:willDisplayMenuForConfiguration:animator: is missing an [RequiresSuper] attribute
!missing-requires-super! UIControl::contextMenuInteraction:willEndForConfiguration:animator: is missing an [RequiresSuper] attribute

## manually bound (better, stronger signature) on `[setT|t]itleTextAttributes:forState:` which is decorated with `UI_APPEARANCE_SELECTOR`
!extra-ui-appearance-support! UIKit.UITextAttributes UIKit.UIBarItem::GetTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UIBarItem::SetTitleTextAttributes(UIKit.UITextAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UITextAttributes UIKit.UINavigationBar::GetTitleTextAttributes() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UINavigationBar::SetTitleTextAttributes(UIKit.UITextAttributes) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UITextAttributes UIKit.UISegmentedControl::GetTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISegmentedControl::SetTitleTextAttributes(UIKit.UITextAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]

## there's no UI_APPEARANCE_SELECTOR in headers - but they can (unofficially) work, YYMV
!extra-ui-appearance-support! System.Void UIKit.UISlider::set_MaxValueImage(UIKit.UIImage) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISlider::set_MinValueImage(UIKit.UIImage) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UISlider::get_MaxValueImage() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UISlider::get_MinValueImage() should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISlider::SetMaxTrackImage(UIKit.UIImage,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISlider::SetMinTrackImage(UIKit.UIImage,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISlider::SetThumbImage(UIKit.UIImage,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UISlider::MaxTrackImage(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UISlider::MinTrackImage(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIImage UIKit.UISlider::ThumbImage(UIKit.UIControlState) should NOT be decorated with [Appearance]
9 changes: 8 additions & 1 deletion tests/xtro-sharpie/tvOS-UIKit.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UIMotionEffect::ComputeKeyPathsAndRelativeValues(UIKit.UIOffset)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UISearchBar::_GetScopeBarButtonTitleTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary UIKit.UISegmentedControl::_GetTitleTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSDictionary`2<Foundation.NSString,Foundation.NSObject> UIKit.UITabBarItem::_GetBadgeTextAttributes(UIKit.UIControlState)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSExtensionContext UIKit.UIViewController::get_ExtensionContext()' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSFileWrapper Foundation.NSAttributedString::GetFileWrapperFromRange(Foundation.NSRange,Foundation.NSDictionary,Foundation.NSError&)' is missing an [NullAllowed] on return type
!missing-null-allowed! 'Foundation.NSIndexPath UIKit.UICollectionView::IndexPathForCell(UIKit.UICollectionViewCell)' is missing an [NullAllowed] on return type
Expand Down Expand Up @@ -405,3 +404,11 @@
!missing-null-allowed! 'UIKit.UIWindow UIKit.UIApplication::get_KeyWindow()' is missing an [NullAllowed] on return type
!missing-null-allowed! 'UIKit.UIWindow UIKit.UITouch::get_Window()' is missing an [NullAllowed] on return type
!missing-null-allowed! 'UIKit.UIWindow UIKit.UIView::get_Window()' is missing an [NullAllowed] on return type

## same as iOS but we used the newer name if `UIStringAttributes` so it requires a different entry
!extra-ui-appearance-support! System.Void UIKit.UIBarItem::SetTitleTextAttributes(UIKit.UIStringAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISearchBar::SetScopeBarButtonTitle(UIKit.UIStringAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! System.Void UIKit.UISegmentedControl::SetTitleTextAttributes(UIKit.UIStringAttributes,UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIStringAttributes UIKit.UIBarItem::GetTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIStringAttributes UIKit.UISearchBar::GetScopeBarButtonTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]
!extra-ui-appearance-support! UIKit.UIStringAttributes UIKit.UISegmentedControl::GetTitleTextAttributes(UIKit.UIControlState) should NOT be decorated with [Appearance]
Loading