forked from OSchip/llvm-project
[clangd] Fix modernize-loop-convert "multiple diag in flight" crash.
Summary: this maybe not ideal, but it is trivial and does fix the crash. Fixes https://github.com/clangd/clangd/issues/156. Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D78715
This commit is contained in:
parent
0eec6662f6
commit
a466e4be38
|
@ -525,13 +525,11 @@ void LoopConvertCheck::doConversion(
|
||||||
const ValueDecl *MaybeContainer, const UsageResult &Usages,
|
const ValueDecl *MaybeContainer, const UsageResult &Usages,
|
||||||
const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit,
|
const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit,
|
||||||
const ForStmt *Loop, RangeDescriptor Descriptor) {
|
const ForStmt *Loop, RangeDescriptor Descriptor) {
|
||||||
auto Diag = diag(Loop->getForLoc(), "use range-based for loop instead");
|
|
||||||
|
|
||||||
std::string VarName;
|
std::string VarName;
|
||||||
bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl;
|
bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl;
|
||||||
bool AliasVarIsRef = false;
|
bool AliasVarIsRef = false;
|
||||||
bool CanCopy = true;
|
bool CanCopy = true;
|
||||||
|
std::vector<FixItHint> FixIts;
|
||||||
if (VarNameFromAlias) {
|
if (VarNameFromAlias) {
|
||||||
const auto *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl());
|
const auto *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl());
|
||||||
VarName = AliasVar->getName().str();
|
VarName = AliasVar->getName().str();
|
||||||
|
@ -563,8 +561,8 @@ void LoopConvertCheck::doConversion(
|
||||||
getAliasRange(Context->getSourceManager(), ReplaceRange);
|
getAliasRange(Context->getSourceManager(), ReplaceRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag << FixItHint::CreateReplacement(
|
FixIts.push_back(FixItHint::CreateReplacement(
|
||||||
CharSourceRange::getTokenRange(ReplaceRange), ReplacementText);
|
CharSourceRange::getTokenRange(ReplaceRange), ReplacementText));
|
||||||
// No further replacements are made to the loop, since the iterator or index
|
// No further replacements are made to the loop, since the iterator or index
|
||||||
// was used exactly once - in the initialization of AliasVar.
|
// was used exactly once - in the initialization of AliasVar.
|
||||||
} else {
|
} else {
|
||||||
|
@ -609,8 +607,8 @@ void LoopConvertCheck::doConversion(
|
||||||
Usage.Kind == Usage::UK_CaptureByCopy ? "&" + VarName : VarName;
|
Usage.Kind == Usage::UK_CaptureByCopy ? "&" + VarName : VarName;
|
||||||
}
|
}
|
||||||
TUInfo->getReplacedVars().insert(std::make_pair(Loop, IndexVar));
|
TUInfo->getReplacedVars().insert(std::make_pair(Loop, IndexVar));
|
||||||
Diag << FixItHint::CreateReplacement(
|
FixIts.push_back(FixItHint::CreateReplacement(
|
||||||
CharSourceRange::getTokenRange(Range), ReplaceText);
|
CharSourceRange::getTokenRange(Range), ReplaceText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,8 +646,9 @@ void LoopConvertCheck::doConversion(
|
||||||
std::string Range = ("(" + TypeString + " " + VarName + " : " +
|
std::string Range = ("(" + TypeString + " " + VarName + " : " +
|
||||||
MaybeDereference + Descriptor.ContainerString + ")")
|
MaybeDereference + Descriptor.ContainerString + ")")
|
||||||
.str();
|
.str();
|
||||||
Diag << FixItHint::CreateReplacement(
|
FixIts.push_back(FixItHint::CreateReplacement(
|
||||||
CharSourceRange::getTokenRange(ParenRange), Range);
|
CharSourceRange::getTokenRange(ParenRange), Range));
|
||||||
|
diag(Loop->getForLoc(), "use range-based for loop instead") << FixIts;
|
||||||
TUInfo->getGeneratedDecls().insert(make_pair(Loop, VarName));
|
TUInfo->getGeneratedDecls().insert(make_pair(Loop, VarName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,33 @@ TEST(DiagnosticsTest, ClangTidy) {
|
||||||
"use a trailing return type for this function")))));
|
"use a trailing return type for this function")))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
|
||||||
|
Annotations Main(R"cpp(
|
||||||
|
template <typename T> struct Foo {
|
||||||
|
T *begin();
|
||||||
|
T *end();
|
||||||
|
};
|
||||||
|
struct LabelInfo {
|
||||||
|
int a;
|
||||||
|
bool b;
|
||||||
|
};
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
Foo<LabelInfo> label_info_map;
|
||||||
|
[[for]] (auto it = label_info_map.begin(); it != label_info_map.end(); ++it) {
|
||||||
|
auto S = *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)cpp");
|
||||||
|
TestTU TU = TestTU::withCode(Main.code());
|
||||||
|
TU.ClangTidyChecks = "modernize-loop-convert";
|
||||||
|
EXPECT_THAT(
|
||||||
|
TU.build().getDiagnostics(),
|
||||||
|
UnorderedElementsAre(::testing::AllOf(
|
||||||
|
Diag(Main.range(), "use range-based for loop instead"),
|
||||||
|
DiagSource(Diag::ClangTidy), DiagName("modernize-loop-convert"))));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DiagnosticTest, ClangTidySuppressionComment) {
|
TEST(DiagnosticTest, ClangTidySuppressionComment) {
|
||||||
Annotations Main(R"cpp(
|
Annotations Main(R"cpp(
|
||||||
int main() {
|
int main() {
|
||||||
|
|
Loading…
Reference in New Issue