Skip to content

Commit 2d9fbe6

Browse files
PeterChou1ilovepi
authored andcommitted
[clang-doc] Add start and end line numbers
This patch adds start and end line numbers to clang-doc. Currently clang-doc only encodes the start line numbers of records, struct, etc. This patch adds start and end line number to clang-doc bitcode which is passed to the generator. This will be used by the mustache backend to generate line ranges. Co-author: Paul Kirth <[email protected]>
1 parent dfdc50b commit 2d9fbe6

17 files changed

+189
-173
lines changed

clang-tools-extra/clang-doc/BitcodeReader.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ static llvm::Error decodeRecord(const Record &R, std::optional<Location> &Field,
7979
if (R[0] > INT_MAX)
8080
return llvm::createStringError(llvm::inconvertibleErrorCode(),
8181
"integer too large to parse");
82-
Field.emplace(static_cast<int>(R[0]), Blob, static_cast<bool>(R[1]));
82+
Field.emplace(static_cast<int>(R[0]), static_cast<int>(R[1]), Blob,
83+
static_cast<bool>(R[2]));
8384
return llvm::Error::success();
8485
}
8586

@@ -130,7 +131,8 @@ static llvm::Error decodeRecord(const Record &R,
130131
if (R[0] > INT_MAX)
131132
return llvm::createStringError(llvm::inconvertibleErrorCode(),
132133
"integer too large to parse");
133-
Field.emplace_back(static_cast<int>(R[0]), Blob, static_cast<bool>(R[1]));
134+
Field.emplace_back(static_cast<int>(R[0]), static_cast<int>(R[1]), Blob,
135+
static_cast<bool>(R[2]));
134136
return llvm::Error::success();
135137
}
136138

clang-tools-extra/clang-doc/BitcodeWriter.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,16 @@ static void genLocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
7878
{// 0. Fixed-size integer (line number)
7979
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
8080
BitCodeConstants::LineNumberSize),
81-
// 1. Boolean (IsFileInRootDir)
81+
// 1. Fixed-size integer (start line number)
82+
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
83+
BitCodeConstants::LineNumberSize),
84+
// 2. Boolean (IsFileInRootDir)
8285
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
8386
BitCodeConstants::BoolSize),
84-
// 2. Fixed-size integer (length of the following string (filename))
87+
// 3. Fixed-size integer (length of the following string (filename))
8588
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
8689
BitCodeConstants::StringLengthSize),
87-
// 3. The string blob
90+
// 4. The string blob
8891
llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
8992
}
9093

@@ -357,7 +360,8 @@ void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
357360
if (!prepRecordData(ID, true))
358361
return;
359362
// FIXME: Assert that the line number is of the appropriate size.
360-
Record.push_back(Loc.LineNumber);
363+
Record.push_back(Loc.StartLineNumber);
364+
Record.push_back(Loc.EndLineNumber);
361365
assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
362366
Record.push_back(Loc.IsFileInRootDir);
363367
Record.push_back(Loc.Filename.size());

clang-tools-extra/clang-doc/HTMLGenerator.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ static std::unique_ptr<TagNode> writeSourceFileRef(const ClangDocContext &CDCtx,
455455

456456
if (!L.IsFileInRootDir && !CDCtx.RepositoryUrl)
457457
return std::make_unique<TagNode>(
458-
HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) +
458+
HTMLTag::TAG_P, "Defined at line " + std::to_string(L.StartLineNumber) +
459459
" of file " + L.Filename);
460460

461461
SmallString<128> FileURL(CDCtx.RepositoryUrl.value_or(""));
@@ -472,13 +472,14 @@ static std::unique_ptr<TagNode> writeSourceFileRef(const ClangDocContext &CDCtx,
472472
llvm::sys::path::Style::windows));
473473
auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
474474
Node->Children.emplace_back(std::make_unique<TextNode>("Defined at line "));
475-
auto LocNumberNode =
476-
std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber));
475+
auto LocNumberNode = std::make_unique<TagNode>(
476+
HTMLTag::TAG_A, std::to_string(L.StartLineNumber));
477477
// The links to a specific line in the source code use the github /
478478
// googlesource notation so it won't work for all hosting pages.
479479
LocNumberNode->Attributes.emplace_back(
480-
"href", formatv("{0}#{1}{2}", FileURL,
481-
CDCtx.RepositoryLinePrefix.value_or(""), L.LineNumber));
480+
"href",
481+
formatv("{0}#{1}{2}", FileURL, CDCtx.RepositoryLinePrefix.value_or(""),
482+
L.StartLineNumber));
482483
Node->Children.emplace_back(std::move(LocNumberNode));
483484
Node->Children.emplace_back(std::make_unique<TextNode>(" of file "));
484485
auto LocFileNode = std::make_unique<TagNode>(

clang-tools-extra/clang-doc/MDGenerator.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ static void writeSourceFileRef(const ClangDocContext &CDCtx, const Location &L,
5656
raw_ostream &OS) {
5757

5858
if (!CDCtx.RepositoryUrl) {
59-
OS << "*Defined at " << L.Filename << "#" << std::to_string(L.LineNumber)
60-
<< "*";
59+
OS << "*Defined at " << L.Filename << "#"
60+
<< std::to_string(L.StartLineNumber) << "*";
6161
} else {
6262

6363
OS << formatv("*Defined at [#{0}{1}{2}](#{0}{1}{3})*",
64-
CDCtx.RepositoryLinePrefix.value_or(""), L.LineNumber,
64+
CDCtx.RepositoryLinePrefix.value_or(""), L.StartLineNumber,
6565
L.Filename, *CDCtx.RepositoryUrl);
6666
}
6767
OS << "\n\n";

clang-tools-extra/clang-doc/Mapper.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ template <typename T> static bool isTypedefAnonRecord(const T *D) {
2828
return false;
2929
}
3030

31+
Location MapASTVisitor::getDeclLocation(const NamedDecl *D) const {
32+
bool IsFileInRootDir;
33+
llvm::SmallString<128> File =
34+
getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
35+
SourceManager &SM = D->getASTContext().getSourceManager();
36+
int Start = SM.getPresumedLoc(D->getBeginLoc()).getLine();
37+
int End = SM.getPresumedLoc(D->getEndLoc()).getLine();
38+
39+
return Location(Start, End, File, IsFileInRootDir);
40+
}
41+
3142
void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
3243
TraverseDecl(Context.getTranslationUnitDecl());
3344
}
@@ -59,9 +70,9 @@ bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) {
5970
bool IsFileInRootDir;
6071
llvm::SmallString<128> File =
6172
getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
62-
auto [Child, Parent] = serialize::emitInfo(
63-
D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()),
64-
File, IsFileInRootDir, CDCtx.PublicOnly);
73+
auto [Child, Parent] =
74+
serialize::emitInfo(D, getComment(D, D->getASTContext()),
75+
getDeclLocation(D), CDCtx.PublicOnly);
6576

6677
// A null in place of a valid Info indicates that the serializer is skipping
6778
// this decl for some reason (e.g. we're only reporting public decls).

clang-tools-extra/clang-doc/Mapper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
4646
template <typename T> bool mapDecl(const T *D, bool IsDefinition);
4747

4848
int getLine(const NamedDecl *D, const ASTContext &Context) const;
49+
50+
Location getDeclLocation(const NamedDecl *D) const;
51+
4952
llvm::SmallString<128> getFile(const NamedDecl *D, const ASTContext &Context,
5053
StringRef RootDir,
5154
bool &IsFileInRootDir) const;

clang-tools-extra/clang-doc/Representation.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,31 +241,29 @@ struct MemberTypeInfo : public FieldTypeInfo {
241241
};
242242

243243
struct Location {
244-
Location(int LineNumber = 0, StringRef Filename = StringRef(),
245-
bool IsFileInRootDir = false)
246-
: LineNumber(LineNumber), Filename(Filename),
247-
IsFileInRootDir(IsFileInRootDir) {}
244+
Location(int StartLineNumber = 0, int EndLineNumber = 0,
245+
StringRef Filename = StringRef(), bool IsFileInRootDir = false)
246+
: StartLineNumber(StartLineNumber), EndLineNumber(EndLineNumber),
247+
Filename(Filename), IsFileInRootDir(IsFileInRootDir) {}
248248

249249
bool operator==(const Location &Other) const {
250-
return std::tie(LineNumber, Filename) ==
251-
std::tie(Other.LineNumber, Other.Filename);
250+
return std::tie(StartLineNumber, EndLineNumber, Filename) ==
251+
std::tie(Other.StartLineNumber, Other.EndLineNumber, Other.Filename);
252252
}
253253

254-
bool operator!=(const Location &Other) const {
255-
return std::tie(LineNumber, Filename) !=
256-
std::tie(Other.LineNumber, Other.Filename);
257-
}
254+
bool operator!=(const Location &Other) const { return !(*this == Other); }
258255

259256
// This operator is used to sort a vector of Locations.
260257
// No specific order (attributes more important than others) is required. Any
261258
// sort is enough, the order is only needed to call std::unique after sorting
262259
// the vector.
263260
bool operator<(const Location &Other) const {
264-
return std::tie(LineNumber, Filename) <
265-
std::tie(Other.LineNumber, Other.Filename);
261+
return std::tie(StartLineNumber, EndLineNumber, Filename) <
262+
std::tie(Other.StartLineNumber, Other.EndLineNumber, Other.Filename);
266263
}
267264

268-
int LineNumber = 0; // Line number of this Location.
265+
int StartLineNumber = 0; // Line number of this Location.
266+
int EndLineNumber = 0;
269267
SmallString<32> Filename; // File for this Location.
270268
bool IsFileInRootDir = false; // Indicates if file is inside root directory
271269
};

clang-tools-extra/clang-doc/Serialize.cpp

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -535,22 +535,18 @@ static void populateInfo(Info &I, const T *D, const FullComment *C,
535535

536536
template <typename T>
537537
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
538-
int LineNumber, StringRef Filename,
539-
bool IsFileInRootDir,
540-
bool &IsInAnonymousNamespace) {
538+
Location Loc, bool &IsInAnonymousNamespace) {
541539
populateInfo(I, D, C, IsInAnonymousNamespace);
542540
if (D->isThisDeclarationADefinition())
543-
I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
541+
I.DefLoc = Loc;
544542
else
545-
I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
543+
I.Loc.emplace_back(Loc);
546544
}
547545

548546
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
549-
const FullComment *FC, int LineNumber,
550-
StringRef Filename, bool IsFileInRootDir,
547+
const FullComment *FC, Location Loc,
551548
bool &IsInAnonymousNamespace) {
552-
populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
553-
IsInAnonymousNamespace);
549+
populateSymbolInfo(I, D, FC, Loc, IsInAnonymousNamespace);
554550
auto &LO = D->getLangOpts();
555551
I.ReturnType = getTypeInfoForType(D->getReturnType(), LO);
556552
parseParameters(I, D);
@@ -579,7 +575,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
579575
static void populateMemberTypeInfo(MemberTypeInfo &I, const Decl *D) {
580576
assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
581577

582-
ASTContext& Context = D->getASTContext();
578+
ASTContext &Context = D->getASTContext();
583579
// TODO investigate whether we can use ASTContext::getCommentForDecl instead
584580
// of this logic. See also similar code in Mapper.cpp.
585581
RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
@@ -643,8 +639,7 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
643639
// reference, its value is not relevant in here so it's not used
644640
// anywhere besides the function call.
645641
bool IsInAnonymousNamespace;
646-
populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{},
647-
/*FileName=*/{}, IsFileInRootDir,
642+
populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*Location=*/{},
648643
IsInAnonymousNamespace);
649644
FI.Access =
650645
getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
@@ -662,8 +657,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
662657
}
663658

664659
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
665-
emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
666-
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
660+
emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
661+
bool PublicOnly) {
667662
auto NSI = std::make_unique<NamespaceInfo>();
668663
bool IsInAnonymousNamespace = false;
669664
populateInfo(*NSI, D, FC, IsInAnonymousNamespace);
@@ -683,12 +678,11 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
683678
}
684679

685680
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
686-
emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
687-
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
681+
emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
682+
bool PublicOnly) {
688683
auto RI = std::make_unique<RecordInfo>();
689684
bool IsInAnonymousNamespace = false;
690-
populateSymbolInfo(*RI, D, FC, LineNumber, File, IsFileInRootDir,
691-
IsInAnonymousNamespace);
685+
populateSymbolInfo(*RI, D, FC, Loc, IsInAnonymousNamespace);
692686
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
693687
return {};
694688

@@ -701,7 +695,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
701695
}
702696
// TODO: remove first call to parseBases, that function should be deleted
703697
parseBases(*RI, C);
704-
parseBases(*RI, C, IsFileInRootDir, PublicOnly, true);
698+
parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true);
705699
}
706700
RI->Path = getInfoRelativePath(RI->Namespace);
707701

@@ -750,12 +744,11 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
750744
}
751745

752746
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
753-
emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
754-
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
747+
emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
748+
bool PublicOnly) {
755749
FunctionInfo Func;
756750
bool IsInAnonymousNamespace = false;
757-
populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
758-
IsInAnonymousNamespace);
751+
populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
759752
Func.Access = clang::AccessSpecifier::AS_none;
760753
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
761754
return {};
@@ -765,12 +758,11 @@ emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
765758
}
766759

767760
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
768-
emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
769-
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
761+
emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
762+
bool PublicOnly) {
770763
FunctionInfo Func;
771764
bool IsInAnonymousNamespace = false;
772-
populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
773-
IsInAnonymousNamespace);
765+
populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
774766
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
775767
return {};
776768

@@ -795,16 +787,15 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
795787
}
796788

797789
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
798-
emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
799-
StringRef File, bool IsFileInRootDir, bool PublicOnly) {
790+
emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
791+
bool PublicOnly) {
800792
TypedefInfo Info;
801-
802793
bool IsInAnonymousNamespace = false;
803794
populateInfo(Info, D, FC, IsInAnonymousNamespace);
804795
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
805796
return {};
806797

807-
Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
798+
Info.DefLoc = Loc;
808799
auto &LO = D->getLangOpts();
809800
Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
810801
if (Info.Underlying.Type.Name.empty()) {
@@ -822,16 +813,16 @@ emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
822813
// A type alias is a C++ "using" declaration for a type. It gets mapped to a
823814
// TypedefInfo with the IsUsing flag set.
824815
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
825-
emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
826-
StringRef File, bool IsFileInRootDir, bool PublicOnly) {
816+
emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc,
817+
bool PublicOnly) {
827818
TypedefInfo Info;
828819

829820
bool IsInAnonymousNamespace = false;
830821
populateInfo(Info, D, FC, IsInAnonymousNamespace);
831822
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
832823
return {};
833824

834-
Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
825+
Info.DefLoc = Loc;
835826
auto &LO = D->getLangOpts();
836827
Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
837828
Info.IsUsing = true;
@@ -841,12 +832,12 @@ emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
841832
}
842833

843834
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
844-
emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
845-
llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
835+
emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
836+
bool PublicOnly) {
846837
EnumInfo Enum;
847838
bool IsInAnonymousNamespace = false;
848-
populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
849-
IsInAnonymousNamespace);
839+
populateSymbolInfo(Enum, D, FC, Loc, IsInAnonymousNamespace);
840+
850841
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
851842
return {};
852843

0 commit comments

Comments
 (0)