diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -525,13 +525,11 @@ const ValueDecl *MaybeContainer, const UsageResult &Usages, const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit, const ForStmt *Loop, RangeDescriptor Descriptor) { - auto Diag = diag(Loop->getForLoc(), "use range-based for loop instead"); - std::string VarName; bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl; bool AliasVarIsRef = false; bool CanCopy = true; - + std::vector FixIts; if (VarNameFromAlias) { const auto *AliasVar = cast(AliasDecl->getSingleDecl()); VarName = AliasVar->getName().str(); @@ -563,8 +561,8 @@ getAliasRange(Context->getSourceManager(), ReplaceRange); } - Diag << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(ReplaceRange), ReplacementText); + FixIts.push_back(FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(ReplaceRange), ReplacementText)); // No further replacements are made to the loop, since the iterator or index // was used exactly once - in the initialization of AliasVar. } else { @@ -609,8 +607,8 @@ Usage.Kind == Usage::UK_CaptureByCopy ? "&" + VarName : VarName; } TUInfo->getReplacedVars().insert(std::make_pair(Loop, IndexVar)); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(Range), ReplaceText); + FixIts.push_back(FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(Range), ReplaceText)); } } @@ -648,8 +646,9 @@ std::string Range = ("(" + TypeString + " " + VarName + " : " + MaybeDereference + Descriptor.ContainerString + ")") .str(); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(ParenRange), Range); + FixIts.push_back(FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(ParenRange), Range)); + diag(Loop->getForLoc(), "use range-based for loop instead") << FixIts; TUInfo->getGeneratedDecls().insert(make_pair(Loop, VarName)); } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -272,6 +272,33 @@ "use a trailing return type for this function"))))); } +TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) { + Annotations Main(R"cpp( + template struct Foo { + T *begin(); + T *end(); + }; + struct LabelInfo { + int a; + bool b; + }; + + void f() { + Foo 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) { Annotations Main(R"cpp( int main() {