arphaman updated this revision to Diff 122949.
arphaman added a comment.

Remove C++ support for now (it will be in a followup patch along with 
non-member function support).


Repository:
  rL LLVM

https://reviews.llvm.org/D39913

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/SemaObjC/method-attributes.m
  test/SemaObjC/unguarded-availability.m
  test/SemaObjC/warn-missing-method-decl-availability.m

Index: test/SemaObjC/warn-missing-method-decl-availability.m
===================================================================
--- /dev/null
+++ test/SemaObjC/warn-missing-method-decl-availability.m
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify -Wno-objc-root-class %s
+
+// Warn about availability attribute when they're specified in the definition
+// of the method instead of the declaration.
+// rdar://15540962
+
+@interface MissingAvailabilityThingsInInterface
+
+- (void)missingIDO; // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+
+- (void)missingDO __attribute__((availability(macos, introduced=10.1))); // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+
+- (void)missingD __attribute__((availability(macos, introduced=10.1))); // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+
+- (void)missingIx2; // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+// expected-warning@-1 {{method declaration is missing an availability attribute for iOS that is specified in the definition}}
+
+- (void)missingIDOiOS __attribute__((availability(macos, introduced=10.1))); // expected-warning {{method declaration is missing an availability attribute for iOS that is specified in the definition}}
+
+- (void)differentIMissingD __attribute__((availability(macos, introduced=10.1))); // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+// expected-note@-1 {{previous attribute is here}}
+
+- (void)missingUnavailable; // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+
+- (void)same
+__attribute__((availability(macos, introduced=10.1)))
+__attribute__((availability(ios, unavailable)));
+
+- (void)missingDeprecatedAttr; // expected-warning {{method declaration is missing a deprecated attribute that is specified in the definition}}
+
+- (void)sameDeprecatedAttr __attribute__((deprecated("y")));
+
+@end
+
+@interface MissingAvailabilityThingsInInterface()
+
+- (void)missingInClassExtension; // expected-warning {{method declaration is missing an availability attribute for macOS that is specified in the definition}}
+
+@end
+
+@implementation MissingAvailabilityThingsInInterface
+
+- (void)missingIDO
+__attribute__((availability(macos, introduced=10.1, deprecated=10.2, obsoleted=10.3))) // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)missingDO
+__attribute__((availability(macos, introduced=10.1)))
+__attribute__((availability(macos, deprecated=10.2, obsoleted=10.3))) // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)missingD
+__attribute__((availability(macos, introduced=10.1, deprecated=10.2))) // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)missingIx2
+__attribute__((availability(ios, introduced=10))) // expected-note {{definition with iOS availability attribute is here}}
+__attribute__((availability(macos, introduced=10.1))) // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)missingIDOiOS
+__attribute__((availability(ios, introduced=10, deprecated=11, obsoleted=11.1))) // expected-note {{definition with iOS availability attribute is here}}
+__attribute__((availability(macOS, introduced=10.1)))
+{ }
+
+- (void)differentIMissingD __attribute__((availability(macos, introduced=10.2, deprecated=10.3))) // expected-note {{definition with macOS availability attribute is here}}
+{ } // expected-warning@-1{{availability does not match previous declaration}}
+
+- (void)missingInClassExtension
+__attribute__((availability(macos, introduced=10.1, deprecated=10.2))) // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)missingUnavailable
+__attribute__((availability(macos, unavailable))); // expected-note {{definition with macOS availability attribute is here}}
+{ }
+
+- (void)same
+__attribute__((availability(macos, introduced=10.1)))
+__attribute__((availability(ios, unavailable)))
+{ }
+
+- (void)missingDeprecatedAttr
+__attribute__((deprecated("x")))  // expected-note {{definition with deprecated attribute is here}}
+{ }
+
+- (void)sameDeprecatedAttr __attribute__((deprecated("y")))
+{ }
+
+@end
+
+@interface MissingAvailabilityThingsInInterface (Category)
+
+- (void)missingInCategory; // expected-warning {{method declaration is missing an availability attribute for tvOS that is specified in the definition}}
+
+@end
+
+@implementation MissingAvailabilityThingsInInterface (Category)
+
+- (void)missingInCategory
+__attribute__((availability(tvOS, introduced=10))) // expected-note {{definition with tvOS availability attribute is here}}
+{ }
+
+@end
+
+@interface DontWarnOnOverrideImpl
+
+- (void)missingIDO
+__attribute__((availability(macos, introduced=10.1, deprecated=10.2, obsoleted=10.3))); // ok
+
+@end
+
+@implementation DontWarnOnOverrideImpl
+
+- (void)missingIDO { }
+
+// ok
+- (void)missingDO
+__attribute__((availability(macos, introduced=10.1)))
+__attribute__((availability(macos, deprecated=10.2, obsoleted=10.3)))
+{ }
+
+@end
+
+@protocol DontWarnOnProtocol
+
+- (void)missingIDO;
+
+@end
+
+@interface DontWarnOnProtocolImpl<DontWarnOnProtocol>
+@end
+
+@implementation DontWarnOnProtocolImpl
+
+- (void)missingIDO
+__attribute__((availability(macos, introduced=10.1, deprecated=10.2, obsoleted=10.3)))
+{}
+
+@end
Index: test/SemaObjC/unguarded-availability.m
===================================================================
--- test/SemaObjC/unguarded-availability.m
+++ test/SemaObjC/unguarded-availability.m
@@ -77,7 +77,7 @@
   int_10_12 bar; // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}}
 }
 - (void)method1;
-- (void)method2;
+- (void)method2 AVAILABLE_10_12;
 @end
 
 @implementation Class_10_11
Index: test/SemaObjC/method-attributes.m
===================================================================
--- test/SemaObjC/method-attributes.m
+++ test/SemaObjC/method-attributes.m
@@ -15,14 +15,14 @@
 @interface INTF
 - (int) foo1: (int)arg1 __attribute__((deprecated));
 
-- (int) foo: (int)arg1;
+- (int) foo: (int)arg1;  // expected-warning {{method declaration is missing a deprecated attribute that is specified in the definition}}
 
 - (int) foo2: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable));
 - (int) foo3: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable)) __attribute__((ns_consumes_self));
 @end
 
 @implementation INTF
-- (int) foo: (int)arg1  __attribute__((deprecated)){
+- (int) foo: (int)arg1  __attribute__((deprecated)){ // expected-note {{definition with deprecated attribute is here}}
         return 10;
 }
 - (int) foo1: (int)arg1 {
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2277,6 +2277,50 @@
   return false;
 }
 
+void Sema::checkMissingAvailabilityClausesInDeclaration(
+    NamedDecl *Original, NamedDecl *Implementation) {
+  if (!Implementation->hasAttrs())
+    return;
+
+  llvm::SmallPtrSet<const IdentifierInfo *, 4> MissingPlatformAttributes;
+  for (auto *Def : Implementation->specific_attrs<AvailabilityAttr>()) {
+    bool MissingIntroduced = !Def->getIntroduced().empty();
+    bool MissingDeprecated = !Def->getDeprecated().empty();
+    bool MissingObsoleted = !Def->getObsoleted().empty();
+    bool MissingUnavailable = Def->getUnavailable();
+    for (auto *Decl : Original->specific_attrs<AvailabilityAttr>()) {
+      if (Def->getPlatform() != Decl->getPlatform())
+        continue;
+      MissingIntroduced =
+          MissingIntroduced ? Decl->getIntroduced().empty() : false;
+      MissingDeprecated =
+          MissingDeprecated ? Decl->getDeprecated().empty() : false;
+      MissingObsoleted =
+          MissingObsoleted ? Decl->getObsoleted().empty() : false;
+      MissingUnavailable = MissingUnavailable ? !Decl->getUnavailable() : false;
+    }
+    if (MissingIntroduced || MissingDeprecated || MissingObsoleted ||
+        MissingUnavailable) {
+      if (!MissingPlatformAttributes.insert(Def->getPlatform()).second)
+        continue;
+      StringRef PlatformSpelling = AvailabilityAttr::getPrettyPlatformName(
+          Def->getPlatform()->getName());
+      Diag(Original->getLocation(),
+           diag::warn_availability_on_implementation_not_interface)
+          << PlatformSpelling;
+      Diag(Def->getLocation(), diag::note_definition_with_availability_here)
+          << PlatformSpelling;
+    }
+  }
+  if (const auto *Dep = Implementation->getAttr<DeprecatedAttr>()) {
+    if (!Original->hasAttr<DeprecatedAttr>()) {
+      Diag(Original->getLocation(),
+           diag::warn_deprecated_on_implementation_not_interface);
+      Diag(Dep->getLocation(), diag::note_definition_with_deprecated_here);
+    }
+  }
+}
+
 AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
                                               IdentifierInfo *Platform,
                                               bool Implicit,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -3572,6 +3572,20 @@
       : isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration
                                                        : AMK_Override;
 
+  // Warn on any availability clauses that are missing in the method's
+  // declaration but specified in the definition.
+  if (const ObjCImplDecl *Imp =
+          dyn_cast<ObjCImplDecl>(newMethod->getDeclContext())) {
+    const Decl *DC = cast<Decl>(oldMethod->getDeclContext());
+    if (Imp->getClassInterface() == DC ||
+        (isa<ObjCCategoryDecl>(DC) &&
+         cast<ObjCCategoryDecl>(DC)->IsClassExtension() &&
+         Imp->getClassInterface() ==
+             cast<ObjCCategoryDecl>(DC)->getClassInterface()) ||
+        (isa<ObjCCategoryImplDecl>(Imp) &&
+         cast<ObjCCategoryImplDecl>(Imp)->getCategoryDecl() == DC))
+      checkMissingAvailabilityClausesInDeclaration(oldMethod, newMethod);
+  }
   mergeDeclAttributes(newMethod, oldMethod, MergeKind);
 
   // Merge attributes from the parameters.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2399,6 +2399,13 @@
     AMK_ProtocolImplementation,
   };
 
+  /// Verifies that availability attribute clauses that are specified on an
+  /// method definition match the clauses from the method's declaration.
+  ///
+  /// This will warn on any missing clauses in the declaration.
+  void checkMissingAvailabilityClausesInDeclaration(NamedDecl *Original,
+                                                    NamedDecl *Implementation);
+
   /// Attribute merging methods. Return true if a new attribute was added.
   AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
                                           IdentifierInfo *Platform,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2917,6 +2917,18 @@
   "%select{the protocol method it implements|its overridden method}1 is "
   "available">,
   InGroup<Availability>;
+def warn_availability_on_implementation_not_interface : Warning<
+  "method declaration is missing an availability attribute for "
+  "%0 that is specified in the definition">,
+  InGroup<Availability>;
+def warn_deprecated_on_implementation_not_interface : Warning<
+  "method declaration is missing a deprecated attribute that is specified in "
+  "the definition">,
+  InGroup<Availability>;
+def note_definition_with_availability_here : Note<
+  "definition with %0 availability attribute is here">;
+def note_definition_with_deprecated_here : Note<
+  "definition with deprecated attribute is here">;
 def note_overridden_method : Note<
   "overridden method is here">;
 def note_protocol_method : Note<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to