mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 23:51:56 +00:00
[clang-format] Add link to source code in file definitions
Two command line options have been added to clang-doc. --repository=<string> - URL of repository that hosts code; used for links to definition locations. --source-root=<string> - Directory where processed files are stored. Links to definition locations will only be generated if the file is in this dir. If the file is in the source-root and a repository options is passed; a link to the source code will be rendered by the HTML generator. Differential Revision: https://reviews.llvm.org/D65483 llvm-svn: 368460
This commit is contained in:
parent
2bf522aea6
commit
665e9676c2
@ -83,7 +83,7 @@ llvm::Error decodeRecord(Record R, llvm::Optional<Location> &Field,
|
||||
if (R[0] > INT_MAX)
|
||||
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
|
||||
llvm::inconvertibleErrorCode());
|
||||
Field.emplace((int)R[0], Blob);
|
||||
Field.emplace((int)R[0], Blob, (bool)R[1]);
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
|
||||
if (R[0] > INT_MAX)
|
||||
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
|
||||
llvm::inconvertibleErrorCode());
|
||||
Field.emplace_back((int)R[0], Blob);
|
||||
Field.emplace_back((int)R[0], Blob, (bool)R[1]);
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,13 @@ static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
|
||||
{// 0. Fixed-size integer (line number)
|
||||
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
|
||||
BitCodeConstants::LineNumberSize),
|
||||
// 1. Fixed-size integer (length of the following string (filename))
|
||||
// 1. Boolean (IsFileInRootDir)
|
||||
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
|
||||
BitCodeConstants::BoolSize),
|
||||
// 2. Fixed-size integer (length of the following string (filename))
|
||||
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
|
||||
BitCodeConstants::StringLengthSize),
|
||||
// 2. The string blob
|
||||
// 3. The string blob
|
||||
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
|
||||
}
|
||||
|
||||
@ -316,6 +319,7 @@ void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
|
||||
// FIXME: Assert that the line number is of the appropriate size.
|
||||
Record.push_back(Loc.LineNumber);
|
||||
assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
|
||||
Record.push_back(Loc.IsFileInRootDir);
|
||||
Record.push_back(Loc.Filename.size());
|
||||
Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
|
||||
}
|
||||
|
@ -301,12 +301,15 @@ genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
|
||||
return Out;
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
|
||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||
StringRef ParentInfoDir);
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
|
||||
StringRef ParentInfoDir);
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genEnumsBlock(const std::vector<EnumInfo> &Enums) {
|
||||
genEnumsBlock(const std::vector<EnumInfo> &Enums,
|
||||
const ClangDocContext &CDCtx) {
|
||||
if (Enums.empty())
|
||||
return {};
|
||||
|
||||
@ -316,7 +319,7 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums) {
|
||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
|
||||
auto &DivBody = Out.back();
|
||||
for (const auto &E : Enums) {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E);
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E, CDCtx);
|
||||
AppendVector(std::move(Nodes), DivBody->Children);
|
||||
}
|
||||
return Out;
|
||||
@ -335,7 +338,7 @@ genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) {
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
|
||||
StringRef ParentInfoDir) {
|
||||
const ClangDocContext &CDCtx, StringRef ParentInfoDir) {
|
||||
if (Functions.empty())
|
||||
return {};
|
||||
|
||||
@ -345,7 +348,8 @@ genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
|
||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
|
||||
auto &DivBody = Out.back();
|
||||
for (const auto &F : Functions) {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes =
|
||||
genHTML(F, CDCtx, ParentInfoDir);
|
||||
AppendVector(std::move(Nodes), DivBody->Children);
|
||||
}
|
||||
return Out;
|
||||
@ -392,10 +396,30 @@ genReferencesBlock(const std::vector<Reference> &References,
|
||||
return Out;
|
||||
}
|
||||
|
||||
static std::unique_ptr<TagNode> writeFileDefinition(const Location &L) {
|
||||
return llvm::make_unique<TagNode>(
|
||||
HTMLTag::TAG_P,
|
||||
"Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename);
|
||||
static std::unique_ptr<TagNode>
|
||||
writeFileDefinition(const Location &L,
|
||||
llvm::Optional<StringRef> RepositoryUrl = None) {
|
||||
if (!L.IsFileInRootDir || !RepositoryUrl)
|
||||
return llvm::make_unique<TagNode>(
|
||||
HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) +
|
||||
" of file " + L.Filename);
|
||||
SmallString<128> FileURL(RepositoryUrl.getValue());
|
||||
llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
|
||||
auto Node = llvm::make_unique<TagNode>(HTMLTag::TAG_P);
|
||||
Node->Children.emplace_back(llvm::make_unique<TextNode>("Defined at line "));
|
||||
auto LocNumberNode =
|
||||
llvm::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber));
|
||||
// The links to a specific line in the source code use the github /
|
||||
// googlesource notation so it won't work for all hosting pages.
|
||||
LocNumberNode->Attributes.try_emplace(
|
||||
"href", (FileURL + "#" + std::to_string(L.LineNumber)).str());
|
||||
Node->Children.emplace_back(std::move(LocNumberNode));
|
||||
Node->Children.emplace_back(llvm::make_unique<TextNode>(" of file "));
|
||||
auto LocFileNode = llvm::make_unique<TagNode>(
|
||||
HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
|
||||
LocFileNode->Attributes.try_emplace("href", FileURL);
|
||||
Node->Children.emplace_back(std::move(LocFileNode));
|
||||
return Node;
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
@ -491,7 +515,8 @@ static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
|
||||
return CommentBlock;
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
|
||||
std::vector<std::unique_ptr<TagNode>> Out;
|
||||
std::string EnumType;
|
||||
if (I.Scoped)
|
||||
@ -508,8 +533,13 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
|
||||
if (Node)
|
||||
Out.emplace_back(std::move(Node));
|
||||
|
||||
if (I.DefLoc)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
if (I.DefLoc) {
|
||||
if (!CDCtx.RepositoryUrl)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
else
|
||||
Out.emplace_back(writeFileDefinition(
|
||||
I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()}));
|
||||
}
|
||||
|
||||
std::string Description;
|
||||
if (!I.Description.empty())
|
||||
@ -518,8 +548,9 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
|
||||
return Out;
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||
StringRef ParentInfoDir) {
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
|
||||
StringRef ParentInfoDir) {
|
||||
std::vector<std::unique_ptr<TagNode>> Out;
|
||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
|
||||
// USR is used as id for functions instead of name to disambiguate function
|
||||
@ -552,8 +583,13 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||
}
|
||||
FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
|
||||
|
||||
if (I.DefLoc)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
if (I.DefLoc) {
|
||||
if (!CDCtx.RepositoryUrl)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
else
|
||||
Out.emplace_back(writeFileDefinition(
|
||||
I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()}));
|
||||
}
|
||||
|
||||
std::string Description;
|
||||
if (!I.Description.empty())
|
||||
@ -563,7 +599,8 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const NamespaceInfo &I, Index &InfoIndex, std::string &InfoTitle) {
|
||||
genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
|
||||
std::string &InfoTitle) {
|
||||
std::vector<std::unique_ptr<TagNode>> Out;
|
||||
if (I.Name.str() == "")
|
||||
InfoTitle = "Global Namespace";
|
||||
@ -584,10 +621,10 @@ genHTML(const NamespaceInfo &I, Index &InfoIndex, std::string &InfoTitle) {
|
||||
AppendVector(std::move(ChildRecords), Out);
|
||||
|
||||
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
||||
genFunctionsBlock(I.ChildFunctions, I.Path);
|
||||
genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
|
||||
AppendVector(std::move(ChildFunctions), Out);
|
||||
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
||||
genEnumsBlock(I.ChildEnums);
|
||||
genEnumsBlock(I.ChildEnums, CDCtx);
|
||||
AppendVector(std::move(ChildEnums), Out);
|
||||
|
||||
if (!I.ChildNamespaces.empty())
|
||||
@ -604,13 +641,19 @@ genHTML(const NamespaceInfo &I, Index &InfoIndex, std::string &InfoTitle) {
|
||||
}
|
||||
|
||||
static std::vector<std::unique_ptr<TagNode>>
|
||||
genHTML(const RecordInfo &I, Index &InfoIndex, std::string &InfoTitle) {
|
||||
genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
|
||||
std::string &InfoTitle) {
|
||||
std::vector<std::unique_ptr<TagNode>> Out;
|
||||
InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
|
||||
Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
|
||||
|
||||
if (I.DefLoc)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
if (I.DefLoc) {
|
||||
if (!CDCtx.RepositoryUrl)
|
||||
Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
|
||||
else
|
||||
Out.emplace_back(writeFileDefinition(
|
||||
I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()}));
|
||||
}
|
||||
|
||||
std::string Description;
|
||||
if (!I.Description.empty())
|
||||
@ -643,10 +686,10 @@ genHTML(const RecordInfo &I, Index &InfoIndex, std::string &InfoTitle) {
|
||||
AppendVector(std::move(ChildRecords), Out);
|
||||
|
||||
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
|
||||
genFunctionsBlock(I.ChildFunctions, I.Path);
|
||||
genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
|
||||
AppendVector(std::move(ChildFunctions), Out);
|
||||
std::vector<std::unique_ptr<TagNode>> ChildEnums =
|
||||
genEnumsBlock(I.ChildEnums);
|
||||
genEnumsBlock(I.ChildEnums, CDCtx);
|
||||
AppendVector(std::move(ChildEnums), Out);
|
||||
|
||||
if (!I.Members.empty())
|
||||
@ -682,26 +725,27 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
|
||||
Index InfoIndex;
|
||||
switch (I->IT) {
|
||||
case InfoType::IT_namespace: {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(
|
||||
*static_cast<clang::doc::NamespaceInfo *>(I), InfoIndex, InfoTitle);
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes =
|
||||
genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoIndex, CDCtx,
|
||||
InfoTitle);
|
||||
AppendVector(std::move(Nodes), MainContentNode->Children);
|
||||
break;
|
||||
}
|
||||
case InfoType::IT_record: {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(
|
||||
*static_cast<clang::doc::RecordInfo *>(I), InfoIndex, InfoTitle);
|
||||
*static_cast<clang::doc::RecordInfo *>(I), InfoIndex, CDCtx, InfoTitle);
|
||||
AppendVector(std::move(Nodes), MainContentNode->Children);
|
||||
break;
|
||||
}
|
||||
case InfoType::IT_enum: {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes =
|
||||
genHTML(*static_cast<clang::doc::EnumInfo *>(I));
|
||||
genHTML(*static_cast<clang::doc::EnumInfo *>(I), CDCtx);
|
||||
AppendVector(std::move(Nodes), MainContentNode->Children);
|
||||
break;
|
||||
}
|
||||
case InfoType::IT_function: {
|
||||
std::vector<std::unique_ptr<TagNode>> Nodes =
|
||||
genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");
|
||||
genHTML(*static_cast<clang::doc::FunctionInfo *>(I), CDCtx, "");
|
||||
AppendVector(std::move(Nodes), MainContentNode->Children);
|
||||
break;
|
||||
}
|
||||
|
@ -36,10 +36,12 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
|
||||
// If there is an error generating a USR for the decl, skip this decl.
|
||||
if (index::generateUSRForDecl(D, USR))
|
||||
return true;
|
||||
|
||||
auto I = serialize::emitInfo(
|
||||
D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()),
|
||||
getFile(D, D->getASTContext()), CDCtx.PublicOnly);
|
||||
bool IsFileInRootDir;
|
||||
llvm::SmallString<128> File =
|
||||
getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
|
||||
auto I = serialize::emitInfo(D, getComment(D, D->getASTContext()),
|
||||
getLine(D, D->getASTContext()), File,
|
||||
IsFileInRootDir, CDCtx.PublicOnly);
|
||||
|
||||
// A null in place of I indicates that the serializer is skipping this decl
|
||||
// for some reason (e.g. we're only reporting public decls).
|
||||
@ -87,11 +89,26 @@ int MapASTVisitor::getLine(const NamedDecl *D,
|
||||
return Context.getSourceManager().getPresumedLoc(D->getBeginLoc()).getLine();
|
||||
}
|
||||
|
||||
llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D,
|
||||
const ASTContext &Context) const {
|
||||
return Context.getSourceManager()
|
||||
.getPresumedLoc(D->getBeginLoc())
|
||||
.getFilename();
|
||||
llvm::SmallString<128> MapASTVisitor::getFile(const NamedDecl *D,
|
||||
const ASTContext &Context,
|
||||
llvm::StringRef RootDir,
|
||||
bool &IsFileInRootDir) const {
|
||||
llvm::SmallString<128> File(Context.getSourceManager()
|
||||
.getPresumedLoc(D->getBeginLoc())
|
||||
.getFilename());
|
||||
IsFileInRootDir = false;
|
||||
if (RootDir.empty() || !File.startswith(RootDir))
|
||||
return File;
|
||||
IsFileInRootDir = true;
|
||||
llvm::SmallString<128> Prefix(RootDir);
|
||||
// replace_path_prefix removes the exact prefix provided. The result of
|
||||
// calling that function on ("A/B/C.c", "A/B", "") would be "/C.c", which
|
||||
// starts with a / that is not needed. This is why we fix Prefix so it always
|
||||
// ends with a / and the result has the desired format.
|
||||
if (!llvm::sys::path::is_separator(Prefix.back()))
|
||||
Prefix += llvm::sys::path::get_separator();
|
||||
llvm::sys::path::replace_path_prefix(File, Prefix, "");
|
||||
return File;
|
||||
}
|
||||
|
||||
} // namespace doc
|
||||
|
@ -44,7 +44,9 @@ private:
|
||||
template <typename T> bool mapDecl(const T *D);
|
||||
|
||||
int getLine(const NamedDecl *D, const ASTContext &Context) const;
|
||||
StringRef getFile(const NamedDecl *D, const ASTContext &Context) const;
|
||||
llvm::SmallString<128> getFile(const NamedDecl *D, const ASTContext &Context,
|
||||
StringRef RootDir,
|
||||
bool &IsFileInRootDir) const;
|
||||
comments::FullComment *getComment(const NamedDecl *D,
|
||||
const ASTContext &Context) const;
|
||||
|
||||
|
@ -235,5 +235,21 @@ void Index::sort() {
|
||||
C.sort();
|
||||
}
|
||||
|
||||
ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
|
||||
bool PublicOnly, StringRef OutDirectory,
|
||||
StringRef SourceRoot, StringRef RepositoryUrl,
|
||||
std::vector<std::string> UserStylesheets,
|
||||
std::vector<std::string> JsScripts)
|
||||
: ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory),
|
||||
SourceRoot(SourceRoot), UserStylesheets(UserStylesheets),
|
||||
JsScripts(JsScripts) {
|
||||
if (!RepositoryUrl.empty()) {
|
||||
this->RepositoryUrl = RepositoryUrl;
|
||||
if (!RepositoryUrl.empty() && RepositoryUrl.find("http://") != 0 &&
|
||||
RepositoryUrl.find("https://") != 0)
|
||||
this->RepositoryUrl->insert(0, "https://");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace doc
|
||||
} // namespace clang
|
||||
|
@ -205,6 +205,9 @@ struct Location {
|
||||
Location() = default;
|
||||
Location(int LineNumber, SmallString<16> Filename)
|
||||
: LineNumber(LineNumber), Filename(std::move(Filename)) {}
|
||||
Location(int LineNumber, SmallString<16> Filename, bool IsFileInRootDir)
|
||||
: LineNumber(LineNumber), Filename(std::move(Filename)),
|
||||
IsFileInRootDir(IsFileInRootDir) {}
|
||||
|
||||
bool operator==(const Location &Other) const {
|
||||
return std::tie(LineNumber, Filename) ==
|
||||
@ -220,8 +223,9 @@ struct Location {
|
||||
std::tie(Other.LineNumber, Other.Filename);
|
||||
}
|
||||
|
||||
int LineNumber; // Line number of this Location.
|
||||
SmallString<32> Filename; // File for this Location.
|
||||
int LineNumber; // Line number of this Location.
|
||||
SmallString<32> Filename; // File for this Location.
|
||||
bool IsFileInRootDir = false; // Indicates if file is inside root directory
|
||||
};
|
||||
|
||||
/// A base struct for Infos.
|
||||
@ -375,14 +379,18 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
|
||||
struct ClangDocContext {
|
||||
ClangDocContext() = default;
|
||||
ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly,
|
||||
StringRef OutDirectory,
|
||||
StringRef OutDirectory, StringRef SourceRoot,
|
||||
StringRef RepositoryUrl,
|
||||
std::vector<std::string> UserStylesheets,
|
||||
std::vector<std::string> JsScripts)
|
||||
: ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory),
|
||||
UserStylesheets(UserStylesheets), JsScripts(JsScripts) {}
|
||||
std::vector<std::string> JsScripts);
|
||||
tooling::ExecutionContext *ECtx;
|
||||
bool PublicOnly;
|
||||
std::string OutDirectory;
|
||||
bool PublicOnly; // Indicates if only public declarations are documented.
|
||||
std::string OutDirectory; // Directory for outputting generated files.
|
||||
std::string SourceRoot; // Directory where processed files are stored. Links
|
||||
// to definition locations will only be generated if
|
||||
// the file is in this dir.
|
||||
// URL of repository that hosts code used for links to definition locations.
|
||||
llvm::Optional<std::string> RepositoryUrl;
|
||||
// Path of CSS stylesheets that will be copied to OutDirectory and used to
|
||||
// style all HTML files.
|
||||
std::vector<std::string> UserStylesheets;
|
||||
|
@ -348,19 +348,21 @@ 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,
|
||||
bool IsFileInRootDir,
|
||||
bool &IsInAnonymousNamespace) {
|
||||
populateInfo(I, D, C, IsInAnonymousNamespace);
|
||||
if (D->isThisDeclarationADefinition())
|
||||
I.DefLoc.emplace(LineNumber, Filename);
|
||||
I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
|
||||
else
|
||||
I.Loc.emplace_back(LineNumber, Filename);
|
||||
I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
|
||||
}
|
||||
|
||||
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
|
||||
const FullComment *FC, int LineNumber,
|
||||
StringRef Filename,
|
||||
StringRef Filename, bool IsFileInRootDir,
|
||||
bool &IsInAnonymousNamespace) {
|
||||
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
|
||||
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
|
||||
IsInAnonymousNamespace);
|
||||
if (const auto *T = getDeclForType(D->getReturnType())) {
|
||||
if (dyn_cast<EnumDecl>(T))
|
||||
I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
|
||||
@ -376,7 +378,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
|
||||
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
|
||||
llvm::StringRef File, bool PublicOnly) {
|
||||
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
|
||||
auto I = llvm::make_unique<NamespaceInfo>();
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateInfo(*I, D, FC, IsInAnonymousNamespace);
|
||||
@ -402,10 +404,11 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
|
||||
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
|
||||
llvm::StringRef File, bool PublicOnly) {
|
||||
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
|
||||
auto I = llvm::make_unique<RecordInfo>();
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateSymbolInfo(*I, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir,
|
||||
IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return {};
|
||||
@ -452,10 +455,11 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
|
||||
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
|
||||
llvm::StringRef File, bool PublicOnly) {
|
||||
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
|
||||
FunctionInfo Func;
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
|
||||
IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return {};
|
||||
@ -477,10 +481,11 @@ emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
|
||||
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
|
||||
llvm::StringRef File, bool PublicOnly) {
|
||||
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
|
||||
FunctionInfo Func;
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
|
||||
IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return {};
|
||||
@ -511,10 +516,11 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
|
||||
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
|
||||
llvm::StringRef File, bool PublicOnly) {
|
||||
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
|
||||
EnumInfo Enum;
|
||||
bool IsInAnonymousNamespace = false;
|
||||
populateSymbolInfo(Enum, D, FC, LineNumber, File, IsInAnonymousNamespace);
|
||||
populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
|
||||
IsInAnonymousNamespace);
|
||||
if (PublicOnly && ((IsInAnonymousNamespace ||
|
||||
!isPublic(D->getAccess(), D->getLinkageInternal()))))
|
||||
return {};
|
||||
|
@ -38,19 +38,19 @@ namespace serialize {
|
||||
// nullptr.
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
|
||||
StringRef File, bool PublicOnly);
|
||||
StringRef File, bool IsFileInRootDir, bool PublicOnly);
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
|
||||
StringRef File, bool PublicOnly);
|
||||
StringRef File, bool IsFileInRootDir, bool PublicOnly);
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
|
||||
StringRef File, bool PublicOnly);
|
||||
StringRef File, bool IsFileInRootDir, bool PublicOnly);
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
|
||||
StringRef File, bool PublicOnly);
|
||||
StringRef File, bool IsFileInRootDir, bool PublicOnly);
|
||||
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
|
||||
emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
|
||||
StringRef File, bool PublicOnly);
|
||||
StringRef File, bool IsFileInRootDir, bool PublicOnly);
|
||||
|
||||
// Function to hash a given USR value for storage.
|
||||
// As USRs (Unified Symbol Resolution) could be large, especially for functions
|
||||
|
@ -76,6 +76,18 @@ static llvm::cl::list<std::string> UserStylesheets(
|
||||
llvm::cl::desc("CSS stylesheets to extend the default styles."),
|
||||
llvm::cl::cat(ClangDocCategory));
|
||||
|
||||
static llvm::cl::opt<std::string> SourceRoot("source-root", llvm::cl::desc(R"(
|
||||
Directory where processed files are stored.
|
||||
Links to definition locations will only be
|
||||
generated if the file is in this dir.)"),
|
||||
llvm::cl::cat(ClangDocCategory));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
RepositoryUrl("repository", llvm::cl::desc(R"(
|
||||
URL of repository that hosts code.
|
||||
Used for links to definition locations.)"),
|
||||
llvm::cl::cat(ClangDocCategory));
|
||||
|
||||
enum OutputFormatTy {
|
||||
md,
|
||||
yaml,
|
||||
@ -142,7 +154,7 @@ bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
|
||||
// <root>/A/B/C.<ext>
|
||||
//
|
||||
// namespace A {
|
||||
// namesapce B {
|
||||
// namespace B {
|
||||
//
|
||||
// class C {};
|
||||
//
|
||||
@ -191,10 +203,18 @@ int main(int argc, const char **argv) {
|
||||
tooling::ArgumentInsertPosition::END),
|
||||
ArgAdjuster);
|
||||
|
||||
llvm::SmallString<128> SourceRootDir;
|
||||
// Check if the --source-root flag has a value
|
||||
if (SourceRoot.empty())
|
||||
// If it's empty the current path is used as the default
|
||||
llvm::sys::fs::current_path(SourceRootDir);
|
||||
|
||||
clang::doc::ClangDocContext CDCtx = {
|
||||
Exec->get()->getExecutionContext(),
|
||||
PublicOnly,
|
||||
OutDirectory,
|
||||
SourceRootDir.str(),
|
||||
RepositoryUrl,
|
||||
{UserStylesheets.begin(), UserStylesheets.end()},
|
||||
{"index.js", "index_json.js"}};
|
||||
|
||||
|
@ -66,7 +66,7 @@ Options
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ clang-doc --help
|
||||
$ clang-doc --help
|
||||
USAGE: clang-doc [options] <source0> [... <sourceN>]
|
||||
|
||||
OPTIONS:
|
||||
@ -79,17 +79,27 @@ Options
|
||||
|
||||
clang-doc options:
|
||||
|
||||
-doxygen - Use only doxygen-style comments to generate docs.
|
||||
-dump - Dump intermediate results to bitcode file.
|
||||
-extra-arg=<string> - Additional argument to append to the compiler command line
|
||||
-extra-arg-before=<string> - Additional argument to prepend to the compiler command line
|
||||
--format=<value> - Format for outputted docs.
|
||||
=yaml - Documentation in YAML format.
|
||||
=md - Documentation in MD format.
|
||||
=html - Documentation in HTML format.
|
||||
-output=<string> - Directory for outputting generated files.
|
||||
-p=<string> - Build path
|
||||
--public - Document only public declarations.
|
||||
--stylesheets=<string> - CSS stylesheets to extend the default styles.
|
||||
--doxygen - Use only doxygen-style comments to generate docs.
|
||||
--extra-arg=<string> - Additional argument to append to the compiler command line
|
||||
--extra-arg-before=<string> - Additional argument to prepend to the compiler command line
|
||||
--format=<value> - Format for outputted docs.
|
||||
=yaml - Documentation in YAML format.
|
||||
=md - Documentation in MD format.
|
||||
=html - Documentation in HTML format.
|
||||
--ignore-map-errors - Continue if files are not mapped correctly.
|
||||
--output=<string> - Directory for outputting generated files.
|
||||
-p=<string> - Build path
|
||||
--public - Document only public declarations.
|
||||
--repository=<string> -
|
||||
URL of repository that hosts code.
|
||||
Used for links to definition locations.
|
||||
--source-root=<string> -
|
||||
Directory where processed files are stored.
|
||||
Links to definition locations will only be
|
||||
generated if the file is in this dir.
|
||||
--stylesheets=<string> - CSS stylesheets to extend the default styles.
|
||||
|
||||
``stylesheets`` should only be used if ``format`` is set to ``html``.
|
||||
The following flags shoud only be used if ``format`` is set to ``html``:
|
||||
- ``repository``
|
||||
- ``source-root``
|
||||
- ``stylesheets``
|
||||
|
@ -23,9 +23,9 @@ std::unique_ptr<Generator> getHTMLGenerator() {
|
||||
}
|
||||
|
||||
ClangDocContext
|
||||
getClangDocContext(std::vector<std::string> UserStylesheets = {}) {
|
||||
ClangDocContext CDCtx;
|
||||
CDCtx.UserStylesheets = {UserStylesheets.begin(), UserStylesheets.end()};
|
||||
getClangDocContext(std::vector<std::string> UserStylesheets = {},
|
||||
StringRef RepositoryUrl = "") {
|
||||
ClangDocContext CDCtx{{}, {}, {}, {}, RepositoryUrl, UserStylesheets, {}};
|
||||
CDCtx.UserStylesheets.insert(
|
||||
CDCtx.UserStylesheets.begin(),
|
||||
"../share/clang/clang-doc-default-stylesheet.css");
|
||||
@ -127,7 +127,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||
I.Path = "X/Y/Z";
|
||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, true);
|
||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||
|
||||
SmallString<16> PathTo;
|
||||
@ -147,7 +147,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||
assert(G);
|
||||
std::string Buffer;
|
||||
llvm::raw_string_ostream Actual(Buffer);
|
||||
ClangDocContext CDCtx = getClangDocContext();
|
||||
ClangDocContext CDCtx = getClangDocContext({}, "http://www.repository.com");
|
||||
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
||||
assert(!Err);
|
||||
std::string Expected = R"raw(<!DOCTYPE html>
|
||||
@ -194,7 +194,12 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||
</ul>
|
||||
<div>
|
||||
<h1>class r</h1>
|
||||
<p>Defined at line 10 of test.cpp</p>
|
||||
<p>
|
||||
Defined at line
|
||||
<a href="http://www.repository.com/dir/test.cpp#10">10</a>
|
||||
of file
|
||||
<a href="http://www.repository.com/dir/test.cpp">test.cpp</a>
|
||||
</p>
|
||||
<p>
|
||||
Inherits from
|
||||
<a href="../../../path/to/F.html">F</a>
|
||||
@ -232,7 +237,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||
I.Name = "f";
|
||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, false);
|
||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||
|
||||
SmallString<16> PathTo;
|
||||
@ -246,7 +251,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||
assert(G);
|
||||
std::string Buffer;
|
||||
llvm::raw_string_ostream Actual(Buffer);
|
||||
ClangDocContext CDCtx = getClangDocContext();
|
||||
ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com");
|
||||
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
||||
assert(!Err);
|
||||
std::string Expected = R"raw(<!DOCTYPE html>
|
||||
@ -263,7 +268,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||
<a href="path/to/int.html">int</a>
|
||||
P)
|
||||
</p>
|
||||
<p>Defined at line 10 of test.cpp</p>
|
||||
<p>Defined at line 10 of file dir/test.cpp</p>
|
||||
</div>
|
||||
)raw";
|
||||
|
||||
@ -275,7 +280,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
|
||||
I.Name = "e";
|
||||
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
||||
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
||||
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}, true);
|
||||
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
||||
|
||||
I.Members.emplace_back("X");
|
||||
@ -285,7 +290,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
|
||||
assert(G);
|
||||
std::string Buffer;
|
||||
llvm::raw_string_ostream Actual(Buffer);
|
||||
ClangDocContext CDCtx = getClangDocContext();
|
||||
ClangDocContext CDCtx = getClangDocContext({}, "www.repository.com");
|
||||
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
||||
assert(!Err);
|
||||
std::string Expected = R"raw(<!DOCTYPE html>
|
||||
@ -299,7 +304,12 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
|
||||
<ul>
|
||||
<li>X</li>
|
||||
</ul>
|
||||
<p>Defined at line 10 of test.cpp</p>
|
||||
<p>
|
||||
Defined at line
|
||||
<a href="https://www.repository.com/test.cpp#10">10</a>
|
||||
of file
|
||||
<a href="https://www.repository.com/test.cpp">test.cpp</a>
|
||||
</p>
|
||||
</div>
|
||||
)raw";
|
||||
|
||||
@ -368,7 +378,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML) {
|
||||
<div>
|
||||
<h3 id="0000000000000000000000000000000000000000">f</h3>
|
||||
<p>void f(int I, int J)</p>
|
||||
<p>Defined at line 10 of test.cpp</p>
|
||||
<p>Defined at line 10 of file test.cpp</p>
|
||||
<div>
|
||||
<div>
|
||||
<p> Brief description.</p>
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
|
||||
template <typename T> bool mapDecl(const T *D) {
|
||||
auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
|
||||
/*File=*/"test.cpp", Public);
|
||||
/*File=*/"test.cpp", true, Public);
|
||||
if (I.first)
|
||||
EmittedInfos.emplace_back(std::move(I.first));
|
||||
if (I.second)
|
||||
|
Loading…
Reference in New Issue
Block a user