#include "clang-include-cleaner/Types.h"
#include "TypesInternal.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/FileEntry.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
namespace clang::include_cleaner {
std::string Symbol::name() const {
switch (kind()) {
case include_cleaner::Symbol::Macro:
return macro().Name->getName().str();
case include_cleaner::Symbol::Declaration:
return llvm::dyn_cast<NamedDecl>(&declaration())
->getQualifiedNameAsString();
}
llvm_unreachable("Unknown symbol kind");
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) {
switch (S.kind()) {
case Symbol::Declaration:
if (const auto *ND = llvm::dyn_cast<NamedDecl>(&S.declaration()))
return OS << ND->getQualifiedNameAsString();
return OS << S.declaration().getDeclKindName();
case Symbol::Macro:
return OS << S.macro().Name->getName();
}
llvm_unreachable("Unhandled Symbol kind");
}
llvm::StringRef Header::resolvedPath() const {
switch (kind()) {
case include_cleaner::Header::Physical:
return physical().getFileEntry().tryGetRealPathName();
case include_cleaner::Header::Standard:
return standard().name().trim("<>\"");
case include_cleaner::Header::Verbatim:
return verbatim().trim("<>\"");
}
llvm_unreachable("Unknown header kind");
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Header &H) {
switch (H.kind()) {
case Header::Physical:
return OS << H.physical().getName();
case Header::Standard:
return OS << H.standard().name();
case Header::Verbatim:
return OS << H.verbatim();
}
llvm_unreachable("Unhandled Header kind");
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Include &I) {
return OS << I.Line << ": " << I.quote() << " => "
<< (I.Resolved ? I.Resolved->getName() : "<missing>");
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolReference &R) {
return OS << R.RT << " reference to " << R.Target << "@0x"
<< llvm::utohexstr(
R.RefLocation.getRawEncoding(), false,
CHAR_BIT * sizeof(SourceLocation::UIntTy));
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, RefType T) {
switch (T) {
case RefType::Explicit:
return OS << "explicit";
case RefType::Implicit:
return OS << "implicit";
case RefType::Ambiguous:
return OS << "ambiguous";
}
llvm_unreachable("Unexpected RefType");
}
std::string Include::quote() const {
return (llvm::StringRef(Angled ? "<" : "\"") + Spelled +
(Angled ? ">" : "\""))
.str();
}
static llvm::SmallString<128> normalizePath(llvm::StringRef Path) {
namespace path = llvm::sys::path;
llvm::SmallString<128> P = Path;
path::remove_dots(P, true);
path::native(P, path::Style::posix);
while (!P.empty() && P.back() == '/')
P.pop_back();
return P;
}
void Includes::addSearchDirectory(llvm::StringRef Path) {
SearchPath.try_emplace(normalizePath(Path));
}
void Includes::add(const Include &I) {
namespace path = llvm::sys::path;
unsigned Index = All.size();
All.push_back(I);
auto BySpellingIt = BySpelling.try_emplace(I.Spelled).first;
All.back().Spelled = BySpellingIt->first();
BySpellingIt->second.push_back(Index);
ByLine[I.Line] = Index;
if (!I.Resolved)
return;
ByFile[&I.Resolved->getFileEntry()].push_back(Index);
auto Path = normalizePath(I.Resolved->getName());
for (llvm::StringRef Parent = path::parent_path(Path); !Parent.empty();
Parent = path::parent_path(Parent)) {
if (!SearchPath.contains(Parent))
continue;
llvm::StringRef Rel =
llvm::StringRef(Path).drop_front(Parent.size()).ltrim('/');
BySpellingAlternate[Rel].push_back(Index);
}
}
const Include *Includes::atLine(unsigned OneBasedIndex) const {
auto It = ByLine.find(OneBasedIndex);
return (It == ByLine.end()) ? nullptr : &All[It->second];
}
llvm::SmallVector<const Include *> Includes::match(Header H) const {
llvm::SmallVector<const Include *> Result;
switch (H.kind()) {
case Header::Physical:
for (unsigned I : ByFile.lookup(H.physical()))
Result.push_back(&All[I]);
break;
case Header::Standard:
for (unsigned I : BySpelling.lookup(H.standard().name().trim("<>")))
Result.push_back(&All[I]);
break;
case Header::Verbatim: {
llvm::StringRef Spelling = H.verbatim().trim("\"<>");
for (unsigned I : BySpelling.lookup(Spelling))
Result.push_back(&All[I]);
for (unsigned I : BySpellingAlternate.lookup(Spelling))
if (!llvm::is_contained(Result, &All[I]))
Result.push_back(&All[I]);
break;
}
}
return Result;
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolLocation &S) {
switch (S.kind()) {
case SymbolLocation::Physical:
return OS << "@0x"
<< llvm::utohexstr(
S.physical().getRawEncoding(), false,
CHAR_BIT * sizeof(SourceLocation::UIntTy));
case SymbolLocation::Standard:
return OS << S.standard().scope() << S.standard().name();
}
llvm_unreachable("Unhandled Symbol kind");
}
bool Header::operator<(const Header &RHS) const {
if (kind() != RHS.kind())
return kind() < RHS.kind();
switch (kind()) {
case Header::Physical:
return physical().getName() < RHS.physical().getName();
case Header::Standard:
return standard().name() < RHS.standard().name();
case Header::Verbatim:
return verbatim() < RHS.verbatim();
}
llvm_unreachable("unhandled Header kind");
}
}