2016-07-08 21:11:38 +08:00
|
|
|
//===-- 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 <algorithm>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace include_fixer {
|
|
|
|
|
2016-07-14 00:43:54 +08:00
|
|
|
namespace {
|
2016-07-08 21:11:38 +08:00
|
|
|
|
2016-07-15 16:12:48 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2016-07-14 00:43:54 +08:00
|
|
|
std::string createQualifiedNameForReplacement(
|
|
|
|
llvm::StringRef RawSymbolName,
|
2016-07-15 16:12:48 +08:00
|
|
|
llvm::StringRef SymbolScopedQualifiersName,
|
2016-07-14 00:43:54 +08:00
|
|
|
const find_all_symbols::SymbolInfo &MatchedSymbol) {
|
2016-07-08 22:28:43 +08:00
|
|
|
// No need to add missing qualifiers if SymbolIndentifer has a global scope
|
|
|
|
// operator "::".
|
2016-07-14 00:43:54 +08:00
|
|
|
if (RawSymbolName.startswith("::"))
|
|
|
|
return RawSymbolName;
|
|
|
|
|
|
|
|
std::string QualifiedName = MatchedSymbol.getQualifiedName();
|
|
|
|
|
2016-07-08 21:11:38 +08:00
|
|
|
// 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.
|
2016-07-15 16:12:48 +08:00
|
|
|
auto SymbolQualifiers = SplitQualifiers(RawSymbolName);
|
2016-07-08 21:11:38 +08:00
|
|
|
std::string StrippedQualifiers;
|
|
|
|
while (!SymbolQualifiers.empty() &&
|
|
|
|
!llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
|
2016-08-02 18:43:10 +08:00
|
|
|
StrippedQualifiers =
|
|
|
|
"::" + SymbolQualifiers.back().str() + StrippedQualifiers;
|
2016-07-08 21:11:38 +08:00
|
|
|
SymbolQualifiers.pop_back();
|
|
|
|
}
|
|
|
|
// Append the missing stripped qualifiers.
|
|
|
|
std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
|
2016-07-14 17:39:12 +08:00
|
|
|
|
2016-07-15 16:12:48 +08:00
|
|
|
// 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;
|
2016-07-14 00:43:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
IncludeFixerContext::IncludeFixerContext(
|
2016-08-09 16:26:19 +08:00
|
|
|
StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
|
2016-07-20 17:00:22 +08:00
|
|
|
std::vector<find_all_symbols::SymbolInfo> Symbols)
|
2016-08-09 16:26:19 +08:00
|
|
|
: FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
|
2016-07-21 21:47:09 +08:00
|
|
|
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) {
|
2016-07-22 17:07:16 +08:00
|
|
|
return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <
|
|
|
|
std::make_pair(B.Range.getOffset(), B.Range.getLength());
|
2016-07-21 21:47:09 +08:00
|
|
|
});
|
|
|
|
QuerySymbolInfos.erase(
|
|
|
|
std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
|
|
|
|
[](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
|
|
|
|
return A.Range == B.Range;
|
|
|
|
}),
|
|
|
|
QuerySymbolInfos.end());
|
2016-07-14 00:43:54 +08:00
|
|
|
for (const auto &Symbol : MatchedSymbols) {
|
2016-07-19 22:49:04 +08:00
|
|
|
HeaderInfos.push_back(
|
|
|
|
{Symbol.getFilePath().str(),
|
|
|
|
createQualifiedNameForReplacement(
|
2016-07-21 21:47:09 +08:00
|
|
|
QuerySymbolInfos.front().RawIdentifier,
|
|
|
|
QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
|
2016-07-14 00:43:54 +08:00
|
|
|
}
|
|
|
|
// 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());
|
2016-07-08 21:11:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // include_fixer
|
|
|
|
} // clang
|