xref: /llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1e010406eSHaojian Wu //===--- ForbiddenSubclassingCheck.cpp - clang-tidy -----------------------===//
2e010406eSHaojian Wu //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e010406eSHaojian Wu //
7e010406eSHaojian Wu //===----------------------------------------------------------------------===//
8e010406eSHaojian Wu 
9e010406eSHaojian Wu #include "ForbiddenSubclassingCheck.h"
10e010406eSHaojian Wu #include "clang/AST/ASTContext.h"
11e010406eSHaojian Wu #include "clang/ASTMatchers/ASTMatchFinder.h"
12e010406eSHaojian Wu #include "llvm/ADT/Hashing.h"
13e010406eSHaojian Wu #include "llvm/ADT/SmallVector.h"
14e010406eSHaojian Wu #include "../utils/OptionsUtils.h"
15e010406eSHaojian Wu 
16e010406eSHaojian Wu using namespace clang::ast_matchers;
17e010406eSHaojian Wu 
18e010406eSHaojian Wu namespace clang {
19e010406eSHaojian Wu namespace tidy {
20e010406eSHaojian Wu namespace objc {
21e010406eSHaojian Wu 
22e010406eSHaojian Wu namespace {
23e010406eSHaojian Wu 
24e010406eSHaojian Wu constexpr char DefaultForbiddenSuperClassNames[] =
25e010406eSHaojian Wu     "ABNewPersonViewController;"
26e010406eSHaojian Wu     "ABPeoplePickerNavigationController;"
27e010406eSHaojian Wu     "ABPersonViewController;"
28e010406eSHaojian Wu     "ABUnknownPersonViewController;"
29e010406eSHaojian Wu     "NSHashTable;"
30e010406eSHaojian Wu     "NSMapTable;"
31e010406eSHaojian Wu     "NSPointerArray;"
32e010406eSHaojian Wu     "NSPointerFunctions;"
33e010406eSHaojian Wu     "NSTimer;"
34e010406eSHaojian Wu     "UIActionSheet;"
35e010406eSHaojian Wu     "UIAlertView;"
36e010406eSHaojian Wu     "UIImagePickerController;"
37e010406eSHaojian Wu     "UITextInputMode;"
38e010406eSHaojian Wu     "UIWebView";
39e010406eSHaojian Wu 
40e010406eSHaojian Wu /// \brief Matches Objective-C classes that directly or indirectly
41e010406eSHaojian Wu /// have a superclass matching \c Base.
42e010406eSHaojian Wu ///
43e010406eSHaojian Wu /// Note that a class is not considered to be a subclass of itself.
44e010406eSHaojian Wu ///
45e010406eSHaojian Wu /// Example matches Y, Z
46e010406eSHaojian Wu /// (matcher = objcInterfaceDecl(hasName("X")))
47e010406eSHaojian Wu /// \code
48e010406eSHaojian Wu ///   @interface X
49e010406eSHaojian Wu ///   @end
50e010406eSHaojian Wu ///   @interface Y : X  // directly derived
51e010406eSHaojian Wu ///   @end
52e010406eSHaojian Wu ///   @interface Z : Y  // indirectly derived
53e010406eSHaojian Wu ///   @end
54e010406eSHaojian Wu /// \endcode
55e010406eSHaojian Wu AST_MATCHER_P(ObjCInterfaceDecl, isSubclassOf,
56e010406eSHaojian Wu               ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) {
57e010406eSHaojian Wu   for (const auto *SuperClass = Node.getSuperClass();
58e010406eSHaojian Wu        SuperClass != nullptr;
59e010406eSHaojian Wu        SuperClass = SuperClass->getSuperClass()) {
60e010406eSHaojian Wu     if (Base.matches(*SuperClass, Finder, Builder)) {
61e010406eSHaojian Wu       return true;
62e010406eSHaojian Wu     }
63e010406eSHaojian Wu   }
64e010406eSHaojian Wu   return false;
65e010406eSHaojian Wu }
66e010406eSHaojian Wu 
67e010406eSHaojian Wu } // namespace
68e010406eSHaojian Wu 
69e010406eSHaojian Wu ForbiddenSubclassingCheck::ForbiddenSubclassingCheck(
70e010406eSHaojian Wu     StringRef Name,
71e010406eSHaojian Wu     ClangTidyContext *Context)
72e010406eSHaojian Wu     : ClangTidyCheck(Name, Context),
73e010406eSHaojian Wu       ForbiddenSuperClassNames(
74e010406eSHaojian Wu           utils::options::parseStringList(
75e010406eSHaojian Wu               Options.get("ClassNames", DefaultForbiddenSuperClassNames))) {
76e010406eSHaojian Wu }
77e010406eSHaojian Wu 
78e010406eSHaojian Wu void ForbiddenSubclassingCheck::registerMatchers(MatchFinder *Finder) {
79c7faee73SYan Zhang   // this check should only be applied to ObjC sources.
80fa98390bSErik Pilkington   if (!getLangOpts().ObjC)
81c7faee73SYan Zhang     return;
82fa98390bSErik Pilkington 
83e010406eSHaojian Wu   Finder->addMatcher(
84e010406eSHaojian Wu       objcInterfaceDecl(
85e010406eSHaojian Wu           isSubclassOf(
86e010406eSHaojian Wu               objcInterfaceDecl(
87e010406eSHaojian Wu                   hasAnyName(
88e010406eSHaojian Wu                       std::vector<StringRef>(
89e010406eSHaojian Wu                           ForbiddenSuperClassNames.begin(),
90e010406eSHaojian Wu                           ForbiddenSuperClassNames.end())))
91e010406eSHaojian Wu               .bind("superclass")))
92e010406eSHaojian Wu       .bind("subclass"),
93e010406eSHaojian Wu       this);
94e010406eSHaojian Wu }
95e010406eSHaojian Wu 
96e010406eSHaojian Wu void ForbiddenSubclassingCheck::check(
97e010406eSHaojian Wu     const MatchFinder::MatchResult &Result) {
98e010406eSHaojian Wu   const auto *SubClass = Result.Nodes.getNodeAs<ObjCInterfaceDecl>(
99e010406eSHaojian Wu       "subclass");
100e010406eSHaojian Wu   assert(SubClass != nullptr);
101e010406eSHaojian Wu   const auto *SuperClass = Result.Nodes.getNodeAs<ObjCInterfaceDecl>(
102e010406eSHaojian Wu       "superclass");
103e010406eSHaojian Wu   assert(SuperClass != nullptr);
104e010406eSHaojian Wu   diag(SubClass->getLocation(),
105e010406eSHaojian Wu        "Objective-C interface %0 subclasses %1, which is not "
106e010406eSHaojian Wu        "intended to be subclassed")
107e010406eSHaojian Wu       << SubClass
108e010406eSHaojian Wu       << SuperClass;
109e010406eSHaojian Wu }
110e010406eSHaojian Wu 
111e010406eSHaojian Wu void ForbiddenSubclassingCheck::storeOptions(
112e010406eSHaojian Wu     ClangTidyOptions::OptionMap &Opts) {
113e010406eSHaojian Wu   Options.store(
114e010406eSHaojian Wu       Opts,
115e010406eSHaojian Wu       "ForbiddenSuperClassNames",
116e010406eSHaojian Wu       utils::options::serializeStringList(ForbiddenSuperClassNames));
117e010406eSHaojian Wu }
118e010406eSHaojian Wu 
119e010406eSHaojian Wu } // namespace objc
120e010406eSHaojian Wu } // namespace tidy
121e010406eSHaojian Wu } // namespace clang
122