116 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "IncludeFixerContext.h"
 | |
| #include "llvm/ADT/STLExtras.h"
 | |
| 
 | |
| namespace clang {
 | |
| namespace include_fixer {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Splits a multiply qualified names (e.g. a::b::c).
 | |
| llvm::SmallVector<llvm::StringRef, 8>
 | |
| SplitQualifiers(llvm::StringRef StringQualifiers) {
 | |
|   llvm::SmallVector<llvm::StringRef, 8> 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 SymbolIdentifier has a global scope
 | |
|   // operator "::".
 | |
|   if (RawSymbolName.startswith("::"))
 | |
|     return std::string(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<QuerySymbolInfo> QuerySymbols,
 | |
|     std::vector<find_all_symbols::SymbolInfo> 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.
 | |
|   llvm::sort(QuerySymbolInfos,
 | |
|              [&](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
 |