brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 7a63763 Raw
209 lines · cpp
1//===--- Types.cpp --------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang-include-cleaner/Types.h"10#include "TypesInternal.h"11#include "clang/AST/Decl.h"12#include "clang/Basic/FileEntry.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/Path.h"19#include "llvm/Support/raw_ostream.h"20#include <vector>21 22namespace clang::include_cleaner {23 24std::string Symbol::name() const {25  switch (kind()) {26  case include_cleaner::Symbol::Macro:27    return macro().Name->getName().str();28  case include_cleaner::Symbol::Declaration:29    return llvm::dyn_cast<NamedDecl>(&declaration())30        ->getQualifiedNameAsString();31  }32  llvm_unreachable("Unknown symbol kind");33}34 35llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) {36  switch (S.kind()) {37  case Symbol::Declaration:38    if (const auto *ND = llvm::dyn_cast<NamedDecl>(&S.declaration()))39      return OS << ND->getQualifiedNameAsString();40    return OS << S.declaration().getDeclKindName();41  case Symbol::Macro:42    return OS << S.macro().Name->getName();43  }44  llvm_unreachable("Unhandled Symbol kind");45}46 47llvm::StringRef Header::resolvedPath() const {48  switch (kind()) {49  case include_cleaner::Header::Physical:50    return physical().getName();51  case include_cleaner::Header::Standard:52    return standard().name().trim("<>\"");53  case include_cleaner::Header::Verbatim:54    return verbatim().trim("<>\"");55  }56  llvm_unreachable("Unknown header kind");57}58 59llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Header &H) {60  switch (H.kind()) {61  case Header::Physical:62    return OS << H.physical().getName();63  case Header::Standard:64    return OS << H.standard().name();65  case Header::Verbatim:66    return OS << H.verbatim();67  }68  llvm_unreachable("Unhandled Header kind");69}70 71llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Include &I) {72  return OS << I.Line << ": " << I.quote() << " => "73            << (I.Resolved ? I.Resolved->getName() : "<missing>");74}75 76llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolReference &R) {77  // We can't decode the Location without SourceManager. Its raw representation78  // isn't completely useless (and distinguishes SymbolReference from Symbol).79  return OS << R.RT << " reference to " << R.Target << "@0x"80            << llvm::utohexstr(81                   R.RefLocation.getRawEncoding(), /*LowerCase=*/false,82                   /*Width=*/CHAR_BIT * sizeof(SourceLocation::UIntTy));83}84 85llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, RefType T) {86  switch (T) {87  case RefType::Explicit:88    return OS << "explicit";89  case RefType::Implicit:90    return OS << "implicit";91  case RefType::Ambiguous:92    return OS << "ambiguous";93  }94  llvm_unreachable("Unexpected RefType");95}96 97std::string Include::quote() const {98  return (llvm::StringRef(Angled ? "<" : "\"") + Spelled +99          (Angled ? ">" : "\""))100      .str();101}102 103static llvm::SmallString<128> normalizePath(llvm::StringRef Path) {104  namespace path = llvm::sys::path;105 106  llvm::SmallString<128> P = Path;107  path::remove_dots(P, /*remove_dot_dot=*/true);108  path::native(P, path::Style::posix);109  while (!P.empty() && P.back() == '/')110    P.pop_back();111  return P;112}113 114void Includes::addSearchDirectory(llvm::StringRef Path) {115  SearchPath.try_emplace(normalizePath(Path));116}117 118void Includes::add(const Include &I) {119  namespace path = llvm::sys::path;120 121  unsigned Index = All.size();122  All.push_back(I);123  auto BySpellingIt = BySpelling.try_emplace(I.Spelled).first;124  All.back().Spelled = BySpellingIt->first(); // Now we own the backing string.125 126  BySpellingIt->second.push_back(Index);127  ByLine[I.Line] = Index;128 129  if (!I.Resolved)130    return;131  ByFile[&I.Resolved->getFileEntry()].push_back(Index);132 133  // While verbatim headers ideally should match #include spelling exactly,134  // we want to be tolerant of different spellings of the same file.135  //136  // If the search path includes "/a/b" and "/a/b/c/d",137  // verbatim "e/f" should match (spelled=c/d/e/f, resolved=/a/b/c/d/e/f).138  // We assume entry's (normalized) name will match the search dirs.139  auto Path = normalizePath(I.Resolved->getName());140  for (llvm::StringRef Parent = path::parent_path(Path); !Parent.empty();141       Parent = path::parent_path(Parent)) {142    if (!SearchPath.contains(Parent))143      continue;144    llvm::StringRef Rel =145        llvm::StringRef(Path).drop_front(Parent.size()).ltrim('/');146    BySpellingAlternate[Rel].push_back(Index);147  }148}149 150const Include *Includes::atLine(unsigned OneBasedIndex) const {151  auto It = ByLine.find(OneBasedIndex);152  return (It == ByLine.end()) ? nullptr : &All[It->second];153}154 155llvm::SmallVector<const Include *> Includes::match(Header H) const {156  llvm::SmallVector<const Include *> Result;157  switch (H.kind()) {158  case Header::Physical:159    for (unsigned I : ByFile.lookup(H.physical()))160      Result.push_back(&All[I]);161    break;162  case Header::Standard:163    for (unsigned I : BySpelling.lookup(H.standard().name().trim("<>")))164      Result.push_back(&All[I]);165    break;166  case Header::Verbatim: {167    llvm::StringRef Spelling = H.verbatim().trim("\"<>");168    for (unsigned I : BySpelling.lookup(Spelling))169      Result.push_back(&All[I]);170    for (unsigned I : BySpellingAlternate.lookup(Spelling))171      if (!llvm::is_contained(Result, &All[I]))172        Result.push_back(&All[I]);173    break;174  }175  }176  return Result;177}178 179llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolLocation &S) {180  switch (S.kind()) {181  case SymbolLocation::Physical:182    // We can't decode the Location without SourceManager. Its raw183    // representation isn't completely useless (and distinguishes184    // SymbolReference from Symbol).185    return OS << "@0x"186              << llvm::utohexstr(187                     S.physical().getRawEncoding(), /*LowerCase=*/false,188                     /*Width=*/CHAR_BIT * sizeof(SourceLocation::UIntTy));189  case SymbolLocation::Standard:190    return OS << S.standard().scope() << S.standard().name();191  }192  llvm_unreachable("Unhandled Symbol kind");193}194 195bool Header::operator<(const Header &RHS) const {196  if (kind() != RHS.kind())197    return kind() < RHS.kind();198  switch (kind()) {199  case Header::Physical:200    return physical().getName() < RHS.physical().getName();201  case Header::Standard:202    return standard().name() < RHS.standard().name();203  case Header::Verbatim:204    return verbatim() < RHS.verbatim();205  }206  llvm_unreachable("unhandled Header kind");207}208} // namespace clang::include_cleaner209