File: | tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp |
Location: | line 627, column 17 |
Description: | Value stored to 'ErrNode' during its initialization is never read |
1 | //=- LocalizationChecker.cpp -------------------------------------*- C++ -*-==// |
2 | // |
3 | // The LLVM Compiler Infrastructure |
4 | // |
5 | // This file is distributed under the University of Illinois Open Source |
6 | // License. See LICENSE.TXT for details. |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | // |
10 | // This file defines a set of checks for localizability including: |
11 | // 1) A checker that warns about uses of non-localized NSStrings passed to |
12 | // UI methods expecting localized strings |
13 | // 2) A syntactic checker that warns against the bad practice of |
14 | // not including a comment in NSLocalizedString macros. |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #include "ClangSACheckers.h" |
19 | #include "clang/AST/Attr.h" |
20 | #include "clang/AST/Decl.h" |
21 | #include "clang/AST/DeclObjC.h" |
22 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" |
23 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
24 | #include "clang/StaticAnalyzer/Core/Checker.h" |
25 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
26 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
27 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
28 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
29 | #include "clang/Lex/Lexer.h" |
30 | #include "clang/AST/RecursiveASTVisitor.h" |
31 | #include "clang/AST/StmtVisitor.h" |
32 | #include "llvm/Support/Unicode.h" |
33 | #include "llvm/ADT/StringSet.h" |
34 | |
35 | using namespace clang; |
36 | using namespace ento; |
37 | |
38 | namespace { |
39 | struct LocalizedState { |
40 | private: |
41 | enum Kind { NonLocalized, Localized } K; |
42 | LocalizedState(Kind InK) : K(InK) {} |
43 | |
44 | public: |
45 | bool isLocalized() const { return K == Localized; } |
46 | bool isNonLocalized() const { return K == NonLocalized; } |
47 | |
48 | static LocalizedState getLocalized() { return LocalizedState(Localized); } |
49 | static LocalizedState getNonLocalized() { |
50 | return LocalizedState(NonLocalized); |
51 | } |
52 | |
53 | // Overload the == operator |
54 | bool operator==(const LocalizedState &X) const { return K == X.K; } |
55 | |
56 | // LLVMs equivalent of a hash function |
57 | void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } |
58 | }; |
59 | |
60 | class NonLocalizedStringChecker |
61 | : public Checker<check::PostCall, check::PreObjCMessage, |
62 | check::PostObjCMessage, |
63 | check::PostStmt<ObjCStringLiteral>> { |
64 | |
65 | mutable std::unique_ptr<BugType> BT; |
66 | |
67 | // Methods that require a localized string |
68 | mutable llvm::DenseMap<const IdentifierInfo *, |
69 | llvm::DenseMap<Selector, uint8_t>> UIMethods; |
70 | // Methods that return a localized string |
71 | mutable llvm::SmallSet<std::pair<const IdentifierInfo *, Selector>, 12> LSM; |
72 | // C Functions that return a localized string |
73 | mutable llvm::SmallSet<const IdentifierInfo *, 5> LSF; |
74 | |
75 | void initUIMethods(ASTContext &Ctx) const; |
76 | void initLocStringsMethods(ASTContext &Ctx) const; |
77 | |
78 | bool hasNonLocalizedState(SVal S, CheckerContext &C) const; |
79 | bool hasLocalizedState(SVal S, CheckerContext &C) const; |
80 | void setNonLocalizedState(SVal S, CheckerContext &C) const; |
81 | void setLocalizedState(SVal S, CheckerContext &C) const; |
82 | |
83 | bool isAnnotatedAsLocalized(const Decl *D) const; |
84 | void reportLocalizationError(SVal S, const ObjCMethodCall &M, |
85 | CheckerContext &C, int argumentNumber = 0) const; |
86 | |
87 | int getLocalizedArgumentForSelector(const IdentifierInfo *Receiver, |
88 | Selector S) const; |
89 | |
90 | public: |
91 | NonLocalizedStringChecker(); |
92 | |
93 | // When this parameter is set to true, the checker assumes all |
94 | // methods that return NSStrings are unlocalized. Thus, more false |
95 | // positives will be reported. |
96 | DefaultBool IsAggressive; |
97 | |
98 | void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; |
99 | void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; |
100 | void checkPostStmt(const ObjCStringLiteral *SL, CheckerContext &C) const; |
101 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const; |
102 | }; |
103 | |
104 | } // end anonymous namespace |
105 | |
106 | REGISTER_MAP_WITH_PROGRAMSTATE(LocalizedMemMap, const MemRegion *,namespace { class LocalizedMemMap {}; typedef llvm::ImmutableMap <const MemRegion *, LocalizedState> LocalizedMemMapTy; } namespace clang { namespace ento { template <> struct ProgramStateTrait <LocalizedMemMap> : public ProgramStatePartialTrait< LocalizedMemMapTy> { static void *GDMIndex() { static int Index ; return &Index; } }; } } |
107 | LocalizedState)namespace { class LocalizedMemMap {}; typedef llvm::ImmutableMap <const MemRegion *, LocalizedState> LocalizedMemMapTy; } namespace clang { namespace ento { template <> struct ProgramStateTrait <LocalizedMemMap> : public ProgramStatePartialTrait< LocalizedMemMapTy> { static void *GDMIndex() { static int Index ; return &Index; } }; } } |
108 | |
109 | NonLocalizedStringChecker::NonLocalizedStringChecker() { |
110 | BT.reset(new BugType(this, "Unlocalizable string", |
111 | "Localizability Issue (Apple)")); |
112 | } |
113 | |
114 | #define NEW_RECEIVER(receiver)llvm::DenseMap<Selector, uint8_t> &receiverM = UIMethods .insert({&Ctx.Idents.get("receiver"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; \ |
115 | llvm::DenseMap<Selector, uint8_t> &receiver##M = \ |
116 | UIMethods.insert({&Ctx.Idents.get(#receiver), \ |
117 | llvm::DenseMap<Selector, uint8_t>()}) \ |
118 | .first->second; |
119 | #define ADD_NULLARY_METHOD(receiver, method, argument)receiverM.insert( {Ctx.Selectors.getNullarySelector(&Ctx. Idents.get("method")), argument}); \ |
120 | receiver##M.insert( \ |
121 | {Ctx.Selectors.getNullarySelector(&Ctx.Idents.get(#method)), argument}); |
122 | #define ADD_UNARY_METHOD(receiver, method, argument)receiverM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("method")), argument}); \ |
123 | receiver##M.insert( \ |
124 | {Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(#method)), argument}); |
125 | #define ADD_METHOD(receiver, method_list, count, argument)receiverM.insert({Ctx.Selectors.getSelector(count, method_list ), argument}); \ |
126 | receiver##M.insert({Ctx.Selectors.getSelector(count, method_list), argument}); |
127 | |
128 | /// Initializes a list of methods that require a localized string |
129 | /// Format: {"ClassName", {{"selectorName:", LocStringArg#}, ...}, ...} |
130 | void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const { |
131 | if (!UIMethods.empty()) |
132 | return; |
133 | |
134 | // UI Methods |
135 | NEW_RECEIVER(UISearchDisplayController)llvm::DenseMap<Selector, uint8_t> &UISearchDisplayControllerM = UIMethods.insert({&Ctx.Idents.get("UISearchDisplayController" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
136 | ADD_UNARY_METHOD(UISearchDisplayController, setSearchResultsTitle, 0)UISearchDisplayControllerM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setSearchResultsTitle")), 0}); |
137 | |
138 | NEW_RECEIVER(UITabBarItem)llvm::DenseMap<Selector, uint8_t> &UITabBarItemM = UIMethods .insert({&Ctx.Idents.get("UITabBarItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
139 | IdentifierInfo *initWithTitleUITabBarItemTag[] = { |
140 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("image"), |
141 | &Ctx.Idents.get("tag")}; |
142 | ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemTag, 3, 0)UITabBarItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleUITabBarItemTag ), 0}); |
143 | IdentifierInfo *initWithTitleUITabBarItemImage[] = { |
144 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("image"), |
145 | &Ctx.Idents.get("selectedImage")}; |
146 | ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemImage, 3, 0)UITabBarItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleUITabBarItemImage ), 0}); |
147 | |
148 | NEW_RECEIVER(NSDockTile)llvm::DenseMap<Selector, uint8_t> &NSDockTileM = UIMethods .insert({&Ctx.Idents.get("NSDockTile"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
149 | ADD_UNARY_METHOD(NSDockTile, setBadgeLabel, 0)NSDockTileM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setBadgeLabel")), 0}); |
150 | |
151 | NEW_RECEIVER(NSStatusItem)llvm::DenseMap<Selector, uint8_t> &NSStatusItemM = UIMethods .insert({&Ctx.Idents.get("NSStatusItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
152 | ADD_UNARY_METHOD(NSStatusItem, setTitle, 0)NSStatusItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
153 | ADD_UNARY_METHOD(NSStatusItem, setToolTip, 0)NSStatusItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); |
154 | |
155 | NEW_RECEIVER(UITableViewRowAction)llvm::DenseMap<Selector, uint8_t> &UITableViewRowActionM = UIMethods.insert({&Ctx.Idents.get("UITableViewRowAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
156 | IdentifierInfo *rowActionWithStyleUITableViewRowAction[] = { |
157 | &Ctx.Idents.get("rowActionWithStyle"), &Ctx.Idents.get("title"), |
158 | &Ctx.Idents.get("handler")}; |
159 | ADD_METHOD(UITableViewRowAction, rowActionWithStyleUITableViewRowAction, 3, 1)UITableViewRowActionM.insert({Ctx.Selectors.getSelector(3, rowActionWithStyleUITableViewRowAction ), 1}); |
160 | ADD_UNARY_METHOD(UITableViewRowAction, setTitle, 0)UITableViewRowActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); |
161 | |
162 | NEW_RECEIVER(NSBox)llvm::DenseMap<Selector, uint8_t> &NSBoxM = UIMethods .insert({&Ctx.Idents.get("NSBox"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
163 | ADD_UNARY_METHOD(NSBox, setTitle, 0)NSBoxM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
164 | |
165 | NEW_RECEIVER(NSButton)llvm::DenseMap<Selector, uint8_t> &NSButtonM = UIMethods .insert({&Ctx.Idents.get("NSButton"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
166 | ADD_UNARY_METHOD(NSButton, setTitle, 0)NSButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
167 | ADD_UNARY_METHOD(NSButton, setAlternateTitle, 0)NSButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setAlternateTitle")), 0}); |
168 | |
169 | NEW_RECEIVER(NSSavePanel)llvm::DenseMap<Selector, uint8_t> &NSSavePanelM = UIMethods .insert({&Ctx.Idents.get("NSSavePanel"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
170 | ADD_UNARY_METHOD(NSSavePanel, setPrompt, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPrompt")), 0}); |
171 | ADD_UNARY_METHOD(NSSavePanel, setTitle, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
172 | ADD_UNARY_METHOD(NSSavePanel, setNameFieldLabel, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setNameFieldLabel")), 0}); |
173 | ADD_UNARY_METHOD(NSSavePanel, setNameFieldStringValue, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setNameFieldStringValue")), 0}); |
174 | ADD_UNARY_METHOD(NSSavePanel, setMessage, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setMessage")), 0}); |
175 | |
176 | NEW_RECEIVER(UIPrintInfo)llvm::DenseMap<Selector, uint8_t> &UIPrintInfoM = UIMethods .insert({&Ctx.Idents.get("UIPrintInfo"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
177 | ADD_UNARY_METHOD(UIPrintInfo, setJobName, 0)UIPrintInfoM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setJobName")), 0}); |
178 | |
179 | NEW_RECEIVER(NSTabViewItem)llvm::DenseMap<Selector, uint8_t> &NSTabViewItemM = UIMethods.insert({&Ctx.Idents.get("NSTabViewItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
180 | ADD_UNARY_METHOD(NSTabViewItem, setLabel, 0)NSTabViewItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setLabel")), 0}); |
181 | ADD_UNARY_METHOD(NSTabViewItem, setToolTip, 0)NSTabViewItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); |
182 | |
183 | NEW_RECEIVER(NSBrowser)llvm::DenseMap<Selector, uint8_t> &NSBrowserM = UIMethods .insert({&Ctx.Idents.get("NSBrowser"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
184 | IdentifierInfo *setTitleNSBrowser[] = {&Ctx.Idents.get("setTitle"), |
185 | &Ctx.Idents.get("ofColumn")}; |
186 | ADD_METHOD(NSBrowser, setTitleNSBrowser, 2, 0)NSBrowserM.insert({Ctx.Selectors.getSelector(2, setTitleNSBrowser ), 0}); |
187 | |
188 | NEW_RECEIVER(UIAccessibilityElement)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityElementM = UIMethods.insert({&Ctx.Idents.get("UIAccessibilityElement" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
189 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityLabel, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityLabel")), 0}); |
190 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityHint, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityHint")), 0}); |
191 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityValue, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityValue")), 0}); |
192 | |
193 | NEW_RECEIVER(UIAlertAction)llvm::DenseMap<Selector, uint8_t> &UIAlertActionM = UIMethods.insert({&Ctx.Idents.get("UIAlertAction"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
194 | IdentifierInfo *actionWithTitleUIAlertAction[] = { |
195 | &Ctx.Idents.get("actionWithTitle"), &Ctx.Idents.get("style"), |
196 | &Ctx.Idents.get("handler")}; |
197 | ADD_METHOD(UIAlertAction, actionWithTitleUIAlertAction, 3, 0)UIAlertActionM.insert({Ctx.Selectors.getSelector(3, actionWithTitleUIAlertAction ), 0}); |
198 | |
199 | NEW_RECEIVER(NSPopUpButton)llvm::DenseMap<Selector, uint8_t> &NSPopUpButtonM = UIMethods.insert({&Ctx.Idents.get("NSPopUpButton"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
200 | ADD_UNARY_METHOD(NSPopUpButton, addItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addItemWithTitle")), 0}); |
201 | IdentifierInfo *insertItemWithTitleNSPopUpButton[] = { |
202 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("atIndex")}; |
203 | ADD_METHOD(NSPopUpButton, insertItemWithTitleNSPopUpButton, 2, 0)NSPopUpButtonM.insert({Ctx.Selectors.getSelector(2, insertItemWithTitleNSPopUpButton ), 0}); |
204 | ADD_UNARY_METHOD(NSPopUpButton, removeItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("removeItemWithTitle")), 0}); |
205 | ADD_UNARY_METHOD(NSPopUpButton, selectItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("selectItemWithTitle")), 0}); |
206 | ADD_UNARY_METHOD(NSPopUpButton, setTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
207 | |
208 | NEW_RECEIVER(NSTableViewRowAction)llvm::DenseMap<Selector, uint8_t> &NSTableViewRowActionM = UIMethods.insert({&Ctx.Idents.get("NSTableViewRowAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
209 | IdentifierInfo *rowActionWithStyleNSTableViewRowAction[] = { |
210 | &Ctx.Idents.get("rowActionWithStyle"), &Ctx.Idents.get("title"), |
211 | &Ctx.Idents.get("handler")}; |
212 | ADD_METHOD(NSTableViewRowAction, rowActionWithStyleNSTableViewRowAction, 3, 1)NSTableViewRowActionM.insert({Ctx.Selectors.getSelector(3, rowActionWithStyleNSTableViewRowAction ), 1}); |
213 | ADD_UNARY_METHOD(NSTableViewRowAction, setTitle, 0)NSTableViewRowActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); |
214 | |
215 | NEW_RECEIVER(NSImage)llvm::DenseMap<Selector, uint8_t> &NSImageM = UIMethods .insert({&Ctx.Idents.get("NSImage"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
216 | ADD_UNARY_METHOD(NSImage, setAccessibilityDescription, 0)NSImageM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setAccessibilityDescription")), 0}); |
217 | |
218 | NEW_RECEIVER(NSUserActivity)llvm::DenseMap<Selector, uint8_t> &NSUserActivityM = UIMethods.insert({&Ctx.Idents.get("NSUserActivity"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
219 | ADD_UNARY_METHOD(NSUserActivity, setTitle, 0)NSUserActivityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
220 | |
221 | NEW_RECEIVER(NSPathControlItem)llvm::DenseMap<Selector, uint8_t> &NSPathControlItemM = UIMethods.insert({&Ctx.Idents.get("NSPathControlItem") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
222 | ADD_UNARY_METHOD(NSPathControlItem, setTitle, 0)NSPathControlItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
223 | |
224 | NEW_RECEIVER(NSCell)llvm::DenseMap<Selector, uint8_t> &NSCellM = UIMethods .insert({&Ctx.Idents.get("NSCell"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
225 | ADD_UNARY_METHOD(NSCell, initTextCell, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("initTextCell")), 0}); |
226 | ADD_UNARY_METHOD(NSCell, setTitle, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
227 | ADD_UNARY_METHOD(NSCell, setStringValue, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setStringValue")), 0}); |
228 | |
229 | NEW_RECEIVER(NSPathControl)llvm::DenseMap<Selector, uint8_t> &NSPathControlM = UIMethods.insert({&Ctx.Idents.get("NSPathControl"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
230 | ADD_UNARY_METHOD(NSPathControl, setPlaceholderString, 0)NSPathControlM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholderString")), 0}); |
231 | |
232 | NEW_RECEIVER(UIAccessibility)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityM = UIMethods.insert({&Ctx.Idents.get("UIAccessibility"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
233 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityLabel, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityLabel")), 0}); |
234 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityHint, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityHint")), 0}); |
235 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityValue, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityValue")), 0}); |
236 | |
237 | NEW_RECEIVER(NSTableColumn)llvm::DenseMap<Selector, uint8_t> &NSTableColumnM = UIMethods.insert({&Ctx.Idents.get("NSTableColumn"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
238 | ADD_UNARY_METHOD(NSTableColumn, setTitle, 0)NSTableColumnM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
239 | ADD_UNARY_METHOD(NSTableColumn, setHeaderToolTip, 0)NSTableColumnM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setHeaderToolTip")), 0}); |
240 | |
241 | NEW_RECEIVER(NSSegmentedControl)llvm::DenseMap<Selector, uint8_t> &NSSegmentedControlM = UIMethods.insert({&Ctx.Idents.get("NSSegmentedControl" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
242 | IdentifierInfo *setLabelNSSegmentedControl[] = { |
243 | &Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")}; |
244 | ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)NSSegmentedControlM.insert({Ctx.Selectors.getSelector(2, setLabelNSSegmentedControl ), 0}); |
245 | |
246 | NEW_RECEIVER(NSButtonCell)llvm::DenseMap<Selector, uint8_t> &NSButtonCellM = UIMethods .insert({&Ctx.Idents.get("NSButtonCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
247 | ADD_UNARY_METHOD(NSButtonCell, setTitle, 0)NSButtonCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
248 | ADD_UNARY_METHOD(NSButtonCell, setAlternateTitle, 0)NSButtonCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setAlternateTitle")), 0}); |
249 | |
250 | NEW_RECEIVER(NSSliderCell)llvm::DenseMap<Selector, uint8_t> &NSSliderCellM = UIMethods .insert({&Ctx.Idents.get("NSSliderCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
251 | ADD_UNARY_METHOD(NSSliderCell, setTitle, 0)NSSliderCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
252 | |
253 | NEW_RECEIVER(NSControl)llvm::DenseMap<Selector, uint8_t> &NSControlM = UIMethods .insert({&Ctx.Idents.get("NSControl"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
254 | ADD_UNARY_METHOD(NSControl, setStringValue, 0)NSControlM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setStringValue")), 0}); |
255 | |
256 | NEW_RECEIVER(NSAccessibility)llvm::DenseMap<Selector, uint8_t> &NSAccessibilityM = UIMethods.insert({&Ctx.Idents.get("NSAccessibility"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
257 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityValueDescription, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityValueDescription")), 0}); |
258 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityLabel, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityLabel")), 0}); |
259 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityTitle, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityTitle")), 0}); |
260 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityPlaceholderValue, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityPlaceholderValue")), 0}); |
261 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityHelp, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityHelp")), 0}); |
262 | |
263 | NEW_RECEIVER(NSMatrix)llvm::DenseMap<Selector, uint8_t> &NSMatrixM = UIMethods .insert({&Ctx.Idents.get("NSMatrix"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
264 | IdentifierInfo *setToolTipNSMatrix[] = {&Ctx.Idents.get("setToolTip"), |
265 | &Ctx.Idents.get("forCell")}; |
266 | ADD_METHOD(NSMatrix, setToolTipNSMatrix, 2, 0)NSMatrixM.insert({Ctx.Selectors.getSelector(2, setToolTipNSMatrix ), 0}); |
267 | |
268 | NEW_RECEIVER(NSPrintPanel)llvm::DenseMap<Selector, uint8_t> &NSPrintPanelM = UIMethods .insert({&Ctx.Idents.get("NSPrintPanel"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
269 | ADD_UNARY_METHOD(NSPrintPanel, setDefaultButtonTitle, 0)NSPrintPanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setDefaultButtonTitle")), 0}); |
270 | |
271 | NEW_RECEIVER(UILocalNotification)llvm::DenseMap<Selector, uint8_t> &UILocalNotificationM = UIMethods.insert({&Ctx.Idents.get("UILocalNotification" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
272 | ADD_UNARY_METHOD(UILocalNotification, setAlertBody, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertBody")), 0}); |
273 | ADD_UNARY_METHOD(UILocalNotification, setAlertAction, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertAction")), 0}); |
274 | ADD_UNARY_METHOD(UILocalNotification, setAlertTitle, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertTitle")), 0}); |
275 | |
276 | NEW_RECEIVER(NSSlider)llvm::DenseMap<Selector, uint8_t> &NSSliderM = UIMethods .insert({&Ctx.Idents.get("NSSlider"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
277 | ADD_UNARY_METHOD(NSSlider, setTitle, 0)NSSliderM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
278 | |
279 | NEW_RECEIVER(UIMenuItem)llvm::DenseMap<Selector, uint8_t> &UIMenuItemM = UIMethods .insert({&Ctx.Idents.get("UIMenuItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
280 | IdentifierInfo *initWithTitleUIMenuItem[] = {&Ctx.Idents.get("initWithTitle"), |
281 | &Ctx.Idents.get("action")}; |
282 | ADD_METHOD(UIMenuItem, initWithTitleUIMenuItem, 2, 0)UIMenuItemM.insert({Ctx.Selectors.getSelector(2, initWithTitleUIMenuItem ), 0}); |
283 | ADD_UNARY_METHOD(UIMenuItem, setTitle, 0)UIMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); |
284 | |
285 | NEW_RECEIVER(UIAlertController)llvm::DenseMap<Selector, uint8_t> &UIAlertControllerM = UIMethods.insert({&Ctx.Idents.get("UIAlertController") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
286 | IdentifierInfo *alertControllerWithTitleUIAlertController[] = { |
287 | &Ctx.Idents.get("alertControllerWithTitle"), &Ctx.Idents.get("message"), |
288 | &Ctx.Idents.get("preferredStyle")}; |
289 | ADD_METHOD(UIAlertController, alertControllerWithTitleUIAlertController, 3, 1)UIAlertControllerM.insert({Ctx.Selectors.getSelector(3, alertControllerWithTitleUIAlertController ), 1}); |
290 | ADD_UNARY_METHOD(UIAlertController, setTitle, 0)UIAlertControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
291 | ADD_UNARY_METHOD(UIAlertController, setMessage, 0)UIAlertControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setMessage")), 0}); |
292 | |
293 | NEW_RECEIVER(UIApplicationShortcutItem)llvm::DenseMap<Selector, uint8_t> &UIApplicationShortcutItemM = UIMethods.insert({&Ctx.Idents.get("UIApplicationShortcutItem" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
294 | IdentifierInfo *initWithTypeUIApplicationShortcutItemIcon[] = { |
295 | &Ctx.Idents.get("initWithType"), &Ctx.Idents.get("localizedTitle"), |
296 | &Ctx.Idents.get("localizedSubtitle"), &Ctx.Idents.get("icon"), |
297 | &Ctx.Idents.get("userInfo")}; |
298 | ADD_METHOD(UIApplicationShortcutItem,UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 5, initWithTypeUIApplicationShortcutItemIcon), 1}); |
299 | initWithTypeUIApplicationShortcutItemIcon, 5, 1)UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 5, initWithTypeUIApplicationShortcutItemIcon), 1}); |
300 | IdentifierInfo *initWithTypeUIApplicationShortcutItem[] = { |
301 | &Ctx.Idents.get("initWithType"), &Ctx.Idents.get("localizedTitle")}; |
302 | ADD_METHOD(UIApplicationShortcutItem, initWithTypeUIApplicationShortcutItem,UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 2, initWithTypeUIApplicationShortcutItem), 1}); |
303 | 2, 1)UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 2, initWithTypeUIApplicationShortcutItem), 1}); |
304 | |
305 | NEW_RECEIVER(UIActionSheet)llvm::DenseMap<Selector, uint8_t> &UIActionSheetM = UIMethods.insert({&Ctx.Idents.get("UIActionSheet"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
306 | IdentifierInfo *initWithTitleUIActionSheet[] = { |
307 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("delegate"), |
308 | &Ctx.Idents.get("cancelButtonTitle"), |
309 | &Ctx.Idents.get("destructiveButtonTitle"), |
310 | &Ctx.Idents.get("otherButtonTitles")}; |
311 | ADD_METHOD(UIActionSheet, initWithTitleUIActionSheet, 5, 0)UIActionSheetM.insert({Ctx.Selectors.getSelector(5, initWithTitleUIActionSheet ), 0}); |
312 | ADD_UNARY_METHOD(UIActionSheet, addButtonWithTitle, 0)UIActionSheetM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addButtonWithTitle")), 0}); |
313 | ADD_UNARY_METHOD(UIActionSheet, setTitle, 0)UIActionSheetM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
314 | |
315 | NEW_RECEIVER(NSURLSessionTask)llvm::DenseMap<Selector, uint8_t> &NSURLSessionTaskM = UIMethods.insert({&Ctx.Idents.get("NSURLSessionTask"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
316 | ADD_UNARY_METHOD(NSURLSessionTask, setTaskDescription, 0)NSURLSessionTaskM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTaskDescription")), 0}); |
317 | |
318 | NEW_RECEIVER(UIAccessibilityCustomAction)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityCustomActionM = UIMethods.insert({&Ctx.Idents.get("UIAccessibilityCustomAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
319 | IdentifierInfo *initWithNameUIAccessibilityCustomAction[] = { |
320 | &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"), |
321 | &Ctx.Idents.get("selector")}; |
322 | ADD_METHOD(UIAccessibilityCustomAction,UIAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameUIAccessibilityCustomAction), 0}); |
323 | initWithNameUIAccessibilityCustomAction, 3, 0)UIAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameUIAccessibilityCustomAction), 0}); |
324 | ADD_UNARY_METHOD(UIAccessibilityCustomAction, setName, 0)UIAccessibilityCustomActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setName")), 0}); |
325 | |
326 | NEW_RECEIVER(UISearchBar)llvm::DenseMap<Selector, uint8_t> &UISearchBarM = UIMethods .insert({&Ctx.Idents.get("UISearchBar"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
327 | ADD_UNARY_METHOD(UISearchBar, setText, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setText")), 0}); |
328 | ADD_UNARY_METHOD(UISearchBar, setPrompt, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPrompt")), 0}); |
329 | ADD_UNARY_METHOD(UISearchBar, setPlaceholder, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholder")), 0}); |
330 | |
331 | NEW_RECEIVER(UIBarItem)llvm::DenseMap<Selector, uint8_t> &UIBarItemM = UIMethods .insert({&Ctx.Idents.get("UIBarItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
332 | ADD_UNARY_METHOD(UIBarItem, setTitle, 0)UIBarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
333 | |
334 | NEW_RECEIVER(UITextView)llvm::DenseMap<Selector, uint8_t> &UITextViewM = UIMethods .insert({&Ctx.Idents.get("UITextView"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
335 | ADD_UNARY_METHOD(UITextView, setText, 0)UITextViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setText")), 0}); |
336 | |
337 | NEW_RECEIVER(NSView)llvm::DenseMap<Selector, uint8_t> &NSViewM = UIMethods .insert({&Ctx.Idents.get("NSView"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
338 | ADD_UNARY_METHOD(NSView, setToolTip, 0)NSViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setToolTip")), 0}); |
339 | |
340 | NEW_RECEIVER(NSTextField)llvm::DenseMap<Selector, uint8_t> &NSTextFieldM = UIMethods .insert({&Ctx.Idents.get("NSTextField"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
341 | ADD_UNARY_METHOD(NSTextField, setPlaceholderString, 0)NSTextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholderString")), 0}); |
342 | |
343 | NEW_RECEIVER(NSAttributedString)llvm::DenseMap<Selector, uint8_t> &NSAttributedStringM = UIMethods.insert({&Ctx.Idents.get("NSAttributedString" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
344 | ADD_UNARY_METHOD(NSAttributedString, initWithString, 0)NSAttributedStringM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("initWithString")), 0}); |
345 | IdentifierInfo *initWithStringNSAttributedString[] = { |
346 | &Ctx.Idents.get("initWithString"), &Ctx.Idents.get("attributes")}; |
347 | ADD_METHOD(NSAttributedString, initWithStringNSAttributedString, 2, 0)NSAttributedStringM.insert({Ctx.Selectors.getSelector(2, initWithStringNSAttributedString ), 0}); |
348 | |
349 | NEW_RECEIVER(NSText)llvm::DenseMap<Selector, uint8_t> &NSTextM = UIMethods .insert({&Ctx.Idents.get("NSText"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
350 | ADD_UNARY_METHOD(NSText, setString, 0)NSTextM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setString")), 0}); |
351 | |
352 | NEW_RECEIVER(UIKeyCommand)llvm::DenseMap<Selector, uint8_t> &UIKeyCommandM = UIMethods .insert({&Ctx.Idents.get("UIKeyCommand"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
353 | IdentifierInfo *keyCommandWithInputUIKeyCommand[] = { |
354 | &Ctx.Idents.get("keyCommandWithInput"), &Ctx.Idents.get("modifierFlags"), |
355 | &Ctx.Idents.get("action"), &Ctx.Idents.get("discoverabilityTitle")}; |
356 | ADD_METHOD(UIKeyCommand, keyCommandWithInputUIKeyCommand, 4, 3)UIKeyCommandM.insert({Ctx.Selectors.getSelector(4, keyCommandWithInputUIKeyCommand ), 3}); |
357 | ADD_UNARY_METHOD(UIKeyCommand, setDiscoverabilityTitle, 0)UIKeyCommandM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setDiscoverabilityTitle")), 0}); |
358 | |
359 | NEW_RECEIVER(UILabel)llvm::DenseMap<Selector, uint8_t> &UILabelM = UIMethods .insert({&Ctx.Idents.get("UILabel"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
360 | ADD_UNARY_METHOD(UILabel, setText, 0)UILabelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setText")), 0}); |
361 | |
362 | NEW_RECEIVER(NSAlert)llvm::DenseMap<Selector, uint8_t> &NSAlertM = UIMethods .insert({&Ctx.Idents.get("NSAlert"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
363 | IdentifierInfo *alertWithMessageTextNSAlert[] = { |
364 | &Ctx.Idents.get("alertWithMessageText"), &Ctx.Idents.get("defaultButton"), |
365 | &Ctx.Idents.get("alternateButton"), &Ctx.Idents.get("otherButton"), |
366 | &Ctx.Idents.get("informativeTextWithFormat")}; |
367 | ADD_METHOD(NSAlert, alertWithMessageTextNSAlert, 5, 0)NSAlertM.insert({Ctx.Selectors.getSelector(5, alertWithMessageTextNSAlert ), 0}); |
368 | ADD_UNARY_METHOD(NSAlert, addButtonWithTitle, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("addButtonWithTitle")), 0}); |
369 | ADD_UNARY_METHOD(NSAlert, setMessageText, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setMessageText")), 0}); |
370 | ADD_UNARY_METHOD(NSAlert, setInformativeText, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setInformativeText")), 0}); |
371 | ADD_UNARY_METHOD(NSAlert, setHelpAnchor, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setHelpAnchor")), 0}); |
372 | |
373 | NEW_RECEIVER(UIMutableApplicationShortcutItem)llvm::DenseMap<Selector, uint8_t> &UIMutableApplicationShortcutItemM = UIMethods.insert({&Ctx.Idents.get("UIMutableApplicationShortcutItem" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
374 | ADD_UNARY_METHOD(UIMutableApplicationShortcutItem, setLocalizedTitle, 0)UIMutableApplicationShortcutItemM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setLocalizedTitle")), 0}); |
375 | ADD_UNARY_METHOD(UIMutableApplicationShortcutItem, setLocalizedSubtitle, 0)UIMutableApplicationShortcutItemM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setLocalizedSubtitle")), 0}); |
376 | |
377 | NEW_RECEIVER(UIButton)llvm::DenseMap<Selector, uint8_t> &UIButtonM = UIMethods .insert({&Ctx.Idents.get("UIButton"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
378 | IdentifierInfo *setTitleUIButton[] = {&Ctx.Idents.get("setTitle"), |
379 | &Ctx.Idents.get("forState")}; |
380 | ADD_METHOD(UIButton, setTitleUIButton, 2, 0)UIButtonM.insert({Ctx.Selectors.getSelector(2, setTitleUIButton ), 0}); |
381 | |
382 | NEW_RECEIVER(NSWindow)llvm::DenseMap<Selector, uint8_t> &NSWindowM = UIMethods .insert({&Ctx.Idents.get("NSWindow"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
383 | ADD_UNARY_METHOD(NSWindow, setTitle, 0)NSWindowM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
384 | IdentifierInfo *minFrameWidthWithTitleNSWindow[] = { |
385 | &Ctx.Idents.get("minFrameWidthWithTitle"), &Ctx.Idents.get("styleMask")}; |
386 | ADD_METHOD(NSWindow, minFrameWidthWithTitleNSWindow, 2, 0)NSWindowM.insert({Ctx.Selectors.getSelector(2, minFrameWidthWithTitleNSWindow ), 0}); |
387 | ADD_UNARY_METHOD(NSWindow, setMiniwindowTitle, 0)NSWindowM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setMiniwindowTitle")), 0}); |
388 | |
389 | NEW_RECEIVER(NSPathCell)llvm::DenseMap<Selector, uint8_t> &NSPathCellM = UIMethods .insert({&Ctx.Idents.get("NSPathCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
390 | ADD_UNARY_METHOD(NSPathCell, setPlaceholderString, 0)NSPathCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setPlaceholderString")), 0}); |
391 | |
392 | NEW_RECEIVER(UIDocumentMenuViewController)llvm::DenseMap<Selector, uint8_t> &UIDocumentMenuViewControllerM = UIMethods.insert({&Ctx.Idents.get("UIDocumentMenuViewController" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
393 | IdentifierInfo *addOptionWithTitleUIDocumentMenuViewController[] = { |
394 | &Ctx.Idents.get("addOptionWithTitle"), &Ctx.Idents.get("image"), |
395 | &Ctx.Idents.get("order"), &Ctx.Idents.get("handler")}; |
396 | ADD_METHOD(UIDocumentMenuViewController,UIDocumentMenuViewControllerM.insert({Ctx.Selectors.getSelector (4, addOptionWithTitleUIDocumentMenuViewController), 0}); |
397 | addOptionWithTitleUIDocumentMenuViewController, 4, 0)UIDocumentMenuViewControllerM.insert({Ctx.Selectors.getSelector (4, addOptionWithTitleUIDocumentMenuViewController), 0}); |
398 | |
399 | NEW_RECEIVER(UINavigationItem)llvm::DenseMap<Selector, uint8_t> &UINavigationItemM = UIMethods.insert({&Ctx.Idents.get("UINavigationItem"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
400 | ADD_UNARY_METHOD(UINavigationItem, initWithTitle, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("initWithTitle")), 0}); |
401 | ADD_UNARY_METHOD(UINavigationItem, setTitle, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
402 | ADD_UNARY_METHOD(UINavigationItem, setPrompt, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setPrompt")), 0}); |
403 | |
404 | NEW_RECEIVER(UIAlertView)llvm::DenseMap<Selector, uint8_t> &UIAlertViewM = UIMethods .insert({&Ctx.Idents.get("UIAlertView"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
405 | IdentifierInfo *initWithTitleUIAlertView[] = { |
406 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("message"), |
407 | &Ctx.Idents.get("delegate"), &Ctx.Idents.get("cancelButtonTitle"), |
408 | &Ctx.Idents.get("otherButtonTitles")}; |
409 | ADD_METHOD(UIAlertView, initWithTitleUIAlertView, 5, 0)UIAlertViewM.insert({Ctx.Selectors.getSelector(5, initWithTitleUIAlertView ), 0}); |
410 | ADD_UNARY_METHOD(UIAlertView, addButtonWithTitle, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addButtonWithTitle")), 0}); |
411 | ADD_UNARY_METHOD(UIAlertView, setTitle, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); |
412 | ADD_UNARY_METHOD(UIAlertView, setMessage, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setMessage")), 0}); |
413 | |
414 | NEW_RECEIVER(NSFormCell)llvm::DenseMap<Selector, uint8_t> &NSFormCellM = UIMethods .insert({&Ctx.Idents.get("NSFormCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
415 | ADD_UNARY_METHOD(NSFormCell, initTextCell, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("initTextCell")), 0}); |
416 | ADD_UNARY_METHOD(NSFormCell, setTitle, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); |
417 | ADD_UNARY_METHOD(NSFormCell, setPlaceholderString, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setPlaceholderString")), 0}); |
418 | |
419 | NEW_RECEIVER(NSUserNotification)llvm::DenseMap<Selector, uint8_t> &NSUserNotificationM = UIMethods.insert({&Ctx.Idents.get("NSUserNotification" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
420 | ADD_UNARY_METHOD(NSUserNotification, setTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
421 | ADD_UNARY_METHOD(NSUserNotification, setSubtitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setSubtitle")), 0}); |
422 | ADD_UNARY_METHOD(NSUserNotification, setInformativeText, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setInformativeText")), 0}); |
423 | ADD_UNARY_METHOD(NSUserNotification, setActionButtonTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setActionButtonTitle")), 0}); |
424 | ADD_UNARY_METHOD(NSUserNotification, setOtherButtonTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setOtherButtonTitle")), 0}); |
425 | ADD_UNARY_METHOD(NSUserNotification, setResponsePlaceholder, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setResponsePlaceholder")), 0}); |
426 | |
427 | NEW_RECEIVER(NSToolbarItem)llvm::DenseMap<Selector, uint8_t> &NSToolbarItemM = UIMethods.insert({&Ctx.Idents.get("NSToolbarItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
428 | ADD_UNARY_METHOD(NSToolbarItem, setLabel, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setLabel")), 0}); |
429 | ADD_UNARY_METHOD(NSToolbarItem, setPaletteLabel, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPaletteLabel")), 0}); |
430 | ADD_UNARY_METHOD(NSToolbarItem, setToolTip, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); |
431 | |
432 | NEW_RECEIVER(NSProgress)llvm::DenseMap<Selector, uint8_t> &NSProgressM = UIMethods .insert({&Ctx.Idents.get("NSProgress"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
433 | ADD_UNARY_METHOD(NSProgress, setLocalizedDescription, 0)NSProgressM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setLocalizedDescription")), 0}); |
434 | ADD_UNARY_METHOD(NSProgress, setLocalizedAdditionalDescription, 0)NSProgressM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setLocalizedAdditionalDescription")), 0}); |
435 | |
436 | NEW_RECEIVER(NSSegmentedCell)llvm::DenseMap<Selector, uint8_t> &NSSegmentedCellM = UIMethods.insert({&Ctx.Idents.get("NSSegmentedCell"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
437 | IdentifierInfo *setLabelNSSegmentedCell[] = {&Ctx.Idents.get("setLabel"), |
438 | &Ctx.Idents.get("forSegment")}; |
439 | ADD_METHOD(NSSegmentedCell, setLabelNSSegmentedCell, 2, 0)NSSegmentedCellM.insert({Ctx.Selectors.getSelector(2, setLabelNSSegmentedCell ), 0}); |
440 | IdentifierInfo *setToolTipNSSegmentedCell[] = {&Ctx.Idents.get("setToolTip"), |
441 | &Ctx.Idents.get("forSegment")}; |
442 | ADD_METHOD(NSSegmentedCell, setToolTipNSSegmentedCell, 2, 0)NSSegmentedCellM.insert({Ctx.Selectors.getSelector(2, setToolTipNSSegmentedCell ), 0}); |
443 | |
444 | NEW_RECEIVER(NSUndoManager)llvm::DenseMap<Selector, uint8_t> &NSUndoManagerM = UIMethods.insert({&Ctx.Idents.get("NSUndoManager"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
445 | ADD_UNARY_METHOD(NSUndoManager, setActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setActionName")), 0}); |
446 | ADD_UNARY_METHOD(NSUndoManager, undoMenuTitleForUndoActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("undoMenuTitleForUndoActionName")), 0}); |
447 | ADD_UNARY_METHOD(NSUndoManager, redoMenuTitleForUndoActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("redoMenuTitleForUndoActionName")), 0}); |
448 | |
449 | NEW_RECEIVER(NSMenuItem)llvm::DenseMap<Selector, uint8_t> &NSMenuItemM = UIMethods .insert({&Ctx.Idents.get("NSMenuItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
450 | IdentifierInfo *initWithTitleNSMenuItem[] = { |
451 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("action"), |
452 | &Ctx.Idents.get("keyEquivalent")}; |
453 | ADD_METHOD(NSMenuItem, initWithTitleNSMenuItem, 3, 0)NSMenuItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleNSMenuItem ), 0}); |
454 | ADD_UNARY_METHOD(NSMenuItem, setTitle, 0)NSMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); |
455 | ADD_UNARY_METHOD(NSMenuItem, setToolTip, 0)NSMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setToolTip")), 0}); |
456 | |
457 | NEW_RECEIVER(NSPopUpButtonCell)llvm::DenseMap<Selector, uint8_t> &NSPopUpButtonCellM = UIMethods.insert({&Ctx.Idents.get("NSPopUpButtonCell") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
458 | IdentifierInfo *initTextCellNSPopUpButtonCell[] = { |
459 | &Ctx.Idents.get("initTextCell"), &Ctx.Idents.get("pullsDown")}; |
460 | ADD_METHOD(NSPopUpButtonCell, initTextCellNSPopUpButtonCell, 2, 0)NSPopUpButtonCellM.insert({Ctx.Selectors.getSelector(2, initTextCellNSPopUpButtonCell ), 0}); |
461 | ADD_UNARY_METHOD(NSPopUpButtonCell, addItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("addItemWithTitle")), 0}); |
462 | IdentifierInfo *insertItemWithTitleNSPopUpButtonCell[] = { |
463 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("atIndex")}; |
464 | ADD_METHOD(NSPopUpButtonCell, insertItemWithTitleNSPopUpButtonCell, 2, 0)NSPopUpButtonCellM.insert({Ctx.Selectors.getSelector(2, insertItemWithTitleNSPopUpButtonCell ), 0}); |
465 | ADD_UNARY_METHOD(NSPopUpButtonCell, removeItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("removeItemWithTitle")), 0}); |
466 | ADD_UNARY_METHOD(NSPopUpButtonCell, selectItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("selectItemWithTitle")), 0}); |
467 | ADD_UNARY_METHOD(NSPopUpButtonCell, setTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
468 | |
469 | NEW_RECEIVER(NSViewController)llvm::DenseMap<Selector, uint8_t> &NSViewControllerM = UIMethods.insert({&Ctx.Idents.get("NSViewController"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
470 | ADD_UNARY_METHOD(NSViewController, setTitle, 0)NSViewControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
471 | |
472 | NEW_RECEIVER(NSMenu)llvm::DenseMap<Selector, uint8_t> &NSMenuM = UIMethods .insert({&Ctx.Idents.get("NSMenu"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
473 | ADD_UNARY_METHOD(NSMenu, initWithTitle, 0)NSMenuM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("initWithTitle")), 0}); |
474 | IdentifierInfo *insertItemWithTitleNSMenu[] = { |
475 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("action"), |
476 | &Ctx.Idents.get("keyEquivalent"), &Ctx.Idents.get("atIndex")}; |
477 | ADD_METHOD(NSMenu, insertItemWithTitleNSMenu, 4, 0)NSMenuM.insert({Ctx.Selectors.getSelector(4, insertItemWithTitleNSMenu ), 0}); |
478 | IdentifierInfo *addItemWithTitleNSMenu[] = { |
479 | &Ctx.Idents.get("addItemWithTitle"), &Ctx.Idents.get("action"), |
480 | &Ctx.Idents.get("keyEquivalent")}; |
481 | ADD_METHOD(NSMenu, addItemWithTitleNSMenu, 3, 0)NSMenuM.insert({Ctx.Selectors.getSelector(3, addItemWithTitleNSMenu ), 0}); |
482 | ADD_UNARY_METHOD(NSMenu, setTitle, 0)NSMenuM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); |
483 | |
484 | NEW_RECEIVER(UIMutableUserNotificationAction)llvm::DenseMap<Selector, uint8_t> &UIMutableUserNotificationActionM = UIMethods.insert({&Ctx.Idents.get("UIMutableUserNotificationAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
485 | ADD_UNARY_METHOD(UIMutableUserNotificationAction, setTitle, 0)UIMutableUserNotificationActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); |
486 | |
487 | NEW_RECEIVER(NSForm)llvm::DenseMap<Selector, uint8_t> &NSFormM = UIMethods .insert({&Ctx.Idents.get("NSForm"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; |
488 | ADD_UNARY_METHOD(NSForm, addEntry, 0)NSFormM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("addEntry")), 0}); |
489 | IdentifierInfo *insertEntryNSForm[] = {&Ctx.Idents.get("insertEntry"), |
490 | &Ctx.Idents.get("atIndex")}; |
491 | ADD_METHOD(NSForm, insertEntryNSForm, 2, 0)NSFormM.insert({Ctx.Selectors.getSelector(2, insertEntryNSForm ), 0}); |
492 | |
493 | NEW_RECEIVER(NSTextFieldCell)llvm::DenseMap<Selector, uint8_t> &NSTextFieldCellM = UIMethods.insert({&Ctx.Idents.get("NSTextFieldCell"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
494 | ADD_UNARY_METHOD(NSTextFieldCell, setPlaceholderString, 0)NSTextFieldCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setPlaceholderString")), 0}); |
495 | |
496 | NEW_RECEIVER(NSUserNotificationAction)llvm::DenseMap<Selector, uint8_t> &NSUserNotificationActionM = UIMethods.insert({&Ctx.Idents.get("NSUserNotificationAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
497 | IdentifierInfo *actionWithIdentifierNSUserNotificationAction[] = { |
498 | &Ctx.Idents.get("actionWithIdentifier"), &Ctx.Idents.get("title")}; |
499 | ADD_METHOD(NSUserNotificationAction,NSUserNotificationActionM.insert({Ctx.Selectors.getSelector(2 , actionWithIdentifierNSUserNotificationAction), 1}); |
500 | actionWithIdentifierNSUserNotificationAction, 2, 1)NSUserNotificationActionM.insert({Ctx.Selectors.getSelector(2 , actionWithIdentifierNSUserNotificationAction), 1}); |
501 | |
502 | NEW_RECEIVER(NSURLSession)llvm::DenseMap<Selector, uint8_t> &NSURLSessionM = UIMethods .insert({&Ctx.Idents.get("NSURLSession"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
503 | ADD_UNARY_METHOD(NSURLSession, setSessionDescription, 0)NSURLSessionM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setSessionDescription")), 0}); |
504 | |
505 | NEW_RECEIVER(UITextField)llvm::DenseMap<Selector, uint8_t> &UITextFieldM = UIMethods .insert({&Ctx.Idents.get("UITextField"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; |
506 | ADD_UNARY_METHOD(UITextField, setText, 0)UITextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setText")), 0}); |
507 | ADD_UNARY_METHOD(UITextField, setPlaceholder, 0)UITextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholder")), 0}); |
508 | |
509 | NEW_RECEIVER(UIBarButtonItem)llvm::DenseMap<Selector, uint8_t> &UIBarButtonItemM = UIMethods.insert({&Ctx.Idents.get("UIBarButtonItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; |
510 | IdentifierInfo *initWithTitleUIBarButtonItem[] = { |
511 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("style"), |
512 | &Ctx.Idents.get("target"), &Ctx.Idents.get("action")}; |
513 | ADD_METHOD(UIBarButtonItem, initWithTitleUIBarButtonItem, 4, 0)UIBarButtonItemM.insert({Ctx.Selectors.getSelector(4, initWithTitleUIBarButtonItem ), 0}); |
514 | |
515 | NEW_RECEIVER(UIViewController)llvm::DenseMap<Selector, uint8_t> &UIViewControllerM = UIMethods.insert({&Ctx.Idents.get("UIViewController"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
516 | ADD_UNARY_METHOD(UIViewController, setTitle, 0)UIViewControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); |
517 | |
518 | NEW_RECEIVER(UISegmentedControl)llvm::DenseMap<Selector, uint8_t> &UISegmentedControlM = UIMethods.insert({&Ctx.Idents.get("UISegmentedControl" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; |
519 | IdentifierInfo *insertSegmentWithTitleUISegmentedControl[] = { |
520 | &Ctx.Idents.get("insertSegmentWithTitle"), &Ctx.Idents.get("atIndex"), |
521 | &Ctx.Idents.get("animated")}; |
522 | ADD_METHOD(UISegmentedControl, insertSegmentWithTitleUISegmentedControl, 3, 0)UISegmentedControlM.insert({Ctx.Selectors.getSelector(3, insertSegmentWithTitleUISegmentedControl ), 0}); |
523 | IdentifierInfo *setTitleUISegmentedControl[] = { |
524 | &Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")}; |
525 | ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)UISegmentedControlM.insert({Ctx.Selectors.getSelector(2, setTitleUISegmentedControl ), 0}); |
526 | } |
527 | |
528 | #define LSF_INSERT(function_name)LSF.insert(&Ctx.Idents.get(function_name)); LSF.insert(&Ctx.Idents.get(function_name)); |
529 | #define LSM_INSERT_NULLARY(receiver, method_name)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getNullarySelector ( &Ctx.Idents.get(method_name))}); \ |
530 | LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getNullarySelector( \ |
531 | &Ctx.Idents.get(method_name))}); |
532 | #define LSM_INSERT_UNARY(receiver, method_name)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getUnarySelector (&Ctx.Idents.get(method_name))}); \ |
533 | LSM.insert({&Ctx.Idents.get(receiver), \ |
534 | Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(method_name))}); |
535 | #define LSM_INSERT_SELECTOR(receiver, method_list, arguments)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getSelector (arguments, method_list)}); \ |
536 | LSM.insert({&Ctx.Idents.get(receiver), \ |
537 | Ctx.Selectors.getSelector(arguments, method_list)}); |
538 | |
539 | /// Initializes a list of methods and C functions that return a localized string |
540 | void NonLocalizedStringChecker::initLocStringsMethods(ASTContext &Ctx) const { |
541 | if (!LSM.empty()) |
542 | return; |
543 | |
544 | IdentifierInfo *LocalizedStringMacro[] = { |
545 | &Ctx.Idents.get("localizedStringForKey"), &Ctx.Idents.get("value"), |
546 | &Ctx.Idents.get("table")}; |
547 | LSM_INSERT_SELECTOR("NSBundle", LocalizedStringMacro, 3)LSM.insert({&Ctx.Idents.get("NSBundle"), Ctx.Selectors.getSelector (3, LocalizedStringMacro)}); |
548 | LSM_INSERT_UNARY("NSDateFormatter", "stringFromDate")LSM.insert({&Ctx.Idents.get("NSDateFormatter"), Ctx.Selectors .getUnarySelector(&Ctx.Idents.get("stringFromDate"))}); |
549 | IdentifierInfo *LocalizedStringFromDate[] = { |
550 | &Ctx.Idents.get("localizedStringFromDate"), &Ctx.Idents.get("dateStyle"), |
551 | &Ctx.Idents.get("timeStyle")}; |
552 | LSM_INSERT_SELECTOR("NSDateFormatter", LocalizedStringFromDate, 3)LSM.insert({&Ctx.Idents.get("NSDateFormatter"), Ctx.Selectors .getSelector(3, LocalizedStringFromDate)}); |
553 | LSM_INSERT_UNARY("NSNumberFormatter", "stringFromNumber")LSM.insert({&Ctx.Idents.get("NSNumberFormatter"), Ctx.Selectors .getUnarySelector(&Ctx.Idents.get("stringFromNumber"))}); |
554 | LSM_INSERT_NULLARY("UITextField", "text")LSM.insert({&Ctx.Idents.get("UITextField"), Ctx.Selectors .getNullarySelector( &Ctx.Idents.get("text"))}); |
555 | LSM_INSERT_NULLARY("UITextView", "text")LSM.insert({&Ctx.Idents.get("UITextView"), Ctx.Selectors. getNullarySelector( &Ctx.Idents.get("text"))}); |
556 | LSM_INSERT_NULLARY("UILabel", "text")LSM.insert({&Ctx.Idents.get("UILabel"), Ctx.Selectors.getNullarySelector ( &Ctx.Idents.get("text"))}); |
557 | |
558 | LSF_INSERT("CFDateFormatterCreateStringWithDate")LSF.insert(&Ctx.Idents.get("CFDateFormatterCreateStringWithDate" ));; |
559 | LSF_INSERT("CFDateFormatterCreateStringWithAbsoluteTime")LSF.insert(&Ctx.Idents.get("CFDateFormatterCreateStringWithAbsoluteTime" ));; |
560 | LSF_INSERT("CFNumberFormatterCreateStringWithNumber")LSF.insert(&Ctx.Idents.get("CFNumberFormatterCreateStringWithNumber" ));; |
561 | } |
562 | |
563 | /// Checks to see if the method / function declaration includes |
564 | /// __attribute__((annotate("returns_localized_nsstring"))) |
565 | bool NonLocalizedStringChecker::isAnnotatedAsLocalized(const Decl *D) const { |
566 | if (!D) |
567 | return false; |
568 | return std::any_of( |
569 | D->specific_attr_begin<AnnotateAttr>(), |
570 | D->specific_attr_end<AnnotateAttr>(), [](const AnnotateAttr *Ann) { |
571 | return Ann->getAnnotation() == "returns_localized_nsstring"; |
572 | }); |
573 | } |
574 | |
575 | /// Returns true if the given SVal is marked as Localized in the program state |
576 | bool NonLocalizedStringChecker::hasLocalizedState(SVal S, |
577 | CheckerContext &C) const { |
578 | const MemRegion *mt = S.getAsRegion(); |
579 | if (mt) { |
580 | const LocalizedState *LS = C.getState()->get<LocalizedMemMap>(mt); |
581 | if (LS && LS->isLocalized()) |
582 | return true; |
583 | } |
584 | return false; |
585 | } |
586 | |
587 | /// Returns true if the given SVal is marked as NonLocalized in the program |
588 | /// state |
589 | bool NonLocalizedStringChecker::hasNonLocalizedState(SVal S, |
590 | CheckerContext &C) const { |
591 | const MemRegion *mt = S.getAsRegion(); |
592 | if (mt) { |
593 | const LocalizedState *LS = C.getState()->get<LocalizedMemMap>(mt); |
594 | if (LS && LS->isNonLocalized()) |
595 | return true; |
596 | } |
597 | return false; |
598 | } |
599 | |
600 | /// Marks the given SVal as Localized in the program state |
601 | void NonLocalizedStringChecker::setLocalizedState(const SVal S, |
602 | CheckerContext &C) const { |
603 | const MemRegion *mt = S.getAsRegion(); |
604 | if (mt) { |
605 | ProgramStateRef State = |
606 | C.getState()->set<LocalizedMemMap>(mt, LocalizedState::getLocalized()); |
607 | C.addTransition(State); |
608 | } |
609 | } |
610 | |
611 | /// Marks the given SVal as NonLocalized in the program state |
612 | void NonLocalizedStringChecker::setNonLocalizedState(const SVal S, |
613 | CheckerContext &C) const { |
614 | const MemRegion *mt = S.getAsRegion(); |
615 | if (mt) { |
616 | ProgramStateRef State = C.getState()->set<LocalizedMemMap>( |
617 | mt, LocalizedState::getNonLocalized()); |
618 | C.addTransition(State); |
619 | } |
620 | } |
621 | |
622 | /// Reports a localization error for the passed in method call and SVal |
623 | void NonLocalizedStringChecker::reportLocalizationError( |
624 | SVal S, const ObjCMethodCall &M, CheckerContext &C, |
625 | int argumentNumber) const { |
626 | |
627 | ExplodedNode *ErrNode = C.getPredecessor(); |
Value stored to 'ErrNode' during its initialization is never read | |
628 | static CheckerProgramPointTag Tag("NonLocalizedStringChecker", |
629 | "UnlocalizedString"); |
630 | ErrNode = C.addTransition(C.getState(), C.getPredecessor(), &Tag); |
631 | |
632 | if (!ErrNode) |
633 | return; |
634 | |
635 | // Generate the bug report. |
636 | std::unique_ptr<BugReport> R(new BugReport( |
637 | *BT, "User-facing text should use localized string macro", ErrNode)); |
638 | if (argumentNumber) { |
639 | R->addRange(M.getArgExpr(argumentNumber - 1)->getSourceRange()); |
640 | } else { |
641 | R->addRange(M.getSourceRange()); |
642 | } |
643 | R->markInteresting(S); |
644 | C.emitReport(std::move(R)); |
645 | } |
646 | |
647 | /// Returns the argument number requiring localized string if it exists |
648 | /// otherwise, returns -1 |
649 | int NonLocalizedStringChecker::getLocalizedArgumentForSelector( |
650 | const IdentifierInfo *Receiver, Selector S) const { |
651 | auto method = UIMethods.find(Receiver); |
652 | |
653 | if (method == UIMethods.end()) |
654 | return -1; |
655 | |
656 | auto argumentIterator = method->getSecond().find(S); |
657 | |
658 | if (argumentIterator == method->getSecond().end()) |
659 | return -1; |
660 | |
661 | int argumentNumber = argumentIterator->getSecond(); |
662 | return argumentNumber; |
663 | } |
664 | |
665 | /// Check if the string being passed in has NonLocalized state |
666 | void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg, |
667 | CheckerContext &C) const { |
668 | initUIMethods(C.getASTContext()); |
669 | |
670 | const ObjCInterfaceDecl *OD = msg.getReceiverInterface(); |
671 | if (!OD) |
672 | return; |
673 | const IdentifierInfo *odInfo = OD->getIdentifier(); |
674 | |
675 | Selector S = msg.getSelector(); |
676 | |
677 | std::string SelectorString = S.getAsString(); |
678 | StringRef SelectorName = SelectorString; |
679 | assert(!SelectorName.empty())((!SelectorName.empty()) ? static_cast<void> (0) : __assert_fail ("!SelectorName.empty()", "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn257205/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp" , 679, __PRETTY_FUNCTION__)); |
680 | |
681 | if (odInfo->isStr("NSString")) { |
682 | // Handle the case where the receiver is an NSString |
683 | // These special NSString methods draw to the screen |
684 | |
685 | if (!(SelectorName.startswith("drawAtPoint") || |
686 | SelectorName.startswith("drawInRect") || |
687 | SelectorName.startswith("drawWithRect"))) |
688 | return; |
689 | |
690 | SVal svTitle = msg.getReceiverSVal(); |
691 | |
692 | bool isNonLocalized = hasNonLocalizedState(svTitle, C); |
693 | |
694 | if (isNonLocalized) { |
695 | reportLocalizationError(svTitle, msg, C); |
696 | } |
697 | } |
698 | |
699 | int argumentNumber = getLocalizedArgumentForSelector(odInfo, S); |
700 | // Go up each hierarchy of superclasses and their protocols |
701 | while (argumentNumber < 0 && OD->getSuperClass() != nullptr) { |
702 | for (const auto *P : OD->all_referenced_protocols()) { |
703 | argumentNumber = getLocalizedArgumentForSelector(P->getIdentifier(), S); |
704 | if (argumentNumber >= 0) |
705 | break; |
706 | } |
707 | if (argumentNumber < 0) { |
708 | OD = OD->getSuperClass(); |
709 | argumentNumber = getLocalizedArgumentForSelector(OD->getIdentifier(), S); |
710 | } |
711 | } |
712 | |
713 | if (argumentNumber < 0) // There was no match in UIMethods |
714 | return; |
715 | |
716 | SVal svTitle = msg.getArgSVal(argumentNumber); |
717 | |
718 | if (const ObjCStringRegion *SR = |
719 | dyn_cast_or_null<ObjCStringRegion>(svTitle.getAsRegion())) { |
720 | StringRef stringValue = |
721 | SR->getObjCStringLiteral()->getString()->getString(); |
722 | if ((stringValue.trim().size() == 0 && stringValue.size() > 0) || |
723 | stringValue.empty()) |
724 | return; |
725 | if (!IsAggressive && llvm::sys::unicode::columnWidthUTF8(stringValue) < 2) |
726 | return; |
727 | } |
728 | |
729 | bool isNonLocalized = hasNonLocalizedState(svTitle, C); |
730 | |
731 | if (isNonLocalized) { |
732 | reportLocalizationError(svTitle, msg, C, argumentNumber + 1); |
733 | } |
734 | } |
735 | |
736 | static inline bool isNSStringType(QualType T, ASTContext &Ctx) { |
737 | |
738 | const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); |
739 | if (!PT) |
740 | return false; |
741 | |
742 | ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); |
743 | if (!Cls) |
744 | return false; |
745 | |
746 | IdentifierInfo *ClsName = Cls->getIdentifier(); |
747 | |
748 | // FIXME: Should we walk the chain of classes? |
749 | return ClsName == &Ctx.Idents.get("NSString") || |
750 | ClsName == &Ctx.Idents.get("NSMutableString"); |
751 | } |
752 | |
753 | /// Marks a string being returned by any call as localized |
754 | /// if it is in LocStringFunctions (LSF) or the function is annotated. |
755 | /// Otherwise, we mark it as NonLocalized (Aggressive) or |
756 | /// NonLocalized only if it is not backed by a SymRegion (Non-Aggressive), |
757 | /// basically leaving only string literals as NonLocalized. |
758 | void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call, |
759 | CheckerContext &C) const { |
760 | initLocStringsMethods(C.getASTContext()); |
761 | |
762 | if (!Call.getOriginExpr()) |
763 | return; |
764 | |
765 | // Anything that takes in a localized NSString as an argument |
766 | // and returns an NSString will be assumed to be returning a |
767 | // localized NSString. (Counter: Incorrectly combining two LocalizedStrings) |
768 | const QualType RT = Call.getResultType(); |
769 | if (isNSStringType(RT, C.getASTContext())) { |
770 | for (unsigned i = 0; i < Call.getNumArgs(); ++i) { |
771 | SVal argValue = Call.getArgSVal(i); |
772 | if (hasLocalizedState(argValue, C)) { |
773 | SVal sv = Call.getReturnValue(); |
774 | setLocalizedState(sv, C); |
775 | return; |
776 | } |
777 | } |
778 | } |
779 | |
780 | const Decl *D = Call.getDecl(); |
781 | if (!D) |
782 | return; |
783 | |
784 | const IdentifierInfo *Identifier = Call.getCalleeIdentifier(); |
785 | |
786 | SVal sv = Call.getReturnValue(); |
787 | if (isAnnotatedAsLocalized(D) || LSF.count(Identifier) != 0) { |
788 | setLocalizedState(sv, C); |
789 | } else if (isNSStringType(RT, C.getASTContext()) && |
790 | !hasLocalizedState(sv, C)) { |
791 | if (IsAggressive) { |
792 | setNonLocalizedState(sv, C); |
793 | } else { |
794 | const SymbolicRegion *SymReg = |
795 | dyn_cast_or_null<SymbolicRegion>(sv.getAsRegion()); |
796 | if (!SymReg) |
797 | setNonLocalizedState(sv, C); |
798 | } |
799 | } |
800 | } |
801 | |
802 | /// Marks a string being returned by an ObjC method as localized |
803 | /// if it is in LocStringMethods or the method is annotated |
804 | void NonLocalizedStringChecker::checkPostObjCMessage(const ObjCMethodCall &msg, |
805 | CheckerContext &C) const { |
806 | initLocStringsMethods(C.getASTContext()); |
807 | |
808 | if (!msg.isInstanceMessage()) |
809 | return; |
810 | |
811 | const ObjCInterfaceDecl *OD = msg.getReceiverInterface(); |
812 | if (!OD) |
813 | return; |
814 | const IdentifierInfo *odInfo = OD->getIdentifier(); |
815 | |
816 | Selector S = msg.getSelector(); |
817 | std::string SelectorName = S.getAsString(); |
818 | |
819 | std::pair<const IdentifierInfo *, Selector> MethodDescription = {odInfo, S}; |
820 | |
821 | if (LSM.count(MethodDescription) || isAnnotatedAsLocalized(msg.getDecl())) { |
822 | SVal sv = msg.getReturnValue(); |
823 | setLocalizedState(sv, C); |
824 | } |
825 | } |
826 | |
827 | /// Marks all empty string literals as localized |
828 | void NonLocalizedStringChecker::checkPostStmt(const ObjCStringLiteral *SL, |
829 | CheckerContext &C) const { |
830 | SVal sv = C.getSVal(SL); |
831 | setNonLocalizedState(sv, C); |
832 | } |
833 | |
834 | namespace { |
835 | class EmptyLocalizationContextChecker |
836 | : public Checker<check::ASTDecl<ObjCImplementationDecl>> { |
837 | |
838 | // A helper class, which walks the AST |
839 | class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { |
840 | const ObjCMethodDecl *MD; |
841 | BugReporter &BR; |
842 | AnalysisManager &Mgr; |
843 | const CheckerBase *Checker; |
844 | LocationOrAnalysisDeclContext DCtx; |
845 | |
846 | public: |
847 | MethodCrawler(const ObjCMethodDecl *InMD, BugReporter &InBR, |
848 | const CheckerBase *Checker, AnalysisManager &InMgr, |
849 | AnalysisDeclContext *InDCtx) |
850 | : MD(InMD), BR(InBR), Mgr(InMgr), Checker(Checker), DCtx(InDCtx) {} |
851 | |
852 | void VisitStmt(const Stmt *S) { VisitChildren(S); } |
853 | |
854 | void VisitObjCMessageExpr(const ObjCMessageExpr *ME); |
855 | |
856 | void reportEmptyContextError(const ObjCMessageExpr *M) const; |
857 | |
858 | void VisitChildren(const Stmt *S) { |
859 | for (const Stmt *Child : S->children()) { |
860 | if (Child) |
861 | this->Visit(Child); |
862 | } |
863 | } |
864 | }; |
865 | |
866 | public: |
867 | void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr, |
868 | BugReporter &BR) const; |
869 | }; |
870 | } // end anonymous namespace |
871 | |
872 | void EmptyLocalizationContextChecker::checkASTDecl( |
873 | const ObjCImplementationDecl *D, AnalysisManager &Mgr, |
874 | BugReporter &BR) const { |
875 | |
876 | for (const ObjCMethodDecl *M : D->methods()) { |
877 | AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M); |
878 | |
879 | const Stmt *Body = M->getBody(); |
880 | assert(Body)((Body) ? static_cast<void> (0) : __assert_fail ("Body" , "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn257205/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp" , 880, __PRETTY_FUNCTION__)); |
881 | |
882 | MethodCrawler MC(M->getCanonicalDecl(), BR, this, Mgr, DCtx); |
883 | MC.VisitStmt(Body); |
884 | } |
885 | } |
886 | |
887 | /// This check attempts to match these macros, assuming they are defined as |
888 | /// follows: |
889 | /// |
890 | /// #define NSLocalizedString(key, comment) \ |
891 | /// [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil] |
892 | /// #define NSLocalizedStringFromTable(key, tbl, comment) \ |
893 | /// [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)] |
894 | /// #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \ |
895 | /// [bundle localizedStringForKey:(key) value:@"" table:(tbl)] |
896 | /// #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) |
897 | /// |
898 | /// We cannot use the path sensitive check because the macro argument we are |
899 | /// checking for (comment) is not used and thus not present in the AST, |
900 | /// so we use Lexer on the original macro call and retrieve the value of |
901 | /// the comment. If it's empty or nil, we raise a warning. |
902 | void EmptyLocalizationContextChecker::MethodCrawler::VisitObjCMessageExpr( |
903 | const ObjCMessageExpr *ME) { |
904 | |
905 | const ObjCInterfaceDecl *OD = ME->getReceiverInterface(); |
906 | if (!OD) |
907 | return; |
908 | |
909 | const IdentifierInfo *odInfo = OD->getIdentifier(); |
910 | |
911 | if (!(odInfo->isStr("NSBundle") && |
912 | ME->getSelector().getAsString() == |
913 | "localizedStringForKey:value:table:")) { |
914 | return; |
915 | } |
916 | |
917 | SourceRange R = ME->getSourceRange(); |
918 | if (!R.getBegin().isMacroID()) |
919 | return; |
920 | |
921 | // getImmediateMacroCallerLoc gets the location of the immediate macro |
922 | // caller, one level up the stack toward the initial macro typed into the |
923 | // source, so SL should point to the NSLocalizedString macro. |
924 | SourceLocation SL = |
925 | Mgr.getSourceManager().getImmediateMacroCallerLoc(R.getBegin()); |
926 | std::pair<FileID, unsigned> SLInfo = |
927 | Mgr.getSourceManager().getDecomposedLoc(SL); |
928 | |
929 | SrcMgr::SLocEntry SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first); |
930 | |
931 | // If NSLocalizedString macro is wrapped in another macro, we need to |
932 | // unwrap the expansion until we get to the NSLocalizedStringMacro. |
933 | while (SE.isExpansion()) { |
934 | SL = SE.getExpansion().getSpellingLoc(); |
935 | SLInfo = Mgr.getSourceManager().getDecomposedLoc(SL); |
936 | SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first); |
937 | } |
938 | |
939 | llvm::MemoryBuffer *BF = SE.getFile().getContentCache()->getRawBuffer(); |
940 | Lexer TheLexer(SL, LangOptions(), BF->getBufferStart(), |
941 | BF->getBufferStart() + SLInfo.second, BF->getBufferEnd()); |
942 | |
943 | Token I; |
944 | Token Result; // This will hold the token just before the last ')' |
945 | int p_count = 0; // This is for parenthesis matching |
946 | while (!TheLexer.LexFromRawLexer(I)) { |
947 | if (I.getKind() == tok::l_paren) |
948 | ++p_count; |
949 | if (I.getKind() == tok::r_paren) { |
950 | if (p_count == 1) |
951 | break; |
952 | --p_count; |
953 | } |
954 | Result = I; |
955 | } |
956 | |
957 | if (isAnyIdentifier(Result.getKind())) { |
958 | if (Result.getRawIdentifier().equals("nil")) { |
959 | reportEmptyContextError(ME); |
960 | return; |
961 | } |
962 | } |
963 | |
964 | if (!isStringLiteral(Result.getKind())) |
965 | return; |
966 | |
967 | StringRef Comment = |
968 | StringRef(Result.getLiteralData(), Result.getLength()).trim("\""); |
969 | |
970 | if ((Comment.trim().size() == 0 && Comment.size() > 0) || // Is Whitespace |
971 | Comment.empty()) { |
972 | reportEmptyContextError(ME); |
973 | } |
974 | } |
975 | |
976 | void EmptyLocalizationContextChecker::MethodCrawler::reportEmptyContextError( |
977 | const ObjCMessageExpr *ME) const { |
978 | // Generate the bug report. |
979 | BR.EmitBasicReport(MD, Checker, "Context Missing", |
980 | "Localizability Issue (Apple)", |
981 | "Localized string macro should include a non-empty " |
982 | "comment for translators", |
983 | PathDiagnosticLocation(ME, BR.getSourceManager(), DCtx)); |
984 | } |
985 | |
986 | namespace { |
987 | class PluralMisuseChecker : public Checker<check::ASTCodeBody> { |
988 | |
989 | // A helper class, which walks the AST |
990 | class MethodCrawler : public RecursiveASTVisitor<MethodCrawler> { |
991 | BugReporter &BR; |
992 | const CheckerBase *Checker; |
993 | AnalysisDeclContext *AC; |
994 | |
995 | // This functions like a stack. We push on any IfStmt or |
996 | // ConditionalOperator that matches the condition |
997 | // and pop it off when we leave that statement |
998 | llvm::SmallVector<const clang::Stmt *, 8> MatchingStatements; |
999 | // This is true when we are the direct-child of a |
1000 | // matching statement |
1001 | bool InMatchingStatement = false; |
1002 | |
1003 | public: |
1004 | explicit MethodCrawler(BugReporter &InBR, const CheckerBase *Checker, |
1005 | AnalysisDeclContext *InAC) |
1006 | : BR(InBR), Checker(Checker), AC(InAC) {} |
1007 | |
1008 | bool VisitIfStmt(const IfStmt *I); |
1009 | bool EndVisitIfStmt(IfStmt *I); |
1010 | bool TraverseIfStmt(IfStmt *x); |
1011 | bool VisitConditionalOperator(const ConditionalOperator *C); |
1012 | bool TraverseConditionalOperator(ConditionalOperator *C); |
1013 | bool VisitCallExpr(const CallExpr *CE); |
1014 | bool VisitObjCMessageExpr(const ObjCMessageExpr *ME); |
1015 | |
1016 | private: |
1017 | void reportPluralMisuseError(const Stmt *S) const; |
1018 | bool isCheckingPlurality(const Expr *E) const; |
1019 | }; |
1020 | |
1021 | public: |
1022 | void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, |
1023 | BugReporter &BR) const { |
1024 | MethodCrawler Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); |
1025 | Visitor.TraverseDecl(const_cast<Decl *>(D)); |
1026 | } |
1027 | }; |
1028 | } // end anonymous namespace |
1029 | |
1030 | // Checks the condition of the IfStmt and returns true if one |
1031 | // of the following heuristics are met: |
1032 | // 1) The conidtion is a variable with "singular" or "plural" in the name |
1033 | // 2) The condition is a binary operator with 1 or 2 on the right-hand side |
1034 | bool PluralMisuseChecker::MethodCrawler::isCheckingPlurality( |
1035 | const Expr *Condition) const { |
1036 | const BinaryOperator *BO = nullptr; |
1037 | // Accounts for when a VarDecl represents a BinaryOperator |
1038 | if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Condition)) { |
1039 | if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { |
1040 | const Expr *InitExpr = VD->getInit(); |
1041 | if (InitExpr) { |
1042 | if (const BinaryOperator *B = |
1043 | dyn_cast<BinaryOperator>(InitExpr->IgnoreParenImpCasts())) { |
1044 | BO = B; |
1045 | } |
1046 | } |
1047 | if (VD->getName().lower().find("plural") != StringRef::npos || |
1048 | VD->getName().lower().find("singular") != StringRef::npos) { |
1049 | return true; |
1050 | } |
1051 | } |
1052 | } else if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) { |
1053 | BO = B; |
1054 | } |
1055 | |
1056 | if (BO == nullptr) |
1057 | return false; |
1058 | |
1059 | if (IntegerLiteral *IL = dyn_cast_or_null<IntegerLiteral>( |
1060 | BO->getRHS()->IgnoreParenImpCasts())) { |
1061 | llvm::APInt Value = IL->getValue(); |
1062 | if (Value == 1 || Value == 2) { |
1063 | return true; |
1064 | } |
1065 | } |
1066 | return false; |
1067 | } |
1068 | |
1069 | // A CallExpr with "LOC" in its identifier that takes in a string literal |
1070 | // has been shown to almost always be a function that returns a localized |
1071 | // string. Raise a diagnostic when this is in a statement that matches |
1072 | // the condition. |
1073 | bool PluralMisuseChecker::MethodCrawler::VisitCallExpr(const CallExpr *CE) { |
1074 | if (InMatchingStatement) { |
1075 | if (const FunctionDecl *FD = CE->getDirectCallee()) { |
1076 | std::string NormalizedName = |
1077 | StringRef(FD->getNameInfo().getAsString()).lower(); |
1078 | if (NormalizedName.find("loc") != std::string::npos) { |
1079 | for (const Expr *Arg : CE->arguments()) { |
1080 | if (isa<ObjCStringLiteral>(Arg)) |
1081 | reportPluralMisuseError(CE); |
1082 | } |
1083 | } |
1084 | } |
1085 | } |
1086 | return true; |
1087 | } |
1088 | |
1089 | // The other case is for NSLocalizedString which also returns |
1090 | // a localized string. It's a macro for the ObjCMessageExpr |
1091 | // [NSBundle localizedStringForKey:value:table:] Raise a |
1092 | // diagnostic when this is in a statement that matches |
1093 | // the condition. |
1094 | bool PluralMisuseChecker::MethodCrawler::VisitObjCMessageExpr( |
1095 | const ObjCMessageExpr *ME) { |
1096 | const ObjCInterfaceDecl *OD = ME->getReceiverInterface(); |
1097 | if (!OD) |
1098 | return true; |
1099 | |
1100 | const IdentifierInfo *odInfo = OD->getIdentifier(); |
1101 | |
1102 | if (odInfo->isStr("NSBundle") && |
1103 | ME->getSelector().getAsString() == "localizedStringForKey:value:table:") { |
1104 | if (InMatchingStatement) { |
1105 | reportPluralMisuseError(ME); |
1106 | } |
1107 | } |
1108 | return true; |
1109 | } |
1110 | |
1111 | /// Override TraverseIfStmt so we know when we are done traversing an IfStmt |
1112 | bool PluralMisuseChecker::MethodCrawler::TraverseIfStmt(IfStmt *I) { |
1113 | RecursiveASTVisitor<MethodCrawler>::TraverseIfStmt(I); |
1114 | return EndVisitIfStmt(I); |
1115 | } |
1116 | |
1117 | // EndVisit callbacks are not provided by the RecursiveASTVisitor |
1118 | // so we override TraverseIfStmt and make a call to EndVisitIfStmt |
1119 | // after traversing the IfStmt |
1120 | bool PluralMisuseChecker::MethodCrawler::EndVisitIfStmt(IfStmt *I) { |
1121 | MatchingStatements.pop_back(); |
1122 | if (!MatchingStatements.empty()) { |
1123 | if (MatchingStatements.back() != nullptr) { |
1124 | InMatchingStatement = true; |
1125 | return true; |
1126 | } |
1127 | } |
1128 | InMatchingStatement = false; |
1129 | return true; |
1130 | } |
1131 | |
1132 | bool PluralMisuseChecker::MethodCrawler::VisitIfStmt(const IfStmt *I) { |
1133 | const Expr *Condition = I->getCond()->IgnoreParenImpCasts(); |
1134 | if (isCheckingPlurality(Condition)) { |
1135 | MatchingStatements.push_back(I); |
1136 | InMatchingStatement = true; |
1137 | } else { |
1138 | MatchingStatements.push_back(nullptr); |
1139 | InMatchingStatement = false; |
1140 | } |
1141 | |
1142 | return true; |
1143 | } |
1144 | |
1145 | // Preliminary support for conditional operators. |
1146 | bool PluralMisuseChecker::MethodCrawler::TraverseConditionalOperator( |
1147 | ConditionalOperator *C) { |
1148 | RecursiveASTVisitor<MethodCrawler>::TraverseConditionalOperator(C); |
1149 | MatchingStatements.pop_back(); |
1150 | if (!MatchingStatements.empty()) { |
1151 | if (MatchingStatements.back() != nullptr) |
1152 | InMatchingStatement = true; |
1153 | else |
1154 | InMatchingStatement = false; |
1155 | } else { |
1156 | InMatchingStatement = false; |
1157 | } |
1158 | return true; |
1159 | } |
1160 | |
1161 | bool PluralMisuseChecker::MethodCrawler::VisitConditionalOperator( |
1162 | const ConditionalOperator *C) { |
1163 | const Expr *Condition = C->getCond()->IgnoreParenImpCasts(); |
1164 | if (isCheckingPlurality(Condition)) { |
1165 | MatchingStatements.push_back(C); |
1166 | InMatchingStatement = true; |
1167 | } else { |
1168 | MatchingStatements.push_back(nullptr); |
1169 | InMatchingStatement = false; |
1170 | } |
1171 | return true; |
1172 | } |
1173 | |
1174 | void PluralMisuseChecker::MethodCrawler::reportPluralMisuseError( |
1175 | const Stmt *S) const { |
1176 | // Generate the bug report. |
1177 | BR.EmitBasicReport(AC->getDecl(), Checker, "Plural Misuse", |
1178 | "Localizability Issue (Apple)", |
1179 | "Plural cases are not supported accross all languages. " |
1180 | "Use a .stringsdict file instead", |
1181 | PathDiagnosticLocation(S, BR.getSourceManager(), AC)); |
1182 | } |
1183 | |
1184 | //===----------------------------------------------------------------------===// |
1185 | // Checker registration. |
1186 | //===----------------------------------------------------------------------===// |
1187 | |
1188 | void ento::registerNonLocalizedStringChecker(CheckerManager &mgr) { |
1189 | NonLocalizedStringChecker *checker = |
1190 | mgr.registerChecker<NonLocalizedStringChecker>(); |
1191 | checker->IsAggressive = |
1192 | mgr.getAnalyzerOptions().getBooleanOption("AggressiveReport", false); |
1193 | } |
1194 | |
1195 | void ento::registerEmptyLocalizationContextChecker(CheckerManager &mgr) { |
1196 | mgr.registerChecker<EmptyLocalizationContextChecker>(); |
1197 | } |
1198 | |
1199 | void ento::registerPluralMisuseChecker(CheckerManager &mgr) { |
1200 | mgr.registerChecker<PluralMisuseChecker>(); |
1201 | } |