[clang-tidy] Fix handling of function types in google-readability-casting

llvm-svn: 294751
This commit is contained in:
Alexander Kornienko 2017-02-10 14:57:19 +00:00
parent a3362a1c9e
commit 01496fe455
2 changed files with 100 additions and 7 deletions

View File

@ -73,14 +73,26 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
QualType SourceType = CastExpr->getSubExprAsWritten()->getType();
QualType DestType = CastExpr->getTypeAsWritten();
if (SourceType == DestType) {
auto isFunction = [](QualType T) {
T = T.getCanonicalType().getNonReferenceType();
return T->isFunctionType() || T->isFunctionPointerType() ||
T->isMemberFunctionPointerType();
};
bool FnToFnCast = isFunction(SourceType) && isFunction(DestType);
// Function pointer/reference casts may be needed to resolve ambiguities in
// case of overloaded functions, so detection of redundant casts is trickier
// in this case. Don't emit "redundant cast" warnings for function
// pointer/reference types.
if (SourceType == DestType && !FnToFnCast) {
diag(CastExpr->getLocStart(), "redundant cast to the same type")
<< FixItHint::CreateRemoval(ParenRange);
return;
}
SourceType = SourceType.getCanonicalType();
DestType = DestType.getCanonicalType();
if (SourceType == DestType) {
if (SourceType == DestType && !FnToFnCast) {
diag(CastExpr->getLocStart(),
"possibly redundant cast between typedefs of the same type");
return;
@ -111,27 +123,34 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
CastExpr->getRParenLoc().getLocWithOffset(-1)),
SM, getLangOpts());
auto diag_builder =
auto Diag =
diag(CastExpr->getLocStart(), "C-style casts are discouraged; use %0");
auto ReplaceWithCast = [&](StringRef CastType) {
diag_builder << CastType;
Diag << CastType;
const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
std::string CastText = (CastType + "<" + DestTypeString + ">").str();
if (!isa<ParenExpr>(SubExpr)) {
CastText.push_back('(');
diag_builder << FixItHint::CreateInsertion(
Diag << FixItHint::CreateInsertion(
Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, SM,
getLangOpts()),
")");
}
diag_builder << FixItHint::CreateReplacement(ParenRange, CastText);
Diag << FixItHint::CreateReplacement(ParenRange, CastText);
};
// Suggest appropriate C++ cast. See [expr.cast] for cast notation semantics.
switch (CastExpr->getCastKind()) {
case CK_FunctionToPointerDecay:
ReplaceWithCast("static_cast");
return;
case CK_NoOp:
if (FnToFnCast) {
ReplaceWithCast("static_cast");
return;
}
if (needsConstCast(SourceType, DestType) &&
pointedTypesAreEqual(SourceType, DestType)) {
ReplaceWithCast("const_cast");
@ -166,7 +185,7 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
break;
}
diag_builder << "static_cast/const_cast/reinterpret_cast";
Diag << "static_cast/const_cast/reinterpret_cast";
}
} // namespace readability

View File

@ -148,3 +148,77 @@ struct A {
static const E ee = e;
};
struct B : public A<E1> {};
void overloaded_function();
void overloaded_function(int);
template<typename Fn>
void g(Fn fn) {
fn();
}
void function_casts() {
typedef void (*FnPtrVoid)();
typedef void (&FnRefVoid)();
typedef void (&FnRefInt)(int);
g((void (*)())overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<void (*)()>(overloaded_function));
g((void (*)())&overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<void (*)()>(&overloaded_function));
g((void (&)())overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<void (&)()>(overloaded_function));
g((FnPtrVoid)overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<FnPtrVoid>(overloaded_function));
g((FnPtrVoid)&overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<FnPtrVoid>(&overloaded_function));
g((FnRefVoid)overloaded_function);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: g(static_cast<FnRefVoid>(overloaded_function));
FnPtrVoid fn0 = (void (*)())&overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: FnPtrVoid fn0 = static_cast<void (*)()>(&overloaded_function);
FnPtrVoid fn1 = (void (*)())overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: FnPtrVoid fn1 = static_cast<void (*)()>(overloaded_function);
FnPtrVoid fn1a = (FnPtrVoid)overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: FnPtrVoid fn1a = static_cast<FnPtrVoid>(overloaded_function);
FnRefInt fn2 = (void (&)(int))overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: FnRefInt fn2 = static_cast<void (&)(int)>(overloaded_function);
auto fn3 = (void (*)())&overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: auto fn3 = static_cast<void (*)()>(&overloaded_function);
auto fn4 = (void (*)())overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: auto fn4 = static_cast<void (*)()>(overloaded_function);
auto fn5 = (void (&)(int))overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: auto fn5 = static_cast<void (&)(int)>(overloaded_function);
void (*fn6)() = (void (*)())&overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: void (*fn6)() = static_cast<void (*)()>(&overloaded_function);
void (*fn7)() = (void (*)())overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: void (*fn7)() = static_cast<void (*)()>(overloaded_function);
void (*fn8)() = (FnPtrVoid)overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: void (*fn8)() = static_cast<FnPtrVoid>(overloaded_function);
void (&fn9)(int) = (void (&)(int))overloaded_function;
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: C-style casts are discouraged; use static_cast [
// CHECK-FIXES: void (&fn9)(int) = static_cast<void (&)(int)>(overloaded_function);
void (*correct1)() = static_cast<void (*)()>(overloaded_function);
FnPtrVoid correct2 = static_cast<void (*)()>(&overloaded_function);
FnRefInt correct3 = static_cast<void (&)(int)>(overloaded_function);
}