-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[clang-doc] add support for concepts #144430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
8d8b900
to
b602047
Compare
9f39ac3
to
ab20818
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see some unhandled switch cases in the CI diagnostics.
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:968:11: warning: enumeration value 'IT_concept' not handled in switch [-Wswitch]
968 | switch (I->IT) {
| ^~~~~
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:1001:11: warning: enumeration value 'IT_concept' not handled in switch [-Wswitch]
1001 | switch (IT) {
| ^~
There's also a failing test:
******************** TEST 'Clang Tools :: clang-doc/json/function-requires.cpp' FAILED ********************
Exit Code: 1
Command Output (stdout):
--
Emiting docs in json format.
Mapping decls...
Collecting infos...
Reducing 1 infos...
Generating docs...
Generating assets for docs...
--
Command Output (stderr):
--
rm -rf /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp && mkdir -p /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp # RUN: at line 1
+ rm -rf /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp
+ mkdir -p /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp
clang-doc --extra-arg -std=c++20 --output=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp --format=json --executor=standalone /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp # RUN: at line 2
+ clang-doc --extra-arg -std=c++20 --output=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp --format=json --executor=standalone /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "/home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp"
No compilation database found in /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp < /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/test/clang-doc/json/Output/function-requires.cpp.tmp/GlobalNamespace/index.json # RUN: at line 3
+ FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp:42:16: error: CHECK-NEXT: is not on the line after the previous match
// CHECK-NEXT: "Parameters": [
^
<stdin>:80:2: note: 'next' match was here
"Parameters": [
^
<stdin>:70:15: note: previous match ended here
"Template": {
^
<stdin>:71:1: note: non-matching line after previous match is here
"Constraints": [
^
Input file: <stdin>
Check file: /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/test/clang-doc/json/function-requires.cpp
-dump-input=help explains the following input dump.
Input was:
<<<<<<
.
.
.
75: "Path": "",
76: "QualName": "Incrementable",
77: "USR": "8EA2F4AC745967890D43D844DBD3EA14C16396C7"
78: }
79: ],
80: "Parameters": [
next:42 !~~~~~~~~~~~~~~ error: match on wrong line
81: "typename T"
82: ]
83: },
84: "USR": "CE80985A5378877E50F5FF1D8DE73E856B8AF683"
85: },
.
.
.
>>>>>>
--
********************
56da9c0
to
e3e7a47
Compare
@llvm/pr-subscribers-clang-tools-extra Author: Erick Velez (evelez7) ChangesPatch is 40.83 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144430.diff 19 Files Affected:
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 35058abab0663..5b70280e7dba8 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -92,6 +92,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field,
case InfoType::IT_default:
case InfoType::IT_enum:
case InfoType::IT_typedef:
+ case InfoType::IT_concept:
Field = IT;
return llvm::Error::success();
}
@@ -108,6 +109,7 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
case FieldId::F_type:
case FieldId::F_child_namespace:
case FieldId::F_child_record:
+ case FieldId::F_concept:
case FieldId::F_default:
Field = F;
return llvm::Error::success();
@@ -391,6 +393,29 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
"invalid field for TemplateParamInfo");
}
+static llvm::Error parseRecord(const Record &R, unsigned ID,
+ llvm::StringRef Blob, ConceptInfo *I) {
+ switch (ID) {
+ case CONCEPT_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case CONCEPT_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case CONCEPT_IS_TYPE:
+ return decodeRecord(R, I->IsType, Blob);
+ case CONCEPT_CONSTRAINT_EXPRESSION:
+ return decodeRecord(R, I->ConstraintExpression, Blob);
+ }
+ llvm_unreachable("invalid field for ConceptInfo");
+}
+
+static llvm::Error parseRecord(const Record &R, unsigned ID,
+ llvm::StringRef Blob, ConstraintInfo *I) {
+ if (ID == CONSTRAINT_EXPRESSION)
+ return decodeRecord(R, I->Expression, Blob);
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "invalid field for ConstraintInfo");
+}
+
template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"invalid type cannot contain CommentInfo");
@@ -429,6 +454,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
return I->Children.back().get();
}
+template <> llvm::Expected<CommentInfo *> getCommentInfo(ConceptInfo *I) {
+ return &I->Description.emplace_back();
+}
+
// When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on
// the parent block to set it. The template specializations define what to do
// for each supported parent block.
@@ -584,6 +613,18 @@ template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) {
}
}
+template <>
+llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_concept:
+ I->ConceptRef = std::move(R);
+ return llvm::Error::success();
+ default:
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "invalid type cannot contain Reference");
+ }
+}
+
template <typename T, typename ChildInfoType>
static void addChild(T I, ChildInfoType &&R) {
llvm::errs() << "invalid child type for info";
@@ -600,6 +641,9 @@ template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) {
I->Children.Typedefs.emplace_back(std::move(R));
}
+template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) {
+ I->Children.Concepts.emplace_back(std::move(R));
+}
// Record children:
template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
@@ -649,6 +693,9 @@ template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) {
template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) {
I->Template.emplace(std::move(P));
}
+template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) {
+ I->Template = std::move(P);
+}
// Template specializations go only into template records.
template <typename T>
@@ -662,6 +709,14 @@ void addTemplateSpecialization(TemplateInfo *I,
I->Specialization.emplace(std::move(TSI));
}
+template <typename T> static void addConstraint(T I, ConstraintInfo &&C) {
+ llvm::errs() << "invalid container for constraint info";
+ exit(1);
+}
+template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) {
+ I->Constraints.emplace_back(std::move(C));
+}
+
// Read records from bitcode into a given info.
template <typename T>
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
@@ -817,6 +872,20 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
addChild(I, std::move(TI));
return llvm::Error::success();
}
+ case BI_CONSTRAINT_BLOCK_ID: {
+ ConstraintInfo CI;
+ if (auto Err = readBlock(ID, &CI))
+ return Err;
+ addConstraint(I, std::move(CI));
+ return llvm::Error::success();
+ }
+ case BI_CONCEPT_BLOCK_ID: {
+ ConceptInfo CI;
+ if (auto Err = readBlock(ID, &CI))
+ return Err;
+ addChild(I, std::move(CI));
+ return llvm::Error::success();
+ }
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"invalid subblock type");
@@ -922,6 +991,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
return createInfo<EnumInfo>(ID);
case BI_TYPEDEF_BLOCK_ID:
return createInfo<TypedefInfo>(ID);
+ case BI_CONCEPT_BLOCK_ID:
+ return createInfo<ConceptInfo>(ID);
case BI_FUNCTION_BLOCK_ID:
return createInfo<FunctionInfo>(ID);
default:
@@ -962,6 +1033,7 @@ ClangDocBitcodeReader::readBitcode() {
case BI_RECORD_BLOCK_ID:
case BI_ENUM_BLOCK_ID:
case BI_TYPEDEF_BLOCK_ID:
+ case BI_CONCEPT_BLOCK_ID:
case BI_FUNCTION_BLOCK_ID: {
auto InfoOrErr = readBlockToInfo(ID);
if (!InfoOrErr)
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index f8a6859169b01..330b919140343 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -128,7 +128,9 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
{BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},
{BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},
{BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
- {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}};
+ {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"},
+ {BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},
+ {BI_CONCEPT_BLOCK_ID, "ConceptBlock"}};
assert(Inits.size() == BlockIdCount);
for (const auto &Init : Inits)
BlockIdNameMap[Init.first] = Init.second;
@@ -205,7 +207,13 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
{TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}},
{TYPEDEF_NAME, {"Name", &genStringAbbrev}},
{TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
- {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}}};
+ {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}},
+ {CONCEPT_USR, {"USR", &genSymbolIdAbbrev}},
+ {CONCEPT_NAME, {"Name", &genStringAbbrev}},
+ {CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},
+ {CONCEPT_CONSTRAINT_EXPRESSION,
+ {"ConstraintExpression", &genStringAbbrev}},
+ {CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}}};
assert(Inits.size() == RecordIdCount);
for (const auto &Init : Inits) {
RecordIdNameMap[Init.first] = Init.second;
@@ -263,7 +271,13 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
// Template Blocks.
{BI_TEMPLATE_BLOCK_ID, {}},
{BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
- {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}};
+ {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}},
+ // Concept Block
+ {BI_CONCEPT_BLOCK_ID,
+ {CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,
+ CONCEPT_CONSTRAINT_EXPRESSION}},
+ // Constraint Block
+ {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}}};
// AbbreviationMap
@@ -524,6 +538,8 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
emitBlock(C);
for (const auto &C : I.Children.Typedefs)
emitBlock(C);
+ for (const auto &C : I.Children.Concepts)
+ emitBlock(C);
}
void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
@@ -627,12 +643,25 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
emitBlock(*I.Template);
}
+void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_CONCEPT_BLOCK_ID);
+ emitRecord(I.USR, CONCEPT_USR);
+ emitRecord(I.Name, CONCEPT_NAME);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
+ emitRecord(I.IsType, CONCEPT_IS_TYPE);
+ emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION);
+ emitBlock(I.Template);
+}
+
void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
for (const auto &P : T.Params)
emitBlock(P);
if (T.Specialization)
emitBlock(*T.Specialization);
+ for (const auto &C : T.Constraints)
+ emitBlock(C);
}
void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
@@ -647,6 +676,12 @@ void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS);
}
+void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) {
+ StreamSubBlockGuard Block(Stream, BI_CONSTRAINT_BLOCK_ID);
+ emitRecord(C.Expression, CONSTRAINT_EXPRESSION);
+ emitBlock(C.ConceptRef, FieldId::F_concept);
+}
+
bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
switch (I->IT) {
case InfoType::IT_namespace:
@@ -664,6 +699,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
case InfoType::IT_typedef:
emitBlock(*static_cast<clang::doc::TypedefInfo *>(I));
break;
+ case InfoType::IT_concept:
+ emitBlock(*static_cast<clang::doc::ConceptInfo *>(I));
+ break;
case InfoType::IT_default:
llvm::errs() << "Unexpected info, unable to write.\n";
return true;
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h
index e33a1aece883c..4d0c0c07805e7 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -66,7 +66,9 @@ enum BlockId {
BI_TEMPLATE_BLOCK_ID,
BI_TEMPLATE_SPECIALIZATION_BLOCK_ID,
BI_TEMPLATE_PARAM_BLOCK_ID,
+ BI_CONSTRAINT_BLOCK_ID,
BI_TYPEDEF_BLOCK_ID,
+ BI_CONCEPT_BLOCK_ID,
BI_LAST,
BI_FIRST = BI_VERSION_BLOCK_ID
};
@@ -135,6 +137,11 @@ enum RecordId {
TYPEDEF_NAME,
TYPEDEF_DEFLOCATION,
TYPEDEF_IS_USING,
+ CONCEPT_USR,
+ CONCEPT_NAME,
+ CONCEPT_IS_TYPE,
+ CONCEPT_CONSTRAINT_EXPRESSION,
+ CONSTRAINT_EXPRESSION,
RI_LAST,
RI_FIRST = VERSION
};
@@ -150,7 +157,8 @@ enum class FieldId {
F_vparent,
F_type,
F_child_namespace,
- F_child_record
+ F_child_record,
+ F_concept
};
class ClangDocBitcodeWriter {
@@ -179,6 +187,8 @@ class ClangDocBitcodeWriter {
void emitBlock(const TemplateInfo &T);
void emitBlock(const TemplateSpecializationInfo &T);
void emitBlock(const TemplateParamInfo &T);
+ void emitBlock(const ConceptInfo &T);
+ void emitBlock(const ConstraintInfo &T);
void emitBlock(const Reference &B, FieldId F);
private:
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 7293a129177c9..935bbfee7a9b1 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -985,6 +985,8 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
MainContentNodes =
genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
break;
+ case InfoType::IT_concept:
+ break;
case InfoType::IT_default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"unexpected info type");
@@ -1011,6 +1013,8 @@ static std::string getRefType(InfoType IT) {
return "enum";
case InfoType::IT_typedef:
return "typedef";
+ case InfoType::IT_concept:
+ return "concept";
}
llvm_unreachable("Unknown InfoType");
}
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 69c670b208440..81ba99c21e374 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -585,6 +585,8 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
case InfoType::IT_typedef:
OS << "IT_typedef\n";
break;
+ case InfoType::IT_concept:
+ break;
case InfoType::IT_default:
return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
}
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 0f7cbafcf5135..60dbd4def6780 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -248,6 +248,26 @@ static void serializeCommonChildren(const ScopeChildren &Children,
}
}
+template <typename T>
+static void serializeArray(const std::vector<T> &Records, Object &Obj,
+ const std::string &Key) {
+ json::Value RecordsArray = Array();
+ auto &RecordsArrayRef = *RecordsArray.getAsArray();
+ RecordsArrayRef.reserve(Records.size());
+ for (const auto &Item : Records) {
+ json::Value ItemVal = Object();
+ auto &ItemObj = *ItemVal.getAsObject();
+ serializeInfo(Item, ItemObj);
+ RecordsArrayRef.push_back(ItemVal);
+ }
+ Obj[Key] = RecordsArray;
+}
+
+static void serializeInfo(const ConstraintInfo &I, Object &Obj) {
+ serializeReference(I.ConceptRef, Obj);
+ Obj["Expression"] = I.Expression;
+}
+
static void serializeInfo(const TemplateInfo &Template, Object &Obj) {
json::Value TemplateVal = Object();
auto &TemplateObj = *TemplateVal.getAsObject();
@@ -277,9 +297,21 @@ static void serializeInfo(const TemplateInfo &Template, Object &Obj) {
TemplateObj["Parameters"] = ParamsArray;
}
+ if (!Template.Constraints.empty()) {
+ serializeArray(Template.Constraints, TemplateObj, "Constraints");
+ }
+
Obj["Template"] = TemplateVal;
}
+static void serializeInfo(const ConceptInfo &I, Object &Obj,
+ std::optional<StringRef> RepositoryUrl) {
+ serializeCommonAttributes(I, Obj, RepositoryUrl);
+ Obj["IsType"] = I.IsType;
+ Obj["ConstraintExpression"] = I.ConstraintExpression;
+ serializeInfo(I.Template, Obj);
+}
+
static void serializeInfo(const TypeInfo &I, Object &Obj) {
Obj["Name"] = I.Type.Name;
Obj["QualName"] = I.Type.QualName;
@@ -470,6 +502,19 @@ static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
Obj["Functions"] = FunctionsArray;
}
+ if (!I.Children.Concepts.empty()) {
+ json::Value ConceptsArray = Array();
+ auto &ConceptsArrayRef = *ConceptsArray.getAsArray();
+ ConceptsArrayRef.reserve(I.Children.Concepts.size());
+ for (const auto &Concept : I.Children.Concepts) {
+ json::Value ConceptVal = Object();
+ auto &ConceptObj = *ConceptVal.getAsObject();
+ serializeInfo(Concept, ConceptObj, RepositoryUrl);
+ ConceptsArrayRef.push_back(ConceptVal);
+ }
+ Obj["Concepts"] = ConceptsArray;
+ }
+
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
}
@@ -520,6 +565,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
case InfoType::IT_record:
serializeInfo(*static_cast<RecordInfo *>(I), Obj, CDCtx.RepositoryUrl);
break;
+ case InfoType::IT_concept:
case InfoType::IT_enum:
case InfoType::IT_function:
case InfoType::IT_typedef:
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 2becccf8b07da..6e68e09cfa2a6 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -372,6 +372,9 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
case InfoType::IT_typedef:
Type = "Typedef";
break;
+ case InfoType::IT_concept:
+ Type = "Concept";
+ break;
case InfoType::IT_default:
Type = "Other";
}
@@ -464,6 +467,8 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
case InfoType::IT_typedef:
genMarkdown(CDCtx, *static_cast<clang::doc::TypedefInfo *>(I), OS);
break;
+ case InfoType::IT_concept:
+ break;
case InfoType::IT_default:
return createStringError(llvm::inconvertibleErrorCode(),
"unexpected InfoType");
diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp
index 9f640b5325da4..6021e17b4696d 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -134,6 +134,10 @@ bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl *D) {
return mapDecl(D, /*isDefinition=*/true);
}
+bool MapASTVisitor::VisitConceptDecl(const ConceptDecl *D) {
+ return mapDecl(D, true);
+}
+
comments::FullComment *
MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
diff --git a/clang-tools-extra/clang-doc/Mapper.h b/clang-tools-extra/clang-doc/Mapper.h
index 36322ea2bfb77..04dc5450c8ba3 100644
--- a/clang-tools-extra/clang-doc/Mapper.h
+++ b/clang-tools-extra/clang-doc/Mapper.h
@@ -41,6 +41,7 @@ class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
bool VisitFunctionDecl(const FunctionDecl *D);
bool VisitTypedefDecl(const TypedefDecl *D);
bool VisitTypeAliasDecl(const TypeAliasDecl *D);
+ bool VisitConceptDecl(const ConceptDecl *D);
private:
template <typename T> bool mapDecl(const T *D, bool IsDefinition);
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 820d644ef8b83..320048aa0fbf8 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -143,6 +143,8 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
return reduce<FunctionInfo>(Values);
case InfoType::IT_typedef:
return reduce<TypedefInfo>(Values);
+ case InfoType::IT_concept:
+ return reduce<ConceptInfo>(Values);
case InfoType::IT_default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"unexpected info type");
@@ -287,6 +289,7 @@ void NamespaceInfo::merge(NamespaceInfo &&Other) {
reduceChildren(Children.Functions, std::move(Other.Children.Functions));
reduceChildren(Children.Enums, std::move(Other.Children.Enums));
reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
+ reduceChildren(Children.Concepts, std::move(Other.Children.Concepts));
mergeBase(std::move(Other));
}
@@ -351,6 +354,13 @@ void TypedefInfo::merge(TypedefInfo &&Other) {
SymbolInfo::merge(std::move(Other));
}
+void ConceptInfo::merge(ConceptInfo &&Other) {
+ assert(mergeable(Other));
+ if (!IsType)
+ IsType = Other.IsType;
+ SymbolInfo::merge(std::move(Other));
+}
+
BaseRecordInfo::BaseRecordInfo() : RecordInfo() {}
BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path,
@@ -387,6 +397,9 @@ llvm::SmallString<16> Info::extractName() const {
case InfoType::IT_function:
return llvm::SmallString<16>("@nonymous_function_" +
toHex(llvm::toStringRef(USR)));
+ case InfoType::IT_concept:
+ return llvm::SmallString<16>("@nonymous_concept_" +
+ toHex(llvm::toStringRef(USR)));
case InfoType::IT_default:
return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
}
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 75da500645819..b7be2d23cbc45 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -35,6 +35,7 @@ struct EnumInfo;
struct FunctionInfo;
struct Info;
struct TypedefInfo;
+struct ConceptI...
[truncated]
|
Linux CI shows failing but looks like all tests passed despite that. Added compound constraint support which just goes through the nested expressions until it reaches the constraint. |
e3e7a47
to
72e4a24
Compare
I've just been clicking re-run on those when i see it. you may want to file abug about it. or chime in on an existing one. |
9754f70
to
2febdc8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. overall really good improvement. most of my comments are me noticing bad existing code we should fix.
I also left a few nit comments to address, but they're rather minor.
return llvm::createStringError(llvm::inconvertibleErrorCode(), | ||
"invalid type cannot contain Reference"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make it more obvious that this is related to concepts somehow? you just have a single arm in the switch, so it may also be preferable to just use an if
, unless you plan to support more feild types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at it now all of the reference error messages are not great. Makes it sound like the type cannot hold any Reference, but it should sound more like this info doesn't hold a Reference to this type.
Maybe in another patch, the FieldId can be emitted as part of the error message?
Something like "ConstraintInfo cannot contain Reference to {FieldId}".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM.
template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) { | ||
I->Template = std::move(P); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not something you need to fix here, but dang do we require a lot of boiler-plate changes to the APIs. It's almost like we're not holding templates in the normal way...
b602047
to
9c18fd3
Compare
2febdc8
to
63143f0
Compare
63143f0
to
00e0bac
Compare
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.
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.