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:
Aaron Ballman 2016-06-07 17:22:47 +00:00
parent 968bb72f58
commit cf6cefd88a
8 changed files with 207 additions and 1 deletions

View File

@ -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

View File

@ -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>(

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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
}
};