Skip to content

Commit 34d8419

Browse files
committed
Merge remote-tracking branch 'otcshare_llvm/sycl-web' into llvmspirv_pulldown
2 parents e026e54 + e2b359c commit 34d8419

File tree

743 files changed

+122724
-11438
lines changed

Some content is hidden

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

743 files changed

+122724
-11438
lines changed

clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp

Lines changed: 148 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,77 @@
1616
using namespace clang::ast_matchers;
1717

1818
namespace clang {
19+
namespace ast_matchers {
20+
AST_POLYMORPHIC_MATCHER_P2(hasAnyArgumentWithParam,
21+
AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
22+
CXXConstructExpr),
23+
internal::Matcher<Expr>, ArgMatcher,
24+
internal::Matcher<ParmVarDecl>, ParamMatcher) {
25+
BoundNodesTreeBuilder Result;
26+
// The first argument of an overloaded member operator is the implicit object
27+
// argument of the method which should not be matched against a parameter, so
28+
// we skip over it here.
29+
BoundNodesTreeBuilder Matches;
30+
unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
31+
.matches(Node, Finder, &Matches)
32+
? 1
33+
: 0;
34+
int ParamIndex = 0;
35+
for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
36+
BoundNodesTreeBuilder ArgMatches(*Builder);
37+
if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()), Finder,
38+
&ArgMatches)) {
39+
BoundNodesTreeBuilder ParamMatches(ArgMatches);
40+
if (expr(anyOf(cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
41+
hasParameter(ParamIndex, ParamMatcher)))),
42+
callExpr(callee(functionDecl(
43+
hasParameter(ParamIndex, ParamMatcher))))))
44+
.matches(Node, Finder, &ParamMatches)) {
45+
Result.addMatch(ParamMatches);
46+
*Builder = std::move(Result);
47+
return true;
48+
}
49+
}
50+
++ParamIndex;
51+
}
52+
return false;
53+
}
54+
55+
AST_MATCHER(Expr, usedInBooleanContext) {
56+
const char *ExprName = "__booleanContextExpr";
57+
auto Result =
58+
expr(expr().bind(ExprName),
59+
anyOf(hasParent(varDecl(hasType(booleanType()))),
60+
hasParent(cxxConstructorDecl(
61+
hasAnyConstructorInitializer(cxxCtorInitializer(
62+
withInitializer(expr(equalsBoundNode(ExprName))),
63+
forField(hasType(booleanType())))))),
64+
hasParent(fieldDecl(hasType(booleanType()))),
65+
hasParent(stmt(anyOf(
66+
explicitCastExpr(hasDestinationType(booleanType())),
67+
ifStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
68+
doStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
69+
whileStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
70+
forStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
71+
conditionalOperator(
72+
hasCondition(expr(equalsBoundNode(ExprName)))),
73+
parenListExpr(hasParent(varDecl(hasType(booleanType())))),
74+
parenExpr(hasParent(
75+
explicitCastExpr(hasDestinationType(booleanType())))),
76+
returnStmt(forFunction(returns(booleanType()))),
77+
cxxUnresolvedConstructExpr(hasType(booleanType())),
78+
callExpr(hasAnyArgumentWithParam(
79+
expr(equalsBoundNode(ExprName)),
80+
parmVarDecl(hasType(booleanType())))),
81+
binaryOperator(hasAnyOperatorName("&&", "||")),
82+
unaryOperator(hasOperatorName("!")).bind("NegOnSize"))))))
83+
.matches(Node, Finder, Builder);
84+
Builder->removeBindings([ExprName](const BoundNodesMap &Nodes) {
85+
return Nodes.getNode(ExprName).getNodeKind().isNone();
86+
});
87+
return Result;
88+
}
89+
} // namespace ast_matchers
1990
namespace tidy {
2091
namespace readability {
2192

@@ -26,18 +97,27 @@ ContainerSizeEmptyCheck::ContainerSizeEmptyCheck(StringRef Name,
2697
: ClangTidyCheck(Name, Context) {}
2798

2899
void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
29-
const auto ValidContainer = qualType(hasUnqualifiedDesugaredType(
30-
recordType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom(
31-
namedDecl(
32-
has(cxxMethodDecl(
33-
isConst(), parameterCountIs(0), isPublic(),
34-
hasName("size"),
35-
returns(qualType(isInteger(), unless(booleanType()))))
36-
.bind("size")),
37-
has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(),
38-
hasName("empty"), returns(booleanType()))
39-
.bind("empty")))
40-
.bind("container")))))));
100+
const auto ValidContainerRecord = cxxRecordDecl(isSameOrDerivedFrom(
101+
namedDecl(
102+
has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(),
103+
hasName("size"),
104+
returns(qualType(isInteger(), unless(booleanType()),
105+
unless(elaboratedType()))))
106+
.bind("size")),
107+
has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(),
108+
hasName("empty"), returns(booleanType()))
109+
.bind("empty")))
110+
.bind("container")));
111+
112+
const auto ValidContainerNonTemplateType =
113+
qualType(hasUnqualifiedDesugaredType(
114+
recordType(hasDeclaration(ValidContainerRecord))));
115+
const auto ValidContainerTemplateType =
116+
qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
117+
hasDeclaration(classTemplateDecl(has(ValidContainerRecord))))));
118+
119+
const auto ValidContainer = qualType(
120+
anyOf(ValidContainerNonTemplateType, ValidContainerTemplateType));
41121

42122
const auto WrongUse = traverse(
43123
TK_AsIs,
@@ -52,18 +132,34 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
52132
anyOf(hasParent(
53133
unaryOperator(hasOperatorName("!")).bind("NegOnSize")),
54134
anything()))),
55-
hasParent(explicitCastExpr(hasDestinationType(booleanType())))));
135+
usedInBooleanContext()));
56136

57137
Finder->addMatcher(
58-
cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer),
138+
cxxMemberCallExpr(unless(isInTemplateInstantiation()),
139+
on(expr(anyOf(hasType(ValidContainer),
59140
hasType(pointsTo(ValidContainer)),
60-
hasType(references(ValidContainer))))),
141+
hasType(references(ValidContainer))))
142+
.bind("MemberCallObject")),
61143
callee(cxxMethodDecl(hasName("size"))), WrongUse,
62144
unless(hasAncestor(cxxMethodDecl(
63145
ofClass(equalsBoundNode("container"))))))
64146
.bind("SizeCallExpr"),
65147
this);
66148

149+
Finder->addMatcher(
150+
callExpr(has(cxxDependentScopeMemberExpr(
151+
hasObjectExpression(
152+
expr(anyOf(hasType(ValidContainer),
153+
hasType(pointsTo(ValidContainer)),
154+
hasType(references(ValidContainer))))
155+
.bind("MemberCallObject")),
156+
hasMemberName("size"))),
157+
WrongUse,
158+
unless(hasAncestor(
159+
cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
160+
.bind("SizeCallExpr"),
161+
this);
162+
67163
// Empty constructor matcher.
68164
const auto DefaultConstructor = cxxConstructExpr(
69165
hasDeclaration(cxxConstructorDecl(isDefaultConstructor())));
@@ -72,12 +168,11 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
72168
ignoringImpCasts(stringLiteral(hasSize(0))),
73169
ignoringImpCasts(cxxBindTemporaryExpr(has(DefaultConstructor))),
74170
ignoringImplicit(DefaultConstructor),
75-
cxxConstructExpr(
76-
hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
77-
has(expr(ignoringImpCasts(DefaultConstructor)))),
78-
cxxConstructExpr(
79-
hasDeclaration(cxxConstructorDecl(isMoveConstructor())),
80-
has(expr(ignoringImpCasts(DefaultConstructor)))));
171+
cxxConstructExpr(hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
172+
has(expr(ignoringImpCasts(DefaultConstructor)))),
173+
cxxConstructExpr(hasDeclaration(cxxConstructorDecl(isMoveConstructor())),
174+
has(expr(ignoringImpCasts(DefaultConstructor)))),
175+
cxxUnresolvedConstructExpr(argumentCountIs(0)));
81176
// Match the object being compared.
82177
const auto STLArg =
83178
anyOf(unaryOperator(
@@ -87,31 +182,41 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
87182
expr(hasType(ValidContainer)).bind("STLObject"));
88183
Finder->addMatcher(
89184
cxxOperatorCallExpr(
185+
unless(isInTemplateInstantiation()),
90186
hasAnyOverloadedOperatorName("==", "!="),
91187
anyOf(allOf(hasArgument(0, WrongComparend), hasArgument(1, STLArg)),
92188
allOf(hasArgument(0, STLArg), hasArgument(1, WrongComparend))),
93189
unless(hasAncestor(
94190
cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
95191
.bind("BinCmp"),
96192
this);
193+
Finder->addMatcher(
194+
binaryOperator(hasAnyOperatorName("==", "!="),
195+
anyOf(allOf(hasLHS(WrongComparend), hasRHS(STLArg)),
196+
allOf(hasLHS(STLArg), hasRHS(WrongComparend))),
197+
unless(hasAncestor(
198+
cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
199+
.bind("BinCmp"),
200+
this);
97201
}
98202

99203
void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
100-
const auto *MemberCall =
101-
Result.Nodes.getNodeAs<CXXMemberCallExpr>("SizeCallExpr");
204+
const auto *MemberCall = Result.Nodes.getNodeAs<Expr>("SizeCallExpr");
205+
const auto *MemberCallObject =
206+
Result.Nodes.getNodeAs<Expr>("MemberCallObject");
102207
const auto *BinCmp = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("BinCmp");
208+
const auto *BinCmpTempl = Result.Nodes.getNodeAs<BinaryOperator>("BinCmp");
103209
const auto *BinaryOp = Result.Nodes.getNodeAs<BinaryOperator>("SizeBinaryOp");
104210
const auto *Pointee = Result.Nodes.getNodeAs<Expr>("Pointee");
105211
const auto *E =
106-
MemberCall
107-
? MemberCall->getImplicitObjectArgument()
212+
MemberCallObject
213+
? MemberCallObject
108214
: (Pointee ? Pointee : Result.Nodes.getNodeAs<Expr>("STLObject"));
109215
FixItHint Hint;
110216
std::string ReplacementText = std::string(
111217
Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
112218
*Result.SourceManager, getLangOpts()));
113-
if (BinCmp && IsBinaryOrTernary(E)) {
114-
// Not just a DeclRefExpr, so parenthesize to be on the safe side.
219+
if (IsBinaryOrTernary(E) || isa<UnaryOperator>(E)) {
115220
ReplacementText = "(" + ReplacementText + ")";
116221
}
117222
if (E->getType()->isPointerType())
@@ -125,7 +230,13 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
125230
}
126231
Hint =
127232
FixItHint::CreateReplacement(BinCmp->getSourceRange(), ReplacementText);
128-
} else if (BinaryOp) { // Determine the correct transformation.
233+
} else if (BinCmpTempl) {
234+
if (BinCmpTempl->getOpcode() == BinaryOperatorKind::BO_NE) {
235+
ReplacementText = "!" + ReplacementText;
236+
}
237+
Hint = FixItHint::CreateReplacement(BinCmpTempl->getSourceRange(),
238+
ReplacementText);
239+
} else if (BinaryOp) { // Determine the correct transformation.
129240
bool Negation = false;
130241
const bool ContainerIsLHS =
131242
!llvm::isa<IntegerLiteral>(BinaryOp->getLHS()->IgnoreImpCasts());
@@ -195,15 +306,17 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
195306
"!" + ReplacementText);
196307
}
197308

198-
if (MemberCall) {
199-
diag(MemberCall->getBeginLoc(),
200-
"the 'empty' method should be used to check "
201-
"for emptiness instead of 'size'")
309+
auto WarnLoc = MemberCall ? MemberCall->getBeginLoc() : SourceLocation{};
310+
311+
if (WarnLoc.isValid()) {
312+
diag(WarnLoc, "the 'empty' method should be used to check "
313+
"for emptiness instead of 'size'")
202314
<< Hint;
203315
} else {
204-
diag(BinCmp->getBeginLoc(),
205-
"the 'empty' method should be used to check "
206-
"for emptiness instead of comparing to an empty object")
316+
WarnLoc = BinCmpTempl ? BinCmpTempl->getBeginLoc()
317+
: (BinCmp ? BinCmp->getBeginLoc() : SourceLocation{});
318+
diag(WarnLoc, "the 'empty' method should be used to check "
319+
"for emptiness instead of comparing to an empty object")
207320
<< Hint;
208321
}
209322

clang-tools-extra/clangd/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ if (NOT DEFINED CLANGD_BUILD_XPC)
1414
unset(CLANGD_BUILD_XPC_DEFAULT)
1515
endif ()
1616

17+
option(CLANGD_MALLOC_TRIM "Call malloc_trim(3) periodically in Clangd. (only takes effect when using glibc)" ON)
18+
1719
llvm_canonicalize_cmake_booleans(
1820
CLANGD_BUILD_XPC
1921
CLANGD_ENABLE_REMOTE
22+
CLANGD_MALLOC_TRIM
2023
LLVM_ENABLE_ZLIB
2124
)
2225

clang-tools-extra/clangd/ClangdLSPServer.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class ClangdLSPServer::MessageHandler : public Transport::MessageHandler {
178178
} else if (auto Handler = Notifications.lookup(Method)) {
179179
Handler(std::move(Params));
180180
Server.maybeExportMemoryProfile();
181+
Server.maybeCleanupMemory();
181182
} else {
182183
log("unhandled notification {0}", Method);
183184
}
@@ -453,6 +454,7 @@ void ClangdLSPServer::callRaw(StringRef Method, llvm::json::Value Params,
453454

454455
void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) {
455456
log("--> {0}", Method);
457+
maybeCleanupMemory();
456458
std::lock_guard<std::mutex> Lock(TranspWriter);
457459
Transp.notify(Method, std::move(Params));
458460
}
@@ -1283,13 +1285,7 @@ void ClangdLSPServer::publishDiagnostics(
12831285
}
12841286

12851287
void ClangdLSPServer::maybeExportMemoryProfile() {
1286-
if (!trace::enabled())
1287-
return;
1288-
// Profiling might be expensive, so we throttle it to happen once every 5
1289-
// minutes.
1290-
static constexpr auto ProfileInterval = std::chrono::minutes(5);
1291-
auto Now = std::chrono::steady_clock::now();
1292-
if (Now < NextProfileTime)
1288+
if (!trace::enabled() || !ShouldProfile())
12931289
return;
12941290

12951291
static constexpr trace::Metric MemoryUsage(
@@ -1298,7 +1294,12 @@ void ClangdLSPServer::maybeExportMemoryProfile() {
12981294
MemoryTree MT;
12991295
profile(MT);
13001296
record(MT, "clangd_lsp_server", MemoryUsage);
1301-
NextProfileTime = Now + ProfileInterval;
1297+
}
1298+
1299+
void ClangdLSPServer::maybeCleanupMemory() {
1300+
if (!Opts.MemoryCleanup || !ShouldCleanupMemory())
1301+
return;
1302+
Opts.MemoryCleanup();
13021303
}
13031304

13041305
// FIXME: This function needs to be properly tested.
@@ -1458,10 +1459,15 @@ void ClangdLSPServer::onAST(const ASTParams &Params,
14581459
ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
14591460
const ThreadsafeFS &TFS,
14601461
const ClangdLSPServer::Options &Opts)
1461-
: BackgroundContext(Context::current().clone()), Transp(Transp),
1462+
: ShouldProfile(/*Period=*/std::chrono::minutes(5),
1463+
/*Delay=*/std::chrono::minutes(1)),
1464+
ShouldCleanupMemory(/*Period=*/std::chrono::minutes(1),
1465+
/*Delay=*/std::chrono::minutes(1)),
1466+
BackgroundContext(Context::current().clone()), Transp(Transp),
14621467
MsgHandler(new MessageHandler(*this)), TFS(TFS),
14631468
SupportedSymbolKinds(defaultSymbolKinds()),
14641469
SupportedCompletionItemKinds(defaultCompletionItemKinds()), Opts(Opts) {
1470+
14651471
// clang-format off
14661472
MsgHandler->bind("initialize", &ClangdLSPServer::onInitialize);
14671473
MsgHandler->bind("initialized", &ClangdLSPServer::onInitialized);
@@ -1506,9 +1512,6 @@ ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
15061512
if (Opts.FoldingRanges)
15071513
MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange);
15081514
// clang-format on
1509-
1510-
// Delay first profile until we've finished warming up.
1511-
NextProfileTime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
15121515
}
15131516

15141517
ClangdLSPServer::~ClangdLSPServer() {
@@ -1621,6 +1624,10 @@ void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version,
16211624
void ClangdLSPServer::onBackgroundIndexProgress(
16221625
const BackgroundQueue::Stats &Stats) {
16231626
static const char ProgressToken[] = "backgroundIndexProgress";
1627+
1628+
// The background index did some work, maybe we need to cleanup
1629+
maybeCleanupMemory();
1630+
16241631
std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
16251632

16261633
auto NotifyProgress = [this](const BackgroundQueue::Stats &Stats) {

clang-tools-extra/clangd/ClangdLSPServer.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "support/Context.h"
2020
#include "support/MemoryTree.h"
2121
#include "support/Path.h"
22+
#include "support/Threading.h"
2223
#include "clang/Tooling/Core/Replacement.h"
2324
#include "llvm/ADT/Optional.h"
2425
#include "llvm/ADT/StringSet.h"
@@ -48,6 +49,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
4849
llvm::Optional<Path> CompileCommandsDir;
4950
/// The offset-encoding to use, or None to negotiate it over LSP.
5051
llvm::Optional<OffsetEncoding> Encoding;
52+
/// If set, periodically called to release memory.
53+
/// Consider malloc_trim(3)
54+
std::function<void()> MemoryCleanup = nullptr;
5155

5256
/// Per-feature options. Generally ClangdServer lets these vary
5357
/// per-request, but LSP allows limited/no customizations.
@@ -183,10 +187,12 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
183187
/// Runs profiling and exports memory usage metrics if tracing is enabled and
184188
/// profiling hasn't happened recently.
185189
void maybeExportMemoryProfile();
190+
PeriodicThrottler ShouldProfile;
186191

187-
/// Timepoint until which profiling is off. It is used to throttle profiling
188-
/// requests.
189-
std::chrono::steady_clock::time_point NextProfileTime;
192+
/// Run the MemoryCleanup callback if it's time.
193+
/// This method is thread safe.
194+
void maybeCleanupMemory();
195+
PeriodicThrottler ShouldCleanupMemory;
190196

191197
/// Since initialization of CDBs and ClangdServer is done lazily, the
192198
/// following context captures the one used while creating ClangdLSPServer and

0 commit comments

Comments
 (0)