• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 #include "NonPrivateMemberVariablesInClassesCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace misc {
18 
19 namespace {
20 
AST_MATCHER(CXXRecordDecl,hasMethods)21 AST_MATCHER(CXXRecordDecl, hasMethods) {
22   return std::distance(Node.method_begin(), Node.method_end()) != 0;
23 }
24 
AST_MATCHER(CXXRecordDecl,hasNonStaticNonImplicitMethod)25 AST_MATCHER(CXXRecordDecl, hasNonStaticNonImplicitMethod) {
26   return hasMethod(unless(anyOf(isStaticStorageClass(), isImplicit())))
27       .matches(Node, Finder, Builder);
28 }
29 
AST_MATCHER(CXXRecordDecl,hasNonPublicMemberVariable)30 AST_MATCHER(CXXRecordDecl, hasNonPublicMemberVariable) {
31   return cxxRecordDecl(has(fieldDecl(unless(isPublic()))))
32       .matches(Node, Finder, Builder);
33 }
34 
AST_POLYMORPHIC_MATCHER_P(boolean,AST_POLYMORPHIC_SUPPORTED_TYPES (Stmt,Decl),bool,Boolean)35 AST_POLYMORPHIC_MATCHER_P(boolean, AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl),
36                           bool, Boolean) {
37   return Boolean;
38 }
39 
40 } // namespace
41 
42 NonPrivateMemberVariablesInClassesCheck::
NonPrivateMemberVariablesInClassesCheck(StringRef Name,ClangTidyContext * Context)43     NonPrivateMemberVariablesInClassesCheck(StringRef Name,
44                                             ClangTidyContext *Context)
45     : ClangTidyCheck(Name, Context),
46       IgnoreClassesWithAllMemberVariablesBeingPublic(
47           Options.get("IgnoreClassesWithAllMemberVariablesBeingPublic", false)),
48       IgnorePublicMemberVariables(
49           Options.get("IgnorePublicMemberVariables", false)) {}
50 
storeOptions(ClangTidyOptions::OptionMap & Opts)51 void NonPrivateMemberVariablesInClassesCheck::storeOptions(
52     ClangTidyOptions::OptionMap &Opts) {
53   Options.store(Opts, "IgnoreClassesWithAllMemberVariablesBeingPublic",
54                 IgnoreClassesWithAllMemberVariablesBeingPublic);
55   Options.store(Opts, "IgnorePublicMemberVariables",
56                 IgnorePublicMemberVariables);
57 }
58 
registerMatchers(MatchFinder * Finder)59 void NonPrivateMemberVariablesInClassesCheck::registerMatchers(
60     MatchFinder *Finder) {
61   // We can ignore structs/classes with all member variables being public.
62   auto ShouldIgnoreRecord =
63       allOf(boolean(IgnoreClassesWithAllMemberVariablesBeingPublic),
64             unless(hasNonPublicMemberVariable()));
65 
66   // There are three visibility types: public, protected, private.
67   // If we are ok with public fields, then we only want to complain about
68   // protected fields, else we want to complain about all non-private fields.
69   // We can ignore public member variables in structs/classes, in unions.
70   auto InterestingField = IgnorePublicMemberVariables
71                               ? fieldDecl(isProtected())
72                               : fieldDecl(unless(isPrivate()));
73 
74   // We only want the records that not only contain the mutable data (non-static
75   // member variables), but also have some logic (non-static, non-implicit
76   // member functions).  We may optionally ignore records where all the member
77   // variables are public.
78   Finder->addMatcher(cxxRecordDecl(anyOf(isStruct(), isClass()), hasMethods(),
79                                    hasNonStaticNonImplicitMethod(),
80                                    unless(ShouldIgnoreRecord),
81                                    forEach(InterestingField.bind("field")))
82                          .bind("record"),
83                      this);
84 }
85 
check(const MatchFinder::MatchResult & Result)86 void NonPrivateMemberVariablesInClassesCheck::check(
87     const MatchFinder::MatchResult &Result) {
88   const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field");
89   assert(Field && "We should have the field we are going to complain about");
90 
91   diag(Field->getLocation(), "member variable %0 has %1 visibility")
92       << Field << Field->getAccess();
93 }
94 
95 } // namespace misc
96 } // namespace tidy
97 } // namespace clang
98