[clang-tools-extra] r260223 - [clang-tidy] Add 'misc-misplaced-widening-cast' check.
Daniel Marjamaki via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 9 06:08:50 PST 2016
Author: danielmarjamaki
Date: Tue Feb 9 08:08:49 2016
New Revision: 260223
URL: http://llvm.org/viewvc/llvm-project?rev=260223&view=rev
Log:
[clang-tidy] Add 'misc-misplaced-widening-cast' check.
Reviewers: alexfh
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D16310
Added:
clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.cpp
clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.h
clang-tools-extra/trunk/docs/clang-tidy/checks/misc-misplaced-widening-cast.rst
clang-tools-extra/trunk/test/clang-tidy/misc-misplaced-widening-cast.cpp
Modified:
clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
Modified: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt?rev=260223&r1=260222&r2=260223&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt Tue Feb 9 08:08:49 2016
@@ -12,6 +12,7 @@ add_clang_library(clangTidyMiscModule
MacroParenthesesCheck.cpp
MacroRepeatedSideEffectsCheck.cpp
MiscTidyModule.cpp
+ MisplacedWideningCastCheck.cpp
MoveConstantArgumentCheck.cpp
MoveConstructorInitCheck.cpp
NewDeleteOverloadsCheck.cpp
Modified: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp?rev=260223&r1=260222&r2=260223&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp Tue Feb 9 08:08:49 2016
@@ -20,6 +20,7 @@
#include "InefficientAlgorithmCheck.h"
#include "MacroParenthesesCheck.h"
#include "MacroRepeatedSideEffectsCheck.h"
+#include "MisplacedWideningCastCheck.h"
#include "MoveConstantArgumentCheck.h"
#include "MoveConstructorInitCheck.h"
#include "NewDeleteOverloadsCheck.h"
@@ -63,6 +64,8 @@ public:
"misc-macro-parentheses");
CheckFactories.registerCheck<MacroRepeatedSideEffectsCheck>(
"misc-macro-repeated-side-effects");
+ CheckFactories.registerCheck<MisplacedWideningCastCheck>(
+ "misc-misplaced-widening-cast");
CheckFactories.registerCheck<MoveConstantArgumentCheck>(
"misc-move-const-arg");
CheckFactories.registerCheck<MoveConstructorInitCheck>(
Added: clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.cpp?rev=260223&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.cpp Tue Feb 9 08:08:49 2016
@@ -0,0 +1,106 @@
+//===--- MisplacedWideningCastCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisplacedWideningCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void MisplacedWideningCastCheck::registerMatchers(MatchFinder *Finder) {
+ auto Calc = expr(anyOf(binaryOperator(anyOf(
+ hasOperatorName("+"), hasOperatorName("-"),
+ hasOperatorName("*"), hasOperatorName("<<"))),
+ unaryOperator(hasOperatorName("~"))),
+ hasType(isInteger()))
+ .bind("Calc");
+
+ auto Cast = explicitCastExpr(anyOf(cStyleCastExpr(), cxxStaticCastExpr(),
+ cxxReinterpretCastExpr()),
+ hasDestinationType(isInteger()),
+ has(Calc))
+ .bind("Cast");
+
+ Finder->addMatcher(varDecl(has(Cast)), this);
+ Finder->addMatcher(returnStmt(has(Cast)), this);
+ Finder->addMatcher(binaryOperator(hasOperatorName("="), hasRHS(Cast)), this);
+}
+
+static unsigned getMaxCalculationWidth(ASTContext &Context, const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (const auto *Bop = dyn_cast<BinaryOperator>(E)) {
+ unsigned LHSWidth = getMaxCalculationWidth(Context, Bop->getLHS());
+ unsigned RHSWidth = getMaxCalculationWidth(Context, Bop->getRHS());
+ if (Bop->getOpcode() == BO_Mul)
+ return LHSWidth + RHSWidth;
+ if (Bop->getOpcode() == BO_Add)
+ return std::max(LHSWidth, RHSWidth) + 1;
+ if (Bop->getOpcode() == BO_Rem) {
+ llvm::APSInt Val;
+ if (Bop->getRHS()->EvaluateAsInt(Val, Context))
+ return Val.getActiveBits();
+ } else if (Bop->getOpcode() == BO_Shl) {
+ llvm::APSInt Bits;
+ if (Bop->getRHS()->EvaluateAsInt(Bits, Context)) {
+ // We don't handle negative values and large values well. It is assumed
+ // that compiler warnings are written for such values so the user will
+ // fix that.
+ return LHSWidth + Bits.getExtValue();
+ }
+
+ // Unknown bitcount, assume there is truncation.
+ return 1024U;
+ }
+ } else if (const auto *Uop = dyn_cast<UnaryOperator>(E)) {
+ // There is truncation when ~ is used.
+ if (Uop->getOpcode() == UO_Not)
+ return 1024U;
+
+ QualType T = Uop->getType();
+ return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
+ } else if (const auto *I = dyn_cast<IntegerLiteral>(E)) {
+ return I->getValue().getActiveBits();
+ }
+
+ return Context.getIntWidth(E->getType());
+}
+
+void MisplacedWideningCastCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Cast = Result.Nodes.getNodeAs<ExplicitCastExpr>("Cast");
+ if (Cast->getLocStart().isMacroID())
+ return;
+
+ const auto *Calc = Result.Nodes.getNodeAs<Expr>("Calc");
+ if (Calc->getLocStart().isMacroID())
+ return;
+
+ ASTContext &Context = *Result.Context;
+
+ QualType CastType = Cast->getType();
+ QualType CalcType = Calc->getType();
+
+ if (Context.getIntWidth(CastType) <= Context.getIntWidth(CalcType))
+ return;
+
+ if (Context.getIntWidth(CalcType) >= getMaxCalculationWidth(Context, Calc))
+ return;
+
+ diag(Cast->getLocStart(), "either cast from %0 to %1 is ineffective, or "
+ "there is loss of precision before the conversion")
+ << CalcType << CastType;
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Added: clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.h?rev=260223&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/MisplacedWideningCastCheck.h Tue Feb 9 08:08:49 2016
@@ -0,0 +1,38 @@
+//===--- MisplacedWideningCastCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_WIDENING_CAST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_WIDENING_CAST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Find explicit redundant casts of calculation results to bigger type.
+/// Typically from int to long. If the intention of the cast is to avoid loss
+/// of precision then the cast is misplaced, and there can be loss of
+/// precision. Otherwise such cast is ineffective.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-misplaced-widening-cast.html
+class MisplacedWideningCastCheck : public ClangTidyCheck {
+public:
+ MisplacedWideningCastCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif
Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=260223&r1=260222&r2=260223&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Tue Feb 9 08:08:49 2016
@@ -53,6 +53,7 @@ Clang-Tidy Checks
misc-inefficient-algorithm
misc-macro-parentheses
misc-macro-repeated-side-effects
+ misc-misplaced-widening-cast
misc-move-constructor-init
misc-new-delete-overloads
misc-noexcept-move-constructor
Added: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-misplaced-widening-cast.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/misc-misplaced-widening-cast.rst?rev=260223&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-misplaced-widening-cast.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-misplaced-widening-cast.rst Tue Feb 9 08:08:49 2016
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - misc-misplaced-widening-cast
+
+misc-misplaced-widening-cast
+============================
+
+This check will warn when there is a explicit redundant cast of a calculation
+result to a bigger type. If the intention of the cast is to avoid loss of
+precision then the cast is misplaced, and there can be loss of precision.
+Otherwise the cast is ineffective.
+
+Example code::
+
+ long f(int x) {
+ return (long)(x*1000);
+ }
+
+The result x*1000 is first calculated using int precision. If the result
+exceeds int precision there is loss of precision. Then the result is casted to
+long.
+
+If there is no loss of precision then the cast can be removed or you can
+explicitly cast to int instead.
+
+If you want to avoid loss of precision then put the cast in a proper location,
+for instance::
+
+ long f(int x) {
+ return (long)x * 1000;
+ }
+
+Floating point
+--------------
+
+Currently warnings are only written for integer conversion. No warning is
+written for this code::
+
+ double f(float x) {
+ return (double)(x * 10.0f);
+ }
Added: clang-tools-extra/trunk/test/clang-tidy/misc-misplaced-widening-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-misplaced-widening-cast.cpp?rev=260223&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-misplaced-widening-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-misplaced-widening-cast.cpp Tue Feb 9 08:08:49 2016
@@ -0,0 +1,63 @@
+// RUN: %check_clang_tidy %s misc-misplaced-widening-cast %t
+
+void assign(int a, int b) {
+ long l;
+
+ l = a * b;
+ l = (long)(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long' is ineffective, or there is loss of precision before the conversion [misc-misplaced-widening-cast]
+ l = (long)a * b;
+
+ l = (long)(a << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = (long)b << 8;
+
+ l = static_cast<long>(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long' is ineffective, or there is loss of precision before the conversion [misc-misplaced-widening-cast]
+}
+
+void init(unsigned int n) {
+ long l = (long)(n << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'unsigned int'
+}
+
+long ret(int a) {
+ return (long)(a * 1000);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: either cast from 'int' to 'long'
+}
+
+void dontwarn1(unsigned char a, int i, unsigned char *p) {
+ long l;
+ // The result is a 9 bit value, there is no truncation in the implicit cast.
+ l = (long)(a + 15);
+ // The result is a 12 bit value, there is no truncation in the implicit cast.
+ l = (long)(a << 4);
+ // The result is a 3 bit value, there is no truncation in the implicit cast.
+ l = (long)((i%5)+1);
+ // The result is a 16 bit value, there is no truncation in the implicit cast.
+ l = (long)(((*p)<<8) + *(p+1));
+}
+
+template <class T> struct DontWarn2 {
+ void assign(T a, T b) {
+ long l;
+ l = (long)(a * b);
+ }
+};
+DontWarn2<int> DW2;
+
+// Cast is not suspicious when casting macro.
+#define A (X<<2)
+long macro1(int X) {
+ return (long)A;
+}
+
+// Don't warn about cast in macro.
+#define B(X,Y) (long)(X*Y)
+long macro2(int x, int y) {
+ return B(x,y);
+}
+
+void floatingpoint(float a, float b) {
+ double d = (double)(a * b); // Currently we don't warn for this.
+}
More information about the cfe-commits
mailing list