mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-09 01:29:52 +00:00
[clang-doc] Handle anonymous namespaces
Improves output for anonymous decls, and updates the '--public' flag to exclude everything under an anonymous namespace. Differential Revision: https://reviews.llvm.org/D52847 llvm-svn: 364674
This commit is contained in:
parent
70a8027c60
commit
d900ef0a5b
@ -21,6 +21,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "Representation.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
namespace clang {
|
||||
namespace doc {
|
||||
@ -194,5 +195,37 @@ void FunctionInfo::merge(FunctionInfo &&Other) {
|
||||
SymbolInfo::merge(std::move(Other));
|
||||
}
|
||||
|
||||
llvm::SmallString<16> Info::extractName() {
|
||||
if (!Name.empty())
|
||||
return Name;
|
||||
|
||||
switch (IT) {
|
||||
case InfoType::IT_namespace:
|
||||
// Cover the case where the project contains a base namespace called
|
||||
// 'GlobalNamespace' (i.e. a namespace at the same level as the global
|
||||
// namespace, which would conflict with the hard-coded global namespace name
|
||||
// below.)
|
||||
if (Name == "GlobalNamespace" && Namespace.empty())
|
||||
return llvm::SmallString<16>("@GlobalNamespace");
|
||||
// The case of anonymous namespaces is taken care of in serialization,
|
||||
// so here we can safely assume an unnamed namespace is the global
|
||||
// one.
|
||||
return llvm::SmallString<16>("GlobalNamespace");
|
||||
case InfoType::IT_record:
|
||||
return llvm::SmallString<16>("@nonymous_record_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_enum:
|
||||
return llvm::SmallString<16>("@nonymous_enum_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_function:
|
||||
return llvm::SmallString<16>("@nonymous_function_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_default:
|
||||
return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
|
||||
}
|
||||
llvm_unreachable("Invalid InfoType.");
|
||||
return llvm::SmallString<16>("");
|
||||
}
|
||||
|
||||
} // namespace doc
|
||||
} // namespace clang
|
||||
|
@ -223,6 +223,8 @@ struct Info {
|
||||
void mergeBase(Info &&I);
|
||||
bool mergeable(const Info &Other);
|
||||
|
||||
llvm::SmallString<16> extractName();
|
||||
|
||||
// Returns a reference to the parent scope (that is, the immediate parent
|
||||
// namespace or class in which this decl resides).
|
||||
llvm::Expected<Reference> getEnclosingScope();
|
||||
|
@ -270,13 +270,19 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
|
||||
template <typename T>
|
||||
static void
|
||||
populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
|
||||
const T *D) {
|
||||
const T *D, bool &IsAnonymousNamespace) {
|
||||
const auto *DC = dyn_cast<DeclContext>(D);
|
||||
while ((DC = DC->getParent())) {
|
||||
if (const auto *N = dyn_cast<NamespaceDecl>(DC))
|
||||
Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
||||
if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
|
||||
std::string Namespace;
|
||||
if (N->isAnonymousNamespace()) {
|
||||
Namespace = "@nonymous_namespace";
|
||||
IsAnonymousNamespace = true;
|
||||
} else
|
||||
Namespace = N->getNameAsString();
|
||||
Namespaces.emplace_back(getUSRForDecl(N), Namespace,
|
||||
InfoType::IT_namespace);
|
||||
else if (const auto *N = dyn_cast<RecordDecl>(DC))
|
||||
} else if (const auto *N = dyn_cast<RecordDecl>(DC))
|
||||
Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
|
||||
InfoType::IT_record);
|
||||
else if (const auto *N = dyn_cast<FunctionDecl>(DC))
|
||||
@ -289,10 +295,11 @@ populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void populateInfo(Info &I, const T *D, const FullComment *C) {
|
||||
static void populateInfo(Info &I, const T *D, const FullComment *C,
|
||||
bool &IsInAnonymousNamespace) {
|
||||
I.USR = getUSRForDecl(D);
|
||||
I.Name = D->getNameAsString();
|
||||
populateParentNamespaces(I.Namespace, D);
|
||||
populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
|
||||
if (C) {
|
||||
I.Description.emplace_back();
|
||||
parseFullComment(C, I.Description.back());
|
||||
@ -301,8 +308,9 @@ static void populateInfo(Info &I, const T *D, const FullComment *C) {
|
||||
|
||||
template <typename T>
|
||||
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
|
||||
int LineNumber, StringRef Filename) {
|
||||
populateInfo(I, D, C);
|
||||
int LineNumber, StringRef Filename,
|
||||
bool &IsInAnonymousNamespace) {
|
||||
populateInfo(I, D, C, IsInAnonymousNamespace);
|
||||
if (D->isThisDeclarationADefinition())
|
||||
I.DefLoc.emplace(LineNumber, Filename);
|
||||
else
|
||||
@ -311,8 +319,9 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
|
||||
|
||||
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
|
||||
const FullComment *FC, int LineNumber,
|
||||
StringRef Filename) {
|
||||
populateSymbolInfo(I, D, FC, LineNumber, Filename);
|
||||
StringRef Filename,
|
||||
bool &IsInAnonymousNamespace) {
|
||||
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
|
||||
if (const auto *T = getDeclForType(D->getReturnType())) {
|
||||
if (dyn_cast<EnumDecl>(T))
|
||||
I.ReturnType =
|
||||
@ -329,21 +338,28 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
|
||||
std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
|
||||
int LineNumber, llvm::StringRef File,
|
||||
bool PublicOnly) {
|
||||
if (PublicOnly && ((D->isAnonymousNamespace()) ||
|
||||
auto I = llvm::make_unique<NamespaceInfo>();
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateInfo(*I, D, FC, IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal())))
|
||||
return nullptr;
|
||||
auto I = llvm::make_unique<NamespaceInfo>();
|
||||
populateInfo(*I, D, FC);
|
||||
I->Name = D->isAnonymousNamespace()
|
||||
? llvm::SmallString<16>("@nonymous_namespace")
|
||||
: I->Name;
|
||||
return std::unique_ptr<Info>{std::move(I)};
|
||||
}
|
||||
|
||||
std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
|
||||
int LineNumber, llvm::StringRef File,
|
||||
bool PublicOnly) {
|
||||
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
|
||||
return nullptr;
|
||||
auto I = llvm::make_unique<RecordInfo>();
|
||||
populateSymbolInfo(*I, D, FC, LineNumber, File);
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateSymbolInfo(*I, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return nullptr;
|
||||
|
||||
I->TagType = D->getTagKind();
|
||||
parseFields(*I, D, PublicOnly);
|
||||
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
|
||||
@ -359,10 +375,13 @@ std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
|
||||
std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
|
||||
int LineNumber, llvm::StringRef File,
|
||||
bool PublicOnly) {
|
||||
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
|
||||
return nullptr;
|
||||
FunctionInfo Func;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File);
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return nullptr;
|
||||
|
||||
Func.Access = clang::AccessSpecifier::AS_none;
|
||||
|
||||
// Wrap in enclosing scope
|
||||
@ -378,10 +397,13 @@ std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
|
||||
std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
|
||||
int LineNumber, llvm::StringRef File,
|
||||
bool PublicOnly) {
|
||||
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
|
||||
return nullptr;
|
||||
FunctionInfo Func;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File);
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return nullptr;
|
||||
|
||||
Func.IsMethod = true;
|
||||
|
||||
const NamedDecl *Parent = nullptr;
|
||||
@ -406,10 +428,13 @@ std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
|
||||
std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
|
||||
int LineNumber, llvm::StringRef File,
|
||||
bool PublicOnly) {
|
||||
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
|
||||
return nullptr;
|
||||
EnumInfo Enum;
|
||||
populateSymbolInfo(Enum, D, FC, LineNumber, File);
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateSymbolInfo(Enum, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return nullptr;
|
||||
|
||||
Enum.Scoped = D->isScoped();
|
||||
parseEnumerators(Enum, D);
|
||||
|
||||
|
@ -132,9 +132,6 @@ getInfoOutputFile(StringRef Root,
|
||||
if (CreateDirectory(Path))
|
||||
return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
|
||||
llvm::inconvertibleErrorCode());
|
||||
|
||||
if (Name.empty())
|
||||
Name = "GlobalNamespace";
|
||||
llvm::sys::path::append(Path, Name + Ext);
|
||||
return Path;
|
||||
}
|
||||
@ -222,8 +219,8 @@ int main(int argc, const char **argv) {
|
||||
|
||||
doc::Info *I = Reduced.get().get();
|
||||
|
||||
auto InfoPath =
|
||||
getInfoOutputFile(OutDirectory, I->Namespace, I->Name, "." + Format);
|
||||
auto InfoPath = getInfoOutputFile(OutDirectory, I->Namespace,
|
||||
I->extractName(), "." + Format);
|
||||
if (!InfoPath) {
|
||||
llvm::errs() << toString(InfoPath.takeError()) << "\n";
|
||||
continue;
|
||||
|
@ -131,6 +131,7 @@ TEST(SerializeTest, emitAnonymousNamespaceInfo) {
|
||||
|
||||
NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
|
||||
NamespaceInfo ExpectedA(EmptySID);
|
||||
ExpectedA.Name = "@nonymous_namespace";
|
||||
CheckNamespaceInfo(&ExpectedA, A);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user