| 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 |