clang-tools 20.0.0git
SuperSelfCheck.cpp
Go to the documentation of this file.
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(*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 objcMessageExpr(hasSelector("self"), isMessagingSuperInstance(),
77 hasAncestor(objcMethodDecl(
78 isInitializer(),
79 hasDeclContext(objcImplementationDecl(hasInterface(
80 isDerivedFrom(hasName("NSObject"))))))))
81 .bind("message"),
82 this);
83}
84
85void SuperSelfCheck::check(const MatchFinder::MatchResult &Result) {
86 const auto *Message = Result.Nodes.getNodeAs<ObjCMessageExpr>("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
CodeCompletionBuilder Builder
::clang::DynTypedNode Node
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
AST_MATCHER_P(UserDefinedLiteral, hasLiteral, clang::ast_matchers::internal::Matcher< Expr >, InnerMatcher)
AST_MATCHER(Decl, declHasNoReturnAttr)
matches a Decl if it has a "no return" attribute of any kind