clang-tools  9.0.0
SuperSelfCheck.cpp
Go to the documentation of this file.
1 //===--- SuperSelfCheck.cpp - clang-tidy ----------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SuperSelfCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace objc {
19 
20 namespace {
21 
22 /// \brief Matches Objective-C methods in the initializer family.
23 ///
24 /// Example matches -init and -initWithInt:.
25 /// (matcher = objcMethodDecl(isInitializer()))
26 /// \code
27 /// @interface Foo
28 /// - (instancetype)init;
29 /// - (instancetype)initWithInt:(int)i;
30 /// + (instancetype)init;
31 /// - (void)bar;
32 /// @end
33 /// \endcode
34 AST_MATCHER(ObjCMethodDecl, isInitializer) {
35  return Node.getMethodFamily() == OMF_init;
36 }
37 
38 /// \brief Matches Objective-C implementations of classes that directly or
39 /// indirectly have a superclass matching \c InterfaceDecl.
40 ///
41 /// Note that a class is not considered to be a subclass of itself.
42 ///
43 /// Example matches implementation declarations for Y and Z.
44 /// (matcher = objcInterfaceDecl(isSubclassOf(hasName("X"))))
45 /// \code
46 /// @interface X
47 /// @end
48 /// @interface Y : X
49 /// @end
50 /// @implementation Y // directly derived
51 /// @end
52 /// @interface Z : Y
53 /// @end
54 /// @implementation Z // indirectly derived
55 /// @end
56 /// \endcode
57 AST_MATCHER_P(ObjCImplementationDecl, isSubclassOf,
58  ast_matchers::internal::Matcher<ObjCInterfaceDecl>,
59  InterfaceDecl) {
60  // Check if any of the superclasses of the class match.
61  for (const ObjCInterfaceDecl *SuperClass =
62  Node.getClassInterface()->getSuperClass();
63  SuperClass != nullptr; SuperClass = SuperClass->getSuperClass()) {
64  if (InterfaceDecl.matches(*SuperClass, Finder, Builder))
65  return true;
66  }
67 
68  // No matches found.
69  return false;
70 }
71 
72 /// \brief Matches Objective-C message expressions where the receiver is the
73 /// super instance.
74 ///
75 /// Example matches the invocations of -banana and -orange.
76 /// (matcher = objcMessageExpr(isMessagingSuperInstance()))
77 /// \code
78 /// - (void)banana {
79 /// [self apple]
80 /// [super banana];
81 /// [super orange];
82 /// }
83 /// \endcode
84 AST_MATCHER(ObjCMessageExpr, isMessagingSuperInstance) {
85  return Node.getReceiverKind() == ObjCMessageExpr::SuperInstance;
86 }
87 
88 } // namespace
89 
90 void SuperSelfCheck::registerMatchers(MatchFinder *Finder) {
91  // This check should only be applied to Objective-C sources.
92  if (!getLangOpts().ObjC)
93  return;
94 
95  Finder->addMatcher(
96  objcMessageExpr(
97  hasSelector("self"), isMessagingSuperInstance(),
98  hasAncestor(objcMethodDecl(isInitializer(),
99  hasDeclContext(objcImplementationDecl(
100  isSubclassOf(hasName("NSObject")))))))
101  .bind("message"),
102  this);
103 }
104 
105 void SuperSelfCheck::check(const MatchFinder::MatchResult &Result) {
106  const auto *Message = Result.Nodes.getNodeAs<ObjCMessageExpr>("message");
107 
108  auto Diag = diag(Message->getExprLoc(), "suspicious invocation of %0 in "
109  "initializer; did you mean to "
110  "invoke a superclass initializer?")
111  << Message->getMethodDecl();
112 
113  SourceLocation ReceiverLoc = Message->getReceiverRange().getBegin();
114  if (ReceiverLoc.isMacroID() || ReceiverLoc.isInvalid())
115  return;
116 
117  SourceLocation SelectorLoc = Message->getSelectorStartLoc();
118  if (SelectorLoc.isMacroID() || SelectorLoc.isInvalid())
119  return;
120 
121  Diag << FixItHint::CreateReplacement(Message->getSourceRange(),
122  StringRef("[super init]"));
123 }
124 
125 } // namespace objc
126 } // namespace tidy
127 } // namespace clang
constexpr llvm::StringLiteral Message
CodeCompletionBuilder Builder
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: Rename.cpp:36
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)