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