SuperSelfCheck.cpp 3.3 KB

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