diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -259,6 +259,8 @@ switch (ID) { case FIELD_TYPE_NAME: return decodeRecord(R, I->Name, Blob); + case FIELD_DEFAULT_VALUE: + return decodeRecord(R, I->DefaultValue, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for TypeInfo"); diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -88,6 +88,7 @@ COMMENT_ATTRVAL, COMMENT_ARG, FIELD_TYPE_NAME, + FIELD_DEFAULT_VALUE, MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS, NAMESPACE_USR, diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -148,6 +148,7 @@ {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}}, {COMMENT_ARG, {"Arg", &StringAbbrev}}, {FIELD_TYPE_NAME, {"Name", &StringAbbrev}}, + {FIELD_DEFAULT_VALUE, {"DefaultValue", &StringAbbrev}}, {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}}, {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}}, {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}}, @@ -207,7 +208,7 @@ // Type Block {BI_TYPE_BLOCK_ID, {}}, // FieldType Block - {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME}}, + {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}}, // MemberType Block {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}}, // Enum Block @@ -419,6 +420,7 @@ StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID); emitBlock(T.Type, FieldId::F_type); emitRecord(T.Name, FIELD_TYPE_NAME); + emitRecord(T.DefaultValue, FIELD_DEFAULT_VALUE); } void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) { diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -181,10 +181,15 @@ : TypeInfo(RefName, Path), Name(Name) {} bool operator==(const FieldTypeInfo &Other) const { - return std::tie(Type, Name) == std::tie(Other.Type, Other.Name); + return std::tie(Type, Name, DefaultValue) == + std::tie(Other.Type, Other.Name, Other.DefaultValue); } SmallString<16> Name; // Name associated with this info. + + // When used for function parameters, contains the string representing the + // expression of the default value, if any. + SmallString<16> DefaultValue; }; // Info for member types. diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -10,6 +10,7 @@ #include "BitcodeWriter.h" #include "clang/AST/Comment.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/SHA1.h" @@ -310,21 +311,31 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { for (const ParmVarDecl *P : D->parameters()) { + FieldTypeInfo *FieldInfo = nullptr; if (const auto *T = getDeclForType(P->getOriginalType())) { if (const auto *N = dyn_cast(T)) { - I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), - InfoType::IT_enum, getInfoRelativePath(N), - P->getNameAsString()); - continue; + FieldInfo = &I.Params.emplace_back( + getUSRForDecl(N), N->getNameAsString(), InfoType::IT_enum, + getInfoRelativePath(N), P->getNameAsString()); } else if (const auto *N = dyn_cast(T)) { - I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), - InfoType::IT_record, getInfoRelativePath(N), - P->getNameAsString()); - continue; + FieldInfo = &I.Params.emplace_back( + getUSRForDecl(N), N->getNameAsString(), InfoType::IT_record, + getInfoRelativePath(N), P->getNameAsString()); } + // Otherwise fall through to the default case below. + } + + if (!FieldInfo) { + FieldInfo = &I.Params.emplace_back(P->getOriginalType().getAsString(), + P->getNameAsString()); + } + + if (const Expr *DefaultArg = P->getDefaultArg()) { + FieldInfo->DefaultValue = Lexer::getSourceText( + CharSourceRange::getTokenRange(DefaultArg->getSourceRange()), + D->getASTContext().getSourceManager(), + D->getASTContext().getLangOpts()); } - I.Params.emplace_back(P->getOriginalType().getAsString(), - P->getNameAsString()); } } diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -109,6 +109,7 @@ static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) { TypeInfoMapping(IO, I); IO.mapOptional("Name", I.Name, SmallString<16>()); + IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>()); } static void InfoMapping(IO &IO, Info &I) { @@ -183,6 +184,7 @@ static void mapping(IO &IO, FieldTypeInfo &I) { TypeInfoMapping(IO, I); IO.mapOptional("Name", I.Name, SmallString<16>()); + IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>()); } }; diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp --- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp @@ -511,7 +511,7 @@ std::vector Args; Args.push_back("-fmodules-ts"); ExtractInfosFromCodeWithArgs(R"raw(export module M; -int moduleFunction(int x); +int moduleFunction(int x, double d = 3.2 - 1.0); static int staticModuleFunction(int x); export double exportedModuleFunction(double y);)raw", 2, /*Public=*/true, Infos, Args); @@ -523,6 +523,8 @@ F.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); F.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); F.Params.emplace_back("int", "x"); + F.Params.emplace_back("double", "d"); + F.Params.back().DefaultValue = "3.2 - 1.0"; F.Access = AccessSpecifier::AS_none; ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F)); CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction); diff --git a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp --- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp @@ -209,6 +209,8 @@ I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default, "path/to/void"); I.Params.emplace_back("int", "path/to/int", "P"); + I.Params.emplace_back("double", "path/to/double", "D"); + I.Params.back().DefaultValue = "2.0 * M_PI"; I.IsMethod = true; I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record); @@ -240,6 +242,11 @@ Name: 'int' Path: 'path/to/int' Name: 'P' + - Type: + Name: 'double' + Path: 'path/to/double' + Name: 'D' + DefaultValue: '2.0 * M_PI' ReturnType: Type: Name: 'void'