Go to the documentation of this file.
35 #include "llvm/ADT/APSInt.h"
37 using namespace clang;
39 using namespace ast_matchers;
43 class NumberObjectConversionChecker :
public Checker<check::ASTCodeBody> {
47 void checkASTCodeBody(
const Decl *D, AnalysisManager &AM,
48 BugReporter &BR)
const;
52 const NumberObjectConversionChecker *
C;
57 Callback(
const NumberObjectConversionChecker *C,
59 :
C(
C), BR(BR), ADC(ADC) {}
65 bool IsPedanticMatch =
66 (Result.Nodes.getNodeAs<
Stmt>(
"pedantic") !=
nullptr);
67 if (IsPedanticMatch && !
C->Pedantic)
72 if (
const Expr *CheckIfNull =
73 Result.Nodes.getNodeAs<
Expr>(
"check_if_null")) {
78 bool MacroIndicatesWeShouldSkipTheCheck =
false;
83 if (MacroName ==
"NULL" || MacroName ==
"nil")
85 if (MacroName ==
"YES" || MacroName ==
"NO")
86 MacroIndicatesWeShouldSkipTheCheck =
true;
88 if (!MacroIndicatesWeShouldSkipTheCheck) {
90 if (CheckIfNull->IgnoreParenCasts()->EvaluateAsInt(
96 IsPedanticMatch =
true;
102 const Stmt *Conv = Result.Nodes.getNodeAs<
Stmt>(
"conv");
105 const Expr *ConvertedCObject = Result.Nodes.getNodeAs<
Expr>(
"c_object");
106 const Expr *ConvertedCppObject = Result.Nodes.getNodeAs<
Expr>(
"cpp_object");
107 const Expr *ConvertedObjCObject = Result.Nodes.getNodeAs<
Expr>(
"objc_object");
108 bool IsCpp = (ConvertedCppObject !=
nullptr);
109 bool IsObjC = (ConvertedObjCObject !=
nullptr);
110 const Expr *Obj = IsObjC ? ConvertedObjCObject
111 : IsCpp ? ConvertedCppObject
116 (Result.Nodes.getNodeAs<
Stmt>(
"comparison") !=
nullptr);
119 (Result.Nodes.getNodeAs<
Decl>(
"osnumber") !=
nullptr);
122 (Result.Nodes.getNodeAs<
QualType>(
"int_type") !=
nullptr);
124 (Result.Nodes.getNodeAs<
QualType>(
"objc_bool_type") !=
nullptr);
126 (Result.Nodes.getNodeAs<
QualType>(
"cpp_bool_type") !=
nullptr);
129 llvm::raw_svector_ostream
OS(Msg);
146 OS <<
"a pointer value of type '" << ObjT <<
"' to a ";
149 std::string SuggestedApi = IsObjC ? (IsInteger ?
"" :
"-boolValue")
150 : IsCpp ? (IsOSNumber ?
"" :
"getValue()")
151 :
"CFNumberGetValue()";
152 if (SuggestedApi.empty()) {
156 "a method on '" + ObjT.getAsString() +
"' to get the scalar value";
161 EuphemismForPlain =
"scalar";
165 OS << EuphemismForPlain <<
" integer value";
167 OS << EuphemismForPlain <<
" BOOL value";
169 OS << EuphemismForPlain <<
" bool value";
171 OS << EuphemismForPlain <<
" boolean value";
175 OS <<
"; instead, either compare the pointer to "
176 << (IsObjC ?
"nil" : IsCpp ?
"nullptr" :
"NULL") <<
" or ";
178 OS <<
"; did you mean to ";
181 OS <<
"compare the result of calling " << SuggestedApi;
183 OS <<
"call " << SuggestedApi;
185 if (!IsPedanticMatch)
189 ADC->getDecl(),
C,
"Suspicious number object conversion",
"Logic error",
195 void NumberObjectConversionChecker::checkASTCodeBody(
const Decl *D,
197 BugReporter &BR)
const {
199 auto CSuspiciousNumberObjectExprM =
200 expr(ignoringParenImpCasts(
208 auto CppSuspiciousNumberObjectExprM =
209 expr(ignoringParenImpCasts(
210 expr(hasType(hasCanonicalType(
216 .bind(
"osnumber"))))))))))
217 .bind(
"cpp_object")));
220 auto ObjCSuspiciousNumberObjectExprM =
221 expr(ignoringParenImpCasts(
222 expr(hasType(hasCanonicalType(
227 .bind(
"objc_object")));
229 auto SuspiciousNumberObjectExprM =
anyOf(
230 CSuspiciousNumberObjectExprM,
231 CppSuspiciousNumberObjectExprM,
232 ObjCSuspiciousNumberObjectExprM);
235 auto AnotherSuspiciousNumberObjectExprM =
237 equalsBoundNode(
"c_object"),
238 equalsBoundNode(
"objc_object"),
239 equalsBoundNode(
"cpp_object")));
242 auto ObjCSuspiciousScalarBooleanTypeM =
247 auto SuspiciousScalarBooleanTypeM =
249 ObjCSuspiciousScalarBooleanTypeM));
254 auto SuspiciousScalarNumberTypeM =
255 qualType(hasCanonicalType(isInteger()),
260 auto SuspiciousScalarTypeM =
262 SuspiciousScalarNumberTypeM));
264 auto SuspiciousScalarExprM =
265 expr(ignoringParenImpCasts(
expr(hasType(SuspiciousScalarTypeM))));
267 auto ConversionThroughAssignmentM =
269 hasLHS(SuspiciousScalarExprM),
270 hasRHS(SuspiciousNumberObjectExprM)));
272 auto ConversionThroughBranchingM =
274 hasCondition(SuspiciousNumberObjectExprM),
276 ))).bind(
"pedantic");
278 auto ConversionThroughCallM =
279 callExpr(hasAnyArgument(
allOf(hasType(SuspiciousScalarTypeM),
280 ignoringParenImpCasts(
281 SuspiciousNumberObjectExprM))));
286 auto ConversionThroughEquivalenceM =
288 hasEitherOperand(SuspiciousNumberObjectExprM),
289 hasEitherOperand(SuspiciousScalarExprM
290 .bind(
"check_if_null"))))
293 auto ConversionThroughComparisonM =
295 hasOperatorName(
"<="), hasOperatorName(
"<")),
296 hasEitherOperand(SuspiciousNumberObjectExprM),
297 hasEitherOperand(SuspiciousScalarExprM)))
300 auto ConversionThroughConditionalOperatorM =
302 hasCondition(SuspiciousNumberObjectExprM),
305 unless(hasFalseExpression(
309 auto ConversionThroughExclamationMarkM =
311 has(
expr(SuspiciousNumberObjectExprM))))
314 auto ConversionThroughExplicitBooleanCastM =
316 has(
expr(SuspiciousNumberObjectExprM))));
318 auto ConversionThroughExplicitNumberCastM =
320 has(
expr(SuspiciousNumberObjectExprM))));
322 auto ConversionThroughInitializerM =
324 varDecl(hasType(SuspiciousScalarTypeM),
325 hasInitializer(SuspiciousNumberObjectExprM))));
327 auto FinalM =
stmt(
anyOf(ConversionThroughAssignmentM,
328 ConversionThroughBranchingM,
329 ConversionThroughCallM,
330 ConversionThroughComparisonM,
331 ConversionThroughConditionalOperatorM,
332 ConversionThroughEquivalenceM,
333 ConversionThroughExclamationMarkM,
334 ConversionThroughExplicitBooleanCastM,
335 ConversionThroughExplicitNumberCastM,
336 ConversionThroughInitializerM)).bind(
"conv");
339 Callback CB(
this, BR, AM.getAnalysisDeclContext(D));
345 void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) {
346 NumberObjectConversionChecker *Chk =
347 Mgr.registerChecker<NumberObjectConversionChecker>();
349 Mgr.getAnalyzerOptions().getCheckerBooleanOption(Chk,
"Pedantic");
352 bool ento::shouldRegisterNumberObjectConversionChecker(
const CheckerManager &mgr) {
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
Encodes a location in the source.
A class to allow finding matches over the Clang AST.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A (possibly-)qualified type.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
QualType getCanonicalType() const
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Stmt, ExplicitCastExpr > explicitCastExpr
Matches explicit cast expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, ObjCInterfaceDecl > objcInterfaceDecl
Matches Objective-C interface declarations.
APValue Val
Val - This is the value the expression can be folded to.
SourceManager & getSourceManager()
internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const AstTypeMatcher< TypedefType > typedefType
Matches typedef types.
EvalResult is a struct with detailed info about an evaluated expression.
const internal::VariadicDynCastAllOfMatcher< Stmt, IfStmt > ifStmt
Matches if statements.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
bool isPointerType() const
const internal::VariadicDynCastAllOfMatcher< Decl, TypedefDecl > typedefDecl
Matches typedef declarations.
@ TK_AsIs
Will traverse all child nodes.
Decl - This represents one declaration (or definition), e.g.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
Contains all information for a given match.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
Stmt - This represents one statement.
@ SE_AllowSideEffects
Allow any unmodeled side effect.
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
This represents one expression.
const AstTypeMatcher< ObjCObjectPointerType > objcObjectPointerType
Matches an Objective-C object pointer type, which is different from a pointer type,...
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclStmt > declStmt
Matches declaration statements.
Called when the Match registered for it was successfully found in the AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, ConditionalOperator > conditionalOperator
Matches conditional operator expressions.
const LangOptions & getLangOpts() const
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
const internal::VariadicAllOfMatcher< QualType > qualType
Matches QualTypes in the clang AST.