Add the misc-misplaced-const check to clang-tidy, which diagnoses when a const-qualifier is applied to a typedef of pointer type rather than to the pointee type.
llvm-svn: 272025
This commit is contained in:
parent
968bb72f58
commit
cf6cefd88a
|
@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
|
|||
add_clang_library(clangTidyMiscModule
|
||||
ArgumentCommentCheck.cpp
|
||||
AssertSideEffectCheck.cpp
|
||||
MisplacedConstCheck.cpp
|
||||
UnconventionalAssignOperatorCheck.cpp
|
||||
BoolPointerImplicitConversionCheck.cpp
|
||||
DanglingHandleCheck.cpp
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../ClangTidyModuleRegistry.h"
|
||||
#include "ArgumentCommentCheck.h"
|
||||
#include "AssertSideEffectCheck.h"
|
||||
#include "MisplacedConstCheck.h"
|
||||
#include "UnconventionalAssignOperatorCheck.h"
|
||||
#include "BoolPointerImplicitConversionCheck.h"
|
||||
#include "DanglingHandleCheck.h"
|
||||
|
@ -61,6 +62,8 @@ public:
|
|||
CheckFactories.registerCheck<ArgumentCommentCheck>("misc-argument-comment");
|
||||
CheckFactories.registerCheck<AssertSideEffectCheck>(
|
||||
"misc-assert-side-effect");
|
||||
CheckFactories.registerCheck<MisplacedConstCheck>(
|
||||
"misc-misplaced-const");
|
||||
CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
|
||||
"misc-unconventional-assign-operator");
|
||||
CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//===--- MisplacedConstCheck.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 "MisplacedConstCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace misc {
|
||||
|
||||
void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(
|
||||
valueDecl(hasType(isConstQualified()),
|
||||
hasType(typedefType(hasDeclaration(
|
||||
typedefDecl(hasType(pointerType(unless(pointee(
|
||||
anyOf(isConstQualified(),
|
||||
ignoringParens(functionType())))))))
|
||||
.bind("typedef")))))
|
||||
.bind("decl"),
|
||||
this);
|
||||
}
|
||||
|
||||
static QualType guessAlternateQualification(ASTContext &Context, QualType QT) {
|
||||
// We're given a QualType from a typedef where the qualifiers apply to the
|
||||
// pointer instead of the pointee. Strip the const qualifier from the pointer
|
||||
// type and add it to the pointee instead.
|
||||
if (!QT->isPointerType())
|
||||
return QT;
|
||||
|
||||
Qualifiers Quals = QT.getLocalQualifiers();
|
||||
Quals.removeConst();
|
||||
|
||||
QualType NewQT = Context.getPointerType(
|
||||
QualType(QT->getPointeeType().getTypePtr(), Qualifiers::Const));
|
||||
return NewQT.withCVRQualifiers(Quals.getCVRQualifiers());
|
||||
}
|
||||
|
||||
void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
|
||||
const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
|
||||
ASTContext &Ctx = *Result.Context;
|
||||
QualType CanQT = Var->getType().getCanonicalType();
|
||||
|
||||
diag(Var->getLocation(), "%0 declared with a const-qualified typedef type; "
|
||||
"results in the type being '%1' instead of '%2'")
|
||||
<< Var << CanQT.getAsString(Ctx.getPrintingPolicy())
|
||||
<< guessAlternateQualification(Ctx, CanQT)
|
||||
.getAsString(Ctx.getPrintingPolicy());
|
||||
diag(Typedef->getLocation(), "typedef declared here", DiagnosticIDs::Note);
|
||||
}
|
||||
|
||||
} // namespace misc
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,36 @@
|
|||
//===--- MisplacedConstCheck.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_CONST_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace misc {
|
||||
|
||||
/// This check diagnoses when a const qualifier is applied to a typedef to a
|
||||
/// pointer type rather than to the pointee.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/misc-misplaced-const.html
|
||||
class MisplacedConstCheck : public ClangTidyCheck {
|
||||
public:
|
||||
MisplacedConstCheck(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 // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H
|
|
@ -4,7 +4,6 @@ Clang-Tidy Checks
|
|||
=========================
|
||||
|
||||
.. toctree::
|
||||
|
||||
boost-use-to-string
|
||||
cert-dcl03-c (redirects to misc-static-assert) <cert-dcl03-c>
|
||||
cert-dcl50-cpp
|
||||
|
@ -63,6 +62,7 @@ Clang-Tidy Checks
|
|||
misc-inefficient-algorithm
|
||||
misc-macro-parentheses
|
||||
misc-macro-repeated-side-effects
|
||||
misc-misplaced-const
|
||||
misc-misplaced-widening-cast
|
||||
misc-move-const-arg
|
||||
misc-move-constructor-init
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
.. title:: clang-tidy - misc-misplaced-const
|
||||
|
||||
misc-misplaced-const
|
||||
====================
|
||||
|
||||
This check diagnoses when a const qualifier is applied to a typedef to a pointer
|
||||
type rather than to the pointee, because such constructs are often misleading to
|
||||
developers because the const applies to the pointer rather than the pointee.
|
||||
|
||||
For instance, in the following code, the resulting type is `int *` const rather
|
||||
than `const int *`:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
typedef int *int_ptr;
|
||||
void f(const int_ptr ptr);
|
||||
|
||||
The check does not diagnose when the underlying typedef type is a pointer to a
|
||||
const type or a function pointer type. This is because the const qualifier is
|
||||
less likely to be mistaken because it would be redundant (or disallowed) on the
|
||||
underlying pointee type.
|
|
@ -0,0 +1,45 @@
|
|||
// RUN: %check_clang_tidy %s misc-misplaced-const %t
|
||||
|
||||
typedef int plain_i;
|
||||
typedef int *ip;
|
||||
typedef const int *cip;
|
||||
|
||||
typedef void (*func_ptr)(void);
|
||||
|
||||
void func(void) {
|
||||
// ok
|
||||
const int *i0 = 0;
|
||||
const plain_i *i1 = 0;
|
||||
const cip i2 = 0; // const applies to both pointer and pointee.
|
||||
|
||||
// Not ok
|
||||
const ip i3 = 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
|
||||
|
||||
ip const i4 = 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i4' declared with a const-qualified
|
||||
|
||||
const volatile ip i5 = 0;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i5' declared with a const-qualified typedef type; results in the type being 'int *const volatile' instead of 'const int *volatile'
|
||||
}
|
||||
|
||||
void func2(const plain_i *i1,
|
||||
const cip i2,
|
||||
const ip i3,
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i3' declared with a const-qualified
|
||||
const int *i4) {
|
||||
}
|
||||
|
||||
struct S {
|
||||
const int *i0;
|
||||
const plain_i *i1;
|
||||
const cip i2;
|
||||
const ip i3;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified
|
||||
};
|
||||
|
||||
// Function pointers should not be diagnosed because a function
|
||||
// pointer type can never be const.
|
||||
void func3(const func_ptr fp) {
|
||||
const func_ptr fp2 = fp;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// RUN: %check_clang_tidy %s misc-misplaced-const %t
|
||||
|
||||
typedef int plain_i;
|
||||
typedef int *ip;
|
||||
typedef const int *cip;
|
||||
|
||||
void func() {
|
||||
if (const int *i = 0)
|
||||
;
|
||||
if (const plain_i *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 ip i = 0)
|
||||
;
|
||||
}
|
||||
|
||||
template <typename Ty>
|
||||
struct S {
|
||||
const Ty *i;
|
||||
const Ty &i2;
|
||||
};
|
||||
|
||||
template struct S<int>;
|
||||
template struct S<ip>; // ok
|
||||
template struct S<cip>;
|
||||
template struct S<int *>; // ok
|
||||
|
||||
struct T {
|
||||
typedef void (T::*PMF)();
|
||||
|
||||
void f() {
|
||||
const PMF val = &T::f; // ok
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue