1940c770dSArtem Dergachev //===- NumberObjectConversionChecker.cpp -------------------------*- C++ -*-==//
2940c770dSArtem Dergachev //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6940c770dSArtem Dergachev //
7940c770dSArtem Dergachev //===----------------------------------------------------------------------===//
8940c770dSArtem Dergachev //
9940c770dSArtem Dergachev // This file defines NumberObjectConversionChecker, which checks for a
10940c770dSArtem Dergachev // particular common mistake when dealing with numbers represented as objects
11940c770dSArtem Dergachev // passed around by pointers. Namely, the language allows to reinterpret the
12940c770dSArtem Dergachev // pointer as a number directly, often without throwing any warnings,
13940c770dSArtem Dergachev // but in most cases the result of such conversion is clearly unexpected,
14940c770dSArtem Dergachev // as pointer value, rather than number value represented by the pointee object,
15940c770dSArtem Dergachev // becomes the result of such operation.
16940c770dSArtem Dergachev //
17940c770dSArtem Dergachev // Currently the checker supports the Objective-C NSNumber class,
18940c770dSArtem Dergachev // and the OSBoolean class found in macOS low-level code; the latter
19940c770dSArtem Dergachev // can only hold boolean values.
20940c770dSArtem Dergachev //
21940c770dSArtem Dergachev // This checker has an option "Pedantic" (boolean), which enables detection of
22940c770dSArtem Dergachev // more conversion patterns (which are most likely more harmless, and therefore
23940c770dSArtem Dergachev // are more likely to produce false positives) - disabled by default,
24940c770dSArtem Dergachev // enabled with `-analyzer-config osx.NumberObjectConversion:Pedantic=true'.
25940c770dSArtem Dergachev //
26940c770dSArtem Dergachev //===----------------------------------------------------------------------===//
27940c770dSArtem Dergachev
2876a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
29940c770dSArtem Dergachev #include "clang/ASTMatchers/ASTMatchFinder.h"
30940c770dSArtem Dergachev #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
31940c770dSArtem Dergachev #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
32940c770dSArtem Dergachev #include "clang/StaticAnalyzer/Core/Checker.h"
33940c770dSArtem Dergachev #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
34940c770dSArtem Dergachev #include "clang/Lex/Lexer.h"
35940c770dSArtem Dergachev #include "llvm/ADT/APSInt.h"
36940c770dSArtem Dergachev
37940c770dSArtem Dergachev using namespace clang;
38940c770dSArtem Dergachev using namespace ento;
39940c770dSArtem Dergachev using namespace ast_matchers;
40940c770dSArtem Dergachev
41940c770dSArtem Dergachev namespace {
42940c770dSArtem Dergachev
43940c770dSArtem Dergachev class NumberObjectConversionChecker : public Checker<check::ASTCodeBody> {
44940c770dSArtem Dergachev public:
45940c770dSArtem Dergachev bool Pedantic;
46940c770dSArtem Dergachev
47940c770dSArtem Dergachev void checkASTCodeBody(const Decl *D, AnalysisManager &AM,
48940c770dSArtem Dergachev BugReporter &BR) const;
49940c770dSArtem Dergachev };
50940c770dSArtem Dergachev
51940c770dSArtem Dergachev class Callback : public MatchFinder::MatchCallback {
52940c770dSArtem Dergachev const NumberObjectConversionChecker *C;
53940c770dSArtem Dergachev BugReporter &BR;
54940c770dSArtem Dergachev AnalysisDeclContext *ADC;
55940c770dSArtem Dergachev
56940c770dSArtem Dergachev public:
Callback(const NumberObjectConversionChecker * C,BugReporter & BR,AnalysisDeclContext * ADC)57940c770dSArtem Dergachev Callback(const NumberObjectConversionChecker *C,
58940c770dSArtem Dergachev BugReporter &BR, AnalysisDeclContext *ADC)
59940c770dSArtem Dergachev : C(C), BR(BR), ADC(ADC) {}
602c2a297bSLogan Smith void run(const MatchFinder::MatchResult &Result) override;
61940c770dSArtem Dergachev };
62940c770dSArtem Dergachev } // end of anonymous namespace
63940c770dSArtem Dergachev
run(const MatchFinder::MatchResult & Result)64940c770dSArtem Dergachev void Callback::run(const MatchFinder::MatchResult &Result) {
65e14d8818SArtem Dergachev bool IsPedanticMatch =
66e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<Stmt>("pedantic") != nullptr);
67940c770dSArtem Dergachev if (IsPedanticMatch && !C->Pedantic)
68940c770dSArtem Dergachev return;
69940c770dSArtem Dergachev
70940c770dSArtem Dergachev ASTContext &ACtx = ADC->getASTContext();
71940c770dSArtem Dergachev
72940c770dSArtem Dergachev if (const Expr *CheckIfNull =
73940c770dSArtem Dergachev Result.Nodes.getNodeAs<Expr>("check_if_null")) {
74e14d8818SArtem Dergachev // Unless the macro indicates that the intended type is clearly not
75e14d8818SArtem Dergachev // a pointer type, we should avoid warning on comparing pointers
76e14d8818SArtem Dergachev // to zero literals in non-pedantic mode.
77e14d8818SArtem Dergachev // FIXME: Introduce an AST matcher to implement the macro-related logic?
78e14d8818SArtem Dergachev bool MacroIndicatesWeShouldSkipTheCheck = false;
79f2ceec48SStephen Kelly SourceLocation Loc = CheckIfNull->getBeginLoc();
80940c770dSArtem Dergachev if (Loc.isMacroID()) {
81940c770dSArtem Dergachev StringRef MacroName = Lexer::getImmediateMacroName(
82940c770dSArtem Dergachev Loc, ACtx.getSourceManager(), ACtx.getLangOpts());
83e14d8818SArtem Dergachev if (MacroName == "NULL" || MacroName == "nil")
84940c770dSArtem Dergachev return;
85e14d8818SArtem Dergachev if (MacroName == "YES" || MacroName == "NO")
86e14d8818SArtem Dergachev MacroIndicatesWeShouldSkipTheCheck = true;
87e14d8818SArtem Dergachev }
88e14d8818SArtem Dergachev if (!MacroIndicatesWeShouldSkipTheCheck) {
89407659abSFangrui Song Expr::EvalResult EVResult;
90940c770dSArtem Dergachev if (CheckIfNull->IgnoreParenCasts()->EvaluateAsInt(
91407659abSFangrui Song EVResult, ACtx, Expr::SE_AllowSideEffects)) {
92407659abSFangrui Song llvm::APSInt Result = EVResult.Val.getInt();
93940c770dSArtem Dergachev if (Result == 0) {
94940c770dSArtem Dergachev if (!C->Pedantic)
95940c770dSArtem Dergachev return;
96940c770dSArtem Dergachev IsPedanticMatch = true;
97940c770dSArtem Dergachev }
98940c770dSArtem Dergachev }
99940c770dSArtem Dergachev }
100940c770dSArtem Dergachev }
101940c770dSArtem Dergachev
102e14d8818SArtem Dergachev const Stmt *Conv = Result.Nodes.getNodeAs<Stmt>("conv");
103e14d8818SArtem Dergachev assert(Conv);
104e14d8818SArtem Dergachev
105e14d8818SArtem Dergachev const Expr *ConvertedCObject = Result.Nodes.getNodeAs<Expr>("c_object");
106e14d8818SArtem Dergachev const Expr *ConvertedCppObject = Result.Nodes.getNodeAs<Expr>("cpp_object");
107e14d8818SArtem Dergachev const Expr *ConvertedObjCObject = Result.Nodes.getNodeAs<Expr>("objc_object");
108e14d8818SArtem Dergachev bool IsCpp = (ConvertedCppObject != nullptr);
109e14d8818SArtem Dergachev bool IsObjC = (ConvertedObjCObject != nullptr);
110e14d8818SArtem Dergachev const Expr *Obj = IsObjC ? ConvertedObjCObject
111e14d8818SArtem Dergachev : IsCpp ? ConvertedCppObject
112e14d8818SArtem Dergachev : ConvertedCObject;
113e14d8818SArtem Dergachev assert(Obj);
114e14d8818SArtem Dergachev
115e14d8818SArtem Dergachev bool IsComparison =
116e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<Stmt>("comparison") != nullptr);
117e14d8818SArtem Dergachev
118e14d8818SArtem Dergachev bool IsOSNumber =
119e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<Decl>("osnumber") != nullptr);
120e14d8818SArtem Dergachev
121e14d8818SArtem Dergachev bool IsInteger =
122e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<QualType>("int_type") != nullptr);
123e14d8818SArtem Dergachev bool IsObjCBool =
124e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<QualType>("objc_bool_type") != nullptr);
125e14d8818SArtem Dergachev bool IsCppBool =
126e14d8818SArtem Dergachev (Result.Nodes.getNodeAs<QualType>("cpp_bool_type") != nullptr);
127e14d8818SArtem Dergachev
128940c770dSArtem Dergachev llvm::SmallString<64> Msg;
129940c770dSArtem Dergachev llvm::raw_svector_ostream OS(Msg);
130940c770dSArtem Dergachev
131e14d8818SArtem Dergachev // Remove ObjC ARC qualifiers.
132e14d8818SArtem Dergachev QualType ObjT = Obj->getType().getUnqualifiedType();
133e14d8818SArtem Dergachev
134e14d8818SArtem Dergachev // Remove consts from pointers.
135e14d8818SArtem Dergachev if (IsCpp) {
136e14d8818SArtem Dergachev assert(ObjT.getCanonicalType()->isPointerType());
137e14d8818SArtem Dergachev ObjT = ACtx.getPointerType(
138e14d8818SArtem Dergachev ObjT->getPointeeType().getCanonicalType().getUnqualifiedType());
139e14d8818SArtem Dergachev }
140e14d8818SArtem Dergachev
141e14d8818SArtem Dergachev if (IsComparison)
142e14d8818SArtem Dergachev OS << "Comparing ";
143940c770dSArtem Dergachev else
144e14d8818SArtem Dergachev OS << "Converting ";
145940c770dSArtem Dergachev
146cfb81690SNathan James OS << "a pointer value of type '" << ObjT << "' to a ";
147e14d8818SArtem Dergachev
148e14d8818SArtem Dergachev std::string EuphemismForPlain = "primitive";
149e14d8818SArtem Dergachev std::string SuggestedApi = IsObjC ? (IsInteger ? "" : "-boolValue")
150e14d8818SArtem Dergachev : IsCpp ? (IsOSNumber ? "" : "getValue()")
151e14d8818SArtem Dergachev : "CFNumberGetValue()";
152e14d8818SArtem Dergachev if (SuggestedApi.empty()) {
153e14d8818SArtem Dergachev // A generic message if we're not sure what API should be called.
154e14d8818SArtem Dergachev // FIXME: Pattern-match the integer type to make a better guess?
155e14d8818SArtem Dergachev SuggestedApi =
156e14d8818SArtem Dergachev "a method on '" + ObjT.getAsString() + "' to get the scalar value";
157e14d8818SArtem Dergachev // "scalar" is not quite correct or common, but some documentation uses it
158e14d8818SArtem Dergachev // when describing object methods we suggest. For consistency, we use
159e14d8818SArtem Dergachev // "scalar" in the whole sentence when we need to use this word in at least
160e14d8818SArtem Dergachev // one place, otherwise we use "primitive".
161e14d8818SArtem Dergachev EuphemismForPlain = "scalar";
162940c770dSArtem Dergachev }
163e14d8818SArtem Dergachev
164e14d8818SArtem Dergachev if (IsInteger)
165e14d8818SArtem Dergachev OS << EuphemismForPlain << " integer value";
166e14d8818SArtem Dergachev else if (IsObjCBool)
167e14d8818SArtem Dergachev OS << EuphemismForPlain << " BOOL value";
168e14d8818SArtem Dergachev else if (IsCppBool)
169e14d8818SArtem Dergachev OS << EuphemismForPlain << " bool value";
170e14d8818SArtem Dergachev else // Branch condition?
171e14d8818SArtem Dergachev OS << EuphemismForPlain << " boolean value";
172e14d8818SArtem Dergachev
173e14d8818SArtem Dergachev
174e14d8818SArtem Dergachev if (IsPedanticMatch)
175e14d8818SArtem Dergachev OS << "; instead, either compare the pointer to "
176e14d8818SArtem Dergachev << (IsObjC ? "nil" : IsCpp ? "nullptr" : "NULL") << " or ";
177e14d8818SArtem Dergachev else
178e14d8818SArtem Dergachev OS << "; did you mean to ";
179e14d8818SArtem Dergachev
180e14d8818SArtem Dergachev if (IsComparison)
181e14d8818SArtem Dergachev OS << "compare the result of calling " << SuggestedApi;
182e14d8818SArtem Dergachev else
183e14d8818SArtem Dergachev OS << "call " << SuggestedApi;
184e14d8818SArtem Dergachev
185e14d8818SArtem Dergachev if (!IsPedanticMatch)
186e14d8818SArtem Dergachev OS << "?";
187940c770dSArtem Dergachev
188940c770dSArtem Dergachev BR.EmitBasicReport(
189940c770dSArtem Dergachev ADC->getDecl(), C, "Suspicious number object conversion", "Logic error",
190940c770dSArtem Dergachev OS.str(),
191940c770dSArtem Dergachev PathDiagnosticLocation::createBegin(Obj, BR.getSourceManager(), ADC),
192940c770dSArtem Dergachev Conv->getSourceRange());
193940c770dSArtem Dergachev }
194940c770dSArtem Dergachev
checkASTCodeBody(const Decl * D,AnalysisManager & AM,BugReporter & BR) const195940c770dSArtem Dergachev void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
196940c770dSArtem Dergachev AnalysisManager &AM,
197940c770dSArtem Dergachev BugReporter &BR) const {
198e14d8818SArtem Dergachev // Currently this matches CoreFoundation opaque pointer typedefs.
199*888673b6SJonas Devlieghere auto CSuspiciousNumberObjectExprM =
200*888673b6SJonas Devlieghere expr(ignoringParenImpCasts(
201*888673b6SJonas Devlieghere expr(hasType(
202*888673b6SJonas Devlieghere typedefType(hasDeclaration(anyOf(
203*888673b6SJonas Devlieghere typedefDecl(hasName("CFNumberRef")),
204*888673b6SJonas Devlieghere typedefDecl(hasName("CFBooleanRef")))))))
205e14d8818SArtem Dergachev .bind("c_object")));
206940c770dSArtem Dergachev
207e14d8818SArtem Dergachev // Currently this matches XNU kernel number-object pointers.
208e14d8818SArtem Dergachev auto CppSuspiciousNumberObjectExprM =
209940c770dSArtem Dergachev expr(ignoringParenImpCasts(
210940c770dSArtem Dergachev expr(hasType(hasCanonicalType(
211940c770dSArtem Dergachev pointerType(pointee(hasCanonicalType(
212940c770dSArtem Dergachev recordType(hasDeclaration(
213e14d8818SArtem Dergachev anyOf(
214e14d8818SArtem Dergachev cxxRecordDecl(hasName("OSBoolean")),
215e14d8818SArtem Dergachev cxxRecordDecl(hasName("OSNumber"))
216e14d8818SArtem Dergachev .bind("osnumber"))))))))))
217e14d8818SArtem Dergachev .bind("cpp_object")));
218940c770dSArtem Dergachev
219e14d8818SArtem Dergachev // Currently this matches NeXTSTEP number objects.
220e14d8818SArtem Dergachev auto ObjCSuspiciousNumberObjectExprM =
221e14d8818SArtem Dergachev expr(ignoringParenImpCasts(
222e14d8818SArtem Dergachev expr(hasType(hasCanonicalType(
223940c770dSArtem Dergachev objcObjectPointerType(pointee(
224940c770dSArtem Dergachev qualType(hasCanonicalType(
225940c770dSArtem Dergachev qualType(hasDeclaration(
226e14d8818SArtem Dergachev objcInterfaceDecl(hasName("NSNumber")))))))))))
227e14d8818SArtem Dergachev .bind("objc_object")));
228940c770dSArtem Dergachev
229e14d8818SArtem Dergachev auto SuspiciousNumberObjectExprM = anyOf(
230e14d8818SArtem Dergachev CSuspiciousNumberObjectExprM,
231e14d8818SArtem Dergachev CppSuspiciousNumberObjectExprM,
232e14d8818SArtem Dergachev ObjCSuspiciousNumberObjectExprM);
233940c770dSArtem Dergachev
234e14d8818SArtem Dergachev // Useful for predicates like "Unless we've seen the same object elsewhere".
235e14d8818SArtem Dergachev auto AnotherSuspiciousNumberObjectExprM =
236e14d8818SArtem Dergachev expr(anyOf(
237e14d8818SArtem Dergachev equalsBoundNode("c_object"),
238e14d8818SArtem Dergachev equalsBoundNode("objc_object"),
239e14d8818SArtem Dergachev equalsBoundNode("cpp_object")));
240940c770dSArtem Dergachev
241940c770dSArtem Dergachev // The .bind here is in order to compose the error message more accurately.
242e14d8818SArtem Dergachev auto ObjCSuspiciousScalarBooleanTypeM =
243*888673b6SJonas Devlieghere qualType(typedefType(hasDeclaration(
244*888673b6SJonas Devlieghere typedefDecl(hasName("BOOL"))))).bind("objc_bool_type");
245940c770dSArtem Dergachev
246940c770dSArtem Dergachev // The .bind here is in order to compose the error message more accurately.
247e14d8818SArtem Dergachev auto SuspiciousScalarBooleanTypeM =
248940c770dSArtem Dergachev qualType(anyOf(qualType(booleanType()).bind("cpp_bool_type"),
249e14d8818SArtem Dergachev ObjCSuspiciousScalarBooleanTypeM));
250940c770dSArtem Dergachev
251940c770dSArtem Dergachev // The .bind here is in order to compose the error message more accurately.
252e14d8818SArtem Dergachev // Also avoid intptr_t and uintptr_t because they were specifically created
253e14d8818SArtem Dergachev // for storing pointers.
254e14d8818SArtem Dergachev auto SuspiciousScalarNumberTypeM =
255940c770dSArtem Dergachev qualType(hasCanonicalType(isInteger()),
256*888673b6SJonas Devlieghere unless(typedefType(hasDeclaration(
257*888673b6SJonas Devlieghere typedefDecl(matchesName("^::u?intptr_t$"))))))
258940c770dSArtem Dergachev .bind("int_type");
259940c770dSArtem Dergachev
260e14d8818SArtem Dergachev auto SuspiciousScalarTypeM =
261e14d8818SArtem Dergachev qualType(anyOf(SuspiciousScalarBooleanTypeM,
262e14d8818SArtem Dergachev SuspiciousScalarNumberTypeM));
263940c770dSArtem Dergachev
264e14d8818SArtem Dergachev auto SuspiciousScalarExprM =
265e14d8818SArtem Dergachev expr(ignoringParenImpCasts(expr(hasType(SuspiciousScalarTypeM))));
266940c770dSArtem Dergachev
267940c770dSArtem Dergachev auto ConversionThroughAssignmentM =
26893fd165bSArtem Dergachev binaryOperator(allOf(hasOperatorName("="),
269e14d8818SArtem Dergachev hasLHS(SuspiciousScalarExprM),
27093fd165bSArtem Dergachev hasRHS(SuspiciousNumberObjectExprM)));
271940c770dSArtem Dergachev
272940c770dSArtem Dergachev auto ConversionThroughBranchingM =
2738dad0e6cSGeorge Karpenkov ifStmt(allOf(
2748dad0e6cSGeorge Karpenkov hasCondition(SuspiciousNumberObjectExprM),
2758dad0e6cSGeorge Karpenkov unless(hasConditionVariableStatement(declStmt())
2768dad0e6cSGeorge Karpenkov ))).bind("pedantic");
277940c770dSArtem Dergachev
278940c770dSArtem Dergachev auto ConversionThroughCallM =
279e14d8818SArtem Dergachev callExpr(hasAnyArgument(allOf(hasType(SuspiciousScalarTypeM),
280e14d8818SArtem Dergachev ignoringParenImpCasts(
281e14d8818SArtem Dergachev SuspiciousNumberObjectExprM))));
282940c770dSArtem Dergachev
283940c770dSArtem Dergachev // We bind "check_if_null" to modify the warning message
284940c770dSArtem Dergachev // in case it was intended to compare a pointer to 0 with a relatively-ok
285940c770dSArtem Dergachev // construct "x == 0" or "x != 0".
286940c770dSArtem Dergachev auto ConversionThroughEquivalenceM =
28793fd165bSArtem Dergachev binaryOperator(allOf(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
288e14d8818SArtem Dergachev hasEitherOperand(SuspiciousNumberObjectExprM),
289e14d8818SArtem Dergachev hasEitherOperand(SuspiciousScalarExprM
29093fd165bSArtem Dergachev .bind("check_if_null"))))
291e14d8818SArtem Dergachev .bind("comparison");
292940c770dSArtem Dergachev
293940c770dSArtem Dergachev auto ConversionThroughComparisonM =
29493fd165bSArtem Dergachev binaryOperator(allOf(anyOf(hasOperatorName(">="), hasOperatorName(">"),
295940c770dSArtem Dergachev hasOperatorName("<="), hasOperatorName("<")),
296e14d8818SArtem Dergachev hasEitherOperand(SuspiciousNumberObjectExprM),
29793fd165bSArtem Dergachev hasEitherOperand(SuspiciousScalarExprM)))
298e14d8818SArtem Dergachev .bind("comparison");
299940c770dSArtem Dergachev
300940c770dSArtem Dergachev auto ConversionThroughConditionalOperatorM =
30193fd165bSArtem Dergachev conditionalOperator(allOf(
302e14d8818SArtem Dergachev hasCondition(SuspiciousNumberObjectExprM),
303e14d8818SArtem Dergachev unless(hasTrueExpression(
304e14d8818SArtem Dergachev hasDescendant(AnotherSuspiciousNumberObjectExprM))),
305e14d8818SArtem Dergachev unless(hasFalseExpression(
30693fd165bSArtem Dergachev hasDescendant(AnotherSuspiciousNumberObjectExprM)))))
307940c770dSArtem Dergachev .bind("pedantic");
308940c770dSArtem Dergachev
309940c770dSArtem Dergachev auto ConversionThroughExclamationMarkM =
31093fd165bSArtem Dergachev unaryOperator(allOf(hasOperatorName("!"),
31193fd165bSArtem Dergachev has(expr(SuspiciousNumberObjectExprM))))
312940c770dSArtem Dergachev .bind("pedantic");
313940c770dSArtem Dergachev
314940c770dSArtem Dergachev auto ConversionThroughExplicitBooleanCastM =
31593fd165bSArtem Dergachev explicitCastExpr(allOf(hasType(SuspiciousScalarBooleanTypeM),
31693fd165bSArtem Dergachev has(expr(SuspiciousNumberObjectExprM))));
317940c770dSArtem Dergachev
318940c770dSArtem Dergachev auto ConversionThroughExplicitNumberCastM =
31993fd165bSArtem Dergachev explicitCastExpr(allOf(hasType(SuspiciousScalarNumberTypeM),
32093fd165bSArtem Dergachev has(expr(SuspiciousNumberObjectExprM))));
321940c770dSArtem Dergachev
322940c770dSArtem Dergachev auto ConversionThroughInitializerM =
323940c770dSArtem Dergachev declStmt(hasSingleDecl(
324e14d8818SArtem Dergachev varDecl(hasType(SuspiciousScalarTypeM),
325e14d8818SArtem Dergachev hasInitializer(SuspiciousNumberObjectExprM))));
326940c770dSArtem Dergachev
327940c770dSArtem Dergachev auto FinalM = stmt(anyOf(ConversionThroughAssignmentM,
328940c770dSArtem Dergachev ConversionThroughBranchingM,
329940c770dSArtem Dergachev ConversionThroughCallM,
330940c770dSArtem Dergachev ConversionThroughComparisonM,
331940c770dSArtem Dergachev ConversionThroughConditionalOperatorM,
332940c770dSArtem Dergachev ConversionThroughEquivalenceM,
333940c770dSArtem Dergachev ConversionThroughExclamationMarkM,
334940c770dSArtem Dergachev ConversionThroughExplicitBooleanCastM,
335940c770dSArtem Dergachev ConversionThroughExplicitNumberCastM,
336940c770dSArtem Dergachev ConversionThroughInitializerM)).bind("conv");
337940c770dSArtem Dergachev
338e14d8818SArtem Dergachev MatchFinder F;
339e14d8818SArtem Dergachev Callback CB(this, BR, AM.getAnalysisDeclContext(D));
340e14d8818SArtem Dergachev
3418d62eba1SStephen Kelly F.addMatcher(traverse(TK_AsIs, stmt(forEachDescendant(FinalM))), &CB);
342940c770dSArtem Dergachev F.match(*D->getBody(), AM.getASTContext());
343940c770dSArtem Dergachev }
344940c770dSArtem Dergachev
registerNumberObjectConversionChecker(CheckerManager & Mgr)345940c770dSArtem Dergachev void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) {
346940c770dSArtem Dergachev NumberObjectConversionChecker *Chk =
347940c770dSArtem Dergachev Mgr.registerChecker<NumberObjectConversionChecker>();
348940c770dSArtem Dergachev Chk->Pedantic =
34983cc1b35SKristof Umann Mgr.getAnalyzerOptions().getCheckerBooleanOption(Chk, "Pedantic");
350940c770dSArtem Dergachev }
351058a7a45SKristof Umann
shouldRegisterNumberObjectConversionChecker(const CheckerManager & mgr)352bda3dd0dSKirstóf Umann bool ento::shouldRegisterNumberObjectConversionChecker(const CheckerManager &mgr) {
353058a7a45SKristof Umann return true;
354058a7a45SKristof Umann }
355