Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -406,25 +406,27 @@ Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted)); }; bool ShouldInsert = C.headerToInsertIfAllowed().hasValue(); - // Calculate include paths and edits for all possible headers. + // Put includes with insertions after those without. + llvm::SmallVector InsertableCandidates; + Completion.Includes.reserve(C.RankedIncludeHeaders.size()); + InsertableCandidates.reserve(C.RankedIncludeHeaders.size()); for (const auto &Inc : C.RankedIncludeHeaders) { if (auto ToInclude = Inserted(Inc)) { CodeCompletion::IncludeCandidate Include; Include.Header = ToInclude->first; if (ToInclude->second && ShouldInsert) Include.Insertion = Includes.insert(ToInclude->first); - Completion.Includes.push_back(std::move(Include)); + (Include.Insertion ? InsertableCandidates : Completion.Includes) + .push_back(std::move(Include)); + } else log("Failed to generate include insertion edits for adding header " "(FileURI='{0}', IncludeHeader='{1}') into {2}", C.IndexResult->CanonicalDeclaration.FileURI, Inc, FileName); } - // Prefer includes that do not need edits (i.e. already exist). - std::stable_partition(Completion.Includes.begin(), - Completion.Includes.end(), - [](const CodeCompletion::IncludeCandidate &I) { - return !I.Insertion.hasValue(); - }); + if (!InsertableCandidates.empty()) + std::move(InsertableCandidates.begin(), InsertableCandidates.end(), + std::back_inserter(Completion.Includes)); } void add(const CompletionCandidate &C, CodeCompletionString *SemaCCS) {