106 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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/// \code24/// @interface Foo25/// - (instancetype)init;26/// - (instancetype)initWithInt:(int)i;27/// + (instancetype)init;28/// - (void)bar;29/// @end30/// \endcode31AST_MATCHER(ObjCMethodDecl, isInitializer) {32 return Node.getMethodFamily() == OMF_init;33}34 35/// Matches Objective-C implementations with interfaces that match36/// \c Base.37///38/// Example matches implementation declarations for X.39/// (matcher = objcImplementationDecl(hasInterface(hasName("X"))))40/// \code41/// @interface X42/// @end43/// @implementation X44/// @end45/// @interface Y46// @end47/// @implementation Y48/// @end49/// \endcode50AST_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 the57/// super instance.58///59/// Example matches the invocations of -banana and -orange.60/// (matcher = objcMessageExpr(isMessagingSuperInstance()))61/// \code62/// - (void)banana {63/// [self apple]64/// [super banana];65/// [super orange];66/// }67/// \endcode68AST_MATCHER(ObjCMessageExpr, isMessagingSuperInstance) {69 return Node.getReceiverKind() == ObjCMessageExpr::SuperInstance;70}71 72} // namespace73 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 const SourceLocation ReceiverLoc = Message->getReceiverRange().getBegin();94 if (ReceiverLoc.isMacroID() || ReceiverLoc.isInvalid())95 return;96 97 const 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::objc106