diff clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children c4bab56944e8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp	Thu Feb 13 15:10:13 2020 +0900
@@ -0,0 +1,115 @@
+//===-- 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 <algorithm>
+
+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.
+  std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
+            [&](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