Skip to content

Commit 8050a6e

Browse files
authored
[clang-doc] add support for concepts (#144430)
Add support for documenting concepts. This handles concepts and constraints on function and class templates. Atomic constraints are not considered yet. We don't order constraints based on their conjunctive or disjunctive properties.
1 parent 2dfcc43 commit 8050a6e

19 files changed

+507
-56
lines changed

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field,
9292
case InfoType::IT_default:
9393
case InfoType::IT_enum:
9494
case InfoType::IT_typedef:
95+
case InfoType::IT_concept:
9596
Field = IT;
9697
return llvm::Error::success();
9798
}
@@ -108,6 +109,7 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
108109
case FieldId::F_type:
109110
case FieldId::F_child_namespace:
110111
case FieldId::F_child_record:
112+
case FieldId::F_concept:
111113
case FieldId::F_default:
112114
Field = F;
113115
return llvm::Error::success();
@@ -391,6 +393,29 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
391393
"invalid field for TemplateParamInfo");
392394
}
393395

396+
static llvm::Error parseRecord(const Record &R, unsigned ID,
397+
llvm::StringRef Blob, ConceptInfo *I) {
398+
switch (ID) {
399+
case CONCEPT_USR:
400+
return decodeRecord(R, I->USR, Blob);
401+
case CONCEPT_NAME:
402+
return decodeRecord(R, I->Name, Blob);
403+
case CONCEPT_IS_TYPE:
404+
return decodeRecord(R, I->IsType, Blob);
405+
case CONCEPT_CONSTRAINT_EXPRESSION:
406+
return decodeRecord(R, I->ConstraintExpression, Blob);
407+
}
408+
llvm_unreachable("invalid field for ConceptInfo");
409+
}
410+
411+
static llvm::Error parseRecord(const Record &R, unsigned ID,
412+
llvm::StringRef Blob, ConstraintInfo *I) {
413+
if (ID == CONSTRAINT_EXPRESSION)
414+
return decodeRecord(R, I->ConstraintExpr, Blob);
415+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
416+
"invalid field for ConstraintInfo");
417+
}
418+
394419
template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
395420
return llvm::createStringError(llvm::inconvertibleErrorCode(),
396421
"invalid type cannot contain CommentInfo");
@@ -429,6 +454,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
429454
return I->Children.back().get();
430455
}
431456

457+
template <> llvm::Expected<CommentInfo *> getCommentInfo(ConceptInfo *I) {
458+
return &I->Description.emplace_back();
459+
}
460+
432461
// When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on
433462
// the parent block to set it. The template specializations define what to do
434463
// for each supported parent block.
@@ -584,6 +613,17 @@ template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) {
584613
}
585614
}
586615

616+
template <>
617+
llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) {
618+
if (F == FieldId::F_concept) {
619+
I->ConceptRef = std::move(R);
620+
return llvm::Error::success();
621+
}
622+
return llvm::createStringError(
623+
llvm::inconvertibleErrorCode(),
624+
"ConstraintInfo cannot contain this Reference");
625+
}
626+
587627
template <typename T, typename ChildInfoType>
588628
static void addChild(T I, ChildInfoType &&R) {
589629
llvm::errs() << "invalid child type for info";
@@ -600,6 +640,9 @@ template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
600640
template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) {
601641
I->Children.Typedefs.emplace_back(std::move(R));
602642
}
643+
template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) {
644+
I->Children.Concepts.emplace_back(std::move(R));
645+
}
603646

604647
// Record children:
605648
template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
@@ -649,6 +692,9 @@ template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) {
649692
template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) {
650693
I->Template.emplace(std::move(P));
651694
}
695+
template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) {
696+
I->Template = std::move(P);
697+
}
652698

653699
// Template specializations go only into template records.
654700
template <typename T>
@@ -662,6 +708,14 @@ void addTemplateSpecialization(TemplateInfo *I,
662708
I->Specialization.emplace(std::move(TSI));
663709
}
664710

711+
template <typename T> static void addConstraint(T I, ConstraintInfo &&C) {
712+
llvm::errs() << "invalid container for constraint info";
713+
exit(1);
714+
}
715+
template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) {
716+
I->Constraints.emplace_back(std::move(C));
717+
}
718+
665719
// Read records from bitcode into a given info.
666720
template <typename T>
667721
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
@@ -716,6 +770,8 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
716770
}
717771
}
718772

773+
// TODO: Create a helper that can receive a function to reduce repetition for
774+
// most blocks.
719775
template <typename T>
720776
llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
721777
llvm::TimeTraceScope("Reducing infos", "readSubBlock");
@@ -817,6 +873,20 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
817873
addChild(I, std::move(TI));
818874
return llvm::Error::success();
819875
}
876+
case BI_CONSTRAINT_BLOCK_ID: {
877+
ConstraintInfo CI;
878+
if (auto Err = readBlock(ID, &CI))
879+
return Err;
880+
addConstraint(I, std::move(CI));
881+
return llvm::Error::success();
882+
}
883+
case BI_CONCEPT_BLOCK_ID: {
884+
ConceptInfo CI;
885+
if (auto Err = readBlock(ID, &CI))
886+
return Err;
887+
addChild(I, std::move(CI));
888+
return llvm::Error::success();
889+
}
820890
default:
821891
return llvm::createStringError(llvm::inconvertibleErrorCode(),
822892
"invalid subblock type");
@@ -922,6 +992,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
922992
return createInfo<EnumInfo>(ID);
923993
case BI_TYPEDEF_BLOCK_ID:
924994
return createInfo<TypedefInfo>(ID);
995+
case BI_CONCEPT_BLOCK_ID:
996+
return createInfo<ConceptInfo>(ID);
925997
case BI_FUNCTION_BLOCK_ID:
926998
return createInfo<FunctionInfo>(ID);
927999
default:
@@ -962,6 +1034,7 @@ ClangDocBitcodeReader::readBitcode() {
9621034
case BI_RECORD_BLOCK_ID:
9631035
case BI_ENUM_BLOCK_ID:
9641036
case BI_TYPEDEF_BLOCK_ID:
1037+
case BI_CONCEPT_BLOCK_ID:
9651038
case BI_FUNCTION_BLOCK_ID: {
9661039
auto InfoOrErr = readBlockToInfo(ID);
9671040
if (!InfoOrErr)

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

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
128128
{BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},
129129
{BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},
130130
{BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
131-
{BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}};
131+
{BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"},
132+
{BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},
133+
{BI_CONCEPT_BLOCK_ID, "ConceptBlock"}};
132134
assert(Inits.size() == BlockIdCount);
133135
for (const auto &Init : Inits)
134136
BlockIdNameMap[Init.first] = Init.second;
@@ -205,7 +207,13 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
205207
{TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}},
206208
{TYPEDEF_NAME, {"Name", &genStringAbbrev}},
207209
{TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
208-
{TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}}};
210+
{TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}},
211+
{CONCEPT_USR, {"USR", &genSymbolIdAbbrev}},
212+
{CONCEPT_NAME, {"Name", &genStringAbbrev}},
213+
{CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},
214+
{CONCEPT_CONSTRAINT_EXPRESSION,
215+
{"ConstraintExpression", &genStringAbbrev}},
216+
{CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}}};
209217
assert(Inits.size() == RecordIdCount);
210218
for (const auto &Init : Inits) {
211219
RecordIdNameMap[Init.first] = Init.second;
@@ -263,7 +271,13 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
263271
// Template Blocks.
264272
{BI_TEMPLATE_BLOCK_ID, {}},
265273
{BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
266-
{BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}};
274+
{BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}},
275+
// Concept Block
276+
{BI_CONCEPT_BLOCK_ID,
277+
{CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,
278+
CONCEPT_CONSTRAINT_EXPRESSION}},
279+
// Constraint Block
280+
{BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}}};
267281

268282
// AbbreviationMap
269283

@@ -524,6 +538,8 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
524538
emitBlock(C);
525539
for (const auto &C : I.Children.Typedefs)
526540
emitBlock(C);
541+
for (const auto &C : I.Children.Concepts)
542+
emitBlock(C);
527543
}
528544

529545
void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
@@ -627,12 +643,25 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
627643
emitBlock(*I.Template);
628644
}
629645

646+
void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) {
647+
StreamSubBlockGuard Block(Stream, BI_CONCEPT_BLOCK_ID);
648+
emitRecord(I.USR, CONCEPT_USR);
649+
emitRecord(I.Name, CONCEPT_NAME);
650+
for (const auto &CI : I.Description)
651+
emitBlock(CI);
652+
emitRecord(I.IsType, CONCEPT_IS_TYPE);
653+
emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION);
654+
emitBlock(I.Template);
655+
}
656+
630657
void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
631658
StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
632659
for (const auto &P : T.Params)
633660
emitBlock(P);
634661
if (T.Specialization)
635662
emitBlock(*T.Specialization);
663+
for (const auto &C : T.Constraints)
664+
emitBlock(C);
636665
}
637666

638667
void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
@@ -647,6 +676,12 @@ void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
647676
emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS);
648677
}
649678

679+
void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) {
680+
StreamSubBlockGuard Block(Stream, BI_CONSTRAINT_BLOCK_ID);
681+
emitRecord(C.ConstraintExpr, CONSTRAINT_EXPRESSION);
682+
emitBlock(C.ConceptRef, FieldId::F_concept);
683+
}
684+
650685
bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
651686
switch (I->IT) {
652687
case InfoType::IT_namespace:
@@ -664,6 +699,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
664699
case InfoType::IT_typedef:
665700
emitBlock(*static_cast<clang::doc::TypedefInfo *>(I));
666701
break;
702+
case InfoType::IT_concept:
703+
emitBlock(*static_cast<clang::doc::ConceptInfo *>(I));
704+
break;
667705
case InfoType::IT_default:
668706
llvm::errs() << "Unexpected info, unable to write.\n";
669707
return true;

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ enum BlockId {
6666
BI_TEMPLATE_BLOCK_ID,
6767
BI_TEMPLATE_SPECIALIZATION_BLOCK_ID,
6868
BI_TEMPLATE_PARAM_BLOCK_ID,
69+
BI_CONSTRAINT_BLOCK_ID,
6970
BI_TYPEDEF_BLOCK_ID,
71+
BI_CONCEPT_BLOCK_ID,
7072
BI_LAST,
7173
BI_FIRST = BI_VERSION_BLOCK_ID
7274
};
@@ -135,6 +137,11 @@ enum RecordId {
135137
TYPEDEF_NAME,
136138
TYPEDEF_DEFLOCATION,
137139
TYPEDEF_IS_USING,
140+
CONCEPT_USR,
141+
CONCEPT_NAME,
142+
CONCEPT_IS_TYPE,
143+
CONCEPT_CONSTRAINT_EXPRESSION,
144+
CONSTRAINT_EXPRESSION,
138145
RI_LAST,
139146
RI_FIRST = VERSION
140147
};
@@ -150,7 +157,8 @@ enum class FieldId {
150157
F_vparent,
151158
F_type,
152159
F_child_namespace,
153-
F_child_record
160+
F_child_record,
161+
F_concept
154162
};
155163

156164
class ClangDocBitcodeWriter {
@@ -179,6 +187,8 @@ class ClangDocBitcodeWriter {
179187
void emitBlock(const TemplateInfo &T);
180188
void emitBlock(const TemplateSpecializationInfo &T);
181189
void emitBlock(const TemplateParamInfo &T);
190+
void emitBlock(const ConceptInfo &T);
191+
void emitBlock(const ConstraintInfo &T);
182192
void emitBlock(const Reference &B, FieldId F);
183193

184194
private:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,8 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
985985
MainContentNodes =
986986
genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
987987
break;
988+
case InfoType::IT_concept:
989+
break;
988990
case InfoType::IT_default:
989991
return llvm::createStringError(llvm::inconvertibleErrorCode(),
990992
"unexpected info type");
@@ -1011,6 +1013,8 @@ static std::string getRefType(InfoType IT) {
10111013
return "enum";
10121014
case InfoType::IT_typedef:
10131015
return "typedef";
1016+
case InfoType::IT_concept:
1017+
return "concept";
10141018
}
10151019
llvm_unreachable("Unknown InfoType");
10161020
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
585585
case InfoType::IT_typedef:
586586
OS << "IT_typedef\n";
587587
break;
588+
case InfoType::IT_concept:
589+
break;
588590
case InfoType::IT_default:
589591
return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
590592
}

0 commit comments

Comments
 (0)