llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: None (PeterChou1) <details> <summary>Changes</summary> Split from https://github.com/llvm/llvm-project/pull/133161 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 is will be used by the mustache backend to generate line ranges --- Full diff: https://github.com/llvm/llvm-project/pull/135081.diff 8 Files Affected: - (modified) clang-tools-extra/clang-doc/BitcodeReader.cpp (+1-1) - (modified) clang-tools-extra/clang-doc/BitcodeWriter.cpp (+6-3) - (modified) clang-tools-extra/clang-doc/Mapper.cpp (+16-2) - (modified) clang-tools-extra/clang-doc/Mapper.h (+3) - (modified) clang-tools-extra/clang-doc/Representation.h (+12-10) - (modified) clang-tools-extra/clang-doc/Serialize.cpp (+44-41) - (modified) clang-tools-extra/clang-doc/Serialize.h (+14-14) - (modified) clang-tools-extra/clang-doc/YAMLGenerator.cpp (+1-1) ``````````diff diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index 1f2fb0a8b2b85..c9f588303fd08 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -85,7 +85,7 @@ llvm::Error decodeRecord(const Record &R, std::optional<Location> &Field, if (R[0] > INT_MAX) return llvm::createStringError(llvm::inconvertibleErrorCode(), "integer too large to parse"); - Field.emplace((int)R[0], Blob, (bool)R[1]); + Field.emplace((int)R[0], (int) R[1], Blob, (bool)R[2]); return llvm::Error::success(); } diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index 06f30f76e33d8..8230097c0726d 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -77,13 +77,16 @@ static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { {// 0. Fixed-size integer (line number) llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumberSize), - // 1. Boolean (IsFileInRootDir) + // 1. Fixed-size integer (start line number) + llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, + BitCodeConstants::LineNumberSize), + // 2. Boolean (IsFileInRootDir) llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, BitCodeConstants::BoolSize), - // 2. Fixed-size integer (length of the following string (filename)) + // 3. Fixed-size integer (length of the following string (filename)) llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, BitCodeConstants::StringLengthSize), - // 3. The string blob + // 4. The string blob llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)}); } diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp index 6c90db03424c6..4dadff41e96e8 100644 --- a/clang-tools-extra/clang-doc/Mapper.cpp +++ b/clang-tools-extra/clang-doc/Mapper.cpp @@ -28,6 +28,21 @@ template <typename T> bool isTypedefAnonRecord(const T *D) { return false; } +Location MapASTVisitor::getDeclLocation(const NamedDecl *D) const { + bool IsFileInRootDir; + llvm::SmallString<128> File = + getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir); + ASTContext &Context = D->getASTContext(); + int Start = Context.getSourceManager() + .getPresumedLoc(D->getBeginLoc()) + .getLine(); + int End = Context.getSourceManager() + .getPresumedLoc(D->getEndLoc()) + .getLine(); + + return Location(Start, End, File, IsFileInRootDir); +} + void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) { TraverseDecl(Context.getTranslationUnitDecl()); } @@ -60,8 +75,7 @@ bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) { 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); + getDeclLocation(D), 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). diff --git a/clang-tools-extra/clang-doc/Mapper.h b/clang-tools-extra/clang-doc/Mapper.h index 75c8e947c8f90..3c3ebdb683911 100644 --- a/clang-tools-extra/clang-doc/Mapper.h +++ b/clang-tools-extra/clang-doc/Mapper.h @@ -46,6 +46,9 @@ class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>, template <typename T> bool mapDecl(const T *D, bool IsDefinition); int getLine(const NamedDecl *D, const ASTContext &Context) const; + + Location getDeclLocation(const NamedDecl *D) const; + llvm::SmallString<128> getFile(const NamedDecl *D, const ASTContext &Context, StringRef RootDir, bool &IsFileInRootDir) const; diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 2153b62864ee3..53a62edf3dbcf 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -238,19 +238,20 @@ struct MemberTypeInfo : public FieldTypeInfo { }; struct Location { - Location(int LineNumber = 0, StringRef Filename = StringRef(), + Location(int StartLineNumber = 0, + int EndLineNumber = 0, StringRef Filename = StringRef(), bool IsFileInRootDir = false) - : LineNumber(LineNumber), Filename(Filename), - IsFileInRootDir(IsFileInRootDir) {} + : StartLineNumber(StartLineNumber), EndLineNumber(EndLineNumber), + Filename(Filename), IsFileInRootDir(IsFileInRootDir) {} bool operator==(const Location &Other) const { - return std::tie(LineNumber, Filename) == - std::tie(Other.LineNumber, Other.Filename); + return std::tie(StartLineNumber, EndLineNumber, Filename) == + std::tie(Other.StartLineNumber, Other.EndLineNumber, Other.Filename); } bool operator!=(const Location &Other) const { - return std::tie(LineNumber, Filename) != - std::tie(Other.LineNumber, Other.Filename); + return std::tie(StartLineNumber, Filename) != + std::tie(Other.StartLineNumber, Other.Filename); } // This operator is used to sort a vector of Locations. @@ -258,11 +259,12 @@ struct Location { // sort is enough, the order is only needed to call std::unique after sorting // the vector. bool operator<(const Location &Other) const { - return std::tie(LineNumber, Filename) < - std::tie(Other.LineNumber, Other.Filename); + return std::tie(StartLineNumber, Filename) < + std::tie(Other.StartLineNumber, Other.Filename); } - int LineNumber = 0; // Line number of this Location. + int StartLineNumber = 0; // Line number of this Location. + int EndLineNumber = 0; SmallString<32> Filename; // File for this Location. bool IsFileInRootDir = false; // Indicates if file is inside root directory }; diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index f737fc75135a1..aa3dff1d210b5 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -527,22 +527,20 @@ 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, + Location Loc, bool &IsInAnonymousNamespace) { populateInfo(I, D, C, IsInAnonymousNamespace); if (D->isThisDeclarationADefinition()) - I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir); + I.DefLoc = Loc; else - I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir); + I.Loc.emplace_back(Loc); } static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, - const FullComment *FC, int LineNumber, - StringRef Filename, bool IsFileInRootDir, + const FullComment *FC, + Location Loc, bool &IsInAnonymousNamespace) { - populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir, - IsInAnonymousNamespace); + populateSymbolInfo(I, D, FC, Loc, IsInAnonymousNamespace); auto &LO = D->getLangOpts(); I.ReturnType = getTypeInfoForType(D->getReturnType(), LO); parseParameters(I, D); @@ -623,8 +621,7 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, // reference, its value is not relevant in here so it's not used // anywhere besides the function call. bool IsInAnonymousNamespace; - populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{}, - /*FileName=*/{}, IsFileInRootDir, + populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*Location=*/{}, IsInAnonymousNamespace); FI.Access = getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe()); @@ -642,8 +639,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, } std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { +emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly) { auto I = std::make_unique<NamespaceInfo>(); bool IsInAnonymousNamespace = false; populateInfo(*I, D, FC, IsInAnonymousNamespace); @@ -663,12 +660,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 IsFileInRootDir, bool PublicOnly) { +emitInfo(const RecordDecl *D, const FullComment *FC, + Location Loc, bool PublicOnly) { auto I = std::make_unique<RecordInfo>(); bool IsInAnonymousNamespace = false; - populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir, - IsInAnonymousNamespace); + populateSymbolInfo(*I, D, FC, Loc, IsInAnonymousNamespace); if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; @@ -681,7 +677,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, } // TODO: remove first call to parseBases, that function should be deleted parseBases(*I, C); - parseBases(*I, C, IsFileInRootDir, PublicOnly, true); + parseBases(*I, C, true, PublicOnly, true); } I->Path = getInfoRelativePath(I->Namespace); @@ -730,30 +726,28 @@ 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 IsFileInRootDir, bool PublicOnly) { +emitInfo(const FunctionDecl *D, const FullComment *FC, + Location Loc, bool PublicOnly) { FunctionInfo Func; bool IsInAnonymousNamespace = false; - populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, - IsInAnonymousNamespace); + populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace); Func.Access = clang::AccessSpecifier::AS_none; if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; - + // Info is wrapped in its parent scope so is returned in the second position. return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))}; } std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { +emitInfo(const CXXMethodDecl *D, const FullComment *FC, + Location Loc, bool PublicOnly) { FunctionInfo Func; bool IsInAnonymousNamespace = false; - populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, - IsInAnonymousNamespace); + populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace); if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; - + Func.IsMethod = true; const NamedDecl *Parent = nullptr; @@ -774,18 +768,21 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, } std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly) { +emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly) { + TypedefInfo Info; - + ASTContext& Context = D->getASTContext(); bool IsInAnonymousNamespace = false; populateInfo(Info, D, FC, IsInAnonymousNamespace); + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; - - Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); + + Info.DefLoc = Loc; auto &LO = D->getLangOpts(); Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); + if (Info.Underlying.Type.Name.empty()) { // Typedef for an unnamed type. This is like "typedef struct { } Foo;" // The record serializer explicitly checks for this syntax and constructs @@ -793,7 +790,13 @@ emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, return {}; } Info.IsUsing = false; - + if (RawComment *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) { + Comment->setAttached(); + if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) { + Info.Description.emplace_back(); + parseFullComment(Fc, Info.Description.back()); + } + } // Info is wrapped in its parent scope so is returned in the second position. return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))}; } @@ -801,8 +804,8 @@ emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, // A type alias is a C++ "using" declaration for a type. It gets mapped to a // TypedefInfo with the IsUsing flag set. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly) { +emitInfo(const TypeAliasDecl *D, const FullComment *FC, + Location Loc, bool PublicOnly) { TypedefInfo Info; bool IsInAnonymousNamespace = false; @@ -810,7 +813,7 @@ emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber, if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; - Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); + Info.DefLoc = Loc; auto &LO = D->getLangOpts(); Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); Info.IsUsing = true; @@ -820,15 +823,15 @@ emitInfo(const TypeAliasDecl *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 IsFileInRootDir, bool PublicOnly) { +emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly) { EnumInfo Enum; bool IsInAnonymousNamespace = false; - populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir, - IsInAnonymousNamespace); + populateSymbolInfo(Enum, D, FC, Loc, IsInAnonymousNamespace); + if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) return {}; - + Enum.Scoped = D->isScoped(); if (D->isFixed()) { auto Name = D->getIntegerType().getAsString(); diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h index 4e203ca7891ac..8874299e9af9e 100644 --- a/clang-tools-extra/clang-doc/Serialize.h +++ b/clang-tools-extra/clang-doc/Serialize.h @@ -37,32 +37,32 @@ namespace serialize { // its parent scope. For NamespaceDecl and RecordDecl both elements are not // nullptr. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> -emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool IsFileInRootDir, bool PublicOnly); +emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc, + bool PublicOnly); // Function to hash a given USR value for storage. // As USRs (Unified Symbol Resolution) could be large, especially for functions diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp index ffabd2fd82229..d990dd4b647e8 100644 --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -169,7 +169,7 @@ static void CommentInfoMapping(IO &IO, CommentInfo &I) { template <> struct MappingTraits<Location> { static void mapping(IO &IO, Location &Loc) { - IO.mapOptional("LineNumber", Loc.LineNumber, 0); + IO.mapOptional("LineNumber", Loc.StartLineNumber, 0); IO.mapOptional("Filename", Loc.Filename, SmallString<32>()); } }; `````````` </details> https://github.com/llvm/llvm-project/pull/135081 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits