-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-tidy] Add option to keep virtual in 'modernize-use-override' #144916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add a new `AllowVirtual` option to 'modernize-use-override', which does not remove the `virtual` specifier. This is useful because some coding guidelines may suggest to use `virtual ... override` for clarity.
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@@ -226,7 +232,8 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) { | |||
CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc)); | |||
} | |||
|
|||
if (HasVirtual) { | |||
// Remove virtual unless requested otherwise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that even when AllowVirtual
is used, the check does not add any missing virtual
keywords. If this is preferred one could instead add a UseVirtualAndOverride
option which would then also add a missing virtual
specifier.
But as this is a bit more work I would first like to judge the interest in that feature in general.
@llvm/pr-subscribers-clang-tidy Author: Frank Winklmeier (fwinkl) ChangesAdd a new Full diff: https://github.com/llvm/llvm-project/pull/144916.diff 4 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
index fd5bd9f0b181b..c18bd68a99b37 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -22,6 +22,7 @@ UseOverrideCheck::UseOverrideCheck(StringRef Name, ClangTidyContext *Context)
IgnoreTemplateInstantiations(
Options.get("IgnoreTemplateInstantiations", false)),
AllowOverrideAndFinal(Options.get("AllowOverrideAndFinal", false)),
+ AllowVirtual(Options.get("AllowVirtual", false)),
OverrideSpelling(Options.get("OverrideSpelling", "override")),
FinalSpelling(Options.get("FinalSpelling", "final")) {}
@@ -30,6 +31,7 @@ void UseOverrideCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreTemplateInstantiations",
IgnoreTemplateInstantiations);
Options.store(Opts, "AllowOverrideAndFinal", AllowOverrideAndFinal);
+ Options.store(Opts, "AllowVirtual", AllowVirtual);
Options.store(Opts, "OverrideSpelling", OverrideSpelling);
Options.store(Opts, "FinalSpelling", FinalSpelling);
}
@@ -111,15 +113,19 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
if ((!OnlyVirtualSpecified && KeywordCount == 1) ||
+ (HasVirtual && HasOverride && AllowVirtual) ||
(!HasVirtual && HasOverride && HasFinal && AllowOverrideAndFinal))
return; // Nothing to do.
std::string Message;
if (OnlyVirtualSpecified) {
- Message = "prefer using '%0' or (rarely) '%1' instead of 'virtual'";
+ if (AllowVirtual)
+ Message = "add '%0' or (rarely) '%1' for 'virtual' function";
+ else
+ Message = "prefer using '%0' or (rarely) '%1' instead of 'virtual'";
} else if (KeywordCount == 0) {
Message = "annotate this function with '%0' or (rarely) '%1'";
- } else {
+ } else if (!AllowVirtual) {
StringRef Redundant =
HasVirtual ? (HasOverride && HasFinal && !AllowOverrideAndFinal
? "'virtual' and '%0' are"
@@ -226,7 +232,8 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
}
- if (HasVirtual) {
+ // Remove virtual unless requested otherwise
+ if (HasVirtual && !AllowVirtual) {
for (Token Tok : Tokens) {
if (Tok.is(tok::kw_virtual)) {
std::optional<Token> NextToken =
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
index 2c624f48fcc85..6879221ab4284 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
@@ -29,6 +29,7 @@ class UseOverrideCheck : public ClangTidyCheck {
const bool IgnoreDestructors;
const bool IgnoreTemplateInstantiations;
const bool AllowOverrideAndFinal;
+ const bool AllowVirtual;
const StringRef OverrideSpelling;
const StringRef FinalSpelling;
};
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
index f8f34794af749..d3ed73ef35a51 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
@@ -4,7 +4,8 @@ modernize-use-override
======================
Adds ``override`` (introduced in C++11) to overridden virtual functions and
-removes ``virtual`` from those functions as it is not required.
+removes ``virtual`` from those functions (unless the `AllowVirtual` option is
+used).
``virtual`` on non base class implementations was used to help indicate to the
user that a function was virtual. C++ compilers did not use the presence of
@@ -40,6 +41,11 @@ Options
members, such as ``gcc -Wsuggest-override``/``gcc -Werror=suggest-override``.
Default is `false`.
+.. option:: AllowVirtual
+
+ If set to `true`, ``virtual`` will not be removed by this check when adding
+ ``override`` or ``final``. Default is `false`.
+
.. option:: OverrideSpelling
Specifies a macro to use instead of ``override``. This is useful when
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp
new file mode 100644
index 0000000000000..17be170e0d9cd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- \
+// RUN: -config="{CheckOptions: {modernize-use-override.AllowVirtual: true}}"
+
+struct Base {
+ virtual ~Base();
+ virtual void a();
+ virtual void b();
+ virtual void c();
+};
+
+struct Derived : public Base {
+ virtual ~Derived() override;
+
+ virtual void a() override;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} virtual void a() override;
+
+ virtual void b();
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: add 'override'
+ // CHECK-FIXES: {{^}} virtual void b() override;
+
+ void c();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate
+ // CHECK-FIXES: {{^}} void c() override;
+};
|
@llvm/pr-subscribers-clang-tools-extra Author: Frank Winklmeier (fwinkl) ChangesAdd a new Full diff: https://github.com/llvm/llvm-project/pull/144916.diff 4 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
index fd5bd9f0b181b..c18bd68a99b37 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -22,6 +22,7 @@ UseOverrideCheck::UseOverrideCheck(StringRef Name, ClangTidyContext *Context)
IgnoreTemplateInstantiations(
Options.get("IgnoreTemplateInstantiations", false)),
AllowOverrideAndFinal(Options.get("AllowOverrideAndFinal", false)),
+ AllowVirtual(Options.get("AllowVirtual", false)),
OverrideSpelling(Options.get("OverrideSpelling", "override")),
FinalSpelling(Options.get("FinalSpelling", "final")) {}
@@ -30,6 +31,7 @@ void UseOverrideCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreTemplateInstantiations",
IgnoreTemplateInstantiations);
Options.store(Opts, "AllowOverrideAndFinal", AllowOverrideAndFinal);
+ Options.store(Opts, "AllowVirtual", AllowVirtual);
Options.store(Opts, "OverrideSpelling", OverrideSpelling);
Options.store(Opts, "FinalSpelling", FinalSpelling);
}
@@ -111,15 +113,19 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
if ((!OnlyVirtualSpecified && KeywordCount == 1) ||
+ (HasVirtual && HasOverride && AllowVirtual) ||
(!HasVirtual && HasOverride && HasFinal && AllowOverrideAndFinal))
return; // Nothing to do.
std::string Message;
if (OnlyVirtualSpecified) {
- Message = "prefer using '%0' or (rarely) '%1' instead of 'virtual'";
+ if (AllowVirtual)
+ Message = "add '%0' or (rarely) '%1' for 'virtual' function";
+ else
+ Message = "prefer using '%0' or (rarely) '%1' instead of 'virtual'";
} else if (KeywordCount == 0) {
Message = "annotate this function with '%0' or (rarely) '%1'";
- } else {
+ } else if (!AllowVirtual) {
StringRef Redundant =
HasVirtual ? (HasOverride && HasFinal && !AllowOverrideAndFinal
? "'virtual' and '%0' are"
@@ -226,7 +232,8 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
}
- if (HasVirtual) {
+ // Remove virtual unless requested otherwise
+ if (HasVirtual && !AllowVirtual) {
for (Token Tok : Tokens) {
if (Tok.is(tok::kw_virtual)) {
std::optional<Token> NextToken =
diff --git a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
index 2c624f48fcc85..6879221ab4284 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
@@ -29,6 +29,7 @@ class UseOverrideCheck : public ClangTidyCheck {
const bool IgnoreDestructors;
const bool IgnoreTemplateInstantiations;
const bool AllowOverrideAndFinal;
+ const bool AllowVirtual;
const StringRef OverrideSpelling;
const StringRef FinalSpelling;
};
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
index f8f34794af749..d3ed73ef35a51 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-override.rst
@@ -4,7 +4,8 @@ modernize-use-override
======================
Adds ``override`` (introduced in C++11) to overridden virtual functions and
-removes ``virtual`` from those functions as it is not required.
+removes ``virtual`` from those functions (unless the `AllowVirtual` option is
+used).
``virtual`` on non base class implementations was used to help indicate to the
user that a function was virtual. C++ compilers did not use the presence of
@@ -40,6 +41,11 @@ Options
members, such as ``gcc -Wsuggest-override``/``gcc -Werror=suggest-override``.
Default is `false`.
+.. option:: AllowVirtual
+
+ If set to `true`, ``virtual`` will not be removed by this check when adding
+ ``override`` or ``final``. Default is `false`.
+
.. option:: OverrideSpelling
Specifies a macro to use instead of ``override``. This is useful when
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp
new file mode 100644
index 0000000000000..17be170e0d9cd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-override-allow-virtual.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- \
+// RUN: -config="{CheckOptions: {modernize-use-override.AllowVirtual: true}}"
+
+struct Base {
+ virtual ~Base();
+ virtual void a();
+ virtual void b();
+ virtual void c();
+};
+
+struct Derived : public Base {
+ virtual ~Derived() override;
+
+ virtual void a() override;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} virtual void a() override;
+
+ virtual void b();
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: add 'override'
+ // CHECK-FIXES: {{^}} virtual void b() override;
+
+ void c();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate
+ // CHECK-FIXES: {{^}} void c() override;
+};
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add your change to ReleaseNotes.rst
// CHECK-MESSAGES-NOT: warning: | ||
// CHECK-FIXES: {{^}} virtual void a() override; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should just write nothing. By default, tests will fail if there will be a message
|
||
virtual void b(); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: add 'override' | ||
// CHECK-FIXES: {{^}} virtual void b() override; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't use {{^}}
, just match string as a whole
|
||
void c(); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate | ||
// CHECK-FIXES: {{^}} void c() override; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto {{^}}
Add a new
AllowVirtual
option to 'modernize-use-override', which does not remove thevirtual
specifier. This is useful because some coding guidelines may suggest to usevirtual ... override
for clarity. See the new unit test for examples.