1//===--- SuperSelfCheck.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 "SuperSelfCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::objc {
16
17namespace {
18
19/// Matches Objective-C methods in the initializer family.
20///
21/// Example matches -init and -initWithInt:.
22/// (matcher = objcMethodDecl(isInitializer()))
23/// \code
24/// @interface Foo
25/// - (instancetype)init;
26/// - (instancetype)initWithInt:(int)i;
27/// + (instancetype)init;
28/// - (void)bar;
29/// @end
30/// \endcode
31AST_MATCHER(ObjCMethodDecl, isInitializer) {
32 return Node.getMethodFamily() == OMF_init;
33}
34
35/// Matches Objective-C implementations with interfaces that match
36/// \c Base.
37///
38/// Example matches implementation declarations for X.
39/// (matcher = objcImplementationDecl(hasInterface(hasName("X"))))
40/// \code
41/// @interface X
42/// @end
43/// @implementation X
44/// @end
45/// @interface Y
46// @end
47/// @implementation Y
48/// @end
49/// \endcode
50AST_MATCHER_P(ObjCImplementationDecl, hasInterface,
51 ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) {
52 const ObjCInterfaceDecl *InterfaceDecl = Node.getClassInterface();
53 return Base.matches(Node: *InterfaceDecl, Finder, Builder);
54}
55
56/// Matches Objective-C message expressions where the receiver is the
57/// super instance.
58///
59/// Example matches the invocations of -banana and -orange.
60/// (matcher = objcMessageExpr(isMessagingSuperInstance()))
61/// \code
62/// - (void)banana {
63/// [self apple]
64/// [super banana];
65/// [super orange];
66/// }
67/// \endcode
68AST_MATCHER(ObjCMessageExpr, isMessagingSuperInstance) {
69 return Node.getReceiverKind() == ObjCMessageExpr::SuperInstance;
70}
71
72} // namespace
73
74void SuperSelfCheck::registerMatchers(MatchFinder *Finder) {
75 Finder->addMatcher(
76 NodeMatch: objcMessageExpr(hasSelector(BaseName: "self"), isMessagingSuperInstance(),
77 hasAncestor(objcMethodDecl(
78 isInitializer(),
79 hasDeclContext(InnerMatcher: objcImplementationDecl(hasInterface(
80 Base: isDerivedFrom(Base: hasName(Name: "NSObject"))))))))
81 .bind(ID: "message"),
82 Action: this);
83}
84
85void SuperSelfCheck::check(const MatchFinder::MatchResult &Result) {
86 const auto *Message = Result.Nodes.getNodeAs<ObjCMessageExpr>(ID: "message");
87
88 auto Diag = diag(Message->getExprLoc(), "suspicious invocation of %0 in "
89 "initializer; did you mean to "
90 "invoke a superclass initializer?")
91 << Message->getMethodDecl();
92
93 SourceLocation ReceiverLoc = Message->getReceiverRange().getBegin();
94 if (ReceiverLoc.isMacroID() || ReceiverLoc.isInvalid())
95 return;
96
97 SourceLocation SelectorLoc = Message->getSelectorStartLoc();
98 if (SelectorLoc.isMacroID() || SelectorLoc.isInvalid())
99 return;
100
101 Diag << FixItHint::CreateReplacement(Message->getSourceRange(),
102 StringRef("[super init]"));
103}
104
105} // namespace clang::tidy::objc
106

source code of clang-tools-extra/clang-tidy/objc/SuperSelfCheck.cpp