Add a warning for overridden methods that are missing the 'override' keyword. 
This diagnostic is only triggered when at least one method is marked 'override' 
in the class, and only in C++11 mode.

This way, codebase owners can be more confident when adding   'override' - it 
can be added one class at a time while asserting that methods are 'override' 
iff they override a base class's method.

http://llvm-reviews.chandlerc.com/D1275

Files:
  include/clang/AST/DeclCXX.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/DeclCXX.cpp
  lib/Sema/SemaDeclCXX.cpp
  test/CXX/class.derived/class.virtual/p3-0x.cpp
  test/FixIt/fixit-cxx0x.cpp
  test/Misc/diag-override.cpp
  test/Parser/MicrosoftExtensions.cpp
  test/SemaCXX/cxx98-compat.cpp
  test/SemaCXX/ms-interface.cpp
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -455,6 +455,9 @@
     /// \brief Whether this class describes a C++ lambda.
     bool IsLambda : 1;
 
+    /// \brief Whether this class has any override annotations
+    bool HasOverrideAnnotation : 1;
+
     /// \brief The number of base class specifiers in Bases.
     unsigned NumBases;
 
@@ -1220,6 +1223,11 @@
   /// (C++11 [class]p6).
   bool isTriviallyCopyable() const;
 
+  /// \brief Whether this class has any methods with an override annotation.
+  bool hasOverrideAnnotation() const {
+    return data().HasOverrideAnnotation;
+  }
+
   /// \brief Determine whether this class is considered trivial.
   ///
   /// C++11 [class]p6:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1535,6 +1535,9 @@
   "base %0 is marked 'final'">;
 def warn_abstract_final_class : Warning<
   "abstract class is marked 'final'">, InGroup<AbstractFinalClass>;
+def warn_missing_override_annotation : Warning<
+  "method %0 overrides %1 method(s) but is not marked 'override'">,
+  InGroup<DiagGroup<"missing-override-annotation">>;
 
 // C++11 attributes
 def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">;
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
@@ -22,6 +23,8 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
+
+
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -61,8 +64,8 @@
     HasDeclaredCopyConstructorWithConstParam(false),
     HasDeclaredCopyAssignmentWithConstParam(false),
     FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
-    IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
-    Definition(D), FirstFriend() {
+    IsLambda(false), HasOverrideAnnotation(false), NumBases(0), NumVBases(0),
+    Bases(), VBases(), Definition(D), FirstFriend() {
 }
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -537,6 +540,7 @@
         data().HasDeclaredCopyAssignmentWithConstParam = true;
     }
 
+
     if (Method->isMoveAssignmentOperator())
       SMKind |= SMF_MoveAssignment;
 
@@ -1237,6 +1241,15 @@
                              E = data().Conversions.end(); 
        I != E; ++I)
     I.setAccess((*I)->getAccess());
+
+  // If any of this class's methods are marked `override`, note that here.
+  for (CXXRecordDecl::method_iterator I = method_begin(), E = method_end();
+       I != E; ++I) {
+    if (I->hasAttr<OverrideAttr>()) {
+      data().HasOverrideAnnotation = true;
+      break;
+    }
+  }
 }
 
 bool CXXRecordDecl::mayBeAbstract() const {
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4140,6 +4140,17 @@
   }
 }
 
+// Issue a diagnostic if the method declaration overrides some other method, but
+// does not have an override specifier.
+static void CheckMissingOverrideSpecifier(Sema &S, CXXMethodDecl *MD) {
+  if (MD->isVirtual() && !MD->hasAttr<OverrideAttr>() &&
+      MD->size_overridden_methods())
+    S.Diag(MD->getLocEnd(), diag::warn_missing_override_annotation)
+        << MD << MD->size_overridden_methods()
+        << MD->getSourceRange()
+        << FixItHint::CreateInsertion(MD->getLocEnd(), " override ");
+}
+
 /// \brief Perform semantic checks on a class definition that has been
 /// completing, introducing implicitly-declared members, checking for
 /// abstract types, etc.
@@ -4231,6 +4242,12 @@
       if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
         CheckExplicitlyDefaultedSpecialMember(*M);
 
+      // Check if any there are any missing overrides, but only if the class
+      // uses an `override` specifier somewhere.
+      // Also avoid issuing this diagnostic if not in C++11 mode.
+      if (getLangOpts().CPlusPlus11 && Record->hasOverrideAnnotation())
+        CheckMissingOverrideSpecifier(*this, *M);
+
       // For an explicitly defaulted or deleted special member, we defer
       // determining triviality until the class is complete. That time is now!
       if (!M->isImplicit() && !M->isUserProvided()) {
Index: test/CXX/class.derived/class.virtual/p3-0x.cpp
===================================================================
--- test/CXX/class.derived/class.virtual/p3-0x.cpp
+++ test/CXX/class.derived/class.virtual/p3-0x.cpp
@@ -83,7 +83,7 @@
   template<typename...T> struct E : X {
     void f(T...) override;
     void g(T...) override; // expected-error {{only virtual member functions can be marked 'override'}}
-    void h(T...) final;
+    void h(T...) final; // expected-warning {{but is not marked 'override'}}
     void i(T...) final; // expected-error {{only virtual member functions can be marked 'final'}}
   };
   // FIXME: Diagnose these in the template definition, not in the instantiation.
@@ -91,13 +91,13 @@
 
   template<typename T> struct Y : T {
     void f() override;
-    void h() final;
+    void h() final; // expected-warning {{but is not marked 'override'}}
   };
   template<typename T> struct Z : T {
     void g() override; // expected-error {{only virtual member functions can be marked 'override'}}
     void i() final; // expected-error {{only virtual member functions can be marked 'final'}}
   };
-  Y<X> y;
+  Y<X> y; // expected-note {{in instantiation of}}
   Z<X> z; // expected-note {{in instantiation of}}
 }
 
Index: test/FixIt/fixit-cxx0x.cpp
===================================================================
--- test/FixIt/fixit-cxx0x.cpp
+++ test/FixIt/fixit-cxx0x.cpp
@@ -33,7 +33,7 @@
     char c, // expected-error {{expected ';' at end of declaration}}
     typedef void F(), // expected-error {{expected ';' at end of declaration}}
     F f1,
-      f2 final,
+      f2 final,  // expected-warning {{but is not marked 'override'}}
       f3 override, // expected-error {{expected ';' at end of declaration}}
   };
 }
Index: test/Misc/diag-override.cpp
===================================================================
--- /dev/null
+++ test/Misc/diag-override.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+class Base {
+  virtual void annotated_override();
+  virtual void missing_annotation();
+};
+
+class Descendant : public Base {
+  virtual void annotated_override() override;
+  // expected-error@+1 {{does not override any member functions}}
+  virtual void not_overriding_anything() override;
+  // expected-warning@+1 {{but is not marked 'override'}}
+  virtual void missing_annotation();
+};
Index: test/Parser/MicrosoftExtensions.cpp
===================================================================
--- test/Parser/MicrosoftExtensions.cpp
+++ test/Parser/MicrosoftExtensions.cpp
@@ -179,7 +179,7 @@
 };
 
 __interface MicrosoftDerivedInterface : public MicrosoftInterface {
-  void foo1();
+  void foo1();  // expected-warning {{but is not marked 'override'}}
   void foo2() override;
   void foo3();
 };
Index: test/SemaCXX/cxx98-compat.cpp
===================================================================
--- test/SemaCXX/cxx98-compat.cpp
+++ test/SemaCXX/cxx98-compat.cpp
@@ -124,7 +124,7 @@
 };
 struct OverrideControl final : OverrideControlBase { // expected-warning {{'final' keyword is incompatible with C++98}}
   virtual void f() override; // expected-warning {{'override' keyword is incompatible with C++98}}
-  virtual void g() final; // expected-warning {{'final' keyword is incompatible with C++98}}
+  virtual void g() final; // expected-warning {{'final' keyword is incompatible with C++98}} expected-warning {{but is not marked 'override'}}
 };
 
 using AliasDecl = int; // expected-warning {{alias declarations are incompatible with C++98}}
Index: test/SemaCXX/ms-interface.cpp
===================================================================
--- test/SemaCXX/ms-interface.cpp
+++ test/SemaCXX/ms-interface.cpp
@@ -44,7 +44,7 @@
 __interface I4 : I1, I2 {
   void fn1() const override;
   // expected-error@+1 {{'final' keyword not permitted with interface types}}
-  void fn2() final;
+  void fn2() final; // expected-warning {{but is not marked 'override'}}
 };
 
 // expected-error@+1 {{interface type cannot inherit from non-public 'interface I1'}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to