Skip to content

Commit 4149d74

Browse files
committed
Merge from 'main' to 'sycl-web' (#1)
CONFLICT (content): Merge conflict in clang/include/clang/Basic/DiagnosticDriverKinds.td
2 parents 1675625 + 29b44ca commit 4149d74

File tree

973 files changed

+28310
-12256
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

973 files changed

+28310
-12256
lines changed

clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,11 @@ AST_POLYMORPHIC_MATCHER(
4747
if (PrefixPosition == StringRef::npos)
4848
return false;
4949
Path = Path.drop_front(PrefixPosition + AbslPrefix.size());
50-
static const char *AbseilLibraries[] = {"algorithm", "base",
51-
"container", "debugging",
52-
"flags", "hash",
53-
"iterator", "memory",
54-
"meta", "numeric",
55-
"random", "status",
56-
"strings", "synchronization",
57-
"time", "types",
58-
"utility"};
50+
static const char *AbseilLibraries[] = {
51+
"algorithm", "base", "container", "debugging", "flags",
52+
"hash", "iterator", "memory", "meta", "numeric",
53+
"profiling", "random", "status", "strings", "synchronization",
54+
"time", "types", "utility"};
5955
return llvm::any_of(AbseilLibraries, [&](const char *Library) {
6056
return Path.startswith(Library);
6157
});

clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule
2626
ProTypeVarargCheck.cpp
2727
SlicingCheck.cpp
2828
SpecialMemberFunctionsCheck.cpp
29+
VirtualClassDestructorCheck.cpp
2930

3031
LINK_LIBS
3132
clangTidy

clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "ProTypeVarargCheck.h"
3636
#include "SlicingCheck.h"
3737
#include "SpecialMemberFunctionsCheck.h"
38+
#include "VirtualClassDestructorCheck.h"
3839

3940
namespace clang {
4041
namespace tidy {
@@ -94,6 +95,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule {
9495
CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing");
9596
CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>(
9697
"cppcoreguidelines-c-copy-assignment-signature");
98+
CheckFactories.registerCheck<VirtualClassDestructorCheck>(
99+
"cppcoreguidelines-virtual-class-destructor");
97100
}
98101

99102
ClangTidyOptions getModuleOptions() override {
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
//===--- VirtualClassDestructorCheck.cpp - clang-tidy -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "VirtualClassDestructorCheck.h"
10+
#include "../utils/LexerUtils.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/ASTMatchers/ASTMatchFinder.h"
13+
#include "clang/Lex/Lexer.h"
14+
#include <string>
15+
16+
using namespace clang::ast_matchers;
17+
18+
namespace clang {
19+
namespace tidy {
20+
namespace cppcoreguidelines {
21+
22+
void VirtualClassDestructorCheck::registerMatchers(MatchFinder *Finder) {
23+
ast_matchers::internal::Matcher<CXXRecordDecl> InheritsVirtualMethod =
24+
hasAnyBase(hasType(cxxRecordDecl(has(cxxMethodDecl(isVirtual())))));
25+
26+
Finder->addMatcher(
27+
cxxRecordDecl(
28+
anyOf(has(cxxMethodDecl(isVirtual())), InheritsVirtualMethod),
29+
unless(anyOf(
30+
has(cxxDestructorDecl(isPublic(), isVirtual())),
31+
has(cxxDestructorDecl(isProtected(), unless(isVirtual()))))))
32+
.bind("ProblematicClassOrStruct"),
33+
this);
34+
}
35+
36+
static CharSourceRange
37+
getVirtualKeywordRange(const CXXDestructorDecl &Destructor,
38+
const SourceManager &SM, const LangOptions &LangOpts) {
39+
SourceLocation VirtualBeginLoc = Destructor.getBeginLoc();
40+
SourceLocation VirtualEndLoc = VirtualBeginLoc.getLocWithOffset(
41+
Lexer::MeasureTokenLength(VirtualBeginLoc, SM, LangOpts));
42+
43+
/// Range ends with \c StartOfNextToken so that any whitespace after \c
44+
/// virtual is included.
45+
SourceLocation StartOfNextToken =
46+
Lexer::findNextToken(VirtualEndLoc, SM, LangOpts)
47+
.getValue()
48+
.getLocation();
49+
50+
return CharSourceRange::getCharRange(VirtualBeginLoc, StartOfNextToken);
51+
}
52+
53+
static const AccessSpecDecl *
54+
getPublicASDecl(const CXXRecordDecl &StructOrClass) {
55+
for (DeclContext::specific_decl_iterator<AccessSpecDecl>
56+
AS{StructOrClass.decls_begin()},
57+
ASEnd{StructOrClass.decls_end()};
58+
AS != ASEnd; ++AS) {
59+
AccessSpecDecl *ASDecl = *AS;
60+
if (ASDecl->getAccess() == AccessSpecifier::AS_public)
61+
return ASDecl;
62+
}
63+
64+
return nullptr;
65+
}
66+
67+
static FixItHint
68+
generateUserDeclaredDestructor(const CXXRecordDecl &StructOrClass,
69+
const SourceManager &SourceManager) {
70+
std::string DestructorString;
71+
SourceLocation Loc;
72+
bool AppendLineBreak = false;
73+
74+
const AccessSpecDecl *AccessSpecDecl = getPublicASDecl(StructOrClass);
75+
76+
if (!AccessSpecDecl) {
77+
if (StructOrClass.isClass()) {
78+
Loc = StructOrClass.getEndLoc();
79+
DestructorString = "public:";
80+
AppendLineBreak = true;
81+
} else {
82+
Loc = StructOrClass.getBraceRange().getBegin().getLocWithOffset(1);
83+
}
84+
} else {
85+
Loc = AccessSpecDecl->getEndLoc().getLocWithOffset(1);
86+
}
87+
88+
DestructorString = (llvm::Twine(DestructorString) + "\nvirtual ~" +
89+
StructOrClass.getName().str() + "() = default;" +
90+
(AppendLineBreak ? "\n" : ""))
91+
.str();
92+
93+
return FixItHint::CreateInsertion(Loc, DestructorString);
94+
}
95+
96+
static std::string getSourceText(const CXXDestructorDecl &Destructor) {
97+
std::string SourceText;
98+
llvm::raw_string_ostream DestructorStream(SourceText);
99+
Destructor.print(DestructorStream);
100+
return SourceText;
101+
}
102+
103+
static std::string eraseKeyword(std::string &DestructorString,
104+
const std::string &Keyword) {
105+
size_t KeywordIndex = DestructorString.find(Keyword);
106+
if (KeywordIndex != std::string::npos)
107+
DestructorString.erase(KeywordIndex, Keyword.length());
108+
return DestructorString;
109+
}
110+
111+
static FixItHint changePrivateDestructorVisibilityTo(
112+
const std::string &Visibility, const CXXDestructorDecl &Destructor,
113+
const SourceManager &SM, const LangOptions &LangOpts) {
114+
std::string DestructorString =
115+
(llvm::Twine() + Visibility + ":\n" +
116+
(Visibility == "public" && !Destructor.isVirtual() ? "virtual " : ""))
117+
.str();
118+
119+
std::string OriginalDestructor = getSourceText(Destructor);
120+
if (Visibility == "protected" && Destructor.isVirtualAsWritten())
121+
OriginalDestructor = eraseKeyword(OriginalDestructor, "virtual ");
122+
123+
DestructorString =
124+
(llvm::Twine(DestructorString) + OriginalDestructor +
125+
(Destructor.isExplicitlyDefaulted() ? ";\n" : "") + "private:")
126+
.str();
127+
128+
/// Semicolons ending an explicitly defaulted destructor have to be deleted.
129+
/// Otherwise, the left-over semicolon trails the \c private: access
130+
/// specifier.
131+
SourceLocation EndLocation;
132+
if (Destructor.isExplicitlyDefaulted())
133+
EndLocation =
134+
utils::lexer::findNextTerminator(Destructor.getEndLoc(), SM, LangOpts)
135+
.getLocWithOffset(1);
136+
else
137+
EndLocation = Destructor.getEndLoc().getLocWithOffset(1);
138+
139+
auto OriginalDestructorRange =
140+
CharSourceRange::getCharRange(Destructor.getBeginLoc(), EndLocation);
141+
return FixItHint::CreateReplacement(OriginalDestructorRange,
142+
DestructorString);
143+
}
144+
145+
void VirtualClassDestructorCheck::check(
146+
const MatchFinder::MatchResult &Result) {
147+
148+
const auto *MatchedClassOrStruct =
149+
Result.Nodes.getNodeAs<CXXRecordDecl>("ProblematicClassOrStruct");
150+
151+
const CXXDestructorDecl *Destructor = MatchedClassOrStruct->getDestructor();
152+
if (!Destructor)
153+
return;
154+
155+
if (Destructor->getAccess() == AccessSpecifier::AS_private) {
156+
diag(MatchedClassOrStruct->getLocation(),
157+
"destructor of %0 is private and prevents using the type")
158+
<< MatchedClassOrStruct;
159+
diag(MatchedClassOrStruct->getLocation(),
160+
/*FixDescription=*/"make it public and virtual", DiagnosticIDs::Note)
161+
<< changePrivateDestructorVisibilityTo(
162+
"public", *Destructor, *Result.SourceManager, getLangOpts());
163+
diag(MatchedClassOrStruct->getLocation(),
164+
/*FixDescription=*/"make it protected", DiagnosticIDs::Note)
165+
<< changePrivateDestructorVisibilityTo(
166+
"protected", *Destructor, *Result.SourceManager, getLangOpts());
167+
168+
return;
169+
}
170+
171+
// Implicit destructors are public and non-virtual for classes and structs.
172+
bool ProtectedAndVirtual = false;
173+
FixItHint Fix;
174+
175+
if (MatchedClassOrStruct->hasUserDeclaredDestructor()) {
176+
if (Destructor->getAccess() == AccessSpecifier::AS_public) {
177+
Fix = FixItHint::CreateInsertion(Destructor->getLocation(), "virtual ");
178+
} else if (Destructor->getAccess() == AccessSpecifier::AS_protected) {
179+
ProtectedAndVirtual = true;
180+
Fix = FixItHint::CreateRemoval(getVirtualKeywordRange(
181+
*Destructor, *Result.SourceManager, Result.Context->getLangOpts()));
182+
}
183+
} else {
184+
Fix = generateUserDeclaredDestructor(*MatchedClassOrStruct,
185+
*Result.SourceManager);
186+
}
187+
188+
diag(MatchedClassOrStruct->getLocation(),
189+
"destructor of %0 is %select{public and non-virtual|protected and "
190+
"virtual}1")
191+
<< MatchedClassOrStruct << ProtectedAndVirtual;
192+
diag(MatchedClassOrStruct->getLocation(),
193+
"make it %select{public and virtual|protected and non-virtual}0",
194+
DiagnosticIDs::Note)
195+
<< ProtectedAndVirtual << Fix;
196+
}
197+
198+
} // namespace cppcoreguidelines
199+
} // namespace tidy
200+
} // namespace clang
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===--- VirtualClassDestructorCheck.h - clang-tidy -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_VIRTUALCLASSDESTRUCTORCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_VIRTUALCLASSDESTRUCTORCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
#include <string>
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace cppcoreguidelines {
18+
19+
/// Finds base classes whose destructor is neither public and virtual
20+
/// nor protected and non-virtual.
21+
///
22+
/// For the user-facing documentation see:
23+
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-virtual-class-destructor.html
24+
class VirtualClassDestructorCheck : public ClangTidyCheck {
25+
public:
26+
VirtualClassDestructorCheck(StringRef Name, ClangTidyContext *Context)
27+
: ClangTidyCheck(Name, Context) {}
28+
29+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
30+
return LangOpts.CPlusPlus;
31+
}
32+
33+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
34+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
35+
};
36+
37+
} // namespace cppcoreguidelines
38+
} // namespace tidy
39+
} // namespace clang
40+
41+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_VIRTUALCLASSDESTRUCTORCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,21 @@ New checks
7575
- New :doc:`bugprone-suspicious-memory-comparison
7676
<clang-tidy/checks/bugprone-suspicious-memory-comparison>` check.
7777

78-
Finds potentially incorrect calls to ``memcmp()`` based on properties of the arguments.
78+
Finds potentially incorrect calls to ``memcmp()`` based on properties of the
79+
arguments.
80+
81+
- New :doc:`cppcoreguidelines-virtual-class-destructor
82+
<clang-tidy/checks/cppcoreguidelines-virtual-class-destructor>` check.
83+
84+
Finds virtual classes whose destructor is neither public and virtual nor
85+
protected and non-virtual.
7986

8087
- New :doc:`readability-identifier-length
8188
<clang-tidy/checks/readability-identifier-length>` check.
8289

83-
Reports identifiers whose names are too short. Currently checks local variables and function parameters only.
90+
Reports identifiers whose names are too short. Currently checks local
91+
variables and function parameters only.
92+
8493

8594
New check aliases
8695
^^^^^^^^^^^^^^^^^
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
.. title:: clang-tidy - cppcoreguidelines-virtual-class-destructor
2+
3+
cppcoreguidelines-virtual-class-destructor
4+
===============================================
5+
6+
Finds virtual classes whose destructor is neither public and virtual
7+
nor protected and non-virtual. A virtual class's destructor should be specified
8+
in one of these ways to prevent undefined behaviour.
9+
10+
This check implements
11+
`C.35 <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-dtor-virtual>`_
12+
from the CppCoreGuidelines.
13+
14+
Note that this check will diagnose a class with a virtual method regardless of
15+
whether the class is used as a base class or not.
16+
17+
Fixes are available for user-declared and implicit destructors that are either
18+
public and non-virtual or protected and virtual. No fixes are offered for
19+
private destructors. There, the decision whether to make them private and
20+
virtual or protected and non-virtual depends on the use case and is thus left
21+
to the user.
22+
23+
Example
24+
-------
25+
26+
For example, the following classes/structs get flagged by the check since they
27+
violate guideline **C.35**:
28+
29+
.. code-block:: c++
30+
31+
struct Foo { // NOK, protected destructor should not be virtual
32+
virtual void f();
33+
protected:
34+
virtual ~Foo(){}
35+
};
36+
37+
class Bar { // NOK, public destructor should be virtual
38+
virtual void f();
39+
public:
40+
~Bar(){}
41+
};
42+
43+
This would be rewritten to look like this:
44+
45+
.. code-block:: c++
46+
47+
struct Foo { // OK, destructor is not virtual anymore
48+
virtual void f();
49+
protected:
50+
~Foo(){}
51+
};
52+
53+
class Bar { // OK, destructor is now virtual
54+
virtual void f();
55+
public:
56+
virtual ~Bar(){}
57+
};

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ Clang-Tidy Checks
169169
`cppcoreguidelines-pro-type-vararg <cppcoreguidelines-pro-type-vararg.html>`_,
170170
`cppcoreguidelines-slicing <cppcoreguidelines-slicing.html>`_,
171171
`cppcoreguidelines-special-member-functions <cppcoreguidelines-special-member-functions.html>`_,
172+
`cppcoreguidelines-virtual-class-destructor <cppcoreguidelines-virtual-class-destructor.html>`_, "Yes"
172173
`darwin-avoid-spinlock <darwin-avoid-spinlock.html>`_,
173174
`darwin-dispatch-once-nonstatic <darwin-dispatch-once-nonstatic.html>`_, "Yes"
174175
`fuchsia-default-arguments-calls <fuchsia-default-arguments-calls.html>`_,

0 commit comments

Comments
 (0)