xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===- NumberObjectConversionChecker.cpp -------------------------*- C++ -*-==//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines NumberObjectConversionChecker, which checks for a
10e5dd7070Spatrick // particular common mistake when dealing with numbers represented as objects
11e5dd7070Spatrick // passed around by pointers. Namely, the language allows to reinterpret the
12e5dd7070Spatrick // pointer as a number directly, often without throwing any warnings,
13e5dd7070Spatrick // but in most cases the result of such conversion is clearly unexpected,
14e5dd7070Spatrick // as pointer value, rather than number value represented by the pointee object,
15e5dd7070Spatrick // becomes the result of such operation.
16e5dd7070Spatrick //
17e5dd7070Spatrick // Currently the checker supports the Objective-C NSNumber class,
18e5dd7070Spatrick // and the OSBoolean class found in macOS low-level code; the latter
19e5dd7070Spatrick // can only hold boolean values.
20e5dd7070Spatrick //
21e5dd7070Spatrick // This checker has an option "Pedantic" (boolean), which enables detection of
22e5dd7070Spatrick // more conversion patterns (which are most likely more harmless, and therefore
23e5dd7070Spatrick // are more likely to produce false positives) - disabled by default,
24e5dd7070Spatrick // enabled with `-analyzer-config osx.NumberObjectConversion:Pedantic=true'.
25e5dd7070Spatrick //
26e5dd7070Spatrick //===----------------------------------------------------------------------===//
27e5dd7070Spatrick 
28e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
29e5dd7070Spatrick #include "clang/ASTMatchers/ASTMatchFinder.h"
30e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
31e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
32e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
33e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
34e5dd7070Spatrick #include "clang/Lex/Lexer.h"
35e5dd7070Spatrick #include "llvm/ADT/APSInt.h"
36e5dd7070Spatrick 
37e5dd7070Spatrick using namespace clang;
38e5dd7070Spatrick using namespace ento;
39e5dd7070Spatrick using namespace ast_matchers;
40e5dd7070Spatrick 
41e5dd7070Spatrick namespace {
42e5dd7070Spatrick 
43e5dd7070Spatrick class NumberObjectConversionChecker : public Checker<check::ASTCodeBody> {
44e5dd7070Spatrick public:
45e5dd7070Spatrick   bool Pedantic;
46e5dd7070Spatrick 
47e5dd7070Spatrick   void checkASTCodeBody(const Decl *D, AnalysisManager &AM,
48e5dd7070Spatrick                         BugReporter &BR) const;
49e5dd7070Spatrick };
50e5dd7070Spatrick 
51e5dd7070Spatrick class Callback : public MatchFinder::MatchCallback {
52e5dd7070Spatrick   const NumberObjectConversionChecker *C;
53e5dd7070Spatrick   BugReporter &BR;
54e5dd7070Spatrick   AnalysisDeclContext *ADC;
55e5dd7070Spatrick 
56e5dd7070Spatrick public:
Callback(const NumberObjectConversionChecker * C,BugReporter & BR,AnalysisDeclContext * ADC)57e5dd7070Spatrick   Callback(const NumberObjectConversionChecker *C,
58e5dd7070Spatrick            BugReporter &BR, AnalysisDeclContext *ADC)
59e5dd7070Spatrick       : C(C), BR(BR), ADC(ADC) {}
60ec727ea7Spatrick   void run(const MatchFinder::MatchResult &Result) override;
61e5dd7070Spatrick };
62e5dd7070Spatrick } // end of anonymous namespace
63e5dd7070Spatrick 
run(const MatchFinder::MatchResult & Result)64e5dd7070Spatrick void Callback::run(const MatchFinder::MatchResult &Result) {
65e5dd7070Spatrick   bool IsPedanticMatch =
66e5dd7070Spatrick       (Result.Nodes.getNodeAs<Stmt>("pedantic") != nullptr);
67e5dd7070Spatrick   if (IsPedanticMatch && !C->Pedantic)
68e5dd7070Spatrick     return;
69e5dd7070Spatrick 
70e5dd7070Spatrick   ASTContext &ACtx = ADC->getASTContext();
71e5dd7070Spatrick 
72e5dd7070Spatrick   if (const Expr *CheckIfNull =
73e5dd7070Spatrick           Result.Nodes.getNodeAs<Expr>("check_if_null")) {
74e5dd7070Spatrick     // Unless the macro indicates that the intended type is clearly not
75e5dd7070Spatrick     // a pointer type, we should avoid warning on comparing pointers
76e5dd7070Spatrick     // to zero literals in non-pedantic mode.
77e5dd7070Spatrick     // FIXME: Introduce an AST matcher to implement the macro-related logic?
78e5dd7070Spatrick     bool MacroIndicatesWeShouldSkipTheCheck = false;
79e5dd7070Spatrick     SourceLocation Loc = CheckIfNull->getBeginLoc();
80e5dd7070Spatrick     if (Loc.isMacroID()) {
81e5dd7070Spatrick       StringRef MacroName = Lexer::getImmediateMacroName(
82e5dd7070Spatrick           Loc, ACtx.getSourceManager(), ACtx.getLangOpts());
83e5dd7070Spatrick       if (MacroName == "NULL" || MacroName == "nil")
84e5dd7070Spatrick         return;
85e5dd7070Spatrick       if (MacroName == "YES" || MacroName == "NO")
86e5dd7070Spatrick         MacroIndicatesWeShouldSkipTheCheck = true;
87e5dd7070Spatrick     }
88e5dd7070Spatrick     if (!MacroIndicatesWeShouldSkipTheCheck) {
89e5dd7070Spatrick       Expr::EvalResult EVResult;
90e5dd7070Spatrick       if (CheckIfNull->IgnoreParenCasts()->EvaluateAsInt(
91e5dd7070Spatrick               EVResult, ACtx, Expr::SE_AllowSideEffects)) {
92e5dd7070Spatrick         llvm::APSInt Result = EVResult.Val.getInt();
93e5dd7070Spatrick         if (Result == 0) {
94e5dd7070Spatrick           if (!C->Pedantic)
95e5dd7070Spatrick             return;
96e5dd7070Spatrick           IsPedanticMatch = true;
97e5dd7070Spatrick         }
98e5dd7070Spatrick       }
99e5dd7070Spatrick     }
100e5dd7070Spatrick   }
101e5dd7070Spatrick 
102e5dd7070Spatrick   const Stmt *Conv = Result.Nodes.getNodeAs<Stmt>("conv");
103e5dd7070Spatrick   assert(Conv);
104e5dd7070Spatrick 
105e5dd7070Spatrick   const Expr *ConvertedCObject = Result.Nodes.getNodeAs<Expr>("c_object");
106e5dd7070Spatrick   const Expr *ConvertedCppObject = Result.Nodes.getNodeAs<Expr>("cpp_object");
107e5dd7070Spatrick   const Expr *ConvertedObjCObject = Result.Nodes.getNodeAs<Expr>("objc_object");
108e5dd7070Spatrick   bool IsCpp = (ConvertedCppObject != nullptr);
109e5dd7070Spatrick   bool IsObjC = (ConvertedObjCObject != nullptr);
110e5dd7070Spatrick   const Expr *Obj = IsObjC ? ConvertedObjCObject
111e5dd7070Spatrick                   : IsCpp ? ConvertedCppObject
112e5dd7070Spatrick                   : ConvertedCObject;
113e5dd7070Spatrick   assert(Obj);
114e5dd7070Spatrick 
115e5dd7070Spatrick   bool IsComparison =
116e5dd7070Spatrick       (Result.Nodes.getNodeAs<Stmt>("comparison") != nullptr);
117e5dd7070Spatrick 
118e5dd7070Spatrick   bool IsOSNumber =
119e5dd7070Spatrick       (Result.Nodes.getNodeAs<Decl>("osnumber") != nullptr);
120e5dd7070Spatrick 
121e5dd7070Spatrick   bool IsInteger =
122e5dd7070Spatrick       (Result.Nodes.getNodeAs<QualType>("int_type") != nullptr);
123e5dd7070Spatrick   bool IsObjCBool =
124e5dd7070Spatrick       (Result.Nodes.getNodeAs<QualType>("objc_bool_type") != nullptr);
125e5dd7070Spatrick   bool IsCppBool =
126e5dd7070Spatrick       (Result.Nodes.getNodeAs<QualType>("cpp_bool_type") != nullptr);
127e5dd7070Spatrick 
128e5dd7070Spatrick   llvm::SmallString<64> Msg;
129e5dd7070Spatrick   llvm::raw_svector_ostream OS(Msg);
130e5dd7070Spatrick 
131e5dd7070Spatrick   // Remove ObjC ARC qualifiers.
132e5dd7070Spatrick   QualType ObjT = Obj->getType().getUnqualifiedType();
133e5dd7070Spatrick 
134e5dd7070Spatrick   // Remove consts from pointers.
135e5dd7070Spatrick   if (IsCpp) {
136e5dd7070Spatrick     assert(ObjT.getCanonicalType()->isPointerType());
137e5dd7070Spatrick     ObjT = ACtx.getPointerType(
138e5dd7070Spatrick         ObjT->getPointeeType().getCanonicalType().getUnqualifiedType());
139e5dd7070Spatrick   }
140e5dd7070Spatrick 
141e5dd7070Spatrick   if (IsComparison)
142e5dd7070Spatrick     OS << "Comparing ";
143e5dd7070Spatrick   else
144e5dd7070Spatrick     OS << "Converting ";
145e5dd7070Spatrick 
146*12c85518Srobert   OS << "a pointer value of type '" << ObjT << "' to a ";
147e5dd7070Spatrick 
148e5dd7070Spatrick   std::string EuphemismForPlain = "primitive";
149e5dd7070Spatrick   std::string SuggestedApi = IsObjC ? (IsInteger ? "" : "-boolValue")
150e5dd7070Spatrick                            : IsCpp ? (IsOSNumber ? "" : "getValue()")
151e5dd7070Spatrick                            : "CFNumberGetValue()";
152e5dd7070Spatrick   if (SuggestedApi.empty()) {
153e5dd7070Spatrick     // A generic message if we're not sure what API should be called.
154e5dd7070Spatrick     // FIXME: Pattern-match the integer type to make a better guess?
155e5dd7070Spatrick     SuggestedApi =
156e5dd7070Spatrick         "a method on '" + ObjT.getAsString() + "' to get the scalar value";
157e5dd7070Spatrick     // "scalar" is not quite correct or common, but some documentation uses it
158e5dd7070Spatrick     // when describing object methods we suggest. For consistency, we use
159e5dd7070Spatrick     // "scalar" in the whole sentence when we need to use this word in at least
160e5dd7070Spatrick     // one place, otherwise we use "primitive".
161e5dd7070Spatrick     EuphemismForPlain = "scalar";
162e5dd7070Spatrick   }
163e5dd7070Spatrick 
164e5dd7070Spatrick   if (IsInteger)
165e5dd7070Spatrick     OS << EuphemismForPlain << " integer value";
166e5dd7070Spatrick   else if (IsObjCBool)
167e5dd7070Spatrick     OS << EuphemismForPlain << " BOOL value";
168e5dd7070Spatrick   else if (IsCppBool)
169e5dd7070Spatrick     OS << EuphemismForPlain << " bool value";
170e5dd7070Spatrick   else // Branch condition?
171e5dd7070Spatrick     OS << EuphemismForPlain << " boolean value";
172e5dd7070Spatrick 
173e5dd7070Spatrick 
174e5dd7070Spatrick   if (IsPedanticMatch)
175e5dd7070Spatrick     OS << "; instead, either compare the pointer to "
176e5dd7070Spatrick        << (IsObjC ? "nil" : IsCpp ? "nullptr" : "NULL") << " or ";
177e5dd7070Spatrick   else
178e5dd7070Spatrick     OS << "; did you mean to ";
179e5dd7070Spatrick 
180e5dd7070Spatrick   if (IsComparison)
181e5dd7070Spatrick     OS << "compare the result of calling " << SuggestedApi;
182e5dd7070Spatrick   else
183e5dd7070Spatrick     OS << "call " << SuggestedApi;
184e5dd7070Spatrick 
185e5dd7070Spatrick   if (!IsPedanticMatch)
186e5dd7070Spatrick     OS << "?";
187e5dd7070Spatrick 
188e5dd7070Spatrick   BR.EmitBasicReport(
189e5dd7070Spatrick       ADC->getDecl(), C, "Suspicious number object conversion", "Logic error",
190e5dd7070Spatrick       OS.str(),
191e5dd7070Spatrick       PathDiagnosticLocation::createBegin(Obj, BR.getSourceManager(), ADC),
192e5dd7070Spatrick       Conv->getSourceRange());
193e5dd7070Spatrick }
194e5dd7070Spatrick 
checkASTCodeBody(const Decl * D,AnalysisManager & AM,BugReporter & BR) const195e5dd7070Spatrick void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
196e5dd7070Spatrick                                                      AnalysisManager &AM,
197e5dd7070Spatrick                                                      BugReporter &BR) const {
198e5dd7070Spatrick   // Currently this matches CoreFoundation opaque pointer typedefs.
199*12c85518Srobert   auto CSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts(
200*12c85518Srobert       expr(hasType(elaboratedType(namesType(typedefType(
201*12c85518Srobert                hasDeclaration(anyOf(typedefDecl(hasName("CFNumberRef")),
202*12c85518Srobert                                     typedefDecl(hasName("CFBooleanRef")))))))))
203e5dd7070Spatrick           .bind("c_object")));
204e5dd7070Spatrick 
205e5dd7070Spatrick   // Currently this matches XNU kernel number-object pointers.
206e5dd7070Spatrick   auto CppSuspiciousNumberObjectExprM =
207e5dd7070Spatrick       expr(ignoringParenImpCasts(
208e5dd7070Spatrick           expr(hasType(hasCanonicalType(
209e5dd7070Spatrick               pointerType(pointee(hasCanonicalType(
210e5dd7070Spatrick                   recordType(hasDeclaration(
211e5dd7070Spatrick                       anyOf(
212e5dd7070Spatrick                         cxxRecordDecl(hasName("OSBoolean")),
213e5dd7070Spatrick                         cxxRecordDecl(hasName("OSNumber"))
214e5dd7070Spatrick                             .bind("osnumber"))))))))))
215e5dd7070Spatrick           .bind("cpp_object")));
216e5dd7070Spatrick 
217e5dd7070Spatrick   // Currently this matches NeXTSTEP number objects.
218e5dd7070Spatrick   auto ObjCSuspiciousNumberObjectExprM =
219e5dd7070Spatrick       expr(ignoringParenImpCasts(
220e5dd7070Spatrick           expr(hasType(hasCanonicalType(
221e5dd7070Spatrick               objcObjectPointerType(pointee(
222e5dd7070Spatrick                   qualType(hasCanonicalType(
223e5dd7070Spatrick                       qualType(hasDeclaration(
224e5dd7070Spatrick                           objcInterfaceDecl(hasName("NSNumber")))))))))))
225e5dd7070Spatrick           .bind("objc_object")));
226e5dd7070Spatrick 
227e5dd7070Spatrick   auto SuspiciousNumberObjectExprM = anyOf(
228e5dd7070Spatrick       CSuspiciousNumberObjectExprM,
229e5dd7070Spatrick       CppSuspiciousNumberObjectExprM,
230e5dd7070Spatrick       ObjCSuspiciousNumberObjectExprM);
231e5dd7070Spatrick 
232e5dd7070Spatrick   // Useful for predicates like "Unless we've seen the same object elsewhere".
233e5dd7070Spatrick   auto AnotherSuspiciousNumberObjectExprM =
234e5dd7070Spatrick       expr(anyOf(
235e5dd7070Spatrick           equalsBoundNode("c_object"),
236e5dd7070Spatrick           equalsBoundNode("objc_object"),
237e5dd7070Spatrick           equalsBoundNode("cpp_object")));
238e5dd7070Spatrick 
239e5dd7070Spatrick   // The .bind here is in order to compose the error message more accurately.
240e5dd7070Spatrick   auto ObjCSuspiciousScalarBooleanTypeM =
241*12c85518Srobert       qualType(elaboratedType(namesType(
242*12c85518Srobert                    typedefType(hasDeclaration(typedefDecl(hasName("BOOL")))))))
243*12c85518Srobert           .bind("objc_bool_type");
244e5dd7070Spatrick 
245e5dd7070Spatrick   // The .bind here is in order to compose the error message more accurately.
246e5dd7070Spatrick   auto SuspiciousScalarBooleanTypeM =
247e5dd7070Spatrick       qualType(anyOf(qualType(booleanType()).bind("cpp_bool_type"),
248e5dd7070Spatrick                      ObjCSuspiciousScalarBooleanTypeM));
249e5dd7070Spatrick 
250e5dd7070Spatrick   // The .bind here is in order to compose the error message more accurately.
251e5dd7070Spatrick   // Also avoid intptr_t and uintptr_t because they were specifically created
252e5dd7070Spatrick   // for storing pointers.
253e5dd7070Spatrick   auto SuspiciousScalarNumberTypeM =
254e5dd7070Spatrick       qualType(hasCanonicalType(isInteger()),
255*12c85518Srobert                unless(elaboratedType(namesType(typedefType(hasDeclaration(
256*12c85518Srobert                    typedefDecl(matchesName("^::u?intptr_t$"))))))))
257e5dd7070Spatrick           .bind("int_type");
258e5dd7070Spatrick 
259e5dd7070Spatrick   auto SuspiciousScalarTypeM =
260e5dd7070Spatrick       qualType(anyOf(SuspiciousScalarBooleanTypeM,
261e5dd7070Spatrick                      SuspiciousScalarNumberTypeM));
262e5dd7070Spatrick 
263e5dd7070Spatrick   auto SuspiciousScalarExprM =
264e5dd7070Spatrick       expr(ignoringParenImpCasts(expr(hasType(SuspiciousScalarTypeM))));
265e5dd7070Spatrick 
266e5dd7070Spatrick   auto ConversionThroughAssignmentM =
267e5dd7070Spatrick       binaryOperator(allOf(hasOperatorName("="),
268e5dd7070Spatrick                            hasLHS(SuspiciousScalarExprM),
269e5dd7070Spatrick                            hasRHS(SuspiciousNumberObjectExprM)));
270e5dd7070Spatrick 
271e5dd7070Spatrick   auto ConversionThroughBranchingM =
272e5dd7070Spatrick       ifStmt(allOf(
273e5dd7070Spatrick           hasCondition(SuspiciousNumberObjectExprM),
274e5dd7070Spatrick           unless(hasConditionVariableStatement(declStmt())
275e5dd7070Spatrick       ))).bind("pedantic");
276e5dd7070Spatrick 
277e5dd7070Spatrick   auto ConversionThroughCallM =
278e5dd7070Spatrick       callExpr(hasAnyArgument(allOf(hasType(SuspiciousScalarTypeM),
279e5dd7070Spatrick                                     ignoringParenImpCasts(
280e5dd7070Spatrick                                         SuspiciousNumberObjectExprM))));
281e5dd7070Spatrick 
282e5dd7070Spatrick   // We bind "check_if_null" to modify the warning message
283e5dd7070Spatrick   // in case it was intended to compare a pointer to 0 with a relatively-ok
284e5dd7070Spatrick   // construct "x == 0" or "x != 0".
285e5dd7070Spatrick   auto ConversionThroughEquivalenceM =
286e5dd7070Spatrick       binaryOperator(allOf(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
287e5dd7070Spatrick                            hasEitherOperand(SuspiciousNumberObjectExprM),
288e5dd7070Spatrick                            hasEitherOperand(SuspiciousScalarExprM
289e5dd7070Spatrick                                             .bind("check_if_null"))))
290e5dd7070Spatrick       .bind("comparison");
291e5dd7070Spatrick 
292e5dd7070Spatrick   auto ConversionThroughComparisonM =
293e5dd7070Spatrick       binaryOperator(allOf(anyOf(hasOperatorName(">="), hasOperatorName(">"),
294e5dd7070Spatrick                                  hasOperatorName("<="), hasOperatorName("<")),
295e5dd7070Spatrick                            hasEitherOperand(SuspiciousNumberObjectExprM),
296e5dd7070Spatrick                            hasEitherOperand(SuspiciousScalarExprM)))
297e5dd7070Spatrick       .bind("comparison");
298e5dd7070Spatrick 
299e5dd7070Spatrick   auto ConversionThroughConditionalOperatorM =
300e5dd7070Spatrick       conditionalOperator(allOf(
301e5dd7070Spatrick           hasCondition(SuspiciousNumberObjectExprM),
302e5dd7070Spatrick           unless(hasTrueExpression(
303e5dd7070Spatrick               hasDescendant(AnotherSuspiciousNumberObjectExprM))),
304e5dd7070Spatrick           unless(hasFalseExpression(
305e5dd7070Spatrick               hasDescendant(AnotherSuspiciousNumberObjectExprM)))))
306e5dd7070Spatrick       .bind("pedantic");
307e5dd7070Spatrick 
308e5dd7070Spatrick   auto ConversionThroughExclamationMarkM =
309e5dd7070Spatrick       unaryOperator(allOf(hasOperatorName("!"),
310e5dd7070Spatrick                           has(expr(SuspiciousNumberObjectExprM))))
311e5dd7070Spatrick       .bind("pedantic");
312e5dd7070Spatrick 
313e5dd7070Spatrick   auto ConversionThroughExplicitBooleanCastM =
314e5dd7070Spatrick       explicitCastExpr(allOf(hasType(SuspiciousScalarBooleanTypeM),
315e5dd7070Spatrick                              has(expr(SuspiciousNumberObjectExprM))));
316e5dd7070Spatrick 
317e5dd7070Spatrick   auto ConversionThroughExplicitNumberCastM =
318e5dd7070Spatrick       explicitCastExpr(allOf(hasType(SuspiciousScalarNumberTypeM),
319e5dd7070Spatrick                              has(expr(SuspiciousNumberObjectExprM))));
320e5dd7070Spatrick 
321e5dd7070Spatrick   auto ConversionThroughInitializerM =
322e5dd7070Spatrick       declStmt(hasSingleDecl(
323e5dd7070Spatrick           varDecl(hasType(SuspiciousScalarTypeM),
324e5dd7070Spatrick                   hasInitializer(SuspiciousNumberObjectExprM))));
325e5dd7070Spatrick 
326e5dd7070Spatrick   auto FinalM = stmt(anyOf(ConversionThroughAssignmentM,
327e5dd7070Spatrick                            ConversionThroughBranchingM,
328e5dd7070Spatrick                            ConversionThroughCallM,
329e5dd7070Spatrick                            ConversionThroughComparisonM,
330e5dd7070Spatrick                            ConversionThroughConditionalOperatorM,
331e5dd7070Spatrick                            ConversionThroughEquivalenceM,
332e5dd7070Spatrick                            ConversionThroughExclamationMarkM,
333e5dd7070Spatrick                            ConversionThroughExplicitBooleanCastM,
334e5dd7070Spatrick                            ConversionThroughExplicitNumberCastM,
335e5dd7070Spatrick                            ConversionThroughInitializerM)).bind("conv");
336e5dd7070Spatrick 
337e5dd7070Spatrick   MatchFinder F;
338e5dd7070Spatrick   Callback CB(this, BR, AM.getAnalysisDeclContext(D));
339e5dd7070Spatrick 
340ec727ea7Spatrick   F.addMatcher(traverse(TK_AsIs, stmt(forEachDescendant(FinalM))), &CB);
341e5dd7070Spatrick   F.match(*D->getBody(), AM.getASTContext());
342e5dd7070Spatrick }
343e5dd7070Spatrick 
registerNumberObjectConversionChecker(CheckerManager & Mgr)344e5dd7070Spatrick void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) {
345e5dd7070Spatrick   NumberObjectConversionChecker *Chk =
346e5dd7070Spatrick       Mgr.registerChecker<NumberObjectConversionChecker>();
347e5dd7070Spatrick   Chk->Pedantic =
348e5dd7070Spatrick       Mgr.getAnalyzerOptions().getCheckerBooleanOption(Chk, "Pedantic");
349e5dd7070Spatrick }
350e5dd7070Spatrick 
shouldRegisterNumberObjectConversionChecker(const CheckerManager & mgr)351ec727ea7Spatrick bool ento::shouldRegisterNumberObjectConversionChecker(const CheckerManager &mgr) {
352e5dd7070Spatrick   return true;
353e5dd7070Spatrick }
354