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