brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.3 KiB · 3887afe Raw
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