116 lines · cpp
1//===-- IncludeFixerContext.cpp - Include fixer context ---------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "IncludeFixerContext.h"10#include "llvm/ADT/STLExtras.h"11 12namespace clang {13namespace include_fixer {14 15namespace {16 17// Splits a multiply qualified names (e.g. a::b::c).18llvm::SmallVector<llvm::StringRef, 8>19SplitQualifiers(llvm::StringRef StringQualifiers) {20 llvm::SmallVector<llvm::StringRef, 8> Qualifiers;21 StringQualifiers.split(Qualifiers, "::");22 return Qualifiers;23}24 25std::string createQualifiedNameForReplacement(26 llvm::StringRef RawSymbolName,27 llvm::StringRef SymbolScopedQualifiersName,28 const find_all_symbols::SymbolInfo &MatchedSymbol) {29 // No need to add missing qualifiers if SymbolIdentifier has a global scope30 // operator "::".31 if (RawSymbolName.starts_with("::"))32 return std::string(RawSymbolName);33 34 std::string QualifiedName = MatchedSymbol.getQualifiedName();35 36 // For nested classes, the qualified name constructed from database misses37 // some stripped qualifiers, because when we search a symbol in database,38 // we strip qualifiers from the end until we find a result. So append the39 // missing stripped qualifiers here.40 //41 // Get stripped qualifiers.42 auto SymbolQualifiers = SplitQualifiers(RawSymbolName);43 std::string StrippedQualifiers;44 while (!SymbolQualifiers.empty() &&45 !llvm::StringRef(QualifiedName).ends_with(SymbolQualifiers.back())) {46 StrippedQualifiers =47 "::" + SymbolQualifiers.back().str() + StrippedQualifiers;48 SymbolQualifiers.pop_back();49 }50 // Append the missing stripped qualifiers.51 std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;52 53 // Try to find and skip the common prefix qualifiers.54 auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName);55 auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName);56 auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin();57 auto SymbolScopedQualifiersIter = ScopedQualifiers.begin();58 while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() &&59 SymbolScopedQualifiersIter != ScopedQualifiers.end()) {60 if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter)61 break;62 ++FullySymbolQualifiersIter;63 ++SymbolScopedQualifiersIter;64 }65 std::string Result;66 for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end();67 ++FullySymbolQualifiersIter) {68 if (!Result.empty())69 Result += "::";70 Result += *FullySymbolQualifiersIter;71 }72 return Result;73}74 75} // anonymous namespace76 77IncludeFixerContext::IncludeFixerContext(78 StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,79 std::vector<find_all_symbols::SymbolInfo> Symbols)80 : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),81 MatchedSymbols(std::move(Symbols)) {82 // Remove replicated QuerySymbolInfos with the same range.83 //84 // QuerySymbolInfos may contain replicated elements. Because CorrectTypo85 // callback doesn't always work as we expected. In somecases, it will be86 // triggered at the same position or unidentified symbol multiple times.87 llvm::sort(QuerySymbolInfos,88 [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {89 return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <90 std::make_pair(B.Range.getOffset(), B.Range.getLength());91 });92 QuerySymbolInfos.erase(93 llvm::unique(QuerySymbolInfos,94 [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {95 return A.Range == B.Range;96 }),97 QuerySymbolInfos.end());98 for (const auto &Symbol : MatchedSymbols) {99 HeaderInfos.push_back(100 {Symbol.getFilePath().str(),101 createQualifiedNameForReplacement(102 QuerySymbolInfos.front().RawIdentifier,103 QuerySymbolInfos.front().ScopedQualifiers, Symbol)});104 }105 // Deduplicate header infos.106 HeaderInfos.erase(llvm::unique(HeaderInfos,107 [](const HeaderInfo &A, const HeaderInfo &B) {108 return A.Header == B.Header &&109 A.QualifiedName == B.QualifiedName;110 }),111 HeaderInfos.end());112}113 114} // include_fixer115} // clang116