Index: clang-tidy/misc/SizeofExpressionCheck.h =================================================================== --- clang-tidy/misc/SizeofExpressionCheck.h +++ clang-tidy/misc/SizeofExpressionCheck.h @@ -29,6 +29,7 @@ private: const bool WarnOnSizeOfConstant; + const bool WarnOnSizeOfIntegerExpression; const bool WarnOnSizeOfThis; const bool WarnOnSizeOfCompareToConstant; }; Index: clang-tidy/misc/SizeofExpressionCheck.cpp =================================================================== --- clang-tidy/misc/SizeofExpressionCheck.cpp +++ clang-tidy/misc/SizeofExpressionCheck.cpp @@ -62,12 +62,16 @@ ClangTidyContext *Context) : ClangTidyCheck(Name, Context), WarnOnSizeOfConstant(Options.get("WarnOnSizeOfConstant", 1) != 0), + WarnOnSizeOfIntegerExpression( + Options.get("WarnOnSizeOfIntegerExpression", 1) != 0), WarnOnSizeOfThis(Options.get("WarnOnSizeOfThis", 1) != 0), WarnOnSizeOfCompareToConstant( Options.get("WarnOnSizeOfCompareToConstant", 1) != 0) {} void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant); + Options.store(Opts, "WarnOnSizeOfIntegerExpression", + WarnOnSizeOfIntegerExpression); Options.store(Opts, "WarnOnSizeOfThis", WarnOnSizeOfThis); Options.store(Opts, "WarnOnSizeOfCompareToConstant", WarnOnSizeOfCompareToConstant); @@ -78,6 +82,8 @@ const auto ConstantExpr = expr(ignoringParenImpCasts( anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)), binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr))))); + const auto IntegerCallExpr = expr(ignoringParenImpCasts( + callExpr(hasType(isInteger()), unless(isInTemplateInstantiation())))); const auto SizeOfExpr = expr(anyOf(sizeOfExpr(has(type())), sizeOfExpr(has(expr())))); const auto SizeOfZero = expr( @@ -94,6 +100,14 @@ this); } + // Detect sizeof(f()) + if (WarnOnSizeOfIntegerExpression) { + Finder->addMatcher( + expr(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr)))) + .bind("sizeof-integer-call"), + this); + } + // Detect expression like: sizeof(this); if (WarnOnSizeOfThis) { Finder->addMatcher( @@ -203,6 +217,10 @@ if (const auto *E = Result.Nodes.getNodeAs("sizeof-constant")) { diag(E->getLocStart(), "suspicious usage of 'sizeof(K)'; did you mean 'K'?"); + } else if (const auto *E = + Result.Nodes.getNodeAs("sizeof-integer-call")) { + diag(E->getLocStart(), "suspicious usage of 'sizeof() on an expression " + "that results in an integer"); } else if (const auto *E = Result.Nodes.getNodeAs("sizeof-this")) { diag(E->getLocStart(), "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'"); Index: docs/clang-tidy/checks/misc-sizeof-expression.rst =================================================================== --- docs/clang-tidy/checks/misc-sizeof-expression.rst +++ docs/clang-tidy/checks/misc-sizeof-expression.rst @@ -22,6 +22,26 @@ char buf[BUFLEN]; memset(buf, 0, sizeof(BUFLEN)); // sizeof(42) ==> sizeof(int) +Suspicious usage of 'sizeof(expr)' +---------------------------------- + +A common mistake is to query the ``sizeof`` on an integer or enum that +represents the type, which will give the size of the integer and not of the +type the integer represents: + +.. code-block:: c++ + + enum data_type { + FLOAT_TYPE, + DOUBLE_TYPE + }; + + data_type get_type() { + return FLOAT_TYPE; + } + + int numBytes = numElements * sizeof(get_type()); // should be sizeof(float) + Suspicious usage of 'sizeof(this)' ---------------------------------- @@ -142,6 +162,11 @@ When non-zero, the check will warn on an expression like ``sizeof(CONSTANT)``. Default is `1`. +.. option:: WarnOnSizeOfIntegerExpression + + When non-zero, the check will warn on an expression like ``sizeof(expr)`` + where the expression results in an integer. Default is `1`. + .. option:: WarnOnSizeOfThis When non-zero, the check will warn on an expression like ``sizeof(this)``. Index: test/clang-tidy/misc-sizeof-expression.cpp =================================================================== --- test/clang-tidy/misc-sizeof-expression.cpp +++ test/clang-tidy/misc-sizeof-expression.cpp @@ -14,6 +14,59 @@ #pragma pack(1) struct S { char a, b, c; }; +enum E { E_VALUE = 0 }; + +int AsInt() { return 0; } +E AsEnum() { return E_VALUE; } +S AsStruct() { return {}; } + +struct M { + int AsInt() { return 0; } + E AsEnum() { return E_VALUE; } + S AsStruct() { return {}; } +}; + +int ReturnOverload(int) { return {}; } +S ReturnOverload(S) { return {}; } + +template +T ReturnTemplate(T) { return {}; } + +template +bool TestTrait1() { + return sizeof(ReturnOverload(T{})) == sizeof(A); +} + +template +bool TestTrait2() { + return sizeof(ReturnTemplate(T{})) == sizeof(A); +} + +template +bool TestTrait3() { + return sizeof(ReturnOverload(0)) == sizeof(T{}); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer +} + +template +bool TestTrait4() { + return sizeof(ReturnTemplate(0)) == sizeof(T{}); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer +} + +bool TestTemplates() { + bool b = true; + b &= TestTrait1(); + b &= TestTrait1(); + b &= TestTrait2(); + b &= TestTrait2(); + b &= TestTrait3(); + b &= TestTrait3(); + b &= TestTrait4(); + b &= TestTrait4(); + return b; +} + int Test1(const char* ptr) { int sum = 0; sum += sizeof(LEN); @@ -22,6 +75,14 @@ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)' sum += sizeof(sum, LEN); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(..., ...)' + sum += sizeof(AsInt()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer + sum += sizeof(AsEnum()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer + sum += sizeof(M{}.AsInt()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer + sum += sizeof(M{}.AsEnum()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof() on an expression that results in an integer sum += sizeof(sizeof(X)); // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))' sum += sizeof(LEN + sizeof(X)); @@ -171,6 +232,8 @@ if (sizeof(A) < 10) sum += sizeof(A); sum += sizeof(int); + sum += sizeof(AsStruct()); + sum += sizeof(M{}.AsStruct()); sum += sizeof(A[sizeof(A) / sizeof(int)]); sum += sizeof(&A[sizeof(A) / sizeof(int)]); sum += sizeof(sizeof(0)); // Special case: sizeof size_t.