stephanemoore updated this revision to Diff 179239.
stephanemoore marked 6 inline comments as done.
stephanemoore added a comment.

Changes:
• Assert on `EncodedDecl`.
• Mention default value in objc-type-encoding-size check notes.

Outstanding action items:
• Evaluate using `hasDeclContext` instead of `hasAncestor`.
• Include type encoding size information in diagnostic messages.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55640/new/

https://reviews.llvm.org/D55640

Files:
  clang-tidy/objc/CMakeLists.txt
  clang-tidy/objc/ObjCTidyModule.cpp
  clang-tidy/objc/TypeEncodingSizeCheck.cpp
  clang-tidy/objc/TypeEncodingSizeCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/objc-type-encoding-size.rst
  test/clang-tidy/objc-type-encoding-size.m

Index: test/clang-tidy/objc-type-encoding-size.m
===================================================================
--- /dev/null
+++ test/clang-tidy/objc-type-encoding-size.m
@@ -0,0 +1,69 @@
+// RUN: %check_clang_tidy %s objc-type-encoding-size %t \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: objc-type-encoding-size.Threshold, value: 15}]}' \
+// RUN: -- -fblocks
+
+typedef struct {
+  int a1;
+  int a2;
+  int a3;
+  int a4;
+  int a5;
+  int a6;
+  int a7;
+  int a8;
+  int a9;
+  int a10;
+  int a11;
+  int a12;
+} SixteenCharStruct;
+
+typedef struct {
+  int a1;
+} FiveCharStruct;
+
+typedef void (^BlockType)(SixteenCharStruct);
+
+@interface Foo {
+  SixteenCharStruct _someStruct;
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: Objective-C type encoding for
+  // '_someStruct' exceeds 15 characters [objc-type-encoding-size]
+
+  int _anInteger;
+}
+
+@property(nonatomic) SixteenCharStruct anotherStruct;
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: Objective-C type encoding for
+// 'anotherStruct' exceeds 15 characters [objc-type-encoding-size]
+// CHECK-MESSAGES: :[[@LINE-3]]:40: warning: Objective-C type encoding for
+// 'setAnotherStruct:' exceeds 15 characters [objc-type-encoding-size]
+
+@property(nonatomic, setter=setAsparagus:) FiveCharStruct bananas;
+// CHECK-MESSAGES: :[[@LINE-1]]:59: warning: Objective-C type encoding for
+// 'bananas' exceeds 15 characters [objc-type-encoding-size]
+
+@end
+
+@implementation Foo
+
+- (void)bar:(SixteenCharStruct)a {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: Objective-C type encoding for 'bar:'
+// exceeds 15 characters [objc-type-encoding-size]
+}
+
+- (int)doThing {
+  int (^block)(SixteenCharStruct) = ^(SixteenCharStruct a) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: Objective-C type encoding for
+    // block expression exceeds 15 characters [objc-type-encoding-size]
+    return a.a4 + 5;
+  };
+
+  return block(_someStruct);
+}
+
+- (const char *)str {
+  // We should not flag explicit encoding statements.
+  return @encode(SixteenCharStruct);
+}
+
+@end
Index: docs/clang-tidy/checks/objc-type-encoding-size.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/objc-type-encoding-size.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - objc-type-encoding-size
+
+objc-type-encoding-size
+=======================
+
+Detects Objective-C type encodings that exceed a configured threshold.
+
+Options
+-------
+
+.. option:: Threshold
+
+   Flag Objective-C type encodings that exceed this number of bytes. The
+   default is `2000`.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -218,6 +218,7 @@
    objc-avoid-spinlock
    objc-forbidden-subclassing
    objc-property-declaration
+   objc-type-encoding-size
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-conversion-in-loop
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -174,6 +174,11 @@
   Detects usage of the deprecated member types of ``std::ios_base`` and replaces
   those that have a non-deprecated equivalent.
 
+- New :doc:`objc-type-encoding-size
+  <clang-tidy/checks/objc-type-encoding-size>` check.
+
+  Detects Objective-C type encodings that exceed a configured threshold.
+
 - New :doc:`readability-isolate-decl
   <clang-tidy/checks/readability-isolate-declaration>` check.
 
Index: clang-tidy/objc/TypeEncodingSizeCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/objc/TypeEncodingSizeCheck.h
@@ -0,0 +1,34 @@
+//===--- TypeEncodingSizeCheck.h - clang-tidy -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+/// Finds Objective-C type encodings that exceed a configured size threshold.
+///
+/// For the user-facing documentation see:
+/// http:///clang.llvm.org/extra/clang-tidy/checks/objc-type-encoding-size.html
+class TypeEncodingSizeCheck : public ClangTidyCheck {
+public:
+  TypeEncodingSizeCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  const unsigned Threshold;
+};
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/objc/TypeEncodingSizeCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/objc/TypeEncodingSizeCheck.cpp
@@ -0,0 +1,112 @@
+//===--- TypeEncodingSizeCheck.cpp - clang-tidy ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeEncodingSizeCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+TypeEncodingSizeCheck::TypeEncodingSizeCheck(StringRef Name,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Threshold(Options.get("Threshold", 2000U)) {}
+
+void TypeEncodingSizeCheck::registerMatchers(MatchFinder *Finder) {
+  // This check should only be applied to Objective-C sources.
+  if (!getLangOpts().ObjC)
+    return;
+
+  Finder->addMatcher(
+      blockExpr(unless(isExpansionInSystemHeader())).bind("block"), this);
+  Finder->addMatcher(
+      objcIvarDecl(unless(isExpansionInSystemHeader())).bind("decl"), this);
+  Finder->addMatcher(
+      objcPropertyDecl(unless(isExpansionInSystemHeader()),
+                       anyOf(hasAncestor(objcInterfaceDecl().bind("interface")),
+                             hasAncestor(objcCategoryDecl().bind("category"))))
+          .bind("decl"),
+      this);
+  Finder->addMatcher(
+      objcMethodDecl(unless(isExpansionInSystemHeader())).bind("decl"), this);
+}
+
+void TypeEncodingSizeCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Block = Result.Nodes.getNodeAs<BlockExpr>("block")) {
+    std::string BlockTypeEncoding =
+        Block->getBlockDecl()->getASTContext().getObjCEncodingForBlock(Block);
+
+    if (BlockTypeEncoding.size() <= Threshold)
+      return;
+
+    diag(Block->getCaretLocation(),
+         "Objective-C type encoding for block expression exceeds %0 "
+         "characters")
+        << Threshold;
+
+    return;
+  }
+
+  const auto *EncodedDecl = Result.Nodes.getNodeAs<NamedDecl>("decl");
+  assert(EncodedDecl);
+
+  std::string TypeEncoding;
+  if (const auto *IvarDecl = dyn_cast<ObjCIvarDecl>(EncodedDecl)) {
+    IvarDecl->getASTContext().getObjCEncodingForType(IvarDecl->getType(),
+                                                     TypeEncoding);
+  } else if (const auto *PropertyDecl =
+                 dyn_cast<ObjCPropertyDecl>(EncodedDecl)) {
+    const Decl *ContainerDecl = nullptr;
+
+    // Properties in interfaces and categories need respective implementations
+    // to determine the type encoding.
+    if (const auto *ClassDecl =
+            Result.Nodes.getNodeAs<ObjCInterfaceDecl>("interface")) {
+      ContainerDecl = ClassDecl->getImplementation();
+
+      // Bail out if we cannot find the implementation because this likely
+      // indicates a finding that cannot be acted upon.
+      if (ContainerDecl == nullptr)
+        return;
+    } else if (const auto *CategoryDecl =
+                   Result.Nodes.getNodeAs<ObjCCategoryDecl>("category")) {
+      ContainerDecl = CategoryDecl->getImplementation();
+
+      // Bail out if we cannot find the implementation because this likely
+      // indicates a finding that cannot be acted upon.
+      if (ContainerDecl == nullptr)
+        return;
+    }
+
+    TypeEncoding = PropertyDecl->getASTContext().getObjCEncodingForPropertyDecl(
+        PropertyDecl, ContainerDecl);
+  } else if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(EncodedDecl)) {
+    TypeEncoding =
+        MethodDecl->getASTContext().getObjCEncodingForMethodDecl(MethodDecl);
+  }
+
+  if (TypeEncoding.size() <= Threshold)
+    return;
+
+  diag(EncodedDecl->getLocation(),
+       "Objective-C type encoding for %0 exceeds %1 characters")
+      << EncodedDecl << Threshold;
+}
+
+void TypeEncodingSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Threshold", Threshold);
+}
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/objc/ObjCTidyModule.cpp
===================================================================
--- clang-tidy/objc/ObjCTidyModule.cpp
+++ clang-tidy/objc/ObjCTidyModule.cpp
@@ -14,6 +14,7 @@
 #include "AvoidSpinlockCheck.h"
 #include "ForbiddenSubclassingCheck.h"
 #include "PropertyDeclarationCheck.h"
+#include "TypeEncodingSizeCheck.h"
 
 using namespace clang::ast_matchers;
 
@@ -32,6 +33,8 @@
         "objc-forbidden-subclassing");
     CheckFactories.registerCheck<PropertyDeclarationCheck>(
         "objc-property-declaration");
+    CheckFactories.registerCheck<TypeEncodingSizeCheck>(
+        "objc-type-encoding-size");
   }
 };
 
Index: clang-tidy/objc/CMakeLists.txt
===================================================================
--- clang-tidy/objc/CMakeLists.txt
+++ clang-tidy/objc/CMakeLists.txt
@@ -6,6 +6,7 @@
   ForbiddenSubclassingCheck.cpp
   ObjCTidyModule.cpp
   PropertyDeclarationCheck.cpp
+  TypeEncodingSizeCheck.cpp
 
   LINK_LIBS
   clangAST
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to