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