[clang-tidy] Add a checker that warns on const string & members.

Summary:
Those are considered unsafe and should be replaced with simple pointers or
full copies. It recognizes both std::string and ::string.

Reviewers: alexfh, djasper

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D4522

llvm-svn: 213133
This commit is contained in:
Benjamin Kramer 2014-07-16 10:00:14 +00:00
parent 2e9427a175
commit b1039759fb
5 changed files with 152 additions and 0 deletions

View File

@ -7,6 +7,7 @@ add_clang_library(clangTidyGoogleModule
GoogleTidyModule.cpp
NamedParameterCheck.cpp
OverloadedUnaryAndCheck.cpp
StringReferenceMemberCheck.cpp
LINK_LIBS
clangAST

View File

@ -15,6 +15,7 @@
#include "ExplicitMakePairCheck.h"
#include "NamedParameterCheck.h"
#include "OverloadedUnaryAndCheck.h"
#include "StringReferenceMemberCheck.h"
using namespace clang::ast_matchers;
@ -33,6 +34,9 @@ public:
CheckFactories.addCheckFactory(
"google-runtime-operator",
new ClangTidyCheckFactory<runtime::OverloadedUnaryAndCheck>());
CheckFactories.addCheckFactory(
"google-runtime-member-string-references",
new ClangTidyCheckFactory<runtime::StringReferenceMemberCheck>());
CheckFactories.addCheckFactory(
"google-readability-casting",
new ClangTidyCheckFactory<readability::AvoidCStyleCastsCheck>());

View File

@ -0,0 +1,48 @@
//===--- StringReferenceMemberCheck.cpp - clang-tidy ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "StringReferenceMemberCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/AST/ASTContext.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace runtime {
void StringReferenceMemberCheck::registerMatchers(
ast_matchers::MatchFinder *Finder) {
// Look for const references to std::string or ::string.
auto String = anyOf(recordDecl(hasName("::std::basic_string")),
recordDecl(hasName("::string")));
auto ConstString = qualType(isConstQualified(), hasDeclaration(String));
// Ignore members in template instantiations.
auto InTemplateInstantiation = hasAncestor(
decl(anyOf(recordDecl(ast_matchers::isTemplateInstantiation()),
functionDecl(ast_matchers::isTemplateInstantiation()))));
Finder->addMatcher(fieldDecl(hasType(references(ConstString)),
unless(InTemplateInstantiation)).bind("member"),
this);
}
void
StringReferenceMemberCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Member = Result.Nodes.getNodeAs<FieldDecl>("member");
diag(Member->getLocStart(), "const string& members are dangerous. It is much "
"better to use alternatives, such as pointers or "
"simple constants.");
}
} // namespace runtime
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,50 @@
//===--- StringReferenceMemberCheck.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_GOOGLE_STRING_REF_MEMBER_CHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_STRING_REF_MEMBER_CHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace runtime {
/// \brief Finds members of type 'const string&'.
///
/// const string reference members are generally considered unsafe as they can
/// be created from a temporary quite easily.
///
/// \code
/// struct S {
/// S(const string &Str) : Str(Str) {}
/// const string &Str;
/// };
/// S instance("string");
/// \endcode
///
/// In the constructor call a string temporary is created from const char * and
/// destroyed immediately after the call. This leaves around a dangling
/// reference.
///
/// This check emit warnings for both std::string and ::string const reference
/// members.
///
/// Corresponding cpplint.py check name: 'runtime/member_string_reference'.
class StringReferenceMemberCheck : public ClangTidyCheck {
public:
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace runtime
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_STRING_REF_MEMBER_CHECK_H

View File

@ -0,0 +1,49 @@
// RUN: clang-tidy %s -checks='-*,google-runtime-member-string-references' -- | FileCheck %s -implicit-check-not="{{warning|error}}:"
namespace std {
template<typename T>
class basic_string {};
typedef basic_string<char> string;
}
class string {};
struct A {
const std::string &s;
// CHECK: :[[@LINE-1]]:3: warning: const string& members are dangerous. It is much better to use alternatives, such as pointers or simple constants.
};
struct B {
std::string &s;
};
struct C {
const std::string s;
};
template <typename T>
struct D {
D();
const T &s;
const std::string &s2;
// CHECK: :[[@LINE-1]]:3: warning: const string& members are dangerous. It is much better to use alternatives, such as pointers or simple constants.
};
D<std::string> d;
struct AA {
const string &s;
// CHECK: :[[@LINE-1]]:3: warning: const string& members are dangerous. It is much better to use alternatives, such as pointers or simple constants.
};
struct BB {
string &s;
};
struct CC {
const string s;
};
D<string> dd;