//===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "IncludeFixerContext.h" #include namespace clang { namespace include_fixer { namespace { // Splits a multiply qualified names (e.g. a::b::c). llvm::SmallVector SplitQualifiers(llvm::StringRef StringQualifiers) { llvm::SmallVector Qualifiers; StringQualifiers.split(Qualifiers, "::"); return Qualifiers; } std::string createQualifiedNameForReplacement( llvm::StringRef RawSymbolName, llvm::StringRef SymbolScopedQualifiersName, const find_all_symbols::SymbolInfo &MatchedSymbol) { // No need to add missing qualifiers if SymbolIndentifer has a global scope // operator "::". if (RawSymbolName.startswith("::")) return RawSymbolName; std::string QualifiedName = MatchedSymbol.getQualifiedName(); // For nested classes, the qualified name constructed from database misses // some stripped qualifiers, because when we search a symbol in database, // we strip qualifiers from the end until we find a result. So append the // missing stripped qualifiers here. // // Get stripped qualifiers. auto SymbolQualifiers = SplitQualifiers(RawSymbolName); std::string StrippedQualifiers; while (!SymbolQualifiers.empty() && !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) { StrippedQualifiers = "::" + SymbolQualifiers.back().str() + StrippedQualifiers; SymbolQualifiers.pop_back(); } // Append the missing stripped qualifiers. std::string FullyQualifiedName = QualifiedName + StrippedQualifiers; // Try to find and skip the common prefix qualifiers. auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName); auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName); auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin(); auto SymbolScopedQualifiersIter = ScopedQualifiers.begin(); while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() && SymbolScopedQualifiersIter != ScopedQualifiers.end()) { if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter) break; ++FullySymbolQualifiersIter; ++SymbolScopedQualifiersIter; } std::string Result; for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end(); ++FullySymbolQualifiersIter) { if (!Result.empty()) Result += "::"; Result += *FullySymbolQualifiersIter; } return Result; } } // anonymous namespace IncludeFixerContext::IncludeFixerContext( StringRef FilePath, std::vector QuerySymbols, std::vector Symbols) : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)), MatchedSymbols(std::move(Symbols)) { // Remove replicated QuerySymbolInfos with the same range. // // QuerySymbolInfos may contain replicated elements. Because CorrectTypo // callback doesn't always work as we expected. In somecases, it will be // triggered at the same position or unidentified symbol multiple times. std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(), [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) { return std::make_pair(A.Range.getOffset(), A.Range.getLength()) < std::make_pair(B.Range.getOffset(), B.Range.getLength()); }); QuerySymbolInfos.erase( std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(), [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) { return A.Range == B.Range; }), QuerySymbolInfos.end()); for (const auto &Symbol : MatchedSymbols) { HeaderInfos.push_back( {Symbol.getFilePath().str(), createQualifiedNameForReplacement( QuerySymbolInfos.front().RawIdentifier, QuerySymbolInfos.front().ScopedQualifiers, Symbol)}); } // Deduplicate header infos. HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(), [](const HeaderInfo &A, const HeaderInfo &B) { return A.Header == B.Header && A.QualifiedName == B.QualifiedName; }), HeaderInfos.end()); } } // include_fixer } // clang