llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: Victor Chernyakin (localspook)

<details>
<summary>Changes</summary>

This removes some of the incredibly painful manual lexing in this check, yay!

Fixes #<!-- -->138486. Also fixes the following case with `= delete("...")` in 
C++26: https://godbolt.org/z/dddfY15Wq.

---
Full diff: https://github.com/llvm/llvm-project/pull/172196.diff


4 Files Affected:

- (modified) clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp 
(+9-71) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-cxx26.cpp 
(+11) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-override.cpp (+9-3) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
index e2e7bba46f2c4..3bcfd9ad6bc27 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -141,90 +141,28 @@ void UseOverrideCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (!FileRange.isValid())
     return;
 
-  // FIXME: Instead of re-lexing and looking for specific macros such as
-  // 'ABSTRACT', properly store the location of 'virtual' and '= 0' in each
-  // FunctionDecl.
+  // FIXME: Instead of re-lexing and looking for the 'virtual' token,
+  // store the location of 'virtual' in each FunctionDecl.
   SmallVector<Token, 16> Tokens = parseTokens(FileRange, Result);
 
   // Add 'override' on inline declarations that don't already have it.
   if (!HasFinal && !HasOverride) {
-    SourceLocation InsertLoc;
-    std::string ReplacementText = (OverrideSpelling + " ").str();
-    const SourceLocation MethodLoc = Method->getLocation();
-
-    for (const Token T : Tokens) {
-      if (T.is(tok::kw___attribute) &&
-          !Sources.isBeforeInTranslationUnit(T.getLocation(), MethodLoc)) {
-        InsertLoc = T.getLocation();
-        break;
-      }
-    }
-
-    if (Method->hasAttrs()) {
-      for (const clang::Attr *A : Method->getAttrs()) {
-        if (!A->isImplicit() && !A->isInherited()) {
-          const SourceLocation Loc =
-              Sources.getExpansionLoc(A->getRange().getBegin());
-          if ((!InsertLoc.isValid() ||
-               Sources.isBeforeInTranslationUnit(Loc, InsertLoc)) &&
-              !Sources.isBeforeInTranslationUnit(Loc, MethodLoc))
-            InsertLoc = Loc;
-        }
-      }
-    }
-
-    if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody() &&
-        Method->getBody() && !Method->isDefaulted()) {
-      // For methods with inline definition, add the override keyword at the
-      // end of the declaration of the function, but prefer to put it on the
-      // same line as the declaration if the beginning brace for the start of
-      // the body falls on the next line.
-      ReplacementText = (" " + OverrideSpelling).str();
-      auto *LastTokenIter = std::prev(Tokens.end());
-      // When try statement is used instead of compound statement as
-      // method body - insert override keyword before it.
-      if (LastTokenIter->is(tok::kw_try))
-        LastTokenIter = std::prev(LastTokenIter);
-      InsertLoc = LastTokenIter->getEndLoc();
-    }
-
-    if (!InsertLoc.isValid()) {
-      // For declarations marked with "= 0" or "= [default|delete]", the end
-      // location will point until after those markings. Therefore, the 
override
-      // keyword shouldn't be inserted at the end, but before the '='.
-      if (Tokens.size() > 2 &&
-          (getText(Tokens.back(), Sources) == "0" ||
-           Tokens.back().is(tok::kw_default) ||
-           Tokens.back().is(tok::kw_delete)) &&
-          getText(Tokens[Tokens.size() - 2], Sources) == "=") {
-        InsertLoc = Tokens[Tokens.size() - 2].getLocation();
-        // Check if we need to insert a space.
-        if ((Tokens[Tokens.size() - 2].getFlags() & Token::LeadingSpace) == 0)
-          ReplacementText = (" " + OverrideSpelling + " ").str();
-      } else if (getText(Tokens.back(), Sources) == "ABSTRACT")
-        InsertLoc = Tokens.back().getLocation();
-    }
-
-    if (!InsertLoc.isValid()) {
-      InsertLoc = FileRange.getEnd();
-      ReplacementText = (" " + OverrideSpelling).str();
-    }
-
     // If the override macro has been specified just ensure it exists,
     // if not don't apply a fixit but keep the warning.
     if (OverrideSpelling != "override" &&
         !Context.Idents.get(OverrideSpelling).hasMacroDefinition())
       return;
 
-    Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
+    Diag << FixItHint::CreateInsertion(
+        Lexer::getLocForEndOfToken(
+            Method->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0, Sources,
+            getLangOpts()),
+        (" " + OverrideSpelling).str());
   }
 
-  if (HasFinal && HasOverride && !AllowOverrideAndFinal) {
-    const SourceLocation OverrideLoc =
-        Method->getAttr<OverrideAttr>()->getLocation();
+  if (HasFinal && HasOverride && !AllowOverrideAndFinal)
     Diag << FixItHint::CreateRemoval(
-        CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
-  }
+        Method->getAttr<OverrideAttr>()->getLocation());
 
   if (HasVirtual) {
     for (const Token Tok : Tokens) {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index d1fb1cba3e45a..8979e393f8363 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -508,6 +508,11 @@ Changes in existing checks
   on Windows when the check was enabled with a 32-bit :program:`clang-tidy`
   binary.
 
+- Improved :doc:`modernize-use-override
+  <clang-tidy/checks/modernize/use-override>` by fixing an issue where
+  the check would sometimes suggest inserting ``override`` in an invalid
+  place.
+
 - Improved :doc:`modernize-use-scoped-lock
   <clang-tidy/checks/modernize/use-scoped-lock>` check by fixing a crash
   on malformed code (common when using :program:`clang-tidy` through
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-cxx26.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-cxx26.cpp
new file mode 100644
index 0000000000000..e0ced1def9b6a
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-cxx26.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy -std=c++26-or-later %s 
modernize-use-override,cppcoreguidelines-explicit-virtual-functions %t
+
+struct Base {
+  virtual void f() = delete("");
+};
+
+struct Derived : Base {
+  virtual void f() = delete("");
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using 'override' or 
(rarely) 'final' instead of 'virtual'
+  // CHECK-FIXES: void f() override = delete("");
+};
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override.cpp
index 8e19fdd4a0a92..c33b8ae2b24fc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override.cpp
@@ -48,6 +48,8 @@ struct Base {
   virtual void t() throw();
 
   virtual void il(IntPair);
+
+  virtual void u(int x __attribute__((unused))) {}
 };
 
 struct SimpleCases : public Base {
@@ -82,11 +84,11 @@ struct SimpleCases : public Base {
 
   virtual void f()=0;
   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
-  // CHECK-FIXES: void f() override =0;
+  // CHECK-FIXES: void f() override=0;
 
   virtual void f2() const=0;
   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
-  // CHECK-FIXES: void f2() const override =0;
+  // CHECK-FIXES: void f2() const override=0;
 
   virtual void g() ABSTRACT;
   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
@@ -132,6 +134,10 @@ struct SimpleCases : public Base {
   virtual       /*      */ void g2();
   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: prefer using 'override' or 
(rarely) 'final' instead of 'virtual'
   // CHECK-FIXES: /*      */ void g2() override;
+
+  virtual void u(int x __attribute__((unused)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using 'override' or 
(rarely) 'final' instead of 'virtual'
+  // CHECK-FIXES: void u(int x __attribute__((unused))) override;
 };
 
 // CHECK-MESSAGES-NOT: warning:
@@ -308,7 +314,7 @@ struct MembersOfSpecializations : public Base2 {
   // CHECK-FIXES: void a() override;
 };
 template <> void MembersOfSpecializations<3>::a() {}
-void ff() { MembersOfSpecializations<3>().a(); };
+void ff() { MembersOfSpecializations<3>().a(); }
 
 // In case try statement is used as a method body,
 // make sure that override fix is placed before try keyword.

``````````

</details>


https://github.com/llvm/llvm-project/pull/172196
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to