31#include "llvm/Support/Unicode.h"
38struct LocalizedState {
40 enum Kind { NonLocalized, Localized } K;
41 LocalizedState(Kind InK) : K(InK) {}
44 bool isLocalized()
const {
return K == Localized; }
45 bool isNonLocalized()
const {
return K == NonLocalized; }
47 static LocalizedState getLocalized() {
return LocalizedState(Localized); }
48 static LocalizedState getNonLocalized() {
49 return LocalizedState(NonLocalized);
53 bool operator==(
const LocalizedState &
X)
const {
return K ==
X.K; }
56 void Profile(llvm::FoldingSetNodeID &ID)
const {
ID.AddInteger(K); }
59class NonLocalizedStringChecker
60 :
public Checker<check::PreCall, check::PostCall, check::PreObjCMessage,
61 check::PostObjCMessage,
62 check::PostStmt<ObjCStringLiteral>> {
64 mutable std::unique_ptr<BugType> BT;
68 llvm::DenseMap<Selector, uint8_t>> UIMethods;
70 mutable llvm::SmallSet<std::pair<const IdentifierInfo *, Selector>, 12> LSM;
72 mutable llvm::SmallSet<const IdentifierInfo *, 5> LSF;
75 void initLocStringsMethods(
ASTContext &Ctx)
const;
82 bool isAnnotatedAsReturningLocalized(
const Decl *D)
const;
83 bool isAnnotatedAsTakingLocalized(
const Decl *D)
const;
85 int argumentNumber = 0)
const;
87 int getLocalizedArgumentForSelector(
const IdentifierInfo *Receiver,
91 NonLocalizedStringChecker();
96 bool IsAggressive =
false;
110NonLocalizedStringChecker::NonLocalizedStringChecker() {
111 BT.reset(
new BugType(
this,
"Unlocalizable string",
112 "Localizability Issue (Apple)"));
122 NonLocalizedStringBRVisitor(
const MemRegion *NonLocalizedString)
123 : NonLocalizedString(NonLocalizedString), Satisfied(
false) {
124 assert(NonLocalizedString);
131 void Profile(llvm::FoldingSetNodeID &ID)
const override {
132 ID.Add(NonLocalizedString);
137#define NEW_RECEIVER(receiver) \
138 llvm::DenseMap<Selector, uint8_t> &receiver##M = \
139 UIMethods.insert({&Ctx.Idents.get(#receiver), \
140 llvm::DenseMap<Selector, uint8_t>()}) \
142#define ADD_NULLARY_METHOD(receiver, method, argument) \
143 receiver##M.insert( \
144 {Ctx.Selectors.getNullarySelector(&Ctx.Idents.get(#method)), argument});
145#define ADD_UNARY_METHOD(receiver, method, argument) \
146 receiver##M.insert( \
147 {Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(#method)), argument});
148#define ADD_METHOD(receiver, method_list, count, argument) \
149 receiver##M.insert({Ctx.Selectors.getSelector(count, method_list), argument});
153void NonLocalizedStringChecker::initUIMethods(
ASTContext &Ctx)
const {
154 if (!UIMethods.empty())
165 ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemTag, 3, 0)
169 ADD_METHOD(UITabBarItem, initWithTitleUITabBarItemImage, 3, 0)
182 ADD_METHOD(UITableViewRowAction, rowActionWithStyleUITableViewRowAction, 3, 1)
194 ADD_METHOD(NSButton, radioButtonWithTitleNSButton, 3, 0)
198 ADD_METHOD(NSButton, buttonWithTitleNSButtonImage, 4, 0)
202 ADD_METHOD(NSButton, checkboxWithTitleNSButton, 3, 0)
206 ADD_METHOD(NSButton, buttonWithTitleNSButtonTarget, 3, 0)
225 ADD_METHOD(NSBrowser, setTitleNSBrowser, 2, 0)
236 ADD_METHOD(UIAlertAction, actionWithTitleUIAlertAction, 3, 0)
242 ADD_METHOD(NSPopUpButton, insertItemWithTitleNSPopUpButton, 2, 0)
251 ADD_METHOD(NSTableViewRowAction, rowActionWithStyleNSTableViewRowAction, 3, 1)
283 ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)
286 ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0)
311 ADD_METHOD(NSMatrix, setToolTipNSMatrix, 2, 0)
327 ADD_METHOD(UIMenuItem, initWithTitleUIMenuItem, 2, 0)
334 ADD_METHOD(UIAlertController, alertControllerWithTitleUIAlertController, 3, 1)
344 initWithTypeUIApplicationShortcutItemIcon, 5, 1)
347 ADD_METHOD(UIApplicationShortcutItem, initWithTypeUIApplicationShortcutItem,
354 &Ctx.
Idents.
get(
"destructiveButtonTitle"),
356 ADD_METHOD(UIActionSheet, initWithTitleUIActionSheet, 5, 0)
365 initWithNameUIAccessibilityCustomAction, 3, 0)
392 ADD_METHOD(NSAttributedString, initWithStringNSAttributedString, 2, 0)
401 ADD_METHOD(UIKeyCommand, keyCommandWithInputUIKeyCommand, 4, 3)
411 &Ctx.
Idents.
get(
"informativeTextWithFormat")};
412 ADD_METHOD(NSAlert, alertWithMessageTextNSAlert, 5, 0)
431 ADD_METHOD(NSWindow, minFrameWidthWithTitleNSWindow, 2, 0)
438 IdentifierInfo *addOptionWithTitleUIDocumentMenuViewController[] = {
442 addOptionWithTitleUIDocumentMenuViewController, 4, 0)
454 ADD_METHOD(UIAlertView, initWithTitleUIAlertView, 5, 0)
484 ADD_METHOD(NSSegmentedCell, setLabelNSSegmentedCell, 2, 0)
487 ADD_METHOD(NSSegmentedCell, setToolTipNSSegmentedCell, 2, 0)
498 ADD_METHOD(NSMenuItem, initWithTitleNSMenuItem, 3, 0)
505 ADD_METHOD(NSPopUpButtonCell, initTextCellNSPopUpButtonCell, 2, 0)
509 ADD_METHOD(NSPopUpButtonCell, insertItemWithTitleNSPopUpButtonCell, 2, 0)
522 ADD_METHOD(NSMenu, insertItemWithTitleNSMenu, 4, 0)
526 ADD_METHOD(NSMenu, addItemWithTitleNSMenu, 3, 0)
542 IdentifierInfo *actionWithIdentifierNSUserNotificationAction[] = {
545 actionWithIdentifierNSUserNotificationAction, 2, 1)
555 ADD_METHOD(UIBarButtonItem, initWithTitleUIBarButtonItem, 4, 0)
564 ADD_METHOD(UISegmentedControl, insertSegmentWithTitleUISegmentedControl, 3, 0)
567 ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)
571 *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = {
572 &Ctx.
Idents.
get(
"initWithItemLoadingToken"),
574 ADD_METHOD(NSAccessibilityCustomRotorItemResult,
575 initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1)
582 ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3,
590 initWithLabelNSAccessibilityCustomRotor, 2, 0)
601 initWithNameNSAccessibilityCustomAction, 2, 0)
602 IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = {
606 initWithNameTargetNSAccessibilityCustomAction, 3, 0)
610#define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name));
611#define LSM_INSERT_NULLARY(receiver, 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) \
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) \
618 LSM.insert({&Ctx.Idents.get(receiver), \
619 Ctx.Selectors.getSelector(arguments, method_list)});
622void NonLocalizedStringChecker::initLocStringsMethods(
ASTContext &Ctx)
const {
640 LSF_INSERT(
"CFDateFormatterCreateStringWithDate");
641 LSF_INSERT(
"CFDateFormatterCreateStringWithAbsoluteTime");
642 LSF_INSERT(
"CFNumberFormatterCreateStringWithNumber");
647bool NonLocalizedStringChecker::isAnnotatedAsReturningLocalized(
648 const Decl *D)
const {
654 return Ann->getAnnotation() ==
"returns_localized_nsstring";
660bool NonLocalizedStringChecker::isAnnotatedAsTakingLocalized(
661 const Decl *D)
const {
667 return Ann->getAnnotation() ==
"takes_localized_nsstring";
672bool NonLocalizedStringChecker::hasLocalizedState(
SVal S,
676 const LocalizedState *LS =
C.getState()->get<LocalizedMemMap>(mt);
677 if (LS && LS->isLocalized())
685bool NonLocalizedStringChecker::hasNonLocalizedState(
SVal S,
689 const LocalizedState *LS =
C.getState()->get<LocalizedMemMap>(mt);
690 if (LS && LS->isNonLocalized())
697void NonLocalizedStringChecker::setLocalizedState(
const SVal S,
702 C.getState()->set<LocalizedMemMap>(mt, LocalizedState::getLocalized());
703 C.addTransition(State);
708void NonLocalizedStringChecker::setNonLocalizedState(
const SVal S,
713 mt, LocalizedState::getNonLocalized());
714 C.addTransition(State);
720 return StringRef(name).lower().find(
"debug") != StringRef::npos;
728 const Decl *D =
C.getCurrentAnalysisDeclContext()->getDecl();
732 if (
auto *ND = dyn_cast<NamedDecl>(D)) {
739 if (
auto *CD = dyn_cast<ObjCContainerDecl>(DC)) {
749void NonLocalizedStringChecker::reportLocalizationError(
758 "UnlocalizedString");
759 ExplodedNode *ErrNode =
C.addTransition(
C.getState(),
C.getPredecessor(), &Tag);
765 auto R = std::make_unique<PathSensitiveBugReport>(
766 *BT,
"User-facing text should use localized string macro", ErrNode);
767 if (argumentNumber) {
772 R->markInteresting(S);
776 R->addVisitor(std::make_unique<NonLocalizedStringBRVisitor>(
StringRegion));
778 C.emitReport(std::move(R));
783int NonLocalizedStringChecker::getLocalizedArgumentForSelector(
785 auto method = UIMethods.find(Receiver);
787 if (method == UIMethods.end())
790 auto argumentIterator = method->getSecond().find(S);
792 if (argumentIterator == method->getSecond().end())
795 int argumentNumber = argumentIterator->getSecond();
796 return argumentNumber;
800void NonLocalizedStringChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
802 initUIMethods(
C.getASTContext());
811 std::string SelectorString = S.getAsString();
812 StringRef SelectorName = SelectorString;
813 assert(!SelectorName.empty());
815 if (odInfo->
isStr(
"NSString")) {
819 if (!(SelectorName.startswith(
"drawAtPoint") ||
820 SelectorName.startswith(
"drawInRect") ||
821 SelectorName.startswith(
"drawWithRect")))
826 bool isNonLocalized = hasNonLocalizedState(svTitle,
C);
828 if (isNonLocalized) {
829 reportLocalizationError(svTitle, msg,
C);
833 int argumentNumber = getLocalizedArgumentForSelector(odInfo, S);
835 while (argumentNumber < 0 && OD->getSuperClass() !=
nullptr) {
837 argumentNumber = getLocalizedArgumentForSelector(
P->getIdentifier(), S);
838 if (argumentNumber >= 0)
841 if (argumentNumber < 0) {
843 argumentNumber = getLocalizedArgumentForSelector(OD->
getIdentifier(), S);
847 if (argumentNumber < 0) {
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])) {
861 if (argumentNumber < 0)
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) ||
873 if (!IsAggressive && llvm::sys::unicode::columnWidthUTF8(stringValue) < 2)
877 bool isNonLocalized = hasNonLocalizedState(svTitle,
C);
879 if (isNonLocalized) {
880 reportLocalizationError(svTitle, msg,
C, argumentNumber + 1);
884void NonLocalizedStringChecker::checkPreCall(
const CallEvent &Call,
886 const auto *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
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);
915 return ClsName == &Ctx.
Idents.
get(
"NSString") ||
916 ClsName == &Ctx.
Idents.
get(
"NSMutableString");
924void NonLocalizedStringChecker::checkPostCall(
const CallEvent &Call,
926 initLocStringsMethods(
C.getASTContext());
928 if (!
Call.getOriginExpr())
936 for (
unsigned i = 0; i <
Call.getNumArgs(); ++i) {
938 if (hasLocalizedState(argValue,
C)) {
940 setLocalizedState(sv,
C);
953 if (isAnnotatedAsReturningLocalized(D) || LSF.contains(
Identifier)) {
954 setLocalizedState(sv,
C);
956 !hasLocalizedState(sv,
C)) {
958 setNonLocalizedState(sv,
C);
961 dyn_cast_or_null<SymbolicRegion>(sv.
getAsRegion());
963 setNonLocalizedState(sv,
C);
970void NonLocalizedStringChecker::checkPostObjCMessage(
const ObjCMethodCall &msg,
972 initLocStringsMethods(
C.getASTContext());
983 std::string SelectorName = S.getAsString();
985 std::pair<const IdentifierInfo *, Selector> MethodDescription = {odInfo, S};
987 if (LSM.count(MethodDescription) ||
988 isAnnotatedAsReturningLocalized(msg.
getDecl())) {
990 setLocalizedState(sv,
C);
997 SVal sv =
C.getSVal(SL);
998 setNonLocalizedState(sv,
C);
1002NonLocalizedStringBRVisitor::VisitNode(
const ExplodedNode *Succ,
1012 auto *LiteralExpr = dyn_cast<ObjCStringLiteral>(Point->getStmt());
1017 if (LiteralSVal.
getAsRegion() != NonLocalizedString)
1028 auto Piece = std::make_shared<PathDiagnosticEventPiece>(
1029 L,
"Non-localized string literal here");
1030 Piece->addRange(LiteralExpr->getSourceRange());
1032 return std::move(Piece);
1036class EmptyLocalizationContextChecker
1037 :
public Checker<check::ASTDecl<ObjCImplementationDecl>> {
1051 : MD(InMD), BR(InBR), Mgr(InMgr),
Checker(
Checker), DCtx(InDCtx) {}
1053 void VisitStmt(
const Stmt *S) { VisitChildren(S); }
1059 void VisitChildren(
const Stmt *S) {
1060 for (
const Stmt *Child : S->children()) {
1073void EmptyLocalizationContextChecker::checkASTDecl(
1080 const Stmt *Body = M->getBody();
1082 assert(M->isSynthesizedAccessorStub());
1086 MethodCrawler MC(M->getCanonicalDecl(), BR,
this, Mgr, DCtx);
1106void EmptyLocalizationContextChecker::MethodCrawler::VisitObjCMessageExpr(
1117 if (!(odInfo->
isStr(
"NSBundle") &&
1119 "localizedStringForKey:value:table:")) {
1132 std::pair<FileID, unsigned> SLInfo =
1145 std::optional<llvm::MemoryBufferRef> BF =
1150 Lexer TheLexer(SL, LangOpts, BF->getBufferStart(),
1151 BF->getBufferStart() + SLInfo.second, BF->getBufferEnd());
1156 while (!TheLexer.LexFromRawLexer(I)) {
1157 if (I.
getKind() == tok::l_paren)
1159 if (I.
getKind() == tok::r_paren) {
1168 if (Result.getRawIdentifier().equals(
"nil")) {
1169 reportEmptyContextError(ME);
1178 StringRef(Result.getLiteralData(), Result.getLength()).trim(
'"');
1180 if ((Comment.trim().size() == 0 && Comment.size() > 0) ||
1182 reportEmptyContextError(ME);
1186void EmptyLocalizationContextChecker::MethodCrawler::reportEmptyContextError(
1190 "Localizability Issue (Apple)",
1191 "Localized string macro should include a non-empty "
1192 "comment for translators",
1197class PluralMisuseChecker :
public Checker<check::ASTCodeBody> {
1211 bool InMatchingStatement =
false;
1218 bool VisitIfStmt(
const IfStmt *I);
1219 bool EndVisitIfStmt(
IfStmt *I);
1220 bool TraverseIfStmt(
IfStmt *x);
1223 bool VisitCallExpr(
const CallExpr *CE);
1227 void reportPluralMisuseError(
const Stmt *S)
const;
1228 bool isCheckingPlurality(
const Expr *E)
const;
1235 Visitor.TraverseDecl(
const_cast<Decl *
>(D));
1244bool PluralMisuseChecker::MethodCrawler::isCheckingPlurality(
1249 if (
const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
1250 const Expr *InitExpr = VD->getInit();
1257 if (VD->getName().lower().find(
"plural") != StringRef::npos ||
1258 VD->getName().lower().find(
"singular") != StringRef::npos) {
1271 llvm::APInt
Value = IL->getValue();
1283bool PluralMisuseChecker::MethodCrawler::VisitCallExpr(
const CallExpr *CE) {
1284 if (InMatchingStatement) {
1286 std::string NormalizedName =
1287 StringRef(FD->getNameInfo().getAsString()).lower();
1288 if (NormalizedName.find(
"loc") != std::string::npos) {
1290 if (isa<ObjCStringLiteral>(Arg))
1291 reportPluralMisuseError(CE);
1304bool PluralMisuseChecker::MethodCrawler::VisitObjCMessageExpr(
1312 if (odInfo->
isStr(
"NSBundle") &&
1314 if (InMatchingStatement) {
1315 reportPluralMisuseError(ME);
1322bool PluralMisuseChecker::MethodCrawler::TraverseIfStmt(
IfStmt *I) {
1324 return EndVisitIfStmt(I);
1330bool PluralMisuseChecker::MethodCrawler::EndVisitIfStmt(
IfStmt *I) {
1331 MatchingStatements.pop_back();
1332 if (!MatchingStatements.empty()) {
1333 if (MatchingStatements.back() !=
nullptr) {
1334 InMatchingStatement =
true;
1338 InMatchingStatement =
false;
1342bool PluralMisuseChecker::MethodCrawler::VisitIfStmt(
const IfStmt *I) {
1348 MatchingStatements.push_back(I);
1349 InMatchingStatement =
true;
1351 MatchingStatements.push_back(
nullptr);
1352 InMatchingStatement =
false;
1359bool PluralMisuseChecker::MethodCrawler::TraverseConditionalOperator(
1362 MatchingStatements.pop_back();
1363 if (!MatchingStatements.empty()) {
1364 if (MatchingStatements.back() !=
nullptr)
1365 InMatchingStatement =
true;
1367 InMatchingStatement =
false;
1369 InMatchingStatement =
false;
1374bool PluralMisuseChecker::MethodCrawler::VisitConditionalOperator(
1378 MatchingStatements.push_back(
C);
1379 InMatchingStatement =
true;
1381 MatchingStatements.push_back(
nullptr);
1382 InMatchingStatement =
false;
1387void PluralMisuseChecker::MethodCrawler::reportPluralMisuseError(
1388 const Stmt *S)
const {
1391 "Localizability Issue (Apple)",
1392 "Plural cases are not supported across all languages. "
1393 "Use a .stringsdict file instead",
1401void ento::registerNonLocalizedStringChecker(
CheckerManager &mgr) {
1402 NonLocalizedStringChecker *checker =
1404 checker->IsAggressive =
1406 checker,
"AggressiveReport");
1409bool ento::shouldRegisterNonLocalizedStringChecker(
const CheckerManager &mgr) {
1413void ento::registerEmptyLocalizationContextChecker(
CheckerManager &mgr) {
1417bool ento::shouldRegisterEmptyLocalizationContextChecker(
1426bool ento::shouldRegisterPluralMisuseChecker(
const CheckerManager &mgr) {
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
#define LSM_INSERT_SELECTOR(receiver, method_list, arguments)
#define NEW_RECEIVER(receiver)
#define LSM_INSERT_NULLARY(receiver, method_name)
#define LSF_INSERT(function_name)
#define ADD_UNARY_METHOD(receiver, method, argument)
#define ADD_METHOD(receiver, method_list, count, argument)
#define LSM_INSERT_UNARY(receiver, method_name)
static bool isDebuggingContext(CheckerContext &C)
Returns true when, heuristically, the analyzer may be analyzing debugging code.
static bool isDebuggingName(std::string name)
static bool isNSStringType(QualType T, ASTContext &Ctx)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
A builtin binary operation expression such as "x + y" or "x <= y".
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
ConditionalOperator - The ?: ternary operator.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
DeclContext * getDeclContext()
specific_attr_iterator< T > specific_attr_end() const
specific_attr_iterator< T > specific_attr_begin() const
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a function declaration or definition.
One of these records is kept for each identifier that is lexed.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
IfStmt - This represents an if/then/else.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
method_range methods() const
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Represents an ObjC class declaration.
all_protocol_range all_referenced_protocols() const
ObjCInterfaceDecl * getSuperClass() const
An expression that sends a message to the given Objective-C object or class.
Selector getSelector() const
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a pointer to an Objective C object.
const ObjCObjectType * getObjectType() const
Gets the type pointed to by this ObjC pointer.
ObjCInterfaceDecl * getInterface() const
Gets the interface declaration for this object type, if the base type really is an interface.
ObjCStringLiteral, used for Objective-C string literals i.e.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Smart pointer class that efficiently represents Objective-C method names.
std::string getAsString() const
Derive the full selector name (e.g.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
SourceLocation getSpellingLoc() const
This is a discriminated union of FileInfo and ExpansionInfo.
const ExpansionInfo & getExpansion() const
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Token - This structure provides full information about a lexed token.
tok::TokenKind getKind() const
const T * getAs() const
Member-template getAs<specific type>'.
Represents a variable declaration or definition.
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
SourceManager & getSourceManager() override
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
Represents an abstract call to a function or method along a particular path.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
SVal getReturnValue() const
Returns the return value of the call.
virtual SourceRange getSourceRange() const
Returns a source range for the entire call, suitable for outputting in diagnostics.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
MemRegion - The root abstract class for all memory regions.
Represents any expression that calls an Objective-C method.
const ObjCMethodDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
bool isInstanceMessage() const
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Selector getSelector() const
The region associated with an ObjCStringLiteral.
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
const MemRegion * getAsRegion() const
StringRegion - Region associated with a StringLiteral.
SymbolicRegion - A special, "non-concrete" region.
llvm::PointerUnion< const LocationContext *, AnalysisDeclContext * > LocationOrAnalysisDeclContext
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
bool isStringLiteral(TokenKind K)
Return true if this is a C or C++ string-literal (or C++11 user-defined-string-literal) token.
bool isAnyIdentifier(TokenKind K)
Return true if this is a raw identifier or an identifier kind.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ C
Languages that the frontend can parse and compile.