Index: clang-tools-extra/trunk/clang-doc/Representation.h =================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.h +++ clang-tools-extra/trunk/clang-doc/Representation.h @@ -223,6 +223,8 @@ 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 getEnclosingScope(); Index: clang-tools-extra/trunk/clang-doc/Representation.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.cpp +++ clang-tools-extra/trunk/clang-doc/Representation.cpp @@ -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 @@ 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 Index: clang-tools-extra/trunk/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/Serialize.cpp +++ clang-tools-extra/trunk/clang-doc/Serialize.cpp @@ -270,13 +270,19 @@ template static void populateParentNamespaces(llvm::SmallVector &Namespaces, - const T *D) { + const T *D, bool &IsAnonymousNamespace) { const auto *DC = dyn_cast(D); while ((DC = DC->getParent())) { - if (const auto *N = dyn_cast(DC)) - Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), + if (const auto *N = dyn_cast(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(DC)) + } else if (const auto *N = dyn_cast(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_record); else if (const auto *N = dyn_cast(DC)) @@ -289,10 +295,11 @@ } template -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 @@ template 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 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(T)) I.ReturnType = @@ -329,21 +338,28 @@ std::unique_ptr emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool PublicOnly) { - if (PublicOnly && ((D->isAnonymousNamespace()) || + auto I = llvm::make_unique(); + 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(); - populateInfo(*I, D, FC); + I->Name = D->isAnonymousNamespace() + ? llvm::SmallString<16>("@nonymous_namespace") + : I->Name; return std::unique_ptr{std::move(I)}; } std::unique_ptr 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(); - 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(D)) { @@ -359,10 +375,13 @@ std::unique_ptr 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 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 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); Index: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp @@ -132,9 +132,6 @@ if (CreateDirectory(Path)) return llvm::make_error("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 @@ 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; Index: clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp @@ -131,6 +131,7 @@ NamespaceInfo *A = InfoAsNamespace(Infos[0].get()); NamespaceInfo ExpectedA(EmptySID); + ExpectedA.Name = "@nonymous_namespace"; CheckNamespaceInfo(&ExpectedA, A); }