NonPrivateMemberVariablesInClassesCheck.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. //===--- NonPrivateMemberVariablesInClassesCheck.cpp - clang-tidy ---------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "NonPrivateMemberVariablesInClassesCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. using namespace clang::ast_matchers;
  12. namespace clang::tidy::misc {
  13. namespace {
  14. AST_MATCHER(CXXRecordDecl, hasMethods) {
  15. return std::distance(Node.method_begin(), Node.method_end()) != 0;
  16. }
  17. AST_MATCHER(CXXRecordDecl, hasNonStaticNonImplicitMethod) {
  18. return hasMethod(unless(anyOf(isStaticStorageClass(), isImplicit())))
  19. .matches(Node, Finder, Builder);
  20. }
  21. AST_MATCHER(CXXRecordDecl, hasNonPublicMemberVariable) {
  22. return cxxRecordDecl(has(fieldDecl(unless(isPublic()))))
  23. .matches(Node, Finder, Builder);
  24. }
  25. AST_POLYMORPHIC_MATCHER_P(boolean, AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl),
  26. bool, Boolean) {
  27. return Boolean;
  28. }
  29. } // namespace
  30. NonPrivateMemberVariablesInClassesCheck::
  31. NonPrivateMemberVariablesInClassesCheck(StringRef Name,
  32. ClangTidyContext *Context)
  33. : ClangTidyCheck(Name, Context),
  34. IgnoreClassesWithAllMemberVariablesBeingPublic(
  35. Options.get("IgnoreClassesWithAllMemberVariablesBeingPublic", false)),
  36. IgnorePublicMemberVariables(
  37. Options.get("IgnorePublicMemberVariables", false)) {}
  38. void NonPrivateMemberVariablesInClassesCheck::storeOptions(
  39. ClangTidyOptions::OptionMap &Opts) {
  40. Options.store(Opts, "IgnoreClassesWithAllMemberVariablesBeingPublic",
  41. IgnoreClassesWithAllMemberVariablesBeingPublic);
  42. Options.store(Opts, "IgnorePublicMemberVariables",
  43. IgnorePublicMemberVariables);
  44. }
  45. void NonPrivateMemberVariablesInClassesCheck::registerMatchers(
  46. MatchFinder *Finder) {
  47. // We can ignore structs/classes with all member variables being public.
  48. auto ShouldIgnoreRecord =
  49. allOf(boolean(IgnoreClassesWithAllMemberVariablesBeingPublic),
  50. unless(hasNonPublicMemberVariable()));
  51. // There are three visibility types: public, protected, private.
  52. // If we are ok with public fields, then we only want to complain about
  53. // protected fields, else we want to complain about all non-private fields.
  54. // We can ignore public member variables in structs/classes, in unions.
  55. auto InterestingField = IgnorePublicMemberVariables
  56. ? fieldDecl(isProtected())
  57. : fieldDecl(unless(isPrivate()));
  58. // We only want the records that not only contain the mutable data (non-static
  59. // member variables), but also have some logic (non-static, non-implicit
  60. // member functions). We may optionally ignore records where all the member
  61. // variables are public.
  62. Finder->addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()), hasMethods(),
  63. hasNonStaticNonImplicitMethod(),
  64. unless(ShouldIgnoreRecord),
  65. forEach(InterestingField.bind("field")))
  66. .bind("record"),
  67. this);
  68. }
  69. void NonPrivateMemberVariablesInClassesCheck::check(
  70. const MatchFinder::MatchResult &Result) {
  71. const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field");
  72. assert(Field && "We should have the field we are going to complain about");
  73. diag(Field->getLocation(), "member variable %0 has %1 visibility")
  74. << Field << Field->getAccess();
  75. }
  76. } // namespace clang::tidy::misc