blob: d6fbdb5fbbb0bd32559e8a70aa315305a722f218 [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())) {
47 StrippedQualifiers = "::" + SymbolQualifiers.back().str();
48 SymbolQualifiers.pop_back();
49 }
50 // Append the missing stripped qualifiers.
51 std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
Haojian Wu0c05e2e2016-07-14 09:39:12 +000052
Haojian Wu39a718c2016-07-15 08:12:48 +000053 // 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;
Haojian Wu68c34a02016-07-13 16:43:54 +000073}
74
75} // anonymous namespace
76
77IncludeFixerContext::IncludeFixerContext(
78 llvm::StringRef Name, llvm::StringRef ScopeQualifiers,
79 std::vector<find_all_symbols::SymbolInfo> Symbols,
80 tooling::Range Range)
81 : SymbolIdentifier(Name), SymbolScopedQualifiers(ScopeQualifiers),
82 MatchedSymbols(std::move(Symbols)), SymbolRange(Range) {
83 for (const auto &Symbol : MatchedSymbols) {
84 HeaderInfos.push_back({Symbol.getFilePath().str(),
85 createQualifiedNameForReplacement(
86 SymbolIdentifier, ScopeQualifiers, Symbol)});
87 }
88 // Deduplicate header infos.
89 HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),
90 [](const HeaderInfo &A, const HeaderInfo &B) {
91 return A.Header == B.Header &&
92 A.QualifiedName == B.QualifiedName;
93 }),
94 HeaderInfos.end());
Haojian Wu783d4312016-07-08 13:11:38 +000095}
96
97} // include_fixer
98} // clang