blob: 8106e20e8dd8abb5a6b5ca6794396d4551b7d1f4 [file] [log] [blame]
Haojian Wu783d4312016-07-08 13:11:38 +00001//===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "IncludeFixerContext.h"
11#include <algorithm>
12
13namespace clang {
14namespace include_fixer {
15
Haojian Wu68c34a02016-07-13 16:43:54 +000016namespace {
Haojian Wu783d4312016-07-08 13:11:38 +000017
Haojian Wu39a718c2016-07-15 08:12:48 +000018// Splits a multiply qualified names (e.g. a::b::c).
19llvm::SmallVector<llvm::StringRef, 8>
20SplitQualifiers(llvm::StringRef StringQualifiers) {
21 llvm::SmallVector<llvm::StringRef, 8> Qualifiers;
22 StringQualifiers.split(Qualifiers, "::");
23 return Qualifiers;
24}
25
Haojian Wu68c34a02016-07-13 16:43:54 +000026std::string createQualifiedNameForReplacement(
27 llvm::StringRef RawSymbolName,
Haojian Wu39a718c2016-07-15 08:12:48 +000028 llvm::StringRef SymbolScopedQualifiersName,
Haojian Wu68c34a02016-07-13 16:43:54 +000029 const find_all_symbols::SymbolInfo &MatchedSymbol) {
Haojian Wu5d9482d2016-07-08 14:28:43 +000030 // No need to add missing qualifiers if SymbolIndentifer has a global scope
31 // operator "::".
Haojian Wu68c34a02016-07-13 16:43:54 +000032 if (RawSymbolName.startswith("::"))
33 return RawSymbolName;
34
35 std::string QualifiedName = MatchedSymbol.getQualifiedName();
36
Haojian Wu783d4312016-07-08 13:11:38 +000037 // For nested classes, the qualified name constructed from database misses
38 // some stripped qualifiers, because when we search a symbol in database,
39 // we strip qualifiers from the end until we find a result. So append the
40 // missing stripped qualifiers here.
41 //
42 // Get stripped qualifiers.
Haojian Wu39a718c2016-07-15 08:12:48 +000043 auto SymbolQualifiers = SplitQualifiers(RawSymbolName);
Haojian Wu783d4312016-07-08 13:11:38 +000044 std::string StrippedQualifiers;
45 while (!SymbolQualifiers.empty() &&
46 !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
Haojian Wuadedac62016-08-02 10:43:10 +000047 StrippedQualifiers =
48 "::" + SymbolQualifiers.back().str() + StrippedQualifiers;
Haojian Wu783d4312016-07-08 13:11:38 +000049 SymbolQualifiers.pop_back();
50 }
51 // Append the missing stripped qualifiers.
52 std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
Haojian Wu0c05e2e2016-07-14 09:39:12 +000053
Haojian Wu39a718c2016-07-15 08:12:48 +000054 // Try to find and skip the common prefix qualifiers.
55 auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName);
56 auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName);
57 auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin();
58 auto SymbolScopedQualifiersIter = ScopedQualifiers.begin();
59 while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() &&
60 SymbolScopedQualifiersIter != ScopedQualifiers.end()) {
61 if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter)
62 break;
63 ++FullySymbolQualifiersIter;
64 ++SymbolScopedQualifiersIter;
65 }
66 std::string Result;
67 for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end();
68 ++FullySymbolQualifiersIter) {
69 if (!Result.empty())
70 Result += "::";
71 Result += *FullySymbolQualifiersIter;
72 }
73 return Result;
Haojian Wu68c34a02016-07-13 16:43:54 +000074}
75
76} // anonymous namespace
77
78IncludeFixerContext::IncludeFixerContext(
Haojian Wuc99f7282016-08-09 08:26:19 +000079 StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
Haojian Wu20dba052016-07-20 09:00:22 +000080 std::vector<find_all_symbols::SymbolInfo> Symbols)
Haojian Wuc99f7282016-08-09 08:26:19 +000081 : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
Haojian Wu62aee522016-07-21 13:47:09 +000082 MatchedSymbols(std::move(Symbols)) {
83 // Remove replicated QuerySymbolInfos with the same range.
84 //
85 // QuerySymbolInfos may contain replicated elements. Because CorrectTypo
86 // callback doesn't always work as we expected. In somecases, it will be
87 // triggered at the same position or unidentified symbol multiple times.
88 std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
89 [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
Benjamin Kramere0f35a52016-07-22 09:07:16 +000090 return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <
91 std::make_pair(B.Range.getOffset(), B.Range.getLength());
Haojian Wu62aee522016-07-21 13:47:09 +000092 });
93 QuerySymbolInfos.erase(
94 std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
95 [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
96 return A.Range == B.Range;
97 }),
98 QuerySymbolInfos.end());
Haojian Wu68c34a02016-07-13 16:43:54 +000099 for (const auto &Symbol : MatchedSymbols) {
Haojian Wu9e4bd0c2016-07-19 14:49:04 +0000100 HeaderInfos.push_back(
101 {Symbol.getFilePath().str(),
102 createQualifiedNameForReplacement(
Haojian Wu62aee522016-07-21 13:47:09 +0000103 QuerySymbolInfos.front().RawIdentifier,
104 QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
Haojian Wu68c34a02016-07-13 16:43:54 +0000105 }
106 // Deduplicate header infos.
107 HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),
108 [](const HeaderInfo &A, const HeaderInfo &B) {
109 return A.Header == B.Header &&
110 A.QualifiedName == B.QualifiedName;
111 }),
112 HeaderInfos.end());
Haojian Wu783d4312016-07-08 13:11:38 +0000113}
114
115} // include_fixer
116} // clang