clang-tools  14.0.0git
IncludeFixerContext.cpp
Go to the documentation of this file.
1 //===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IncludeFixerContext.h"
10 #include <algorithm>
11 
12 namespace clang {
13 namespace include_fixer {
14 
15 namespace {
16 
17 // Splits a multiply qualified names (e.g. a::b::c).
18 llvm::SmallVector<llvm::StringRef, 8>
19 SplitQualifiers(llvm::StringRef StringQualifiers) {
20  llvm::SmallVector<llvm::StringRef, 8> Qualifiers;
21  StringQualifiers.split(Qualifiers, "::");
22  return Qualifiers;
23 }
24 
25 std::string createQualifiedNameForReplacement(
26  llvm::StringRef RawSymbolName,
27  llvm::StringRef SymbolScopedQualifiersName,
28  const find_all_symbols::SymbolInfo &MatchedSymbol) {
29  // No need to add missing qualifiers if SymbolIdentifier has a global scope
30  // operator "::".
31  if (RawSymbolName.startswith("::"))
32  return std::string(RawSymbolName);
33 
34  std::string QualifiedName = MatchedSymbol.getQualifiedName();
35 
36  // For nested classes, the qualified name constructed from database misses
37  // some stripped qualifiers, because when we search a symbol in database,
38  // we strip qualifiers from the end until we find a result. So append the
39  // missing stripped qualifiers here.
40  //
41  // Get stripped qualifiers.
42  auto SymbolQualifiers = SplitQualifiers(RawSymbolName);
43  std::string StrippedQualifiers;
44  while (!SymbolQualifiers.empty() &&
45  !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
46  StrippedQualifiers =
47  "::" + SymbolQualifiers.back().str() + StrippedQualifiers;
48  SymbolQualifiers.pop_back();
49  }
50  // Append the missing stripped qualifiers.
51  std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
52 
53  // 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;
73 }
74 
75 } // anonymous namespace
76 
78  StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
79  std::vector<find_all_symbols::SymbolInfo> Symbols)
80  : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
81  MatchedSymbols(std::move(Symbols)) {
82  // Remove replicated QuerySymbolInfos with the same range.
83  //
84  // QuerySymbolInfos may contain replicated elements. Because CorrectTypo
85  // callback doesn't always work as we expected. In somecases, it will be
86  // triggered at the same position or unidentified symbol multiple times.
87  std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
88  [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
89  return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <
90  std::make_pair(B.Range.getOffset(), B.Range.getLength());
91  });
92  QuerySymbolInfos.erase(
93  std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
94  [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
95  return A.Range == B.Range;
96  }),
97  QuerySymbolInfos.end());
98  for (const auto &Symbol : MatchedSymbols) {
99  HeaderInfos.push_back(
100  {Symbol.getFilePath().str(),
101  createQualifiedNameForReplacement(
102  QuerySymbolInfos.front().RawIdentifier,
103  QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
104  }
105  // Deduplicate header infos.
106  HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),
107  [](const HeaderInfo &A, const HeaderInfo &B) {
108  return A.Header == B.Header &&
109  A.QualifiedName == B.QualifiedName;
110  }),
111  HeaderInfos.end());
112 }
113 
114 } // include_fixer
115 } // clang
clang::include_fixer::IncludeFixerContext::IncludeFixerContext
IncludeFixerContext()=default
ns1::ns2::A
@ A
Definition: CategoricalFeature.h:3
clang::tidy::bugprone::model::MixFlags::Qualifiers
@ Qualifiers
The mix involves change in the qualifiers.
clang::include_fixer::IncludeFixerContext::QuerySymbolInfo
Definition: IncludeFixerContext.h:32
clang::include_fixer::IncludeFixerContext::HeaderInfo
Definition: IncludeFixerContext.h:24
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
IncludeFixerContext.h
SymbolInfo
clang::find_all_symbols::SymbolInfo SymbolInfo
Definition: FindAllSymbolsMain.cpp:38
ns1::ns2::B
@ B
Definition: CategoricalFeature.h:3