File: | build/source/clang/include/clang/Lex/Token.h |
Warning: | line 93, column 36 Undefined or garbage value returned to caller |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //=- LocalizationChecker.cpp -------------------------------------*- C++ -*-==// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file defines a set of checks for localizability including: | |||
10 | // 1) A checker that warns about uses of non-localized NSStrings passed to | |||
11 | // UI methods expecting localized strings | |||
12 | // 2) A syntactic checker that warns against the bad practice of | |||
13 | // not including a comment in NSLocalizedString macros. | |||
14 | // | |||
15 | //===----------------------------------------------------------------------===// | |||
16 | ||||
17 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" | |||
18 | #include "clang/AST/Attr.h" | |||
19 | #include "clang/AST/Decl.h" | |||
20 | #include "clang/AST/DeclObjC.h" | |||
21 | #include "clang/AST/RecursiveASTVisitor.h" | |||
22 | #include "clang/AST/StmtVisitor.h" | |||
23 | #include "clang/Lex/Lexer.h" | |||
24 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" | |||
25 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | |||
26 | #include "clang/StaticAnalyzer/Core/Checker.h" | |||
27 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" | |||
28 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | |||
29 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | |||
30 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" | |||
31 | #include "llvm/Support/Unicode.h" | |||
32 | #include <optional> | |||
33 | ||||
34 | using namespace clang; | |||
35 | using namespace ento; | |||
36 | ||||
37 | namespace { | |||
38 | struct LocalizedState { | |||
39 | private: | |||
40 | enum Kind { NonLocalized, Localized } K; | |||
41 | LocalizedState(Kind InK) : K(InK) {} | |||
42 | ||||
43 | public: | |||
44 | bool isLocalized() const { return K == Localized; } | |||
45 | bool isNonLocalized() const { return K == NonLocalized; } | |||
46 | ||||
47 | static LocalizedState getLocalized() { return LocalizedState(Localized); } | |||
48 | static LocalizedState getNonLocalized() { | |||
49 | return LocalizedState(NonLocalized); | |||
50 | } | |||
51 | ||||
52 | // Overload the == operator | |||
53 | bool operator==(const LocalizedState &X) const { return K == X.K; } | |||
54 | ||||
55 | // LLVMs equivalent of a hash function | |||
56 | void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } | |||
57 | }; | |||
58 | ||||
59 | class NonLocalizedStringChecker | |||
60 | : public Checker<check::PreCall, check::PostCall, check::PreObjCMessage, | |||
61 | check::PostObjCMessage, | |||
62 | check::PostStmt<ObjCStringLiteral>> { | |||
63 | ||||
64 | mutable std::unique_ptr<BugType> BT; | |||
65 | ||||
66 | // Methods that require a localized string | |||
67 | mutable llvm::DenseMap<const IdentifierInfo *, | |||
68 | llvm::DenseMap<Selector, uint8_t>> UIMethods; | |||
69 | // Methods that return a localized string | |||
70 | mutable llvm::SmallSet<std::pair<const IdentifierInfo *, Selector>, 12> LSM; | |||
71 | // C Functions that return a localized string | |||
72 | mutable llvm::SmallSet<const IdentifierInfo *, 5> LSF; | |||
73 | ||||
74 | void initUIMethods(ASTContext &Ctx) const; | |||
75 | void initLocStringsMethods(ASTContext &Ctx) const; | |||
76 | ||||
77 | bool hasNonLocalizedState(SVal S, CheckerContext &C) const; | |||
78 | bool hasLocalizedState(SVal S, CheckerContext &C) const; | |||
79 | void setNonLocalizedState(SVal S, CheckerContext &C) const; | |||
80 | void setLocalizedState(SVal S, CheckerContext &C) const; | |||
81 | ||||
82 | bool isAnnotatedAsReturningLocalized(const Decl *D) const; | |||
83 | bool isAnnotatedAsTakingLocalized(const Decl *D) const; | |||
84 | void reportLocalizationError(SVal S, const CallEvent &M, CheckerContext &C, | |||
85 | 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 | bool IsAggressive = false; | |||
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 checkPreCall(const CallEvent &Call, CheckerContext &C) const; | |||
102 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const; | |||
103 | }; | |||
104 | ||||
105 | } // end anonymous namespace | |||
106 | ||||
107 | REGISTER_MAP_WITH_PROGRAMSTATE(LocalizedMemMap, const MemRegion *,namespace { class LocalizedMemMap {}; using LocalizedMemMapTy = llvm::ImmutableMap<const MemRegion *, LocalizedState> ; } namespace clang { namespace ento { template <> struct ProgramStateTrait<LocalizedMemMap> : public ProgramStatePartialTrait <LocalizedMemMapTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } | |||
108 | LocalizedState)namespace { class LocalizedMemMap {}; using LocalizedMemMapTy = llvm::ImmutableMap<const MemRegion *, LocalizedState> ; } namespace clang { namespace ento { template <> struct ProgramStateTrait<LocalizedMemMap> : public ProgramStatePartialTrait <LocalizedMemMapTy> { static void *GDMIndex() { static int Index; return &Index; } }; } } | |||
109 | ||||
110 | NonLocalizedStringChecker::NonLocalizedStringChecker() { | |||
111 | BT.reset(new BugType(this, "Unlocalizable string", | |||
112 | "Localizability Issue (Apple)")); | |||
113 | } | |||
114 | ||||
115 | namespace { | |||
116 | class NonLocalizedStringBRVisitor final : public BugReporterVisitor { | |||
117 | ||||
118 | const MemRegion *NonLocalizedString; | |||
119 | bool Satisfied; | |||
120 | ||||
121 | public: | |||
122 | NonLocalizedStringBRVisitor(const MemRegion *NonLocalizedString) | |||
123 | : NonLocalizedString(NonLocalizedString), Satisfied(false) { | |||
124 | assert(NonLocalizedString)(static_cast <bool> (NonLocalizedString) ? void (0) : __assert_fail ("NonLocalizedString", "clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp" , 124, __extension__ __PRETTY_FUNCTION__)); | |||
125 | } | |||
126 | ||||
127 | PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, | |||
128 | BugReporterContext &BRC, | |||
129 | PathSensitiveBugReport &BR) override; | |||
130 | ||||
131 | void Profile(llvm::FoldingSetNodeID &ID) const override { | |||
132 | ID.Add(NonLocalizedString); | |||
133 | } | |||
134 | }; | |||
135 | } // End anonymous namespace. | |||
136 | ||||
137 | #define NEW_RECEIVER(receiver)llvm::DenseMap<Selector, uint8_t> &receiverM = UIMethods .insert({&Ctx.Idents.get("receiver"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; \ | |||
138 | llvm::DenseMap<Selector, uint8_t> &receiver##M = \ | |||
139 | UIMethods.insert({&Ctx.Idents.get(#receiver), \ | |||
140 | llvm::DenseMap<Selector, uint8_t>()}) \ | |||
141 | .first->second; | |||
142 | #define ADD_NULLARY_METHOD(receiver, method, argument)receiverM.insert( {Ctx.Selectors.getNullarySelector(&Ctx. Idents.get("method")), argument}); \ | |||
143 | receiver##M.insert( \ | |||
144 | {Ctx.Selectors.getNullarySelector(&Ctx.Idents.get(#method)), argument}); | |||
145 | #define ADD_UNARY_METHOD(receiver, method, argument)receiverM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("method")), argument}); \ | |||
146 | receiver##M.insert( \ | |||
147 | {Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(#method)), argument}); | |||
148 | #define ADD_METHOD(receiver, method_list, count, argument)receiverM.insert({Ctx.Selectors.getSelector(count, method_list ), argument}); \ | |||
149 | receiver##M.insert({Ctx.Selectors.getSelector(count, method_list), argument}); | |||
150 | ||||
151 | /// Initializes a list of methods that require a localized string | |||
152 | /// Format: {"ClassName", {{"selectorName:", LocStringArg#}, ...}, ...} | |||
153 | void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const { | |||
154 | if (!UIMethods.empty()) | |||
155 | return; | |||
156 | ||||
157 | // UI Methods | |||
158 | NEW_RECEIVER(UISearchDisplayController)llvm::DenseMap<Selector, uint8_t> &UISearchDisplayControllerM = UIMethods.insert({&Ctx.Idents.get("UISearchDisplayController" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
159 | ADD_UNARY_METHOD(UISearchDisplayController, setSearchResultsTitle, 0)UISearchDisplayControllerM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setSearchResultsTitle")), 0}); | |||
160 | ||||
161 | NEW_RECEIVER(UITabBarItem)llvm::DenseMap<Selector, uint8_t> &UITabBarItemM = UIMethods .insert({&Ctx.Idents.get("UITabBarItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
162 | IdentifierInfo *initWithTitleUITabBarItemTag[] = { | |||
163 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("image"), | |||
164 | &Ctx.Idents.get("tag")}; | |||
165 | ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemTag, 3, 0)UITabBarItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleUITabBarItemTag ), 0}); | |||
166 | IdentifierInfo *initWithTitleUITabBarItemImage[] = { | |||
167 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("image"), | |||
168 | &Ctx.Idents.get("selectedImage")}; | |||
169 | ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemImage, 3, 0)UITabBarItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleUITabBarItemImage ), 0}); | |||
170 | ||||
171 | NEW_RECEIVER(NSDockTile)llvm::DenseMap<Selector, uint8_t> &NSDockTileM = UIMethods .insert({&Ctx.Idents.get("NSDockTile"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
172 | ADD_UNARY_METHOD(NSDockTile, setBadgeLabel, 0)NSDockTileM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setBadgeLabel")), 0}); | |||
173 | ||||
174 | NEW_RECEIVER(NSStatusItem)llvm::DenseMap<Selector, uint8_t> &NSStatusItemM = UIMethods .insert({&Ctx.Idents.get("NSStatusItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
175 | ADD_UNARY_METHOD(NSStatusItem, setTitle, 0)NSStatusItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
176 | ADD_UNARY_METHOD(NSStatusItem, setToolTip, 0)NSStatusItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); | |||
177 | ||||
178 | NEW_RECEIVER(UITableViewRowAction)llvm::DenseMap<Selector, uint8_t> &UITableViewRowActionM = UIMethods.insert({&Ctx.Idents.get("UITableViewRowAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
179 | IdentifierInfo *rowActionWithStyleUITableViewRowAction[] = { | |||
180 | &Ctx.Idents.get("rowActionWithStyle"), &Ctx.Idents.get("title"), | |||
181 | &Ctx.Idents.get("handler")}; | |||
182 | ADD_METHOD(UITableViewRowAction, rowActionWithStyleUITableViewRowAction, 3, 1)UITableViewRowActionM.insert({Ctx.Selectors.getSelector(3, rowActionWithStyleUITableViewRowAction ), 1}); | |||
183 | ADD_UNARY_METHOD(UITableViewRowAction, setTitle, 0)UITableViewRowActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); | |||
184 | ||||
185 | NEW_RECEIVER(NSBox)llvm::DenseMap<Selector, uint8_t> &NSBoxM = UIMethods .insert({&Ctx.Idents.get("NSBox"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
186 | ADD_UNARY_METHOD(NSBox, setTitle, 0)NSBoxM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
187 | ||||
188 | NEW_RECEIVER(NSButton)llvm::DenseMap<Selector, uint8_t> &NSButtonM = UIMethods .insert({&Ctx.Idents.get("NSButton"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
189 | ADD_UNARY_METHOD(NSButton, setTitle, 0)NSButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
190 | ADD_UNARY_METHOD(NSButton, setAlternateTitle, 0)NSButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setAlternateTitle")), 0}); | |||
191 | IdentifierInfo *radioButtonWithTitleNSButton[] = { | |||
192 | &Ctx.Idents.get("radioButtonWithTitle"), &Ctx.Idents.get("target"), | |||
193 | &Ctx.Idents.get("action")}; | |||
194 | ADD_METHOD(NSButton, radioButtonWithTitleNSButton, 3, 0)NSButtonM.insert({Ctx.Selectors.getSelector(3, radioButtonWithTitleNSButton ), 0}); | |||
195 | IdentifierInfo *buttonWithTitleNSButtonImage[] = { | |||
196 | &Ctx.Idents.get("buttonWithTitle"), &Ctx.Idents.get("image"), | |||
197 | &Ctx.Idents.get("target"), &Ctx.Idents.get("action")}; | |||
198 | ADD_METHOD(NSButton, buttonWithTitleNSButtonImage, 4, 0)NSButtonM.insert({Ctx.Selectors.getSelector(4, buttonWithTitleNSButtonImage ), 0}); | |||
199 | IdentifierInfo *checkboxWithTitleNSButton[] = { | |||
200 | &Ctx.Idents.get("checkboxWithTitle"), &Ctx.Idents.get("target"), | |||
201 | &Ctx.Idents.get("action")}; | |||
202 | ADD_METHOD(NSButton, checkboxWithTitleNSButton, 3, 0)NSButtonM.insert({Ctx.Selectors.getSelector(3, checkboxWithTitleNSButton ), 0}); | |||
203 | IdentifierInfo *buttonWithTitleNSButtonTarget[] = { | |||
204 | &Ctx.Idents.get("buttonWithTitle"), &Ctx.Idents.get("target"), | |||
205 | &Ctx.Idents.get("action")}; | |||
206 | ADD_METHOD(NSButton, buttonWithTitleNSButtonTarget, 3, 0)NSButtonM.insert({Ctx.Selectors.getSelector(3, buttonWithTitleNSButtonTarget ), 0}); | |||
207 | ||||
208 | NEW_RECEIVER(NSSavePanel)llvm::DenseMap<Selector, uint8_t> &NSSavePanelM = UIMethods .insert({&Ctx.Idents.get("NSSavePanel"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
209 | ADD_UNARY_METHOD(NSSavePanel, setPrompt, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPrompt")), 0}); | |||
210 | ADD_UNARY_METHOD(NSSavePanel, setTitle, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
211 | ADD_UNARY_METHOD(NSSavePanel, setNameFieldLabel, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setNameFieldLabel")), 0}); | |||
212 | ADD_UNARY_METHOD(NSSavePanel, setNameFieldStringValue, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setNameFieldStringValue")), 0}); | |||
213 | ADD_UNARY_METHOD(NSSavePanel, setMessage, 0)NSSavePanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setMessage")), 0}); | |||
214 | ||||
215 | NEW_RECEIVER(UIPrintInfo)llvm::DenseMap<Selector, uint8_t> &UIPrintInfoM = UIMethods .insert({&Ctx.Idents.get("UIPrintInfo"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
216 | ADD_UNARY_METHOD(UIPrintInfo, setJobName, 0)UIPrintInfoM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setJobName")), 0}); | |||
217 | ||||
218 | NEW_RECEIVER(NSTabViewItem)llvm::DenseMap<Selector, uint8_t> &NSTabViewItemM = UIMethods.insert({&Ctx.Idents.get("NSTabViewItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
219 | ADD_UNARY_METHOD(NSTabViewItem, setLabel, 0)NSTabViewItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setLabel")), 0}); | |||
220 | ADD_UNARY_METHOD(NSTabViewItem, setToolTip, 0)NSTabViewItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); | |||
221 | ||||
222 | NEW_RECEIVER(NSBrowser)llvm::DenseMap<Selector, uint8_t> &NSBrowserM = UIMethods .insert({&Ctx.Idents.get("NSBrowser"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
223 | IdentifierInfo *setTitleNSBrowser[] = {&Ctx.Idents.get("setTitle"), | |||
224 | &Ctx.Idents.get("ofColumn")}; | |||
225 | ADD_METHOD(NSBrowser, setTitleNSBrowser, 2, 0)NSBrowserM.insert({Ctx.Selectors.getSelector(2, setTitleNSBrowser ), 0}); | |||
226 | ||||
227 | NEW_RECEIVER(UIAccessibilityElement)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityElementM = UIMethods.insert({&Ctx.Idents.get("UIAccessibilityElement" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
228 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityLabel, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityLabel")), 0}); | |||
229 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityHint, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityHint")), 0}); | |||
230 | ADD_UNARY_METHOD(UIAccessibilityElement, setAccessibilityValue, 0)UIAccessibilityElementM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setAccessibilityValue")), 0}); | |||
231 | ||||
232 | NEW_RECEIVER(UIAlertAction)llvm::DenseMap<Selector, uint8_t> &UIAlertActionM = UIMethods.insert({&Ctx.Idents.get("UIAlertAction"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
233 | IdentifierInfo *actionWithTitleUIAlertAction[] = { | |||
234 | &Ctx.Idents.get("actionWithTitle"), &Ctx.Idents.get("style"), | |||
235 | &Ctx.Idents.get("handler")}; | |||
236 | ADD_METHOD(UIAlertAction, actionWithTitleUIAlertAction, 3, 0)UIAlertActionM.insert({Ctx.Selectors.getSelector(3, actionWithTitleUIAlertAction ), 0}); | |||
237 | ||||
238 | NEW_RECEIVER(NSPopUpButton)llvm::DenseMap<Selector, uint8_t> &NSPopUpButtonM = UIMethods.insert({&Ctx.Idents.get("NSPopUpButton"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
239 | ADD_UNARY_METHOD(NSPopUpButton, addItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addItemWithTitle")), 0}); | |||
240 | IdentifierInfo *insertItemWithTitleNSPopUpButton[] = { | |||
241 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("atIndex")}; | |||
242 | ADD_METHOD(NSPopUpButton, insertItemWithTitleNSPopUpButton, 2, 0)NSPopUpButtonM.insert({Ctx.Selectors.getSelector(2, insertItemWithTitleNSPopUpButton ), 0}); | |||
243 | ADD_UNARY_METHOD(NSPopUpButton, removeItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("removeItemWithTitle")), 0}); | |||
244 | ADD_UNARY_METHOD(NSPopUpButton, selectItemWithTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("selectItemWithTitle")), 0}); | |||
245 | ADD_UNARY_METHOD(NSPopUpButton, setTitle, 0)NSPopUpButtonM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
246 | ||||
247 | NEW_RECEIVER(NSTableViewRowAction)llvm::DenseMap<Selector, uint8_t> &NSTableViewRowActionM = UIMethods.insert({&Ctx.Idents.get("NSTableViewRowAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
248 | IdentifierInfo *rowActionWithStyleNSTableViewRowAction[] = { | |||
249 | &Ctx.Idents.get("rowActionWithStyle"), &Ctx.Idents.get("title"), | |||
250 | &Ctx.Idents.get("handler")}; | |||
251 | ADD_METHOD(NSTableViewRowAction, rowActionWithStyleNSTableViewRowAction, 3, 1)NSTableViewRowActionM.insert({Ctx.Selectors.getSelector(3, rowActionWithStyleNSTableViewRowAction ), 1}); | |||
252 | ADD_UNARY_METHOD(NSTableViewRowAction, setTitle, 0)NSTableViewRowActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); | |||
253 | ||||
254 | NEW_RECEIVER(NSImage)llvm::DenseMap<Selector, uint8_t> &NSImageM = UIMethods .insert({&Ctx.Idents.get("NSImage"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
255 | ADD_UNARY_METHOD(NSImage, setAccessibilityDescription, 0)NSImageM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setAccessibilityDescription")), 0}); | |||
256 | ||||
257 | NEW_RECEIVER(NSUserActivity)llvm::DenseMap<Selector, uint8_t> &NSUserActivityM = UIMethods.insert({&Ctx.Idents.get("NSUserActivity"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
258 | ADD_UNARY_METHOD(NSUserActivity, setTitle, 0)NSUserActivityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
259 | ||||
260 | NEW_RECEIVER(NSPathControlItem)llvm::DenseMap<Selector, uint8_t> &NSPathControlItemM = UIMethods.insert({&Ctx.Idents.get("NSPathControlItem") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
261 | ADD_UNARY_METHOD(NSPathControlItem, setTitle, 0)NSPathControlItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
262 | ||||
263 | NEW_RECEIVER(NSCell)llvm::DenseMap<Selector, uint8_t> &NSCellM = UIMethods .insert({&Ctx.Idents.get("NSCell"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
264 | ADD_UNARY_METHOD(NSCell, initTextCell, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("initTextCell")), 0}); | |||
265 | ADD_UNARY_METHOD(NSCell, setTitle, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
266 | ADD_UNARY_METHOD(NSCell, setStringValue, 0)NSCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setStringValue")), 0}); | |||
267 | ||||
268 | NEW_RECEIVER(NSPathControl)llvm::DenseMap<Selector, uint8_t> &NSPathControlM = UIMethods.insert({&Ctx.Idents.get("NSPathControl"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
269 | ADD_UNARY_METHOD(NSPathControl, setPlaceholderString, 0)NSPathControlM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholderString")), 0}); | |||
270 | ||||
271 | NEW_RECEIVER(UIAccessibility)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityM = UIMethods.insert({&Ctx.Idents.get("UIAccessibility"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
272 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityLabel, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityLabel")), 0}); | |||
273 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityHint, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityHint")), 0}); | |||
274 | ADD_UNARY_METHOD(UIAccessibility, setAccessibilityValue, 0)UIAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityValue")), 0}); | |||
275 | ||||
276 | NEW_RECEIVER(NSTableColumn)llvm::DenseMap<Selector, uint8_t> &NSTableColumnM = UIMethods.insert({&Ctx.Idents.get("NSTableColumn"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
277 | ADD_UNARY_METHOD(NSTableColumn, setTitle, 0)NSTableColumnM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
278 | ADD_UNARY_METHOD(NSTableColumn, setHeaderToolTip, 0)NSTableColumnM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setHeaderToolTip")), 0}); | |||
279 | ||||
280 | NEW_RECEIVER(NSSegmentedControl)llvm::DenseMap<Selector, uint8_t> &NSSegmentedControlM = UIMethods.insert({&Ctx.Idents.get("NSSegmentedControl" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
281 | IdentifierInfo *setLabelNSSegmentedControl[] = { | |||
282 | &Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")}; | |||
283 | ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)NSSegmentedControlM.insert({Ctx.Selectors.getSelector(2, setLabelNSSegmentedControl ), 0}); | |||
284 | IdentifierInfo *setToolTipNSSegmentedControl[] = { | |||
285 | &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")}; | |||
286 | ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0)NSSegmentedControlM.insert({Ctx.Selectors.getSelector(2, setToolTipNSSegmentedControl ), 0}); | |||
287 | ||||
288 | NEW_RECEIVER(NSButtonCell)llvm::DenseMap<Selector, uint8_t> &NSButtonCellM = UIMethods .insert({&Ctx.Idents.get("NSButtonCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
289 | ADD_UNARY_METHOD(NSButtonCell, setTitle, 0)NSButtonCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
290 | ADD_UNARY_METHOD(NSButtonCell, setAlternateTitle, 0)NSButtonCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setAlternateTitle")), 0}); | |||
291 | ||||
292 | NEW_RECEIVER(NSDatePickerCell)llvm::DenseMap<Selector, uint8_t> &NSDatePickerCellM = UIMethods.insert({&Ctx.Idents.get("NSDatePickerCell"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
293 | ADD_UNARY_METHOD(NSDatePickerCell, initTextCell, 0)NSDatePickerCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("initTextCell")), 0}); | |||
294 | ||||
295 | NEW_RECEIVER(NSSliderCell)llvm::DenseMap<Selector, uint8_t> &NSSliderCellM = UIMethods .insert({&Ctx.Idents.get("NSSliderCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
296 | ADD_UNARY_METHOD(NSSliderCell, setTitle, 0)NSSliderCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
297 | ||||
298 | NEW_RECEIVER(NSControl)llvm::DenseMap<Selector, uint8_t> &NSControlM = UIMethods .insert({&Ctx.Idents.get("NSControl"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
299 | ADD_UNARY_METHOD(NSControl, setStringValue, 0)NSControlM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setStringValue")), 0}); | |||
300 | ||||
301 | NEW_RECEIVER(NSAccessibility)llvm::DenseMap<Selector, uint8_t> &NSAccessibilityM = UIMethods.insert({&Ctx.Idents.get("NSAccessibility"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
302 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityValueDescription, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityValueDescription")), 0}); | |||
303 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityLabel, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityLabel")), 0}); | |||
304 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityTitle, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityTitle")), 0}); | |||
305 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityPlaceholderValue, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityPlaceholderValue")), 0}); | |||
306 | ADD_UNARY_METHOD(NSAccessibility, setAccessibilityHelp, 0)NSAccessibilityM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setAccessibilityHelp")), 0}); | |||
307 | ||||
308 | NEW_RECEIVER(NSMatrix)llvm::DenseMap<Selector, uint8_t> &NSMatrixM = UIMethods .insert({&Ctx.Idents.get("NSMatrix"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
309 | IdentifierInfo *setToolTipNSMatrix[] = {&Ctx.Idents.get("setToolTip"), | |||
310 | &Ctx.Idents.get("forCell")}; | |||
311 | ADD_METHOD(NSMatrix, setToolTipNSMatrix, 2, 0)NSMatrixM.insert({Ctx.Selectors.getSelector(2, setToolTipNSMatrix ), 0}); | |||
312 | ||||
313 | NEW_RECEIVER(NSPrintPanel)llvm::DenseMap<Selector, uint8_t> &NSPrintPanelM = UIMethods .insert({&Ctx.Idents.get("NSPrintPanel"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
314 | ADD_UNARY_METHOD(NSPrintPanel, setDefaultButtonTitle, 0)NSPrintPanelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setDefaultButtonTitle")), 0}); | |||
315 | ||||
316 | NEW_RECEIVER(UILocalNotification)llvm::DenseMap<Selector, uint8_t> &UILocalNotificationM = UIMethods.insert({&Ctx.Idents.get("UILocalNotification" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
317 | ADD_UNARY_METHOD(UILocalNotification, setAlertBody, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertBody")), 0}); | |||
318 | ADD_UNARY_METHOD(UILocalNotification, setAlertAction, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertAction")), 0}); | |||
319 | ADD_UNARY_METHOD(UILocalNotification, setAlertTitle, 0)UILocalNotificationM.insert( {Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("setAlertTitle")), 0}); | |||
320 | ||||
321 | NEW_RECEIVER(NSSlider)llvm::DenseMap<Selector, uint8_t> &NSSliderM = UIMethods .insert({&Ctx.Idents.get("NSSlider"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
322 | ADD_UNARY_METHOD(NSSlider, setTitle, 0)NSSliderM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
323 | ||||
324 | NEW_RECEIVER(UIMenuItem)llvm::DenseMap<Selector, uint8_t> &UIMenuItemM = UIMethods .insert({&Ctx.Idents.get("UIMenuItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
325 | IdentifierInfo *initWithTitleUIMenuItem[] = {&Ctx.Idents.get("initWithTitle"), | |||
326 | &Ctx.Idents.get("action")}; | |||
327 | ADD_METHOD(UIMenuItem, initWithTitleUIMenuItem, 2, 0)UIMenuItemM.insert({Ctx.Selectors.getSelector(2, initWithTitleUIMenuItem ), 0}); | |||
328 | ADD_UNARY_METHOD(UIMenuItem, setTitle, 0)UIMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); | |||
329 | ||||
330 | NEW_RECEIVER(UIAlertController)llvm::DenseMap<Selector, uint8_t> &UIAlertControllerM = UIMethods.insert({&Ctx.Idents.get("UIAlertController") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
331 | IdentifierInfo *alertControllerWithTitleUIAlertController[] = { | |||
332 | &Ctx.Idents.get("alertControllerWithTitle"), &Ctx.Idents.get("message"), | |||
333 | &Ctx.Idents.get("preferredStyle")}; | |||
334 | ADD_METHOD(UIAlertController, alertControllerWithTitleUIAlertController, 3, 1)UIAlertControllerM.insert({Ctx.Selectors.getSelector(3, alertControllerWithTitleUIAlertController ), 1}); | |||
335 | ADD_UNARY_METHOD(UIAlertController, setTitle, 0)UIAlertControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
336 | ADD_UNARY_METHOD(UIAlertController, setMessage, 0)UIAlertControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setMessage")), 0}); | |||
337 | ||||
338 | NEW_RECEIVER(UIApplicationShortcutItem)llvm::DenseMap<Selector, uint8_t> &UIApplicationShortcutItemM = UIMethods.insert({&Ctx.Idents.get("UIApplicationShortcutItem" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
339 | IdentifierInfo *initWithTypeUIApplicationShortcutItemIcon[] = { | |||
340 | &Ctx.Idents.get("initWithType"), &Ctx.Idents.get("localizedTitle"), | |||
341 | &Ctx.Idents.get("localizedSubtitle"), &Ctx.Idents.get("icon"), | |||
342 | &Ctx.Idents.get("userInfo")}; | |||
343 | ADD_METHOD(UIApplicationShortcutItem,UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 5, initWithTypeUIApplicationShortcutItemIcon), 1}); | |||
344 | initWithTypeUIApplicationShortcutItemIcon, 5, 1)UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 5, initWithTypeUIApplicationShortcutItemIcon), 1}); | |||
345 | IdentifierInfo *initWithTypeUIApplicationShortcutItem[] = { | |||
346 | &Ctx.Idents.get("initWithType"), &Ctx.Idents.get("localizedTitle")}; | |||
347 | ADD_METHOD(UIApplicationShortcutItem, initWithTypeUIApplicationShortcutItem,UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 2, initWithTypeUIApplicationShortcutItem), 1}); | |||
348 | 2, 1)UIApplicationShortcutItemM.insert({Ctx.Selectors.getSelector( 2, initWithTypeUIApplicationShortcutItem), 1}); | |||
349 | ||||
350 | NEW_RECEIVER(UIActionSheet)llvm::DenseMap<Selector, uint8_t> &UIActionSheetM = UIMethods.insert({&Ctx.Idents.get("UIActionSheet"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
351 | IdentifierInfo *initWithTitleUIActionSheet[] = { | |||
352 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("delegate"), | |||
353 | &Ctx.Idents.get("cancelButtonTitle"), | |||
354 | &Ctx.Idents.get("destructiveButtonTitle"), | |||
355 | &Ctx.Idents.get("otherButtonTitles")}; | |||
356 | ADD_METHOD(UIActionSheet, initWithTitleUIActionSheet, 5, 0)UIActionSheetM.insert({Ctx.Selectors.getSelector(5, initWithTitleUIActionSheet ), 0}); | |||
357 | ADD_UNARY_METHOD(UIActionSheet, addButtonWithTitle, 0)UIActionSheetM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addButtonWithTitle")), 0}); | |||
358 | ADD_UNARY_METHOD(UIActionSheet, setTitle, 0)UIActionSheetM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
359 | ||||
360 | NEW_RECEIVER(UIAccessibilityCustomAction)llvm::DenseMap<Selector, uint8_t> &UIAccessibilityCustomActionM = UIMethods.insert({&Ctx.Idents.get("UIAccessibilityCustomAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
361 | IdentifierInfo *initWithNameUIAccessibilityCustomAction[] = { | |||
362 | &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"), | |||
363 | &Ctx.Idents.get("selector")}; | |||
364 | ADD_METHOD(UIAccessibilityCustomAction,UIAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameUIAccessibilityCustomAction), 0}); | |||
365 | initWithNameUIAccessibilityCustomAction, 3, 0)UIAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameUIAccessibilityCustomAction), 0}); | |||
366 | ADD_UNARY_METHOD(UIAccessibilityCustomAction, setName, 0)UIAccessibilityCustomActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setName")), 0}); | |||
367 | ||||
368 | NEW_RECEIVER(UISearchBar)llvm::DenseMap<Selector, uint8_t> &UISearchBarM = UIMethods .insert({&Ctx.Idents.get("UISearchBar"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
369 | ADD_UNARY_METHOD(UISearchBar, setText, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setText")), 0}); | |||
370 | ADD_UNARY_METHOD(UISearchBar, setPrompt, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPrompt")), 0}); | |||
371 | ADD_UNARY_METHOD(UISearchBar, setPlaceholder, 0)UISearchBarM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholder")), 0}); | |||
372 | ||||
373 | NEW_RECEIVER(UIBarItem)llvm::DenseMap<Selector, uint8_t> &UIBarItemM = UIMethods .insert({&Ctx.Idents.get("UIBarItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
374 | ADD_UNARY_METHOD(UIBarItem, setTitle, 0)UIBarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
375 | ||||
376 | NEW_RECEIVER(UITextView)llvm::DenseMap<Selector, uint8_t> &UITextViewM = UIMethods .insert({&Ctx.Idents.get("UITextView"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
377 | ADD_UNARY_METHOD(UITextView, setText, 0)UITextViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setText")), 0}); | |||
378 | ||||
379 | NEW_RECEIVER(NSView)llvm::DenseMap<Selector, uint8_t> &NSViewM = UIMethods .insert({&Ctx.Idents.get("NSView"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
380 | ADD_UNARY_METHOD(NSView, setToolTip, 0)NSViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setToolTip")), 0}); | |||
381 | ||||
382 | NEW_RECEIVER(NSTextField)llvm::DenseMap<Selector, uint8_t> &NSTextFieldM = UIMethods .insert({&Ctx.Idents.get("NSTextField"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
383 | ADD_UNARY_METHOD(NSTextField, setPlaceholderString, 0)NSTextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholderString")), 0}); | |||
384 | ADD_UNARY_METHOD(NSTextField, textFieldWithString, 0)NSTextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("textFieldWithString")), 0}); | |||
385 | ADD_UNARY_METHOD(NSTextField, wrappingLabelWithString, 0)NSTextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("wrappingLabelWithString")), 0}); | |||
386 | ADD_UNARY_METHOD(NSTextField, labelWithString, 0)NSTextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("labelWithString")), 0}); | |||
387 | ||||
388 | NEW_RECEIVER(NSAttributedString)llvm::DenseMap<Selector, uint8_t> &NSAttributedStringM = UIMethods.insert({&Ctx.Idents.get("NSAttributedString" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
389 | ADD_UNARY_METHOD(NSAttributedString, initWithString, 0)NSAttributedStringM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("initWithString")), 0}); | |||
390 | IdentifierInfo *initWithStringNSAttributedString[] = { | |||
391 | &Ctx.Idents.get("initWithString"), &Ctx.Idents.get("attributes")}; | |||
392 | ADD_METHOD(NSAttributedString, initWithStringNSAttributedString, 2, 0)NSAttributedStringM.insert({Ctx.Selectors.getSelector(2, initWithStringNSAttributedString ), 0}); | |||
393 | ||||
394 | NEW_RECEIVER(NSText)llvm::DenseMap<Selector, uint8_t> &NSTextM = UIMethods .insert({&Ctx.Idents.get("NSText"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
395 | ADD_UNARY_METHOD(NSText, setString, 0)NSTextM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setString")), 0}); | |||
396 | ||||
397 | NEW_RECEIVER(UIKeyCommand)llvm::DenseMap<Selector, uint8_t> &UIKeyCommandM = UIMethods .insert({&Ctx.Idents.get("UIKeyCommand"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
398 | IdentifierInfo *keyCommandWithInputUIKeyCommand[] = { | |||
399 | &Ctx.Idents.get("keyCommandWithInput"), &Ctx.Idents.get("modifierFlags"), | |||
400 | &Ctx.Idents.get("action"), &Ctx.Idents.get("discoverabilityTitle")}; | |||
401 | ADD_METHOD(UIKeyCommand, keyCommandWithInputUIKeyCommand, 4, 3)UIKeyCommandM.insert({Ctx.Selectors.getSelector(4, keyCommandWithInputUIKeyCommand ), 3}); | |||
402 | ADD_UNARY_METHOD(UIKeyCommand, setDiscoverabilityTitle, 0)UIKeyCommandM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setDiscoverabilityTitle")), 0}); | |||
403 | ||||
404 | NEW_RECEIVER(UILabel)llvm::DenseMap<Selector, uint8_t> &UILabelM = UIMethods .insert({&Ctx.Idents.get("UILabel"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
405 | ADD_UNARY_METHOD(UILabel, setText, 0)UILabelM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setText")), 0}); | |||
406 | ||||
407 | NEW_RECEIVER(NSAlert)llvm::DenseMap<Selector, uint8_t> &NSAlertM = UIMethods .insert({&Ctx.Idents.get("NSAlert"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
408 | IdentifierInfo *alertWithMessageTextNSAlert[] = { | |||
409 | &Ctx.Idents.get("alertWithMessageText"), &Ctx.Idents.get("defaultButton"), | |||
410 | &Ctx.Idents.get("alternateButton"), &Ctx.Idents.get("otherButton"), | |||
411 | &Ctx.Idents.get("informativeTextWithFormat")}; | |||
412 | ADD_METHOD(NSAlert, alertWithMessageTextNSAlert, 5, 0)NSAlertM.insert({Ctx.Selectors.getSelector(5, alertWithMessageTextNSAlert ), 0}); | |||
413 | ADD_UNARY_METHOD(NSAlert, addButtonWithTitle, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("addButtonWithTitle")), 0}); | |||
414 | ADD_UNARY_METHOD(NSAlert, setMessageText, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setMessageText")), 0}); | |||
415 | ADD_UNARY_METHOD(NSAlert, setInformativeText, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setInformativeText")), 0}); | |||
416 | ADD_UNARY_METHOD(NSAlert, setHelpAnchor, 0)NSAlertM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setHelpAnchor")), 0}); | |||
417 | ||||
418 | NEW_RECEIVER(UIMutableApplicationShortcutItem)llvm::DenseMap<Selector, uint8_t> &UIMutableApplicationShortcutItemM = UIMethods.insert({&Ctx.Idents.get("UIMutableApplicationShortcutItem" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
419 | ADD_UNARY_METHOD(UIMutableApplicationShortcutItem, setLocalizedTitle, 0)UIMutableApplicationShortcutItemM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setLocalizedTitle")), 0}); | |||
420 | ADD_UNARY_METHOD(UIMutableApplicationShortcutItem, setLocalizedSubtitle, 0)UIMutableApplicationShortcutItemM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setLocalizedSubtitle")), 0}); | |||
421 | ||||
422 | NEW_RECEIVER(UIButton)llvm::DenseMap<Selector, uint8_t> &UIButtonM = UIMethods .insert({&Ctx.Idents.get("UIButton"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
423 | IdentifierInfo *setTitleUIButton[] = {&Ctx.Idents.get("setTitle"), | |||
424 | &Ctx.Idents.get("forState")}; | |||
425 | ADD_METHOD(UIButton, setTitleUIButton, 2, 0)UIButtonM.insert({Ctx.Selectors.getSelector(2, setTitleUIButton ), 0}); | |||
426 | ||||
427 | NEW_RECEIVER(NSWindow)llvm::DenseMap<Selector, uint8_t> &NSWindowM = UIMethods .insert({&Ctx.Idents.get("NSWindow"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
428 | ADD_UNARY_METHOD(NSWindow, setTitle, 0)NSWindowM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
429 | IdentifierInfo *minFrameWidthWithTitleNSWindow[] = { | |||
430 | &Ctx.Idents.get("minFrameWidthWithTitle"), &Ctx.Idents.get("styleMask")}; | |||
431 | ADD_METHOD(NSWindow, minFrameWidthWithTitleNSWindow, 2, 0)NSWindowM.insert({Ctx.Selectors.getSelector(2, minFrameWidthWithTitleNSWindow ), 0}); | |||
432 | ADD_UNARY_METHOD(NSWindow, setMiniwindowTitle, 0)NSWindowM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setMiniwindowTitle")), 0}); | |||
433 | ||||
434 | NEW_RECEIVER(NSPathCell)llvm::DenseMap<Selector, uint8_t> &NSPathCellM = UIMethods .insert({&Ctx.Idents.get("NSPathCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
435 | ADD_UNARY_METHOD(NSPathCell, setPlaceholderString, 0)NSPathCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setPlaceholderString")), 0}); | |||
436 | ||||
437 | NEW_RECEIVER(UIDocumentMenuViewController)llvm::DenseMap<Selector, uint8_t> &UIDocumentMenuViewControllerM = UIMethods.insert({&Ctx.Idents.get("UIDocumentMenuViewController" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
438 | IdentifierInfo *addOptionWithTitleUIDocumentMenuViewController[] = { | |||
439 | &Ctx.Idents.get("addOptionWithTitle"), &Ctx.Idents.get("image"), | |||
440 | &Ctx.Idents.get("order"), &Ctx.Idents.get("handler")}; | |||
441 | ADD_METHOD(UIDocumentMenuViewController,UIDocumentMenuViewControllerM.insert({Ctx.Selectors.getSelector (4, addOptionWithTitleUIDocumentMenuViewController), 0}); | |||
442 | addOptionWithTitleUIDocumentMenuViewController, 4, 0)UIDocumentMenuViewControllerM.insert({Ctx.Selectors.getSelector (4, addOptionWithTitleUIDocumentMenuViewController), 0}); | |||
443 | ||||
444 | NEW_RECEIVER(UINavigationItem)llvm::DenseMap<Selector, uint8_t> &UINavigationItemM = UIMethods.insert({&Ctx.Idents.get("UINavigationItem"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
445 | ADD_UNARY_METHOD(UINavigationItem, initWithTitle, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("initWithTitle")), 0}); | |||
446 | ADD_UNARY_METHOD(UINavigationItem, setTitle, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
447 | ADD_UNARY_METHOD(UINavigationItem, setPrompt, 0)UINavigationItemM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setPrompt")), 0}); | |||
448 | ||||
449 | NEW_RECEIVER(UIAlertView)llvm::DenseMap<Selector, uint8_t> &UIAlertViewM = UIMethods .insert({&Ctx.Idents.get("UIAlertView"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
450 | IdentifierInfo *initWithTitleUIAlertView[] = { | |||
451 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("message"), | |||
452 | &Ctx.Idents.get("delegate"), &Ctx.Idents.get("cancelButtonTitle"), | |||
453 | &Ctx.Idents.get("otherButtonTitles")}; | |||
454 | ADD_METHOD(UIAlertView, initWithTitleUIAlertView, 5, 0)UIAlertViewM.insert({Ctx.Selectors.getSelector(5, initWithTitleUIAlertView ), 0}); | |||
455 | ADD_UNARY_METHOD(UIAlertView, addButtonWithTitle, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("addButtonWithTitle")), 0}); | |||
456 | ADD_UNARY_METHOD(UIAlertView, setTitle, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
457 | ADD_UNARY_METHOD(UIAlertView, setMessage, 0)UIAlertViewM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setMessage")), 0}); | |||
458 | ||||
459 | NEW_RECEIVER(NSFormCell)llvm::DenseMap<Selector, uint8_t> &NSFormCellM = UIMethods .insert({&Ctx.Idents.get("NSFormCell"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
460 | ADD_UNARY_METHOD(NSFormCell, initTextCell, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("initTextCell")), 0}); | |||
461 | ADD_UNARY_METHOD(NSFormCell, setTitle, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); | |||
462 | ADD_UNARY_METHOD(NSFormCell, setPlaceholderString, 0)NSFormCellM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setPlaceholderString")), 0}); | |||
463 | ||||
464 | NEW_RECEIVER(NSUserNotification)llvm::DenseMap<Selector, uint8_t> &NSUserNotificationM = UIMethods.insert({&Ctx.Idents.get("NSUserNotification" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
465 | ADD_UNARY_METHOD(NSUserNotification, setTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
466 | ADD_UNARY_METHOD(NSUserNotification, setSubtitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setSubtitle")), 0}); | |||
467 | ADD_UNARY_METHOD(NSUserNotification, setInformativeText, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setInformativeText")), 0}); | |||
468 | ADD_UNARY_METHOD(NSUserNotification, setActionButtonTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setActionButtonTitle")), 0}); | |||
469 | ADD_UNARY_METHOD(NSUserNotification, setOtherButtonTitle, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setOtherButtonTitle")), 0}); | |||
470 | ADD_UNARY_METHOD(NSUserNotification, setResponsePlaceholder, 0)NSUserNotificationM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setResponsePlaceholder")), 0}); | |||
471 | ||||
472 | NEW_RECEIVER(NSToolbarItem)llvm::DenseMap<Selector, uint8_t> &NSToolbarItemM = UIMethods.insert({&Ctx.Idents.get("NSToolbarItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
473 | ADD_UNARY_METHOD(NSToolbarItem, setLabel, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setLabel")), 0}); | |||
474 | ADD_UNARY_METHOD(NSToolbarItem, setPaletteLabel, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPaletteLabel")), 0}); | |||
475 | ADD_UNARY_METHOD(NSToolbarItem, setToolTip, 0)NSToolbarItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); | |||
476 | ||||
477 | NEW_RECEIVER(NSProgress)llvm::DenseMap<Selector, uint8_t> &NSProgressM = UIMethods .insert({&Ctx.Idents.get("NSProgress"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
478 | ADD_UNARY_METHOD(NSProgress, setLocalizedDescription, 0)NSProgressM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setLocalizedDescription")), 0}); | |||
479 | ADD_UNARY_METHOD(NSProgress, setLocalizedAdditionalDescription, 0)NSProgressM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setLocalizedAdditionalDescription")), 0}); | |||
480 | ||||
481 | NEW_RECEIVER(NSSegmentedCell)llvm::DenseMap<Selector, uint8_t> &NSSegmentedCellM = UIMethods.insert({&Ctx.Idents.get("NSSegmentedCell"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
482 | IdentifierInfo *setLabelNSSegmentedCell[] = {&Ctx.Idents.get("setLabel"), | |||
483 | &Ctx.Idents.get("forSegment")}; | |||
484 | ADD_METHOD(NSSegmentedCell, setLabelNSSegmentedCell, 2, 0)NSSegmentedCellM.insert({Ctx.Selectors.getSelector(2, setLabelNSSegmentedCell ), 0}); | |||
485 | IdentifierInfo *setToolTipNSSegmentedCell[] = {&Ctx.Idents.get("setToolTip"), | |||
486 | &Ctx.Idents.get("forSegment")}; | |||
487 | ADD_METHOD(NSSegmentedCell, setToolTipNSSegmentedCell, 2, 0)NSSegmentedCellM.insert({Ctx.Selectors.getSelector(2, setToolTipNSSegmentedCell ), 0}); | |||
488 | ||||
489 | NEW_RECEIVER(NSUndoManager)llvm::DenseMap<Selector, uint8_t> &NSUndoManagerM = UIMethods.insert({&Ctx.Idents.get("NSUndoManager"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
490 | ADD_UNARY_METHOD(NSUndoManager, setActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setActionName")), 0}); | |||
491 | ADD_UNARY_METHOD(NSUndoManager, undoMenuTitleForUndoActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("undoMenuTitleForUndoActionName")), 0}); | |||
492 | ADD_UNARY_METHOD(NSUndoManager, redoMenuTitleForUndoActionName, 0)NSUndoManagerM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("redoMenuTitleForUndoActionName")), 0}); | |||
493 | ||||
494 | NEW_RECEIVER(NSMenuItem)llvm::DenseMap<Selector, uint8_t> &NSMenuItemM = UIMethods .insert({&Ctx.Idents.get("NSMenuItem"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
495 | IdentifierInfo *initWithTitleNSMenuItem[] = { | |||
496 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("action"), | |||
497 | &Ctx.Idents.get("keyEquivalent")}; | |||
498 | ADD_METHOD(NSMenuItem, initWithTitleNSMenuItem, 3, 0)NSMenuItemM.insert({Ctx.Selectors.getSelector(3, initWithTitleNSMenuItem ), 0}); | |||
499 | ADD_UNARY_METHOD(NSMenuItem, setTitle, 0)NSMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setTitle")), 0}); | |||
500 | ADD_UNARY_METHOD(NSMenuItem, setToolTip, 0)NSMenuItemM.insert( {Ctx.Selectors.getUnarySelector(&Ctx. Idents.get("setToolTip")), 0}); | |||
501 | ||||
502 | NEW_RECEIVER(NSPopUpButtonCell)llvm::DenseMap<Selector, uint8_t> &NSPopUpButtonCellM = UIMethods.insert({&Ctx.Idents.get("NSPopUpButtonCell") , llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
503 | IdentifierInfo *initTextCellNSPopUpButtonCell[] = { | |||
504 | &Ctx.Idents.get("initTextCell"), &Ctx.Idents.get("pullsDown")}; | |||
505 | ADD_METHOD(NSPopUpButtonCell, initTextCellNSPopUpButtonCell, 2, 0)NSPopUpButtonCellM.insert({Ctx.Selectors.getSelector(2, initTextCellNSPopUpButtonCell ), 0}); | |||
506 | ADD_UNARY_METHOD(NSPopUpButtonCell, addItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("addItemWithTitle")), 0}); | |||
507 | IdentifierInfo *insertItemWithTitleNSPopUpButtonCell[] = { | |||
508 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("atIndex")}; | |||
509 | ADD_METHOD(NSPopUpButtonCell, insertItemWithTitleNSPopUpButtonCell, 2, 0)NSPopUpButtonCellM.insert({Ctx.Selectors.getSelector(2, insertItemWithTitleNSPopUpButtonCell ), 0}); | |||
510 | ADD_UNARY_METHOD(NSPopUpButtonCell, removeItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("removeItemWithTitle")), 0}); | |||
511 | ADD_UNARY_METHOD(NSPopUpButtonCell, selectItemWithTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("selectItemWithTitle")), 0}); | |||
512 | ADD_UNARY_METHOD(NSPopUpButtonCell, setTitle, 0)NSPopUpButtonCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
513 | ||||
514 | NEW_RECEIVER(NSViewController)llvm::DenseMap<Selector, uint8_t> &NSViewControllerM = UIMethods.insert({&Ctx.Idents.get("NSViewController"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
515 | ADD_UNARY_METHOD(NSViewController, setTitle, 0)NSViewControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
516 | ||||
517 | NEW_RECEIVER(NSMenu)llvm::DenseMap<Selector, uint8_t> &NSMenuM = UIMethods .insert({&Ctx.Idents.get("NSMenu"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
518 | ADD_UNARY_METHOD(NSMenu, initWithTitle, 0)NSMenuM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("initWithTitle")), 0}); | |||
519 | IdentifierInfo *insertItemWithTitleNSMenu[] = { | |||
520 | &Ctx.Idents.get("insertItemWithTitle"), &Ctx.Idents.get("action"), | |||
521 | &Ctx.Idents.get("keyEquivalent"), &Ctx.Idents.get("atIndex")}; | |||
522 | ADD_METHOD(NSMenu, insertItemWithTitleNSMenu, 4, 0)NSMenuM.insert({Ctx.Selectors.getSelector(4, insertItemWithTitleNSMenu ), 0}); | |||
523 | IdentifierInfo *addItemWithTitleNSMenu[] = { | |||
524 | &Ctx.Idents.get("addItemWithTitle"), &Ctx.Idents.get("action"), | |||
525 | &Ctx.Idents.get("keyEquivalent")}; | |||
526 | ADD_METHOD(NSMenu, addItemWithTitleNSMenu, 3, 0)NSMenuM.insert({Ctx.Selectors.getSelector(3, addItemWithTitleNSMenu ), 0}); | |||
527 | ADD_UNARY_METHOD(NSMenu, setTitle, 0)NSMenuM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("setTitle")), 0}); | |||
528 | ||||
529 | NEW_RECEIVER(UIMutableUserNotificationAction)llvm::DenseMap<Selector, uint8_t> &UIMutableUserNotificationActionM = UIMethods.insert({&Ctx.Idents.get("UIMutableUserNotificationAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
530 | ADD_UNARY_METHOD(UIMutableUserNotificationAction, setTitle, 0)UIMutableUserNotificationActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setTitle")), 0}); | |||
531 | ||||
532 | NEW_RECEIVER(NSForm)llvm::DenseMap<Selector, uint8_t> &NSFormM = UIMethods .insert({&Ctx.Idents.get("NSForm"), llvm::DenseMap<Selector , uint8_t>()}) .first->second; | |||
533 | ADD_UNARY_METHOD(NSForm, addEntry, 0)NSFormM.insert( {Ctx.Selectors.getUnarySelector(&Ctx.Idents .get("addEntry")), 0}); | |||
534 | IdentifierInfo *insertEntryNSForm[] = {&Ctx.Idents.get("insertEntry"), | |||
535 | &Ctx.Idents.get("atIndex")}; | |||
536 | ADD_METHOD(NSForm, insertEntryNSForm, 2, 0)NSFormM.insert({Ctx.Selectors.getSelector(2, insertEntryNSForm ), 0}); | |||
537 | ||||
538 | NEW_RECEIVER(NSTextFieldCell)llvm::DenseMap<Selector, uint8_t> &NSTextFieldCellM = UIMethods.insert({&Ctx.Idents.get("NSTextFieldCell"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
539 | ADD_UNARY_METHOD(NSTextFieldCell, setPlaceholderString, 0)NSTextFieldCellM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setPlaceholderString")), 0}); | |||
540 | ||||
541 | NEW_RECEIVER(NSUserNotificationAction)llvm::DenseMap<Selector, uint8_t> &NSUserNotificationActionM = UIMethods.insert({&Ctx.Idents.get("NSUserNotificationAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
542 | IdentifierInfo *actionWithIdentifierNSUserNotificationAction[] = { | |||
543 | &Ctx.Idents.get("actionWithIdentifier"), &Ctx.Idents.get("title")}; | |||
544 | ADD_METHOD(NSUserNotificationAction,NSUserNotificationActionM.insert({Ctx.Selectors.getSelector(2 , actionWithIdentifierNSUserNotificationAction), 1}); | |||
545 | actionWithIdentifierNSUserNotificationAction, 2, 1)NSUserNotificationActionM.insert({Ctx.Selectors.getSelector(2 , actionWithIdentifierNSUserNotificationAction), 1}); | |||
546 | ||||
547 | NEW_RECEIVER(UITextField)llvm::DenseMap<Selector, uint8_t> &UITextFieldM = UIMethods .insert({&Ctx.Idents.get("UITextField"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
548 | ADD_UNARY_METHOD(UITextField, setText, 0)UITextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setText")), 0}); | |||
549 | ADD_UNARY_METHOD(UITextField, setPlaceholder, 0)UITextFieldM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setPlaceholder")), 0}); | |||
550 | ||||
551 | NEW_RECEIVER(UIBarButtonItem)llvm::DenseMap<Selector, uint8_t> &UIBarButtonItemM = UIMethods.insert({&Ctx.Idents.get("UIBarButtonItem"), llvm ::DenseMap<Selector, uint8_t>()}) .first->second; | |||
552 | IdentifierInfo *initWithTitleUIBarButtonItem[] = { | |||
553 | &Ctx.Idents.get("initWithTitle"), &Ctx.Idents.get("style"), | |||
554 | &Ctx.Idents.get("target"), &Ctx.Idents.get("action")}; | |||
555 | ADD_METHOD(UIBarButtonItem, initWithTitleUIBarButtonItem, 4, 0)UIBarButtonItemM.insert({Ctx.Selectors.getSelector(4, initWithTitleUIBarButtonItem ), 0}); | |||
556 | ||||
557 | NEW_RECEIVER(UIViewController)llvm::DenseMap<Selector, uint8_t> &UIViewControllerM = UIMethods.insert({&Ctx.Idents.get("UIViewController"), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
558 | ADD_UNARY_METHOD(UIViewController, setTitle, 0)UIViewControllerM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
559 | ||||
560 | NEW_RECEIVER(UISegmentedControl)llvm::DenseMap<Selector, uint8_t> &UISegmentedControlM = UIMethods.insert({&Ctx.Idents.get("UISegmentedControl" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
561 | IdentifierInfo *insertSegmentWithTitleUISegmentedControl[] = { | |||
562 | &Ctx.Idents.get("insertSegmentWithTitle"), &Ctx.Idents.get("atIndex"), | |||
563 | &Ctx.Idents.get("animated")}; | |||
564 | ADD_METHOD(UISegmentedControl, insertSegmentWithTitleUISegmentedControl, 3, 0)UISegmentedControlM.insert({Ctx.Selectors.getSelector(3, insertSegmentWithTitleUISegmentedControl ), 0}); | |||
565 | IdentifierInfo *setTitleUISegmentedControl[] = { | |||
566 | &Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")}; | |||
567 | ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)UISegmentedControlM.insert({Ctx.Selectors.getSelector(2, setTitleUISegmentedControl ), 0}); | |||
568 | ||||
569 | NEW_RECEIVER(NSAccessibilityCustomRotorItemResult)llvm::DenseMap<Selector, uint8_t> &NSAccessibilityCustomRotorItemResultM = UIMethods.insert({&Ctx.Idents.get("NSAccessibilityCustomRotorItemResult" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
570 | IdentifierInfo | |||
571 | *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = { | |||
572 | &Ctx.Idents.get("initWithItemLoadingToken"), | |||
573 | &Ctx.Idents.get("customLabel")}; | |||
574 | ADD_METHOD(NSAccessibilityCustomRotorItemResult,NSAccessibilityCustomRotorItemResultM.insert({Ctx.Selectors.getSelector (2, initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult ), 1}); | |||
575 | initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1)NSAccessibilityCustomRotorItemResultM.insert({Ctx.Selectors.getSelector (2, initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult ), 1}); | |||
576 | ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0)NSAccessibilityCustomRotorItemResultM.insert( {Ctx.Selectors. getUnarySelector(&Ctx.Idents.get("setCustomLabel")), 0}); | |||
577 | ||||
578 | NEW_RECEIVER(UIContextualAction)llvm::DenseMap<Selector, uint8_t> &UIContextualActionM = UIMethods.insert({&Ctx.Idents.get("UIContextualAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
579 | IdentifierInfo *contextualActionWithStyleUIContextualAction[] = { | |||
580 | &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"), | |||
581 | &Ctx.Idents.get("handler")}; | |||
582 | ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3,UIContextualActionM.insert({Ctx.Selectors.getSelector(3, contextualActionWithStyleUIContextualAction ), 1}); | |||
583 | 1)UIContextualActionM.insert({Ctx.Selectors.getSelector(3, contextualActionWithStyleUIContextualAction ), 1}); | |||
584 | ADD_UNARY_METHOD(UIContextualAction, setTitle, 0)UIContextualActionM.insert( {Ctx.Selectors.getUnarySelector(& Ctx.Idents.get("setTitle")), 0}); | |||
585 | ||||
586 | NEW_RECEIVER(NSAccessibilityCustomRotor)llvm::DenseMap<Selector, uint8_t> &NSAccessibilityCustomRotorM = UIMethods.insert({&Ctx.Idents.get("NSAccessibilityCustomRotor" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
587 | IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = { | |||
588 | &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")}; | |||
589 | ADD_METHOD(NSAccessibilityCustomRotor,NSAccessibilityCustomRotorM.insert({Ctx.Selectors.getSelector (2, initWithLabelNSAccessibilityCustomRotor), 0}); | |||
590 | initWithLabelNSAccessibilityCustomRotor, 2, 0)NSAccessibilityCustomRotorM.insert({Ctx.Selectors.getSelector (2, initWithLabelNSAccessibilityCustomRotor), 0}); | |||
591 | ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0)NSAccessibilityCustomRotorM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setLabel")), 0}); | |||
592 | ||||
593 | NEW_RECEIVER(NSWindowTab)llvm::DenseMap<Selector, uint8_t> &NSWindowTabM = UIMethods .insert({&Ctx.Idents.get("NSWindowTab"), llvm::DenseMap< Selector, uint8_t>()}) .first->second; | |||
594 | ADD_UNARY_METHOD(NSWindowTab, setTitle, 0)NSWindowTabM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setTitle")), 0}); | |||
595 | ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0)NSWindowTabM.insert( {Ctx.Selectors.getUnarySelector(&Ctx .Idents.get("setToolTip")), 0}); | |||
596 | ||||
597 | NEW_RECEIVER(NSAccessibilityCustomAction)llvm::DenseMap<Selector, uint8_t> &NSAccessibilityCustomActionM = UIMethods.insert({&Ctx.Idents.get("NSAccessibilityCustomAction" ), llvm::DenseMap<Selector, uint8_t>()}) .first->second ; | |||
598 | IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = { | |||
599 | &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")}; | |||
600 | ADD_METHOD(NSAccessibilityCustomAction,NSAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (2, initWithNameNSAccessibilityCustomAction), 0}); | |||
601 | initWithNameNSAccessibilityCustomAction, 2, 0)NSAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (2, initWithNameNSAccessibilityCustomAction), 0}); | |||
602 | IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = { | |||
603 | &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"), | |||
604 | &Ctx.Idents.get("selector")}; | |||
605 | ADD_METHOD(NSAccessibilityCustomAction,NSAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameTargetNSAccessibilityCustomAction), 0}); | |||
606 | initWithNameTargetNSAccessibilityCustomAction, 3, 0)NSAccessibilityCustomActionM.insert({Ctx.Selectors.getSelector (3, initWithNameTargetNSAccessibilityCustomAction), 0}); | |||
607 | ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0)NSAccessibilityCustomActionM.insert( {Ctx.Selectors.getUnarySelector (&Ctx.Idents.get("setName")), 0}); | |||
608 | } | |||
609 | ||||
610 | #define LSF_INSERT(function_name)LSF.insert(&Ctx.Idents.get(function_name)); LSF.insert(&Ctx.Idents.get(function_name)); | |||
611 | #define LSM_INSERT_NULLARY(receiver, method_name)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getNullarySelector ( &Ctx.Idents.get(method_name))}); \ | |||
612 | LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getNullarySelector( \ | |||
613 | &Ctx.Idents.get(method_name))}); | |||
614 | #define LSM_INSERT_UNARY(receiver, method_name)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getUnarySelector (&Ctx.Idents.get(method_name))}); \ | |||
615 | LSM.insert({&Ctx.Idents.get(receiver), \ | |||
616 | Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(method_name))}); | |||
617 | #define LSM_INSERT_SELECTOR(receiver, method_list, arguments)LSM.insert({&Ctx.Idents.get(receiver), Ctx.Selectors.getSelector (arguments, method_list)}); \ | |||
618 | LSM.insert({&Ctx.Idents.get(receiver), \ | |||
619 | Ctx.Selectors.getSelector(arguments, method_list)}); | |||
620 | ||||
621 | /// Initializes a list of methods and C functions that return a localized string | |||
622 | void NonLocalizedStringChecker::initLocStringsMethods(ASTContext &Ctx) const { | |||
623 | if (!LSM.empty()) | |||
624 | return; | |||
625 | ||||
626 | IdentifierInfo *LocalizedStringMacro[] = { | |||
627 | &Ctx.Idents.get("localizedStringForKey"), &Ctx.Idents.get("value"), | |||
628 | &Ctx.Idents.get("table")}; | |||
629 | LSM_INSERT_SELECTOR("NSBundle", LocalizedStringMacro, 3)LSM.insert({&Ctx.Idents.get("NSBundle"), Ctx.Selectors.getSelector (3, LocalizedStringMacro)}); | |||
630 | LSM_INSERT_UNARY("NSDateFormatter", "stringFromDate")LSM.insert({&Ctx.Idents.get("NSDateFormatter"), Ctx.Selectors .getUnarySelector(&Ctx.Idents.get("stringFromDate"))}); | |||
631 | IdentifierInfo *LocalizedStringFromDate[] = { | |||
632 | &Ctx.Idents.get("localizedStringFromDate"), &Ctx.Idents.get("dateStyle"), | |||
633 | &Ctx.Idents.get("timeStyle")}; | |||
634 | LSM_INSERT_SELECTOR("NSDateFormatter", LocalizedStringFromDate, 3)LSM.insert({&Ctx.Idents.get("NSDateFormatter"), Ctx.Selectors .getSelector(3, LocalizedStringFromDate)}); | |||
635 | LSM_INSERT_UNARY("NSNumberFormatter", "stringFromNumber")LSM.insert({&Ctx.Idents.get("NSNumberFormatter"), Ctx.Selectors .getUnarySelector(&Ctx.Idents.get("stringFromNumber"))}); | |||
636 | LSM_INSERT_NULLARY("UITextField", "text")LSM.insert({&Ctx.Idents.get("UITextField"), Ctx.Selectors .getNullarySelector( &Ctx.Idents.get("text"))}); | |||
637 | LSM_INSERT_NULLARY("UITextView", "text")LSM.insert({&Ctx.Idents.get("UITextView"), Ctx.Selectors. getNullarySelector( &Ctx.Idents.get("text"))}); | |||
638 | LSM_INSERT_NULLARY("UILabel", "text")LSM.insert({&Ctx.Idents.get("UILabel"), Ctx.Selectors.getNullarySelector ( &Ctx.Idents.get("text"))}); | |||
639 | ||||
640 | LSF_INSERT("CFDateFormatterCreateStringWithDate")LSF.insert(&Ctx.Idents.get("CFDateFormatterCreateStringWithDate" ));; | |||
641 | LSF_INSERT("CFDateFormatterCreateStringWithAbsoluteTime")LSF.insert(&Ctx.Idents.get("CFDateFormatterCreateStringWithAbsoluteTime" ));; | |||
642 | LSF_INSERT("CFNumberFormatterCreateStringWithNumber")LSF.insert(&Ctx.Idents.get("CFNumberFormatterCreateStringWithNumber" ));; | |||
643 | } | |||
644 | ||||
645 | /// Checks to see if the method / function declaration includes | |||
646 | /// __attribute__((annotate("returns_localized_nsstring"))) | |||
647 | bool NonLocalizedStringChecker::isAnnotatedAsReturningLocalized( | |||
648 | const Decl *D) const { | |||
649 | if (!D) | |||
650 | return false; | |||
651 | return std::any_of( | |||
652 | D->specific_attr_begin<AnnotateAttr>(), | |||
653 | D->specific_attr_end<AnnotateAttr>(), [](const AnnotateAttr *Ann) { | |||
654 | return Ann->getAnnotation() == "returns_localized_nsstring"; | |||
655 | }); | |||
656 | } | |||
657 | ||||
658 | /// Checks to see if the method / function declaration includes | |||
659 | /// __attribute__((annotate("takes_localized_nsstring"))) | |||
660 | bool NonLocalizedStringChecker::isAnnotatedAsTakingLocalized( | |||
661 | const Decl *D) const { | |||
662 | if (!D) | |||
663 | return false; | |||
664 | return std::any_of( | |||
665 | D->specific_attr_begin<AnnotateAttr>(), | |||
666 | D->specific_attr_end<AnnotateAttr>(), [](const AnnotateAttr *Ann) { | |||
667 | return Ann->getAnnotation() == "takes_localized_nsstring"; | |||
668 | }); | |||
669 | } | |||
670 | ||||
671 | /// Returns true if the given SVal is marked as Localized in the program state | |||
672 | bool NonLocalizedStringChecker::hasLocalizedState(SVal S, | |||
673 | CheckerContext &C) const { | |||
674 | const MemRegion *mt = S.getAsRegion(); | |||
675 | if (mt) { | |||
676 | const LocalizedState *LS = C.getState()->get<LocalizedMemMap>(mt); | |||
677 | if (LS && LS->isLocalized()) | |||
678 | return true; | |||
679 | } | |||
680 | return false; | |||
681 | } | |||
682 | ||||
683 | /// Returns true if the given SVal is marked as NonLocalized in the program | |||
684 | /// state | |||
685 | bool NonLocalizedStringChecker::hasNonLocalizedState(SVal S, | |||
686 | CheckerContext &C) const { | |||
687 | const MemRegion *mt = S.getAsRegion(); | |||
688 | if (mt) { | |||
689 | const LocalizedState *LS = C.getState()->get<LocalizedMemMap>(mt); | |||
690 | if (LS && LS->isNonLocalized()) | |||
691 | return true; | |||
692 | } | |||
693 | return false; | |||
694 | } | |||
695 | ||||
696 | /// Marks the given SVal as Localized in the program state | |||
697 | void NonLocalizedStringChecker::setLocalizedState(const SVal S, | |||
698 | CheckerContext &C) const { | |||
699 | const MemRegion *mt = S.getAsRegion(); | |||
700 | if (mt) { | |||
701 | ProgramStateRef State = | |||
702 | C.getState()->set<LocalizedMemMap>(mt, LocalizedState::getLocalized()); | |||
703 | C.addTransition(State); | |||
704 | } | |||
705 | } | |||
706 | ||||
707 | /// Marks the given SVal as NonLocalized in the program state | |||
708 | void NonLocalizedStringChecker::setNonLocalizedState(const SVal S, | |||
709 | CheckerContext &C) const { | |||
710 | const MemRegion *mt = S.getAsRegion(); | |||
711 | if (mt) { | |||
712 | ProgramStateRef State = C.getState()->set<LocalizedMemMap>( | |||
713 | mt, LocalizedState::getNonLocalized()); | |||
714 | C.addTransition(State); | |||
715 | } | |||
716 | } | |||
717 | ||||
718 | ||||
719 | static bool isDebuggingName(std::string name) { | |||
720 | return StringRef(name).lower().find("debug") != StringRef::npos; | |||
721 | } | |||
722 | ||||
723 | /// Returns true when, heuristically, the analyzer may be analyzing debugging | |||
724 | /// code. We use this to suppress localization diagnostics in un-localized user | |||
725 | /// interfaces that are only used for debugging and are therefore not user | |||
726 | /// facing. | |||
727 | static bool isDebuggingContext(CheckerContext &C) { | |||
728 | const Decl *D = C.getCurrentAnalysisDeclContext()->getDecl(); | |||
729 | if (!D) | |||
730 | return false; | |||
731 | ||||
732 | if (auto *ND = dyn_cast<NamedDecl>(D)) { | |||
733 | if (isDebuggingName(ND->getNameAsString())) | |||
734 | return true; | |||
735 | } | |||
736 | ||||
737 | const DeclContext *DC = D->getDeclContext(); | |||
738 | ||||
739 | if (auto *CD = dyn_cast<ObjCContainerDecl>(DC)) { | |||
740 | if (isDebuggingName(CD->getNameAsString())) | |||
741 | return true; | |||
742 | } | |||
743 | ||||
744 | return false; | |||
745 | } | |||
746 | ||||
747 | ||||
748 | /// Reports a localization error for the passed in method call and SVal | |||
749 | void NonLocalizedStringChecker::reportLocalizationError( | |||
750 | SVal S, const CallEvent &M, CheckerContext &C, int argumentNumber) const { | |||
751 | ||||
752 | // Don't warn about localization errors in classes and methods that | |||
753 | // may be debug code. | |||
754 | if (isDebuggingContext(C)) | |||
755 | return; | |||
756 | ||||
757 | static CheckerProgramPointTag Tag("NonLocalizedStringChecker", | |||
758 | "UnlocalizedString"); | |||
759 | ExplodedNode *ErrNode = C.addTransition(C.getState(), C.getPredecessor(), &Tag); | |||
760 | ||||
761 | if (!ErrNode) | |||
762 | return; | |||
763 | ||||
764 | // Generate the bug report. | |||
765 | auto R = std::make_unique<PathSensitiveBugReport>( | |||
766 | *BT, "User-facing text should use localized string macro", ErrNode); | |||
767 | if (argumentNumber) { | |||
768 | R->addRange(M.getArgExpr(argumentNumber - 1)->getSourceRange()); | |||
769 | } else { | |||
770 | R->addRange(M.getSourceRange()); | |||
771 | } | |||
772 | R->markInteresting(S); | |||
773 | ||||
774 | const MemRegion *StringRegion = S.getAsRegion(); | |||
775 | if (StringRegion) | |||
776 | R->addVisitor(std::make_unique<NonLocalizedStringBRVisitor>(StringRegion)); | |||
777 | ||||
778 | C.emitReport(std::move(R)); | |||
779 | } | |||
780 | ||||
781 | /// Returns the argument number requiring localized string if it exists | |||
782 | /// otherwise, returns -1 | |||
783 | int NonLocalizedStringChecker::getLocalizedArgumentForSelector( | |||
784 | const IdentifierInfo *Receiver, Selector S) const { | |||
785 | auto method = UIMethods.find(Receiver); | |||
786 | ||||
787 | if (method == UIMethods.end()) | |||
788 | return -1; | |||
789 | ||||
790 | auto argumentIterator = method->getSecond().find(S); | |||
791 | ||||
792 | if (argumentIterator == method->getSecond().end()) | |||
793 | return -1; | |||
794 | ||||
795 | int argumentNumber = argumentIterator->getSecond(); | |||
796 | return argumentNumber; | |||
797 | } | |||
798 | ||||
799 | /// Check if the string being passed in has NonLocalized state | |||
800 | void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg, | |||
801 | CheckerContext &C) const { | |||
802 | initUIMethods(C.getASTContext()); | |||
803 | ||||
804 | const ObjCInterfaceDecl *OD = msg.getReceiverInterface(); | |||
805 | if (!OD) | |||
806 | return; | |||
807 | const IdentifierInfo *odInfo = OD->getIdentifier(); | |||
808 | ||||
809 | Selector S = msg.getSelector(); | |||
810 | ||||
811 | std::string SelectorString = S.getAsString(); | |||
812 | StringRef SelectorName = SelectorString; | |||
813 | assert(!SelectorName.empty())(static_cast <bool> (!SelectorName.empty()) ? void (0) : __assert_fail ("!SelectorName.empty()", "clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp" , 813, __extension__ __PRETTY_FUNCTION__)); | |||
814 | ||||
815 | if (odInfo->isStr("NSString")) { | |||
816 | // Handle the case where the receiver is an NSString | |||
817 | // These special NSString methods draw to the screen | |||
818 | ||||
819 | if (!(SelectorName.startswith("drawAtPoint") || | |||
820 | SelectorName.startswith("drawInRect") || | |||
821 | SelectorName.startswith("drawWithRect"))) | |||
822 | return; | |||
823 | ||||
824 | SVal svTitle = msg.getReceiverSVal(); | |||
825 | ||||
826 | bool isNonLocalized = hasNonLocalizedState(svTitle, C); | |||
827 | ||||
828 | if (isNonLocalized) { | |||
829 | reportLocalizationError(svTitle, msg, C); | |||
830 | } | |||
831 | } | |||
832 | ||||
833 | int argumentNumber = getLocalizedArgumentForSelector(odInfo, S); | |||
834 | // Go up each hierarchy of superclasses and their protocols | |||
835 | while (argumentNumber < 0 && OD->getSuperClass() != nullptr) { | |||
836 | for (const auto *P : OD->all_referenced_protocols()) { | |||
837 | argumentNumber = getLocalizedArgumentForSelector(P->getIdentifier(), S); | |||
838 | if (argumentNumber >= 0) | |||
839 | break; | |||
840 | } | |||
841 | if (argumentNumber < 0) { | |||
842 | OD = OD->getSuperClass(); | |||
843 | argumentNumber = getLocalizedArgumentForSelector(OD->getIdentifier(), S); | |||
844 | } | |||
845 | } | |||
846 | ||||
847 | if (argumentNumber < 0) { // There was no match in UIMethods | |||
848 | if (const Decl *D = msg.getDecl()) { | |||
849 | if (const ObjCMethodDecl *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) { | |||
850 | auto formals = OMD->parameters(); | |||
851 | for (unsigned i = 0, ei = formals.size(); i != ei; ++i) { | |||
852 | if (isAnnotatedAsTakingLocalized(formals[i])) { | |||
853 | argumentNumber = i; | |||
854 | break; | |||
855 | } | |||
856 | } | |||
857 | } | |||
858 | } | |||
859 | } | |||
860 | ||||
861 | if (argumentNumber < 0) // Still no match | |||
862 | return; | |||
863 | ||||
864 | SVal svTitle = msg.getArgSVal(argumentNumber); | |||
865 | ||||
866 | if (const ObjCStringRegion *SR = | |||
867 | dyn_cast_or_null<ObjCStringRegion>(svTitle.getAsRegion())) { | |||
868 | StringRef stringValue = | |||
869 | SR->getObjCStringLiteral()->getString()->getString(); | |||
870 | if ((stringValue.trim().size() == 0 && stringValue.size() > 0) || | |||
871 | stringValue.empty()) | |||
872 | return; | |||
873 | if (!IsAggressive && llvm::sys::unicode::columnWidthUTF8(stringValue) < 2) | |||
874 | return; | |||
875 | } | |||
876 | ||||
877 | bool isNonLocalized = hasNonLocalizedState(svTitle, C); | |||
878 | ||||
879 | if (isNonLocalized) { | |||
880 | reportLocalizationError(svTitle, msg, C, argumentNumber + 1); | |||
881 | } | |||
882 | } | |||
883 | ||||
884 | void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call, | |||
885 | CheckerContext &C) const { | |||
886 | const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); | |||
887 | if (!FD) | |||
888 | return; | |||
889 | ||||
890 | auto formals = FD->parameters(); | |||
891 | for (unsigned i = 0, ei = std::min(static_cast<unsigned>(formals.size()), | |||
892 | Call.getNumArgs()); i != ei; ++i) { | |||
893 | if (isAnnotatedAsTakingLocalized(formals[i])) { | |||
894 | auto actual = Call.getArgSVal(i); | |||
895 | if (hasNonLocalizedState(actual, C)) { | |||
896 | reportLocalizationError(actual, Call, C, i + 1); | |||
897 | } | |||
898 | } | |||
899 | } | |||
900 | } | |||
901 | ||||
902 | static inline bool isNSStringType(QualType T, ASTContext &Ctx) { | |||
903 | ||||
904 | const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); | |||
905 | if (!PT) | |||
906 | return false; | |||
907 | ||||
908 | ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); | |||
909 | if (!Cls) | |||
910 | return false; | |||
911 | ||||
912 | IdentifierInfo *ClsName = Cls->getIdentifier(); | |||
913 | ||||
914 | // FIXME: Should we walk the chain of classes? | |||
915 | return ClsName == &Ctx.Idents.get("NSString") || | |||
916 | ClsName == &Ctx.Idents.get("NSMutableString"); | |||
917 | } | |||
918 | ||||
919 | /// Marks a string being returned by any call as localized | |||
920 | /// if it is in LocStringFunctions (LSF) or the function is annotated. | |||
921 | /// Otherwise, we mark it as NonLocalized (Aggressive) or | |||
922 | /// NonLocalized only if it is not backed by a SymRegion (Non-Aggressive), | |||
923 | /// basically leaving only string literals as NonLocalized. | |||
924 | void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call, | |||
925 | CheckerContext &C) const { | |||
926 | initLocStringsMethods(C.getASTContext()); | |||
927 | ||||
928 | if (!Call.getOriginExpr()) | |||
929 | return; | |||
930 | ||||
931 | // Anything that takes in a localized NSString as an argument | |||
932 | // and returns an NSString will be assumed to be returning a | |||
933 | // localized NSString. (Counter: Incorrectly combining two LocalizedStrings) | |||
934 | const QualType RT = Call.getResultType(); | |||
935 | if (isNSStringType(RT, C.getASTContext())) { | |||
936 | for (unsigned i = 0; i < Call.getNumArgs(); ++i) { | |||
937 | SVal argValue = Call.getArgSVal(i); | |||
938 | if (hasLocalizedState(argValue, C)) { | |||
939 | SVal sv = Call.getReturnValue(); | |||
940 | setLocalizedState(sv, C); | |||
941 | return; | |||
942 | } | |||
943 | } | |||
944 | } | |||
945 | ||||
946 | const Decl *D = Call.getDecl(); | |||
947 | if (!D) | |||
948 | return; | |||
949 | ||||
950 | const IdentifierInfo *Identifier = Call.getCalleeIdentifier(); | |||
951 | ||||
952 | SVal sv = Call.getReturnValue(); | |||
953 | if (isAnnotatedAsReturningLocalized(D) || LSF.contains(Identifier)) { | |||
954 | setLocalizedState(sv, C); | |||
955 | } else if (isNSStringType(RT, C.getASTContext()) && | |||
956 | !hasLocalizedState(sv, C)) { | |||
957 | if (IsAggressive) { | |||
958 | setNonLocalizedState(sv, C); | |||
959 | } else { | |||
960 | const SymbolicRegion *SymReg = | |||
961 | dyn_cast_or_null<SymbolicRegion>(sv.getAsRegion()); | |||
962 | if (!SymReg) | |||
963 | setNonLocalizedState(sv, C); | |||
964 | } | |||
965 | } | |||
966 | } | |||
967 | ||||
968 | /// Marks a string being returned by an ObjC method as localized | |||
969 | /// if it is in LocStringMethods or the method is annotated | |||
970 | void NonLocalizedStringChecker::checkPostObjCMessage(const ObjCMethodCall &msg, | |||
971 | CheckerContext &C) const { | |||
972 | initLocStringsMethods(C.getASTContext()); | |||
973 | ||||
974 | if (!msg.isInstanceMessage()) | |||
975 | return; | |||
976 | ||||
977 | const ObjCInterfaceDecl *OD = msg.getReceiverInterface(); | |||
978 | if (!OD) | |||
979 | return; | |||
980 | const IdentifierInfo *odInfo = OD->getIdentifier(); | |||
981 | ||||
982 | Selector S = msg.getSelector(); | |||
983 | std::string SelectorName = S.getAsString(); | |||
984 | ||||
985 | std::pair<const IdentifierInfo *, Selector> MethodDescription = {odInfo, S}; | |||
986 | ||||
987 | if (LSM.count(MethodDescription) || | |||
988 | isAnnotatedAsReturningLocalized(msg.getDecl())) { | |||
989 | SVal sv = msg.getReturnValue(); | |||
990 | setLocalizedState(sv, C); | |||
991 | } | |||
992 | } | |||
993 | ||||
994 | /// Marks all empty string literals as localized | |||
995 | void NonLocalizedStringChecker::checkPostStmt(const ObjCStringLiteral *SL, | |||
996 | CheckerContext &C) const { | |||
997 | SVal sv = C.getSVal(SL); | |||
998 | setNonLocalizedState(sv, C); | |||
999 | } | |||
1000 | ||||
1001 | PathDiagnosticPieceRef | |||
1002 | NonLocalizedStringBRVisitor::VisitNode(const ExplodedNode *Succ, | |||
1003 | BugReporterContext &BRC, | |||
1004 | PathSensitiveBugReport &BR) { | |||
1005 | if (Satisfied) | |||
1006 | return nullptr; | |||
1007 | ||||
1008 | std::optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>(); | |||
1009 | if (!Point) | |||
1010 | return nullptr; | |||
1011 | ||||
1012 | auto *LiteralExpr = dyn_cast<ObjCStringLiteral>(Point->getStmt()); | |||
1013 | if (!LiteralExpr) | |||
1014 | return nullptr; | |||
1015 | ||||
1016 | SVal LiteralSVal = Succ->getSVal(LiteralExpr); | |||
1017 | if (LiteralSVal.getAsRegion() != NonLocalizedString) | |||
1018 | return nullptr; | |||
1019 | ||||
1020 | Satisfied = true; | |||
1021 | ||||
1022 | PathDiagnosticLocation L = | |||
1023 | PathDiagnosticLocation::create(*Point, BRC.getSourceManager()); | |||
1024 | ||||
1025 | if (!L.isValid() || !L.asLocation().isValid()) | |||
1026 | return nullptr; | |||
1027 | ||||
1028 | auto Piece = std::make_shared<PathDiagnosticEventPiece>( | |||
1029 | L, "Non-localized string literal here"); | |||
1030 | Piece->addRange(LiteralExpr->getSourceRange()); | |||
1031 | ||||
1032 | return std::move(Piece); | |||
1033 | } | |||
1034 | ||||
1035 | namespace { | |||
1036 | class EmptyLocalizationContextChecker | |||
1037 | : public Checker<check::ASTDecl<ObjCImplementationDecl>> { | |||
1038 | ||||
1039 | // A helper class, which walks the AST | |||
1040 | class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { | |||
1041 | const ObjCMethodDecl *MD; | |||
1042 | BugReporter &BR; | |||
1043 | AnalysisManager &Mgr; | |||
1044 | const CheckerBase *Checker; | |||
1045 | LocationOrAnalysisDeclContext DCtx; | |||
1046 | ||||
1047 | public: | |||
1048 | MethodCrawler(const ObjCMethodDecl *InMD, BugReporter &InBR, | |||
1049 | const CheckerBase *Checker, AnalysisManager &InMgr, | |||
1050 | AnalysisDeclContext *InDCtx) | |||
1051 | : MD(InMD), BR(InBR), Mgr(InMgr), Checker(Checker), DCtx(InDCtx) {} | |||
1052 | ||||
1053 | void VisitStmt(const Stmt *S) { VisitChildren(S); } | |||
1054 | ||||
1055 | void VisitObjCMessageExpr(const ObjCMessageExpr *ME); | |||
1056 | ||||
1057 | void reportEmptyContextError(const ObjCMessageExpr *M) const; | |||
1058 | ||||
1059 | void VisitChildren(const Stmt *S) { | |||
1060 | for (const Stmt *Child : S->children()) { | |||
1061 | if (Child) | |||
1062 | this->Visit(Child); | |||
1063 | } | |||
1064 | } | |||
1065 | }; | |||
1066 | ||||
1067 | public: | |||
1068 | void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr, | |||
1069 | BugReporter &BR) const; | |||
1070 | }; | |||
1071 | } // end anonymous namespace | |||
1072 | ||||
1073 | void EmptyLocalizationContextChecker::checkASTDecl( | |||
1074 | const ObjCImplementationDecl *D, AnalysisManager &Mgr, | |||
1075 | BugReporter &BR) const { | |||
1076 | ||||
1077 | for (const ObjCMethodDecl *M : D->methods()) { | |||
1078 | AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M); | |||
1079 | ||||
1080 | const Stmt *Body = M->getBody(); | |||
1081 | if (!Body) { | |||
1082 | assert(M->isSynthesizedAccessorStub())(static_cast <bool> (M->isSynthesizedAccessorStub()) ? void (0) : __assert_fail ("M->isSynthesizedAccessorStub()" , "clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp" , 1082, __extension__ __PRETTY_FUNCTION__)); | |||
1083 | continue; | |||
1084 | } | |||
1085 | ||||
1086 | MethodCrawler MC(M->getCanonicalDecl(), BR, this, Mgr, DCtx); | |||
1087 | MC.VisitStmt(Body); | |||
1088 | } | |||
1089 | } | |||
1090 | ||||
1091 | /// This check attempts to match these macros, assuming they are defined as | |||
1092 | /// follows: | |||
1093 | /// | |||
1094 | /// #define NSLocalizedString(key, comment) \ | |||
1095 | /// [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil] | |||
1096 | /// #define NSLocalizedStringFromTable(key, tbl, comment) \ | |||
1097 | /// [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)] | |||
1098 | /// #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \ | |||
1099 | /// [bundle localizedStringForKey:(key) value:@"" table:(tbl)] | |||
1100 | /// #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) | |||
1101 | /// | |||
1102 | /// We cannot use the path sensitive check because the macro argument we are | |||
1103 | /// checking for (comment) is not used and thus not present in the AST, | |||
1104 | /// so we use Lexer on the original macro call and retrieve the value of | |||
1105 | /// the comment. If it's empty or nil, we raise a warning. | |||
1106 | void EmptyLocalizationContextChecker::MethodCrawler::VisitObjCMessageExpr( | |||
1107 | const ObjCMessageExpr *ME) { | |||
1108 | ||||
1109 | // FIXME: We may be able to use PPCallbacks to check for empty context | |||
1110 | // comments as part of preprocessing and avoid this re-lexing hack. | |||
1111 | const ObjCInterfaceDecl *OD = ME->getReceiverInterface(); | |||
1112 | if (!OD) | |||
| ||||
1113 | return; | |||
1114 | ||||
1115 | const IdentifierInfo *odInfo = OD->getIdentifier(); | |||
1116 | ||||
1117 | if (!(odInfo->isStr("NSBundle") && | |||
1118 | ME->getSelector().getAsString() == | |||
1119 | "localizedStringForKey:value:table:")) { | |||
1120 | return; | |||
1121 | } | |||
1122 | ||||
1123 | SourceRange R = ME->getSourceRange(); | |||
1124 | if (!R.getBegin().isMacroID()) | |||
1125 | return; | |||
1126 | ||||
1127 | // getImmediateMacroCallerLoc gets the location of the immediate macro | |||
1128 | // caller, one level up the stack toward the initial macro typed into the | |||
1129 | // source, so SL should point to the NSLocalizedString macro. | |||
1130 | SourceLocation SL = | |||
1131 | Mgr.getSourceManager().getImmediateMacroCallerLoc(R.getBegin()); | |||
1132 | std::pair<FileID, unsigned> SLInfo = | |||
1133 | Mgr.getSourceManager().getDecomposedLoc(SL); | |||
1134 | ||||
1135 | SrcMgr::SLocEntry SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first); | |||
1136 | ||||
1137 | // If NSLocalizedString macro is wrapped in another macro, we need to | |||
1138 | // unwrap the expansion until we get to the NSLocalizedStringMacro. | |||
1139 | while (SE.isExpansion()) { | |||
1140 | SL = SE.getExpansion().getSpellingLoc(); | |||
1141 | SLInfo = Mgr.getSourceManager().getDecomposedLoc(SL); | |||
1142 | SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first); | |||
1143 | } | |||
1144 | ||||
1145 | std::optional<llvm::MemoryBufferRef> BF = | |||
1146 | Mgr.getSourceManager().getBufferOrNone(SLInfo.first, SL); | |||
1147 | if (!BF) | |||
1148 | return; | |||
1149 | LangOptions LangOpts; | |||
1150 | Lexer TheLexer(SL, LangOpts, BF->getBufferStart(), | |||
1151 | BF->getBufferStart() + SLInfo.second, BF->getBufferEnd()); | |||
1152 | ||||
1153 | Token I; | |||
1154 | Token Result; // This will hold the token just before the last ')' | |||
1155 | int p_count = 0; // This is for parenthesis matching | |||
1156 | while (!TheLexer.LexFromRawLexer(I)) { | |||
1157 | if (I.getKind() == tok::l_paren) | |||
1158 | ++p_count; | |||
1159 | if (I.getKind() == tok::r_paren) { | |||
1160 | if (p_count == 1) | |||
1161 | break; | |||
1162 | --p_count; | |||
1163 | } | |||
1164 | Result = I; | |||
1165 | } | |||
1166 | ||||
1167 | if (isAnyIdentifier(Result.getKind())) { | |||
1168 | if (Result.getRawIdentifier().equals("nil")) { | |||
1169 | reportEmptyContextError(ME); | |||
1170 | return; | |||
1171 | } | |||
1172 | } | |||
1173 | ||||
1174 | if (!isStringLiteral(Result.getKind())) | |||
1175 | return; | |||
1176 | ||||
1177 | StringRef Comment = | |||
1178 | StringRef(Result.getLiteralData(), Result.getLength()).trim('"'); | |||
1179 | ||||
1180 | if ((Comment.trim().size() == 0 && Comment.size() > 0) || // Is Whitespace | |||
1181 | Comment.empty()) { | |||
1182 | reportEmptyContextError(ME); | |||
1183 | } | |||
1184 | } | |||
1185 | ||||
1186 | void EmptyLocalizationContextChecker::MethodCrawler::reportEmptyContextError( | |||
1187 | const ObjCMessageExpr *ME) const { | |||
1188 | // Generate the bug report. | |||
1189 | BR.EmitBasicReport(MD, Checker, "Context Missing", | |||
1190 | "Localizability Issue (Apple)", | |||
1191 | "Localized string macro should include a non-empty " | |||
1192 | "comment for translators", | |||
1193 | PathDiagnosticLocation(ME, BR.getSourceManager(), DCtx)); | |||
1194 | } | |||
1195 | ||||
1196 | namespace { | |||
1197 | class PluralMisuseChecker : public Checker<check::ASTCodeBody> { | |||
1198 | ||||
1199 | // A helper class, which walks the AST | |||
1200 | class MethodCrawler : public RecursiveASTVisitor<MethodCrawler> { | |||
1201 | BugReporter &BR; | |||
1202 | const CheckerBase *Checker; | |||
1203 | AnalysisDeclContext *AC; | |||
1204 | ||||
1205 | // This functions like a stack. We push on any IfStmt or | |||
1206 | // ConditionalOperator that matches the condition | |||
1207 | // and pop it off when we leave that statement | |||
1208 | llvm::SmallVector<const clang::Stmt *, 8> MatchingStatements; | |||
1209 | // This is true when we are the direct-child of a | |||
1210 | // matching statement | |||
1211 | bool InMatchingStatement = false; | |||
1212 | ||||
1213 | public: | |||
1214 | explicit MethodCrawler(BugReporter &InBR, const CheckerBase *Checker, | |||
1215 | AnalysisDeclContext *InAC) | |||
1216 | : BR(InBR), Checker(Checker), AC(InAC) {} | |||
1217 | ||||
1218 | bool VisitIfStmt(const IfStmt *I); | |||
1219 | bool EndVisitIfStmt(IfStmt *I); | |||
1220 | bool TraverseIfStmt(IfStmt *x); | |||
1221 | bool VisitConditionalOperator(const ConditionalOperator *C); | |||
1222 | bool TraverseConditionalOperator(ConditionalOperator *C); | |||
1223 | bool VisitCallExpr(const CallExpr *CE); | |||
1224 | bool VisitObjCMessageExpr(const ObjCMessageExpr *ME); | |||
1225 | ||||
1226 | private: | |||
1227 | void reportPluralMisuseError(const Stmt *S) const; | |||
1228 | bool isCheckingPlurality(const Expr *E) const; | |||
1229 | }; | |||
1230 | ||||
1231 | public: | |||
1232 | void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, | |||
1233 | BugReporter &BR) const { | |||
1234 | MethodCrawler Visitor(BR, this, Mgr.getAnalysisDeclContext(D)); | |||
1235 | Visitor.TraverseDecl(const_cast<Decl *>(D)); | |||
1236 | } | |||
1237 | }; | |||
1238 | } // end anonymous namespace | |||
1239 | ||||
1240 | // Checks the condition of the IfStmt and returns true if one | |||
1241 | // of the following heuristics are met: | |||
1242 | // 1) The conidtion is a variable with "singular" or "plural" in the name | |||
1243 | // 2) The condition is a binary operator with 1 or 2 on the right-hand side | |||
1244 | bool PluralMisuseChecker::MethodCrawler::isCheckingPlurality( | |||
1245 | const Expr *Condition) const { | |||
1246 | const BinaryOperator *BO = nullptr; | |||
1247 | // Accounts for when a VarDecl represents a BinaryOperator | |||
1248 | if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Condition)) { | |||
1249 | if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { | |||
1250 | const Expr *InitExpr = VD->getInit(); | |||
1251 | if (InitExpr) { | |||
1252 | if (const BinaryOperator *B = | |||
1253 | dyn_cast<BinaryOperator>(InitExpr->IgnoreParenImpCasts())) { | |||
1254 | BO = B; | |||
1255 | } | |||
1256 | } | |||
1257 | if (VD->getName().lower().find("plural") != StringRef::npos || | |||
1258 | VD->getName().lower().find("singular") != StringRef::npos) { | |||
1259 | return true; | |||
1260 | } | |||
1261 | } | |||
1262 | } else if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) { | |||
1263 | BO = B; | |||
1264 | } | |||
1265 | ||||
1266 | if (BO == nullptr) | |||
1267 | return false; | |||
1268 | ||||
1269 | if (IntegerLiteral *IL = dyn_cast_or_null<IntegerLiteral>( | |||
1270 | BO->getRHS()->IgnoreParenImpCasts())) { | |||
1271 | llvm::APInt Value = IL->getValue(); | |||
1272 | if (Value == 1 || Value == 2) { | |||
1273 | return true; | |||
1274 | } | |||
1275 | } | |||
1276 | return false; | |||
1277 | } | |||
1278 | ||||
1279 | // A CallExpr with "LOC" in its identifier that takes in a string literal | |||
1280 | // has been shown to almost always be a function that returns a localized | |||
1281 | // string. Raise a diagnostic when this is in a statement that matches | |||
1282 | // the condition. | |||
1283 | bool PluralMisuseChecker::MethodCrawler::VisitCallExpr(const CallExpr *CE) { | |||
1284 | if (InMatchingStatement) { | |||
1285 | if (const FunctionDecl *FD = CE->getDirectCallee()) { | |||
1286 | std::string NormalizedName = | |||
1287 | StringRef(FD->getNameInfo().getAsString()).lower(); | |||
1288 | if (NormalizedName.find("loc") != std::string::npos) { | |||
1289 | for (const Expr *Arg : CE->arguments()) { | |||
1290 | if (isa<ObjCStringLiteral>(Arg)) | |||
1291 | reportPluralMisuseError(CE); | |||
1292 | } | |||
1293 | } | |||
1294 | } | |||
1295 | } | |||
1296 | return true; | |||
1297 | } | |||
1298 | ||||
1299 | // The other case is for NSLocalizedString which also returns | |||
1300 | // a localized string. It's a macro for the ObjCMessageExpr | |||
1301 | // [NSBundle localizedStringForKey:value:table:] Raise a | |||
1302 | // diagnostic when this is in a statement that matches | |||
1303 | // the condition. | |||
1304 | bool PluralMisuseChecker::MethodCrawler::VisitObjCMessageExpr( | |||
1305 | const ObjCMessageExpr *ME) { | |||
1306 | const ObjCInterfaceDecl *OD = ME->getReceiverInterface(); | |||
1307 | if (!OD) | |||
1308 | return true; | |||
1309 | ||||
1310 | const IdentifierInfo *odInfo = OD->getIdentifier(); | |||
1311 | ||||
1312 | if (odInfo->isStr("NSBundle") && | |||
1313 | ME->getSelector().getAsString() == "localizedStringForKey:value:table:") { | |||
1314 | if (InMatchingStatement) { | |||
1315 | reportPluralMisuseError(ME); | |||
1316 | } | |||
1317 | } | |||
1318 | return true; | |||
1319 | } | |||
1320 | ||||
1321 | /// Override TraverseIfStmt so we know when we are done traversing an IfStmt | |||
1322 | bool PluralMisuseChecker::MethodCrawler::TraverseIfStmt(IfStmt *I) { | |||
1323 | RecursiveASTVisitor<MethodCrawler>::TraverseIfStmt(I); | |||
1324 | return EndVisitIfStmt(I); | |||
1325 | } | |||
1326 | ||||
1327 | // EndVisit callbacks are not provided by the RecursiveASTVisitor | |||
1328 | // so we override TraverseIfStmt and make a call to EndVisitIfStmt | |||
1329 | // after traversing the IfStmt | |||
1330 | bool PluralMisuseChecker::MethodCrawler::EndVisitIfStmt(IfStmt *I) { | |||
1331 | MatchingStatements.pop_back(); | |||
1332 | if (!MatchingStatements.empty()) { | |||
1333 | if (MatchingStatements.back() != nullptr) { | |||
1334 | InMatchingStatement = true; | |||
1335 | return true; | |||
1336 | } | |||
1337 | } | |||
1338 | InMatchingStatement = false; | |||
1339 | return true; | |||
1340 | } | |||
1341 | ||||
1342 | bool PluralMisuseChecker::MethodCrawler::VisitIfStmt(const IfStmt *I) { | |||
1343 | const Expr *Condition = I->getCond(); | |||
1344 | if (!Condition) | |||
1345 | return true; | |||
1346 | Condition = Condition->IgnoreParenImpCasts(); | |||
1347 | if (isCheckingPlurality(Condition)) { | |||
1348 | MatchingStatements.push_back(I); | |||
1349 | InMatchingStatement = true; | |||
1350 | } else { | |||
1351 | MatchingStatements.push_back(nullptr); | |||
1352 | InMatchingStatement = false; | |||
1353 | } | |||
1354 | ||||
1355 | return true; | |||
1356 | } | |||
1357 | ||||
1358 | // Preliminary support for conditional operators. | |||
1359 | bool PluralMisuseChecker::MethodCrawler::TraverseConditionalOperator( | |||
1360 | ConditionalOperator *C) { | |||
1361 | RecursiveASTVisitor<MethodCrawler>::TraverseConditionalOperator(C); | |||
1362 | MatchingStatements.pop_back(); | |||
1363 | if (!MatchingStatements.empty()) { | |||
1364 | if (MatchingStatements.back() != nullptr) | |||
1365 | InMatchingStatement = true; | |||
1366 | else | |||
1367 | InMatchingStatement = false; | |||
1368 | } else { | |||
1369 | InMatchingStatement = false; | |||
1370 | } | |||
1371 | return true; | |||
1372 | } | |||
1373 | ||||
1374 | bool PluralMisuseChecker::MethodCrawler::VisitConditionalOperator( | |||
1375 | const ConditionalOperator *C) { | |||
1376 | const Expr *Condition = C->getCond()->IgnoreParenImpCasts(); | |||
1377 | if (isCheckingPlurality(Condition)) { | |||
1378 | MatchingStatements.push_back(C); | |||
1379 | InMatchingStatement = true; | |||
1380 | } else { | |||
1381 | MatchingStatements.push_back(nullptr); | |||
1382 | InMatchingStatement = false; | |||
1383 | } | |||
1384 | return true; | |||
1385 | } | |||
1386 | ||||
1387 | void PluralMisuseChecker::MethodCrawler::reportPluralMisuseError( | |||
1388 | const Stmt *S) const { | |||
1389 | // Generate the bug report. | |||
1390 | BR.EmitBasicReport(AC->getDecl(), Checker, "Plural Misuse", | |||
1391 | "Localizability Issue (Apple)", | |||
1392 | "Plural cases are not supported across all languages. " | |||
1393 | "Use a .stringsdict file instead", | |||
1394 | PathDiagnosticLocation(S, BR.getSourceManager(), AC)); | |||
1395 | } | |||
1396 | ||||
1397 | //===----------------------------------------------------------------------===// | |||
1398 | // Checker registration. | |||
1399 | //===----------------------------------------------------------------------===// | |||
1400 | ||||
1401 | void ento::registerNonLocalizedStringChecker(CheckerManager &mgr) { | |||
1402 | NonLocalizedStringChecker *checker = | |||
1403 | mgr.registerChecker<NonLocalizedStringChecker>(); | |||
1404 | checker->IsAggressive = | |||
1405 | mgr.getAnalyzerOptions().getCheckerBooleanOption( | |||
1406 | checker, "AggressiveReport"); | |||
1407 | } | |||
1408 | ||||
1409 | bool ento::shouldRegisterNonLocalizedStringChecker(const CheckerManager &mgr) { | |||
1410 | return true; | |||
1411 | } | |||
1412 | ||||
1413 | void ento::registerEmptyLocalizationContextChecker(CheckerManager &mgr) { | |||
1414 | mgr.registerChecker<EmptyLocalizationContextChecker>(); | |||
1415 | } | |||
1416 | ||||
1417 | bool ento::shouldRegisterEmptyLocalizationContextChecker( | |||
1418 | const CheckerManager &mgr) { | |||
1419 | return true; | |||
1420 | } | |||
1421 | ||||
1422 | void ento::registerPluralMisuseChecker(CheckerManager &mgr) { | |||
1423 | mgr.registerChecker<PluralMisuseChecker>(); | |||
1424 | } | |||
1425 | ||||
1426 | bool ento::shouldRegisterPluralMisuseChecker(const CheckerManager &mgr) { | |||
1427 | return true; | |||
1428 | } |
1 | //===--- Token.h - Token interface ------------------------------*- C++ -*-===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file defines the Token interface. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #ifndef LLVM_CLANG_LEX_TOKEN_H | |||
14 | #define LLVM_CLANG_LEX_TOKEN_H | |||
15 | ||||
16 | #include "clang/Basic/SourceLocation.h" | |||
17 | #include "clang/Basic/TokenKinds.h" | |||
18 | #include "llvm/ADT/ArrayRef.h" | |||
19 | #include "llvm/ADT/StringRef.h" | |||
20 | #include <cassert> | |||
21 | ||||
22 | namespace clang { | |||
23 | ||||
24 | class IdentifierInfo; | |||
25 | ||||
26 | /// Token - This structure provides full information about a lexed token. | |||
27 | /// It is not intended to be space efficient, it is intended to return as much | |||
28 | /// information as possible about each returned token. This is expected to be | |||
29 | /// compressed into a smaller form if memory footprint is important. | |||
30 | /// | |||
31 | /// The parser can create a special "annotation token" representing a stream of | |||
32 | /// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>" | |||
33 | /// can be represented by a single typename annotation token that carries | |||
34 | /// information about the SourceRange of the tokens and the type object. | |||
35 | class Token { | |||
36 | /// The location of the token. This is actually a SourceLocation. | |||
37 | SourceLocation::UIntTy Loc; | |||
38 | ||||
39 | // Conceptually these next two fields could be in a union. However, this | |||
40 | // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical | |||
41 | // routine. Keeping as separate members with casts until a more beautiful fix | |||
42 | // presents itself. | |||
43 | ||||
44 | /// UintData - This holds either the length of the token text, when | |||
45 | /// a normal token, or the end of the SourceRange when an annotation | |||
46 | /// token. | |||
47 | SourceLocation::UIntTy UintData; | |||
48 | ||||
49 | /// PtrData - This is a union of four different pointer types, which depends | |||
50 | /// on what type of token this is: | |||
51 | /// Identifiers, keywords, etc: | |||
52 | /// This is an IdentifierInfo*, which contains the uniqued identifier | |||
53 | /// spelling. | |||
54 | /// Literals: isLiteral() returns true. | |||
55 | /// This is a pointer to the start of the token in a text buffer, which | |||
56 | /// may be dirty (have trigraphs / escaped newlines). | |||
57 | /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). | |||
58 | /// This is a pointer to sema-specific data for the annotation token. | |||
59 | /// Eof: | |||
60 | // This is a pointer to a Decl. | |||
61 | /// Other: | |||
62 | /// This is null. | |||
63 | void *PtrData; | |||
64 | ||||
65 | /// Kind - The actual flavor of token this is. | |||
66 | tok::TokenKind Kind; | |||
67 | ||||
68 | /// Flags - Bits we track about this token, members of the TokenFlags enum. | |||
69 | unsigned short Flags; | |||
70 | ||||
71 | public: | |||
72 | // Various flags set per token: | |||
73 | enum TokenFlags { | |||
74 | StartOfLine = 0x01, // At start of line or only after whitespace | |||
75 | // (considering the line after macro expansion). | |||
76 | LeadingSpace = 0x02, // Whitespace exists before this token (considering | |||
77 | // whitespace after macro expansion). | |||
78 | DisableExpand = 0x04, // This identifier may never be macro expanded. | |||
79 | NeedsCleaning = 0x08, // Contained an escaped newline or trigraph. | |||
80 | LeadingEmptyMacro = 0x10, // Empty macro exists before this token. | |||
81 | HasUDSuffix = 0x20, // This string or character literal has a ud-suffix. | |||
82 | HasUCN = 0x40, // This identifier contains a UCN. | |||
83 | IgnoredComma = 0x80, // This comma is not a macro argument separator (MS). | |||
84 | StringifiedInMacro = 0x100, // This string or character literal is formed by | |||
85 | // macro stringizing or charizing operator. | |||
86 | CommaAfterElided = 0x200, // The comma following this token was elided (MS). | |||
87 | IsEditorPlaceholder = 0x400, // This identifier is a placeholder. | |||
88 | IsReinjected = 0x800, // A phase 4 token that was produced before and | |||
89 | // re-added, e.g. via EnterTokenStream. Annotation | |||
90 | // tokens are *not* reinjected. | |||
91 | }; | |||
92 | ||||
93 | tok::TokenKind getKind() const { return Kind; } | |||
| ||||
94 | void setKind(tok::TokenKind K) { Kind = K; } | |||
95 | ||||
96 | /// is/isNot - Predicates to check if this token is a specific kind, as in | |||
97 | /// "if (Tok.is(tok::l_brace)) {...}". | |||
98 | bool is(tok::TokenKind K) const { return Kind == K; } | |||
99 | bool isNot(tok::TokenKind K) const { return Kind != K; } | |||
100 | bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { | |||
101 | return is(K1) || is(K2); | |||
102 | } | |||
103 | template <typename... Ts> bool isOneOf(tok::TokenKind K1, Ts... Ks) const { | |||
104 | return is(K1) || isOneOf(Ks...); | |||
105 | } | |||
106 | ||||
107 | /// Return true if this is a raw identifier (when lexing | |||
108 | /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). | |||
109 | bool isAnyIdentifier() const { | |||
110 | return tok::isAnyIdentifier(getKind()); | |||
111 | } | |||
112 | ||||
113 | /// Return true if this is a "literal", like a numeric | |||
114 | /// constant, string, etc. | |||
115 | bool isLiteral() const { | |||
116 | return tok::isLiteral(getKind()); | |||
117 | } | |||
118 | ||||
119 | /// Return true if this is any of tok::annot_* kind tokens. | |||
120 | bool isAnnotation() const { | |||
121 | return tok::isAnnotation(getKind()); | |||
122 | } | |||
123 | ||||
124 | /// Return a source location identifier for the specified | |||
125 | /// offset in the current file. | |||
126 | SourceLocation getLocation() const { | |||
127 | return SourceLocation::getFromRawEncoding(Loc); | |||
128 | } | |||
129 | unsigned getLength() const { | |||
130 | assert(!isAnnotation() && "Annotation tokens have no length field")(static_cast <bool> (!isAnnotation() && "Annotation tokens have no length field" ) ? void (0) : __assert_fail ("!isAnnotation() && \"Annotation tokens have no length field\"" , "clang/include/clang/Lex/Token.h", 130, __extension__ __PRETTY_FUNCTION__ )); | |||
131 | return UintData; | |||
132 | } | |||
133 | ||||
134 | void setLocation(SourceLocation L) { Loc = L.getRawEncoding(); } | |||
135 | void setLength(unsigned Len) { | |||
136 | assert(!isAnnotation() && "Annotation tokens have no length field")(static_cast <bool> (!isAnnotation() && "Annotation tokens have no length field" ) ? void (0) : __assert_fail ("!isAnnotation() && \"Annotation tokens have no length field\"" , "clang/include/clang/Lex/Token.h", 136, __extension__ __PRETTY_FUNCTION__ )); | |||
137 | UintData = Len; | |||
138 | } | |||
139 | ||||
140 | SourceLocation getAnnotationEndLoc() const { | |||
141 | assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token")(static_cast <bool> (isAnnotation() && "Used AnnotEndLocID on non-annotation token" ) ? void (0) : __assert_fail ("isAnnotation() && \"Used AnnotEndLocID on non-annotation token\"" , "clang/include/clang/Lex/Token.h", 141, __extension__ __PRETTY_FUNCTION__ )); | |||
142 | return SourceLocation::getFromRawEncoding(UintData ? UintData : Loc); | |||
143 | } | |||
144 | void setAnnotationEndLoc(SourceLocation L) { | |||
145 | assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token")(static_cast <bool> (isAnnotation() && "Used AnnotEndLocID on non-annotation token" ) ? void (0) : __assert_fail ("isAnnotation() && \"Used AnnotEndLocID on non-annotation token\"" , "clang/include/clang/Lex/Token.h", 145, __extension__ __PRETTY_FUNCTION__ )); | |||
146 | UintData = L.getRawEncoding(); | |||
147 | } | |||
148 | ||||
149 | SourceLocation getLastLoc() const { | |||
150 | return isAnnotation() ? getAnnotationEndLoc() : getLocation(); | |||
151 | } | |||
152 | ||||
153 | SourceLocation getEndLoc() const { | |||
154 | return isAnnotation() ? getAnnotationEndLoc() | |||
155 | : getLocation().getLocWithOffset(getLength()); | |||
156 | } | |||
157 | ||||
158 | /// SourceRange of the group of tokens that this annotation token | |||
159 | /// represents. | |||
160 | SourceRange getAnnotationRange() const { | |||
161 | return SourceRange(getLocation(), getAnnotationEndLoc()); | |||
162 | } | |||
163 | void setAnnotationRange(SourceRange R) { | |||
164 | setLocation(R.getBegin()); | |||
165 | setAnnotationEndLoc(R.getEnd()); | |||
166 | } | |||
167 | ||||
168 | const char *getName() const { return tok::getTokenName(Kind); } | |||
169 | ||||
170 | /// Reset all flags to cleared. | |||
171 | void startToken() { | |||
172 | Kind = tok::unknown; | |||
173 | Flags = 0; | |||
174 | PtrData = nullptr; | |||
175 | UintData = 0; | |||
176 | Loc = SourceLocation().getRawEncoding(); | |||
177 | } | |||
178 | ||||
179 | bool hasPtrData() const { return PtrData != nullptr; } | |||
180 | ||||
181 | IdentifierInfo *getIdentifierInfo() const { | |||
182 | assert(isNot(tok::raw_identifier) &&(static_cast <bool> (isNot(tok::raw_identifier) && "getIdentifierInfo() on a tok::raw_identifier token!") ? void (0) : __assert_fail ("isNot(tok::raw_identifier) && \"getIdentifierInfo() on a tok::raw_identifier token!\"" , "clang/include/clang/Lex/Token.h", 183, __extension__ __PRETTY_FUNCTION__ )) | |||
183 | "getIdentifierInfo() on a tok::raw_identifier token!")(static_cast <bool> (isNot(tok::raw_identifier) && "getIdentifierInfo() on a tok::raw_identifier token!") ? void (0) : __assert_fail ("isNot(tok::raw_identifier) && \"getIdentifierInfo() on a tok::raw_identifier token!\"" , "clang/include/clang/Lex/Token.h", 183, __extension__ __PRETTY_FUNCTION__ )); | |||
184 | assert(!isAnnotation() &&(static_cast <bool> (!isAnnotation() && "getIdentifierInfo() on an annotation token!" ) ? void (0) : __assert_fail ("!isAnnotation() && \"getIdentifierInfo() on an annotation token!\"" , "clang/include/clang/Lex/Token.h", 185, __extension__ __PRETTY_FUNCTION__ )) | |||
185 | "getIdentifierInfo() on an annotation token!")(static_cast <bool> (!isAnnotation() && "getIdentifierInfo() on an annotation token!" ) ? void (0) : __assert_fail ("!isAnnotation() && \"getIdentifierInfo() on an annotation token!\"" , "clang/include/clang/Lex/Token.h", 185, __extension__ __PRETTY_FUNCTION__ )); | |||
186 | if (isLiteral()) return nullptr; | |||
187 | if (is(tok::eof)) return nullptr; | |||
188 | return (IdentifierInfo*) PtrData; | |||
189 | } | |||
190 | void setIdentifierInfo(IdentifierInfo *II) { | |||
191 | PtrData = (void*) II; | |||
192 | } | |||
193 | ||||
194 | const void *getEofData() const { | |||
195 | assert(is(tok::eof))(static_cast <bool> (is(tok::eof)) ? void (0) : __assert_fail ("is(tok::eof)", "clang/include/clang/Lex/Token.h", 195, __extension__ __PRETTY_FUNCTION__)); | |||
196 | return reinterpret_cast<const void *>(PtrData); | |||
197 | } | |||
198 | void setEofData(const void *D) { | |||
199 | assert(is(tok::eof))(static_cast <bool> (is(tok::eof)) ? void (0) : __assert_fail ("is(tok::eof)", "clang/include/clang/Lex/Token.h", 199, __extension__ __PRETTY_FUNCTION__)); | |||
200 | assert(!PtrData)(static_cast <bool> (!PtrData) ? void (0) : __assert_fail ("!PtrData", "clang/include/clang/Lex/Token.h", 200, __extension__ __PRETTY_FUNCTION__)); | |||
201 | PtrData = const_cast<void *>(D); | |||
202 | } | |||
203 | ||||
204 | /// getRawIdentifier - For a raw identifier token (i.e., an identifier | |||
205 | /// lexed in raw mode), returns a reference to the text substring in the | |||
206 | /// buffer if known. | |||
207 | StringRef getRawIdentifier() const { | |||
208 | assert(is(tok::raw_identifier))(static_cast <bool> (is(tok::raw_identifier)) ? void (0 ) : __assert_fail ("is(tok::raw_identifier)", "clang/include/clang/Lex/Token.h" , 208, __extension__ __PRETTY_FUNCTION__)); | |||
209 | return StringRef(reinterpret_cast<const char *>(PtrData), getLength()); | |||
210 | } | |||
211 | void setRawIdentifierData(const char *Ptr) { | |||
212 | assert(is(tok::raw_identifier))(static_cast <bool> (is(tok::raw_identifier)) ? void (0 ) : __assert_fail ("is(tok::raw_identifier)", "clang/include/clang/Lex/Token.h" , 212, __extension__ __PRETTY_FUNCTION__)); | |||
213 | PtrData = const_cast<char*>(Ptr); | |||
214 | } | |||
215 | ||||
216 | /// getLiteralData - For a literal token (numeric constant, string, etc), this | |||
217 | /// returns a pointer to the start of it in the text buffer if known, null | |||
218 | /// otherwise. | |||
219 | const char *getLiteralData() const { | |||
220 | assert(isLiteral() && "Cannot get literal data of non-literal")(static_cast <bool> (isLiteral() && "Cannot get literal data of non-literal" ) ? void (0) : __assert_fail ("isLiteral() && \"Cannot get literal data of non-literal\"" , "clang/include/clang/Lex/Token.h", 220, __extension__ __PRETTY_FUNCTION__ )); | |||
221 | return reinterpret_cast<const char*>(PtrData); | |||
222 | } | |||
223 | void setLiteralData(const char *Ptr) { | |||
224 | assert(isLiteral() && "Cannot set literal data of non-literal")(static_cast <bool> (isLiteral() && "Cannot set literal data of non-literal" ) ? void (0) : __assert_fail ("isLiteral() && \"Cannot set literal data of non-literal\"" , "clang/include/clang/Lex/Token.h", 224, __extension__ __PRETTY_FUNCTION__ )); | |||
225 | PtrData = const_cast<char*>(Ptr); | |||
226 | } | |||
227 | ||||
228 | void *getAnnotationValue() const { | |||
229 | assert(isAnnotation() && "Used AnnotVal on non-annotation token")(static_cast <bool> (isAnnotation() && "Used AnnotVal on non-annotation token" ) ? void (0) : __assert_fail ("isAnnotation() && \"Used AnnotVal on non-annotation token\"" , "clang/include/clang/Lex/Token.h", 229, __extension__ __PRETTY_FUNCTION__ )); | |||
230 | return PtrData; | |||
231 | } | |||
232 | void setAnnotationValue(void *val) { | |||
233 | assert(isAnnotation() && "Used AnnotVal on non-annotation token")(static_cast <bool> (isAnnotation() && "Used AnnotVal on non-annotation token" ) ? void (0) : __assert_fail ("isAnnotation() && \"Used AnnotVal on non-annotation token\"" , "clang/include/clang/Lex/Token.h", 233, __extension__ __PRETTY_FUNCTION__ )); | |||
234 | PtrData = val; | |||
235 | } | |||
236 | ||||
237 | /// Set the specified flag. | |||
238 | void setFlag(TokenFlags Flag) { | |||
239 | Flags |= Flag; | |||
240 | } | |||
241 | ||||
242 | /// Get the specified flag. | |||
243 | bool getFlag(TokenFlags Flag) const { | |||
244 | return (Flags & Flag) != 0; | |||
245 | } | |||
246 | ||||
247 | /// Unset the specified flag. | |||
248 | void clearFlag(TokenFlags Flag) { | |||
249 | Flags &= ~Flag; | |||
250 | } | |||
251 | ||||
252 | /// Return the internal represtation of the flags. | |||
253 | /// | |||
254 | /// This is only intended for low-level operations such as writing tokens to | |||
255 | /// disk. | |||
256 | unsigned getFlags() const { | |||
257 | return Flags; | |||
258 | } | |||
259 | ||||
260 | /// Set a flag to either true or false. | |||
261 | void setFlagValue(TokenFlags Flag, bool Val) { | |||
262 | if (Val) | |||
263 | setFlag(Flag); | |||
264 | else | |||
265 | clearFlag(Flag); | |||
266 | } | |||
267 | ||||
268 | /// isAtStartOfLine - Return true if this token is at the start of a line. | |||
269 | /// | |||
270 | bool isAtStartOfLine() const { return getFlag(StartOfLine); } | |||
271 | ||||
272 | /// Return true if this token has whitespace before it. | |||
273 | /// | |||
274 | bool hasLeadingSpace() const { return getFlag(LeadingSpace); } | |||
275 | ||||
276 | /// Return true if this identifier token should never | |||
277 | /// be expanded in the future, due to C99 6.10.3.4p2. | |||
278 | bool isExpandDisabled() const { return getFlag(DisableExpand); } | |||
279 | ||||
280 | /// Return true if we have an ObjC keyword identifier. | |||
281 | bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; | |||
282 | ||||
283 | /// Return the ObjC keyword kind. | |||
284 | tok::ObjCKeywordKind getObjCKeywordID() const; | |||
285 | ||||
286 | /// Return true if this token has trigraphs or escaped newlines in it. | |||
287 | bool needsCleaning() const { return getFlag(NeedsCleaning); } | |||
288 | ||||
289 | /// Return true if this token has an empty macro before it. | |||
290 | /// | |||
291 | bool hasLeadingEmptyMacro() const { return getFlag(LeadingEmptyMacro); } | |||
292 | ||||
293 | /// Return true if this token is a string or character literal which | |||
294 | /// has a ud-suffix. | |||
295 | bool hasUDSuffix() const { return getFlag(HasUDSuffix); } | |||
296 | ||||
297 | /// Returns true if this token contains a universal character name. | |||
298 | bool hasUCN() const { return getFlag(HasUCN); } | |||
299 | ||||
300 | /// Returns true if this token is formed by macro by stringizing or charizing | |||
301 | /// operator. | |||
302 | bool stringifiedInMacro() const { return getFlag(StringifiedInMacro); } | |||
303 | ||||
304 | /// Returns true if the comma after this token was elided. | |||
305 | bool commaAfterElided() const { return getFlag(CommaAfterElided); } | |||
306 | ||||
307 | /// Returns true if this token is an editor placeholder. | |||
308 | /// | |||
309 | /// Editor placeholders are produced by the code-completion engine and are | |||
310 | /// represented as characters between '<#' and '#>' in the source code. The | |||
311 | /// lexer uses identifier tokens to represent placeholders. | |||
312 | bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); } | |||
313 | }; | |||
314 | ||||
315 | /// Information about the conditional stack (\#if directives) | |||
316 | /// currently active. | |||
317 | struct PPConditionalInfo { | |||
318 | /// Location where the conditional started. | |||
319 | SourceLocation IfLoc; | |||
320 | ||||
321 | /// True if this was contained in a skipping directive, e.g., | |||
322 | /// in a "\#if 0" block. | |||
323 | bool WasSkipping; | |||
324 | ||||
325 | /// True if we have emitted tokens already, and now we're in | |||
326 | /// an \#else block or something. Only useful in Skipping blocks. | |||
327 | bool FoundNonSkip; | |||
328 | ||||
329 | /// True if we've seen a \#else in this block. If so, | |||
330 | /// \#elif/\#else directives are not allowed. | |||
331 | bool FoundElse; | |||
332 | }; | |||
333 | ||||
334 | // Extra information needed for annonation tokens. | |||
335 | struct PragmaLoopHintInfo { | |||
336 | Token PragmaName; | |||
337 | Token Option; | |||
338 | ArrayRef<Token> Toks; | |||
339 | }; | |||
340 | } // end namespace clang | |||
341 | ||||
342 | #endif // LLVM_CLANG_LEX_TOKEN_H |