xref: /llvm-project/clang-tools-extra/clang-tidy/objc/SuperSelfCheck.cpp (revision 11a411a49b62c129bba551df4587dd446fcdc660)
1b0c1f8c0SStephane Moore //===--- SuperSelfCheck.cpp - clang-tidy ----------------------------------===//
2b0c1f8c0SStephane Moore //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b0c1f8c0SStephane Moore //
7b0c1f8c0SStephane Moore //===----------------------------------------------------------------------===//
8b0c1f8c0SStephane Moore 
9b0c1f8c0SStephane Moore #include "SuperSelfCheck.h"
10b0c1f8c0SStephane Moore #include "clang/AST/ASTContext.h"
11b0c1f8c0SStephane Moore #include "clang/ASTMatchers/ASTMatchFinder.h"
12b0c1f8c0SStephane Moore 
13b0c1f8c0SStephane Moore using namespace clang::ast_matchers;
14b0c1f8c0SStephane Moore 
157d2ea6c4SCarlos Galvez namespace clang::tidy::objc {
16b0c1f8c0SStephane Moore 
17b0c1f8c0SStephane Moore namespace {
18b0c1f8c0SStephane Moore 
19282dc72cSDmitri Gribenko /// Matches Objective-C methods in the initializer family.
20b0c1f8c0SStephane Moore ///
21b0c1f8c0SStephane Moore /// Example matches -init and -initWithInt:.
22b0c1f8c0SStephane Moore ///   (matcher = objcMethodDecl(isInitializer()))
23b0c1f8c0SStephane Moore /// \code
24b0c1f8c0SStephane Moore ///   @interface Foo
25b0c1f8c0SStephane Moore ///   - (instancetype)init;
26b0c1f8c0SStephane Moore ///   - (instancetype)initWithInt:(int)i;
27b0c1f8c0SStephane Moore ///   + (instancetype)init;
28b0c1f8c0SStephane Moore ///   - (void)bar;
29b0c1f8c0SStephane Moore ///   @end
30b0c1f8c0SStephane Moore /// \endcode
AST_MATCHER(ObjCMethodDecl,isInitializer)31b0c1f8c0SStephane Moore AST_MATCHER(ObjCMethodDecl, isInitializer) {
32b0c1f8c0SStephane Moore   return Node.getMethodFamily() == OMF_init;
33b0c1f8c0SStephane Moore }
34b0c1f8c0SStephane Moore 
35*11a411a4SPiotr Zegar /// Matches Objective-C implementations with interfaces that match
36*11a411a4SPiotr Zegar /// \c Base.
37*11a411a4SPiotr Zegar ///
38*11a411a4SPiotr Zegar /// Example matches implementation declarations for X.
39*11a411a4SPiotr Zegar ///   (matcher = objcImplementationDecl(hasInterface(hasName("X"))))
40*11a411a4SPiotr Zegar /// \code
41*11a411a4SPiotr Zegar ///   @interface X
42*11a411a4SPiotr Zegar ///   @end
43*11a411a4SPiotr Zegar ///   @implementation X
44*11a411a4SPiotr Zegar ///   @end
45*11a411a4SPiotr Zegar ///   @interface Y
46*11a411a4SPiotr Zegar //    @end
47*11a411a4SPiotr Zegar ///   @implementation Y
48*11a411a4SPiotr Zegar ///   @end
49*11a411a4SPiotr Zegar /// \endcode
AST_MATCHER_P(ObjCImplementationDecl,hasInterface,ast_matchers::internal::Matcher<ObjCInterfaceDecl>,Base)50*11a411a4SPiotr Zegar AST_MATCHER_P(ObjCImplementationDecl, hasInterface,
51*11a411a4SPiotr Zegar               ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) {
52*11a411a4SPiotr Zegar   const ObjCInterfaceDecl *InterfaceDecl = Node.getClassInterface();
53*11a411a4SPiotr Zegar   return Base.matches(*InterfaceDecl, Finder, Builder);
54*11a411a4SPiotr Zegar }
55*11a411a4SPiotr Zegar 
56282dc72cSDmitri Gribenko /// Matches Objective-C message expressions where the receiver is the
57b0c1f8c0SStephane Moore /// super instance.
58b0c1f8c0SStephane Moore ///
59b0c1f8c0SStephane Moore /// Example matches the invocations of -banana and -orange.
60b0c1f8c0SStephane Moore ///   (matcher = objcMessageExpr(isMessagingSuperInstance()))
61b0c1f8c0SStephane Moore /// \code
62b0c1f8c0SStephane Moore ///   - (void)banana {
63b0c1f8c0SStephane Moore ///     [self apple]
64b0c1f8c0SStephane Moore ///     [super banana];
65b0c1f8c0SStephane Moore ///     [super orange];
66b0c1f8c0SStephane Moore ///   }
67b0c1f8c0SStephane Moore /// \endcode
AST_MATCHER(ObjCMessageExpr,isMessagingSuperInstance)68b0c1f8c0SStephane Moore AST_MATCHER(ObjCMessageExpr, isMessagingSuperInstance) {
69b0c1f8c0SStephane Moore   return Node.getReceiverKind() == ObjCMessageExpr::SuperInstance;
70b0c1f8c0SStephane Moore }
71b0c1f8c0SStephane Moore 
72b0c1f8c0SStephane Moore } // namespace
73b0c1f8c0SStephane Moore 
registerMatchers(MatchFinder * Finder)74b0c1f8c0SStephane Moore void SuperSelfCheck::registerMatchers(MatchFinder *Finder) {
75b0c1f8c0SStephane Moore   Finder->addMatcher(
76a53cce94SStephane Moore       objcMessageExpr(hasSelector("self"), isMessagingSuperInstance(),
77a53cce94SStephane Moore                       hasAncestor(objcMethodDecl(
78a53cce94SStephane Moore                           isInitializer(),
79a53cce94SStephane Moore                           hasDeclContext(objcImplementationDecl(hasInterface(
80a53cce94SStephane Moore                               isDerivedFrom(hasName("NSObject"))))))))
81b0c1f8c0SStephane Moore           .bind("message"),
82b0c1f8c0SStephane Moore       this);
83b0c1f8c0SStephane Moore }
84b0c1f8c0SStephane Moore 
check(const MatchFinder::MatchResult & Result)85b0c1f8c0SStephane Moore void SuperSelfCheck::check(const MatchFinder::MatchResult &Result) {
86b0c1f8c0SStephane Moore   const auto *Message = Result.Nodes.getNodeAs<ObjCMessageExpr>("message");
87b0c1f8c0SStephane Moore 
88b0c1f8c0SStephane Moore   auto Diag = diag(Message->getExprLoc(), "suspicious invocation of %0 in "
89b0c1f8c0SStephane Moore                                           "initializer; did you mean to "
90b0c1f8c0SStephane Moore                                           "invoke a superclass initializer?")
91b0c1f8c0SStephane Moore               << Message->getMethodDecl();
92b0c1f8c0SStephane Moore 
93b0c1f8c0SStephane Moore   SourceLocation ReceiverLoc = Message->getReceiverRange().getBegin();
94b0c1f8c0SStephane Moore   if (ReceiverLoc.isMacroID() || ReceiverLoc.isInvalid())
95b0c1f8c0SStephane Moore     return;
96b0c1f8c0SStephane Moore 
97b0c1f8c0SStephane Moore   SourceLocation SelectorLoc = Message->getSelectorStartLoc();
98b0c1f8c0SStephane Moore   if (SelectorLoc.isMacroID() || SelectorLoc.isInvalid())
99b0c1f8c0SStephane Moore     return;
100b0c1f8c0SStephane Moore 
101b0c1f8c0SStephane Moore   Diag << FixItHint::CreateReplacement(Message->getSourceRange(),
102b0c1f8c0SStephane Moore                                        StringRef("[super init]"));
103b0c1f8c0SStephane Moore }
104b0c1f8c0SStephane Moore 
1057d2ea6c4SCarlos Galvez } // namespace clang::tidy::objc
106