forked from OSchip/llvm-project
Extend misc-misplaced-const to detect using declarations as well as typedef
This commit is contained in:
parent
4460cb5bcd
commit
ecc7dae50c
|
@ -17,13 +17,16 @@ namespace tidy {
|
||||||
namespace misc {
|
namespace misc {
|
||||||
|
|
||||||
void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
|
void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
|
||||||
|
auto NonConstAndNonFunctionPointerType = hasType(pointerType(unless(
|
||||||
|
pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
|
||||||
|
|
||||||
Finder->addMatcher(
|
Finder->addMatcher(
|
||||||
valueDecl(hasType(isConstQualified()),
|
valueDecl(
|
||||||
hasType(typedefType(hasDeclaration(
|
hasType(isConstQualified()),
|
||||||
typedefDecl(hasType(pointerType(unless(pointee(
|
hasType(typedefType(hasDeclaration(anyOf(
|
||||||
anyOf(isConstQualified(),
|
typedefDecl(NonConstAndNonFunctionPointerType).bind("typedef"),
|
||||||
ignoringParens(functionType())))))))
|
typeAliasDecl(NonConstAndNonFunctionPointerType)
|
||||||
.bind("typedef")))))
|
.bind("typeAlias"))))))
|
||||||
.bind("decl"),
|
.bind("decl"),
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
@ -45,16 +48,29 @@ static QualType guessAlternateQualification(ASTContext &Context, QualType QT) {
|
||||||
|
|
||||||
void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
|
void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
|
||||||
const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
|
const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
|
||||||
const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
|
|
||||||
ASTContext &Ctx = *Result.Context;
|
ASTContext &Ctx = *Result.Context;
|
||||||
QualType CanQT = Var->getType().getCanonicalType();
|
QualType CanQT = Var->getType().getCanonicalType();
|
||||||
|
|
||||||
diag(Var->getLocation(), "%0 declared with a const-qualified typedef type; "
|
SourceLocation AliasLoc;
|
||||||
"results in the type being '%1' instead of '%2'")
|
const char *AliasType;
|
||||||
<< Var << CanQT.getAsString(Ctx.getPrintingPolicy())
|
if (const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef")) {
|
||||||
|
AliasLoc = Typedef->getLocation();
|
||||||
|
AliasType = "typedef";
|
||||||
|
} else if (const auto *TypeAlias =
|
||||||
|
Result.Nodes.getNodeAs<TypeAliasDecl>("typeAlias")) {
|
||||||
|
AliasLoc = TypeAlias->getLocation();
|
||||||
|
AliasType = "type alias";
|
||||||
|
} else {
|
||||||
|
llvm_unreachable("registerMatchers has registered an unknown matcher,"
|
||||||
|
" code out of sync");
|
||||||
|
}
|
||||||
|
|
||||||
|
diag(Var->getLocation(), "%0 declared with a const-qualified %1; "
|
||||||
|
"results in the type being '%2' instead of '%3'")
|
||||||
|
<< Var << AliasType << CanQT.getAsString(Ctx.getPrintingPolicy())
|
||||||
<< guessAlternateQualification(Ctx, CanQT)
|
<< guessAlternateQualification(Ctx, CanQT)
|
||||||
.getAsString(Ctx.getPrintingPolicy());
|
.getAsString(Ctx.getPrintingPolicy());
|
||||||
diag(Typedef->getLocation(), "typedef declared here", DiagnosticIDs::Note);
|
diag(AliasLoc, "%0 declared here", DiagnosticIDs::Note) << AliasType;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace misc
|
} // namespace misc
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
misc-misplaced-const
|
misc-misplaced-const
|
||||||
====================
|
====================
|
||||||
|
|
||||||
This check diagnoses when a ``const`` qualifier is applied to a ``typedef`` to a
|
This check diagnoses when a ``const`` qualifier is applied to a ``typedef``/
|
||||||
pointer type rather than to the pointee, because such constructs are often
|
``using`` to a pointer type rather than to the pointee, because such constructs
|
||||||
misleading to developers because the ``const`` applies to the pointer rather
|
are often misleading to developers because the ``const`` applies to the pointer
|
||||||
than the pointee.
|
rather than the pointee.
|
||||||
|
|
||||||
For instance, in the following code, the resulting type is ``int *`` ``const``
|
For instance, in the following code, the resulting type is ``int *`` ``const``
|
||||||
rather than ``const int *``:
|
rather than ``const int *``:
|
||||||
|
@ -14,9 +14,12 @@ rather than ``const int *``:
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
typedef int *int_ptr;
|
typedef int *int_ptr;
|
||||||
void f(const int_ptr ptr);
|
void f(const int_ptr ptr) {
|
||||||
|
*ptr = 0; // potentially quite unexpectedly the int can be modified here
|
||||||
|
ptr = 0; // does not compile
|
||||||
|
}
|
||||||
|
|
||||||
The check does not diagnose when the underlying ``typedef`` type is a pointer to
|
The check does not diagnose when the underlying ``typedef``/``using`` type is a
|
||||||
a ``const`` type or a function pointer type. This is because the ``const``
|
pointer to a ``const`` type or a function pointer type. This is because the
|
||||||
qualifier is less likely to be mistaken because it would be redundant (or
|
``const`` qualifier is less likely to be mistaken because it would be redundant
|
||||||
disallowed) on the underlying pointee type.
|
(or disallowed) on the underlying pointee type.
|
||||||
|
|
|
@ -1,20 +1,40 @@
|
||||||
// RUN: %check_clang_tidy %s misc-misplaced-const %t
|
// RUN: %check_clang_tidy %s misc-misplaced-const %t -- -- -DUSING
|
||||||
|
// RUN: %check_clang_tidy %s misc-misplaced-const %t -- -- -DTYPEDEF
|
||||||
|
|
||||||
typedef int plain_i;
|
#ifdef TYPEDEF
|
||||||
typedef int *ip;
|
typedef int int_;
|
||||||
typedef const int *cip;
|
typedef int *ptr_to_int;
|
||||||
|
typedef const int *ptr_to_const_int;
|
||||||
|
#endif
|
||||||
|
#ifdef USING
|
||||||
|
using int_ = int;
|
||||||
|
using ptr_to_int = int *;
|
||||||
|
using ptr_to_const_int = const int *;
|
||||||
|
#endif
|
||||||
|
|
||||||
void func() {
|
void const_pointers() {
|
||||||
if (const int *i = 0)
|
if (const int *i = 0) {
|
||||||
;
|
i = 0;
|
||||||
if (const plain_i *i = 0)
|
// *i = 0;
|
||||||
;
|
}
|
||||||
if (const cip i = 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
// CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'i' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
|
if (const int_ *i = 0) {
|
||||||
if (const ip i = 0)
|
i = 0;
|
||||||
;
|
// *i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const ptr_to_const_int i = 0) {
|
||||||
|
// i = 0;
|
||||||
|
// *i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Potentially quite unexpectedly the int can be modified here
|
||||||
|
// CHECK-MESSAGES: :[[@LINE+1]]:23: warning: 'i' declared with a const-qualified {{.*}}; results in the type being 'int *const' instead of 'const int *'
|
||||||
|
if (const ptr_to_int i = 0) {
|
||||||
|
//i = 0;
|
||||||
|
|
||||||
|
*i = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Ty>
|
template <typename Ty>
|
||||||
|
@ -24,8 +44,8 @@ struct S {
|
||||||
};
|
};
|
||||||
|
|
||||||
template struct S<int>;
|
template struct S<int>;
|
||||||
template struct S<ip>; // ok
|
template struct S<ptr_to_int>; // ok
|
||||||
template struct S<cip>;
|
template struct S<ptr_to_const_int>;
|
||||||
|
|
||||||
template <typename Ty>
|
template <typename Ty>
|
||||||
struct U {
|
struct U {
|
||||||
|
|
Loading…
Reference in New Issue