From 2af7f28370626fb2ededee8d66535a11cfad4a03 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Fri, 21 Feb 2025 16:06:19 -0300 Subject: [PATCH] best match corpus lookup algorithm #feat --- .github/workflows/ci.yml | 4 +- src/lib/AST/ParseRef.cpp | 115 +++-- src/lib/AST/ParseRef.hpp | 2 + src/lib/Lib/CorpusImpl.cpp | 463 +++++++++++------- src/lib/Lib/CorpusImpl.hpp | 32 +- .../Metadata/Finalizers/JavadocFinalizer.cpp | 33 +- .../Metadata/Finalizers/JavadocFinalizer.hpp | 4 - src/lib/Metadata/Type.cpp | 18 +- .../javadoc/copydoc/decay-params.adoc | 227 +++++++++ .../javadoc/copydoc/decay-params.cpp | 37 ++ .../javadoc/copydoc/decay-params.html | 290 +++++++++++ .../javadoc/copydoc/decay-params.xml | 90 ++++ .../javadoc/copydoc/no-param.adoc | 212 ++++++++ .../golden-tests/javadoc/copydoc/no-param.cpp | 38 ++ .../javadoc/copydoc/no-param.html | 258 ++++++++++ .../golden-tests/javadoc/copydoc/no-param.xml | 91 ++++ .../{ref => copydoc}/operator-param.adoc | 10 + .../{ref => copydoc}/operator-param.cpp | 0 .../{ref => copydoc}/operator-param.html | 15 + .../{ref => copydoc}/operator-param.xml | 6 + 20 files changed, 1666 insertions(+), 279 deletions(-) create mode 100644 test-files/golden-tests/javadoc/copydoc/decay-params.adoc create mode 100644 test-files/golden-tests/javadoc/copydoc/decay-params.cpp create mode 100644 test-files/golden-tests/javadoc/copydoc/decay-params.html create mode 100644 test-files/golden-tests/javadoc/copydoc/decay-params.xml create mode 100644 test-files/golden-tests/javadoc/copydoc/no-param.adoc create mode 100644 test-files/golden-tests/javadoc/copydoc/no-param.cpp create mode 100644 test-files/golden-tests/javadoc/copydoc/no-param.html create mode 100644 test-files/golden-tests/javadoc/copydoc/no-param.xml rename test-files/golden-tests/javadoc/{ref => copydoc}/operator-param.adoc (90%) rename test-files/golden-tests/javadoc/{ref => copydoc}/operator-param.cpp (100%) rename test-files/golden-tests/javadoc/{ref => copydoc}/operator-param.html (91%) rename test-files/golden-tests/javadoc/{ref => copydoc}/operator-param.xml (89%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff14fa77b0..971bc8e1fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -659,6 +659,8 @@ jobs: - name: Generate Demos run: | + set -x + declare -a generators=( "adoc" "xml" @@ -670,7 +672,7 @@ jobs: for generator in "${generators[@]}"; do [[ $generator = xml && $variant = multi ]] && continue [[ $variant = multi ]] && multipage="true" || multipage="false" - mrdocs --config="$(pwd)/boost/libs/url/doc/mrdocs.yml" "../CMakeLists.txt" --output="$(pwd)/demos/boost-url/$variant/$generator" --multipage=$multipage --generate="$generator" + mrdocs --config="$(pwd)/boost/libs/url/doc/mrdocs.yml" "../CMakeLists.txt" --output="$(pwd)/demos/boost-url/$variant/$generator" --multipage=$multipage --generate="$generator" --log-level=debug echo "Number of files in demos/boost-url/$variant/$generator: $(find demos/boost-url/$variant/$generator -type f | wc -l)" done done diff --git a/src/lib/AST/ParseRef.cpp b/src/lib/AST/ParseRef.cpp index 6fb78eba9b..b1dffb8a71 100644 --- a/src/lib/AST/ParseRef.cpp +++ b/src/lib/AST/ParseRef.cpp @@ -85,12 +85,14 @@ class RefParser } MRDOCS_CHECK_OR(parseComponents(), false); skipWhitespace(); - if (peek('(')) + result_.HasFunctionParameters = peek('(', ' '); + if (result_.HasFunctionParameters) { ParsedMemberFunctionSuffix functionParameters; MRDOCS_CHECK_OR(parseFunctionSuffix(functionParameters), false); result_.FunctionParameters = std::move(functionParameters.Params); result_.IsVariadic = functionParameters.IsVariadic; + result_.ExceptionSpec = std::move(functionParameters.ExceptionSpec); result_.IsConst = functionParameters.IsConst; result_.IsVolatile = functionParameters.IsVolatile; result_.Kind = functionParameters.Kind; @@ -647,6 +649,7 @@ class RefParser // this? decl-specifier-seq char const* start = ptr_; + skipWhitespace(); if (!parseLiteral('(')) { ptr_ = start; @@ -934,6 +937,8 @@ class RefParser if (contains_any(specifiers, {"signed", "unsigned"})) { bool explicitlySigned = contains(specifiers, "signed"); + std::string_view signStr = explicitlySigned ? "signed" : "unsigned"; + // Infer basic fundamental type from "signed" or "unsigned" if (!dest) { NamedTypeInfo NTI; @@ -942,42 +947,29 @@ class RefParser NTI.Name = NI; dest = NTI; } - else + // Check if the type is named + if (!dest->isNamed()) { - if (!dest->isNamed()) - { - if (explicitlySigned) - { - setError("expected type for 'signed' specifier"); - } - else - { - setError("expected type for 'unsigned' specifier"); - } - ptr_ = start; - return false; - } - if (auto& namedParam = dynamic_cast(*dest); - namedParam.Name->Name != "int" && - namedParam.Name->Name != "char") - { - if (explicitlySigned) - { - setError(start, "expected 'int' or 'char' for 'signed' specifier"); - } - else - { - setError(start, "expected 'int' or 'char' for 'unsigned' specifier"); - } - ptr_ = start; - return false; - } + setError(fmt::format("expected named type for '{}' specifier", signStr)); + ptr_ = start; + return false; } + // Check if the type is "int" or "char" + auto& namedParam = dynamic_cast(*dest); + if (!contains({"int", "char"}, namedParam.Name->Name)) + { + setError(fmt::format("expected 'int' or 'char' for '{}' specifier", signStr)); + ptr_ = start; + return false; + } + // Add the specifier to the type name + namedParam.Name->Name = fmt::format("{} {}", signStr, namedParam.Name->Name); } // - "short" can be combined with int. if (contains(specifiers, "short")) { + // Infer basic fundamental type from "short" if (!dest) { NamedTypeInfo NTI; @@ -986,27 +978,29 @@ class RefParser NTI.Name = NI; dest = NTI; } - else + // Check if the type is named + if (!dest->isNamed()) { - if (!dest->isNamed()) - { - setError(start, "expected type for 'short' specifier"); - ptr_ = start; - return false; - } - if (auto& namedParam = dynamic_cast(*dest); - namedParam.Name->Name != "int") - { - setError(start, "expected 'int' for 'short' specifier"); - ptr_ = start; - return false; - } + setError(start, "expected named type for 'short' specifier"); + ptr_ = start; + return false; } + // Check if the type is "int" + auto& namedParam = dynamic_cast(*dest); + if (!contains({"int", "signed int", "unsigned int"}, namedParam.Name->Name)) + { + setError(start, "expected 'int' for 'short' specifier"); + ptr_ = start; + return false; + } + // Add the specifier to the type name + namedParam.Name->Name = fmt::format("short {}", namedParam.Name->Name); } // - "long" can be combined with "int", "double" and "long" if (contains(specifiers, "long")) { + // Infer basic fundamental type from "long" if (!dest) { NamedTypeInfo NTI; @@ -1015,26 +1009,26 @@ class RefParser NTI.Name = NI; dest = NTI; } - else + // Check if the type is named + if (!dest->isNamed()) { - if (!dest->isNamed()) - { - setError(start, "expected type for 'long' specifier"); - ptr_ = start; - return false; - } - if (auto& namedParam = dynamic_cast(*dest); - namedParam.Name->Name != "int" && - namedParam.Name->Name != "double" && - namedParam.Name->Name != "long") - { - setError(start, "expected 'int', 'double' or 'long' for 'long' specifier"); - ptr_ = start; - return false; - } + setError(start, "expected named type for 'long' specifier"); + ptr_ = start; + return false; + } + auto& namedParam = dynamic_cast(*dest); + if (!contains({"int", "signed int", "unsigned int", "double"}, namedParam.Name->Name)) + { + setError(start, "expected 'int' or 'double' for 'long' specifier"); + ptr_ = start; + return false; } + // Add the specifier to the type name + bool const isLongLong = contains_n(specifiers, "long", 2); + namedParam.Name->Name = fmt::format("{} {}", isLongLong ? "long long" : "long", namedParam.Name->Name); } + // Final check: if dest is still empty, we have an error if (!dest) { ptr_ = start; @@ -1042,6 +1036,7 @@ class RefParser return false; } + // Set cv qualifiers dest->IsConst = contains(specifiers, "const"); dest->IsVolatile = contains(specifiers, "volatile"); diff --git a/src/lib/AST/ParseRef.hpp b/src/lib/AST/ParseRef.hpp index 153c9e6fbc..8ea15152d4 100644 --- a/src/lib/AST/ParseRef.hpp +++ b/src/lib/AST/ParseRef.hpp @@ -60,12 +60,14 @@ struct ParsedRef { llvm::SmallVector Components; // The following are populated when the last element is a function + bool HasFunctionParameters = false; llvm::SmallVector, 8> FunctionParameters; bool IsVariadic = false; bool IsExplicitObjectMemberFunction = false; ReferenceKind Kind = ReferenceKind::None; bool IsConst = false; bool IsVolatile = false; + NoexceptInfo ExceptionSpec; }; Expected diff --git a/src/lib/Lib/CorpusImpl.cpp b/src/lib/Lib/CorpusImpl.cpp index c62943cc80..c5c7dda4a5 100644 --- a/src/lib/Lib/CorpusImpl.cpp +++ b/src/lib/Lib/CorpusImpl.cpp @@ -84,141 +84,96 @@ find(SymbolID const& id) const noexcept } namespace { -template -Info const* -memberMatches( - InfoSet const& info, - SymbolID const& MId, - ParsedRefComponent const& c, - ParsedRef const& s) +bool +isTransparent(Info const& info) { - auto const memberIt = info.find(MId); - MRDOCS_CHECK_OR(memberIt != info.end(), nullptr); - Info const* memberPtr = memberIt->get(); - MRDOCS_CHECK_OR(memberPtr, nullptr); - Info const& member = *memberPtr; - - auto isMatch = visit(member, [&](MInfoTy const& M) + return visit(info, []( + InfoTy const& I) -> bool { - // Name match - if constexpr (requires { { M.OverloadedOperator } -> std::same_as; }) - { - if (c.Operator != OperatorKind::None) - { - MRDOCS_CHECK_OR(M.OverloadedOperator == c.Operator, false); - } - else - { - MRDOCS_CHECK_OR(member.Name == c.Name, false); - } - } - else - { - MRDOCS_CHECK_OR(member.Name == c.Name, false); - } - - if constexpr (checkTemplateArguments) + if constexpr (InfoTy::isNamespace()) { - if constexpr (requires { M.Template; }) - { - std::optional const& templateInfo = M.Template; - MRDOCS_CHECK_OR(templateInfo.has_value(), false); - MRDOCS_CHECK_OR(templateInfo->Params.size() == c.TemplateArguments.size(), false); - } - else - { - return false; - } + return I.IsInline; } - - if constexpr (checkFunctionParameters) + if constexpr (InfoTy::isEnum()) { - if constexpr (MInfoTy::isFunction()) - { - MRDOCS_CHECK_OR(M.Params.size() == s.FunctionParameters.size(), false); - } - else - { - return false; - } + return !I.Scoped; } - - return true; + return false; }); - if (isMatch) - { - return memberPtr; - } - return nullptr; } -template -Info const* -findMemberMatch( +SymbolID +findFirstParentInfo( InfoSet const& info, - Info const& context, - ParsedRefComponent const& c, - ParsedRef const& s) + SymbolID const& contextID) { - if constexpr (checkTemplateArguments) - { - MRDOCS_CHECK_OR(c.isSpecialization(), nullptr); - } - if constexpr (checkFunctionParameters) - { - MRDOCS_CHECK_OR(!s.FunctionParameters.empty(), nullptr); - } + SymbolID currentID = contextID; - return visit(context, [&](CInfoTy const& C) - -> Info const* + while (true) { - if constexpr (InfoParent) + auto const contextIt = info.find(currentID); + MRDOCS_CHECK_OR(contextIt != info.end(), SymbolID::invalid); + auto& contextUniquePtr = *contextIt; + MRDOCS_CHECK_OR(contextUniquePtr, SymbolID::invalid); + auto& context = *contextUniquePtr; + bool const isParent = visit(context, []( + InfoTy const& I) -> bool { - for (SymbolID const& MId : allMembers(C)) - { - auto const memberIt = info.find(MId); - MRDOCS_CHECK_OR_CONTINUE(memberIt != info.end()); - Info const* memberPtr = memberIt->get(); - MRDOCS_CHECK_OR_CONTINUE(memberPtr); - Info const& member = *memberPtr; - if (member.isOverloads()) - { - if (Info const* r = findMemberMatch< - checkTemplateArguments, - checkFunctionParameters>(info, member, c, s)) - { - return r; - } - } - - if (Info const* r = memberMatches< - checkTemplateArguments, checkFunctionParameters>( - info, MId, c, s)) - { - return r; - } - } + return InfoParent; + }); + if (isParent) + { + return context.id; } - return nullptr; - }); + currentID = context.Parent; + } } bool -isTransparent(Info const& info) +isDecayedEqual( + Polymorphic const& lhs, + Polymorphic const& rhs) { - return visit(info, []( - InfoTy const& I) -> bool + // When comparing two parameters, we need to compare + // them as if they are decayed at the top level + // the same way function parameters are decayed to + // consider if they redefine an overload. + if (lhs == rhs) { - if constexpr (InfoTy::isNamespace()) - { - return I.IsInline; - } - if constexpr (InfoTy::isEnum()) - { - return !I.Scoped; - } - return false; - }); + return true; + } + + // const and volatile are ignored at the top level + auto lhsDecay = lhs; + lhsDecay->IsConst = false; + lhsDecay->IsVolatile = false; + auto rhsDecay = rhs; + rhsDecay->IsConst = false; + rhsDecay->IsVolatile = false; + + // Arrays decay to pointer + if (lhsDecay->isArray()) + { + auto& lhsAsArray = dynamic_cast(*lhsDecay); + PointerTypeInfo lhsAsPtr; + lhsAsPtr.PointeeType = std::move(lhsAsArray.ElementType); + // Copy all fields from base type + dynamic_cast(lhsAsPtr) = dynamic_cast(lhsAsArray); + lhsAsPtr.Kind = TypeKind::Pointer; + lhsDecay = std::move(lhsAsPtr); + } + if (rhsDecay->isArray()) + { + auto& rhsAsArray = dynamic_cast(*rhsDecay); + PointerTypeInfo rhsAsPtr; + rhsAsPtr.PointeeType = std::move(rhsAsArray.ElementType); + // Copy all fields from base type + dynamic_cast(rhsAsPtr) = dynamic_cast(rhsAsArray); + rhsAsPtr.Kind = TypeKind::Pointer; + rhsDecay = std::move(rhsAsPtr); + } + + return lhsDecay == rhsDecay; } } @@ -239,35 +194,42 @@ lookup(SymbolID const& context, std::string_view name) template Expected> CorpusImpl:: -lookupImpl(Self&& self, SymbolID const& context, std::string_view name) +lookupImpl(Self&& self, SymbolID const& contextId0, std::string_view name) { + report::trace("Looking up '{}'", name); if (name.starts_with("::")) { return lookupImpl(self, SymbolID::global, name.substr(2)); } - if (auto [info, found] = self.lookupCacheGet(context, name); found) + // Skip contexts that can't have members + SymbolID const contextId = findFirstParentInfo(self.info_, contextId0); + MRDOCS_CHECK(contextId != SymbolID::invalid, formatError("Failed to find '{}'", contextId0)); + report::trace(" Context: '{}'", contextId); + if (auto [info, found] = self.lookupCacheGet(contextId, name); + found) { if (!info) { return Unexpected(formatError( "Failed to find '{}' from context '{}'", name, - self.Corpus::qualifiedName(*self.find(context)))); + self.Corpus::qualifiedName(*self.find(contextId)))); } return std::cref(*info); } - Expected const s = parseRef(name); - if (!s) + Expected const expRef = parseRef(name); + if (!expRef) { - return Unexpected(formatError("Failed to parse '{}'\n {}", name, s.error().reason())); + return Unexpected(formatError("Failed to parse '{}'\n {}", name, expRef.error().reason())); } - Info const* res = lookupImpl(self, context, *s, name, false); + ParsedRef const& ref = *expRef; + Info const* res = lookupImpl(self, contextId, ref, name, false); if (!res) { - auto const contextPtr = self.find(context); + auto const contextPtr = self.find(contextId); if (!contextPtr) { - return Unexpected(formatError("Failed to find '{}'", context)); + return Unexpected(formatError("Failed to find '{}'", contextId)); } return Unexpected(formatError( "Failed to find '{}' from context '{}'", @@ -283,10 +245,11 @@ CorpusImpl:: lookupImpl( Self&& self, SymbolID const& contextId, - ParsedRef const& s, + ParsedRef const& ref, std::string_view name, bool const cache) { + report::trace("Looking up parsed '{}'", name); if (cache) { if (auto [info, found] = self.lookupCacheGet(contextId, name); found) @@ -297,27 +260,29 @@ lookupImpl( Info const* contextPtr = self.find(contextId); MRDOCS_CHECK_OR(contextPtr, nullptr); + report::trace(" Context: '{}'", contextPtr->Name); // Check the current contextId - Info const* cur = contextPtr; - for (std::size_t i = 0; i < s.Components.size(); ++i) + Info const* curContext = contextPtr; + for (std::size_t i = 0; i < ref.Components.size(); ++i) { - ParsedRefComponent const& c = s.Components[i]; - cur = self.lookupImpl(cur->id, c, s, i == s.Components.size() - 1); - if (!cur) + ParsedRefComponent const& component = ref.Components[i]; + bool const isLast = i == ref.Components.size() - 1; + curContext = self.lookupImpl(curContext->id, component, ref, isLast); + if (!curContext) { break; } } - if (cur) + if (curContext) { - self.lookupCacheSet(contextId, name, cur); - return cur; + self.lookupCacheSet(contextId, name, curContext); + return curContext; } // Fallback to parent contextId Info const& contextInfo = *contextPtr; - Info const* res = lookupImpl(self, contextInfo.Parent, s, name, true); + Info const* res = lookupImpl(self, contextInfo.Parent, ref, name, true); self.lookupCacheSet(contextId, name, res); return res; } @@ -326,74 +291,206 @@ Info const* CorpusImpl:: lookupImpl( SymbolID const& contextId, - ParsedRefComponent const& c, - ParsedRef const& s, + ParsedRefComponent const& component, + ParsedRef const& ref, bool const checkParameters) const { - // Find context - auto const contextIt = info_.find(contextId); - MRDOCS_CHECK_OR(contextIt != info_.end(), nullptr); - Info const* contextPtr = contextIt->get(); + report::trace("Looking up component '{}'", component.Name); + // 1. Find context + Info const* contextPtr = this->find(contextId); MRDOCS_CHECK_OR(contextPtr, nullptr); + report::trace(" Context: '{}'", contextPtr->Name); + + // If context is a typedef, lookup in the resolved type + if (auto* TI = dynamic_cast(contextPtr)) + { + MRDOCS_CHECK_OR(TI->Type, nullptr); + SymbolID resolvedSymbolID = TI->Type->namedSymbol(); + contextPtr = this->find(resolvedSymbolID); + MRDOCS_CHECK_OR(contextPtr, nullptr); + } Info const& context = *contextPtr; - if (checkParameters) + // 2. Get a list of members + report::trace(" Finding members of context '{}'", contextPtr->Name); + SmallVector memberIDs; + auto pushAllMembersOf = [&](Info const& I) { - if (Info const* r = findMemberMatch(info_, context, c, s)) + visit(I, [&](CInfoTy const& C) -> Info const* { - return r; - } + if constexpr (InfoParent) + { + for (SymbolID const& MId : allMembers(C)) + { + memberIDs.push_back(MId); + } + } + return nullptr; + }); + }; + pushAllMembersOf(context); + MRDOCS_CHECK_OR(!memberIDs.empty(), nullptr); + + // If a member is overloads, we also push the specific overloads + std::size_t const rootMembersSize = memberIDs.size(); + for (std::size_t i = 0; i < rootMembersSize; ++i) + { + SymbolID const& id = memberIDs[i]; + Info const* I = find(id); + MRDOCS_CHECK_OR_CONTINUE(I); + MRDOCS_CHECK_OR_CONTINUE(I->isOverloads()); + pushAllMembersOf(*I); + } - if (Info const* r = findMemberMatch(info_, context, c, s)) + // 3. Find the member that matches the component + enum class MatchLevel { + None, + Name, + TemplateArgsSize, + TemplateArgs, + FunctionParametersSize, + FunctionParametersSizeAndDocumented, + FunctionParameters, + Qualifiers, + NoExceptDefinition, + NoExceptKind, + NoExceptOperand + }; + auto const highestMatchLevel = + !checkParameters || !ref.HasFunctionParameters ? + MatchLevel::TemplateArgsSize : + MatchLevel::Qualifiers; + auto matchLevel = MatchLevel::None; + Info const* res = nullptr; + for (SymbolID const& memberID : memberIDs) + { + Info const* memberPtr = find(memberID); + MRDOCS_CHECK_OR_CONTINUE(memberPtr); + Info const& member = *memberPtr; + report::trace(" Attempting to match {} '{}'", toString(member.Kind), member.Name); + MatchLevel const memberMatchLevel = + visit(member, [&](MInfoTy const& M) + -> MatchLevel { - return r; - } - } + auto matchRes = MatchLevel::None; - if (Info const* r = findMemberMatch(info_, context, c, s)) - { - return r; - } + // Name match + if constexpr (requires { { M.OverloadedOperator } -> std::same_as; }) + { + if (component.Operator != OperatorKind::None) + { + MRDOCS_CHECK_OR(M.OverloadedOperator == component.Operator, matchRes); + } + else + { + MRDOCS_CHECK_OR(member.Name == component.Name, matchRes); + } + } + else + { + MRDOCS_CHECK_OR(member.Name == component.Name, matchRes); + } + matchRes = MatchLevel::Name; - if (Info const* r = findMemberMatch(info_, context, c, s)) - { - return r; + // Template arguments match + if constexpr (requires { M.Template; }) + { + std::optional const& templateInfo = M.Template; + if (component.TemplateArguments.empty()) + { + MRDOCS_CHECK_OR( + !templateInfo.has_value() || + templateInfo->Args.empty(), matchRes); + } + else + { + MRDOCS_CHECK_OR( + templateInfo.has_value() && + templateInfo->Args.size() == component.TemplateArguments.size(), matchRes); + } + } + else + { + MRDOCS_CHECK_OR(component.TemplateArguments.empty(), matchRes); + } + matchRes = MatchLevel::TemplateArgsSize; + + // Function parameters size match + MRDOCS_CHECK_OR(checkParameters && ref.HasFunctionParameters, matchRes); + MRDOCS_CHECK_OR(MInfoTy::isFunction(), matchRes); + auto const& F = dynamic_cast(M); + MRDOCS_CHECK_OR(F.Params.size() == ref.FunctionParameters.size(), matchRes); + matchRes = MatchLevel::FunctionParametersSize; + + // Function parameters size and documented match + // This is an intermediary level because among choices that + // doesn't exactly match the function parameters, we prefer + // the one that is documented as the most "natural" choice. + if (F.javadoc) + { + matchRes = MatchLevel::FunctionParametersSizeAndDocumented; + } + + // Function parameters match + MRDOCS_CHECK_OR(F.IsExplicitObjectMemberFunction == ref.IsExplicitObjectMemberFunction, matchRes); + for (std::size_t i = 0; i < F.Params.size(); ++i) + { + auto& lhsType = F.Params[i].Type; + auto& rhsType = ref.FunctionParameters[i]; + MRDOCS_CHECK_OR(isDecayedEqual(lhsType, rhsType), matchRes); + } + MRDOCS_CHECK_OR(F.IsVariadic == ref.IsVariadic, matchRes); + matchRes = MatchLevel::FunctionParameters; + + // Qualifiers match + MRDOCS_CHECK_OR(F.RefQualifier == ref.Kind, matchRes); + MRDOCS_CHECK_OR(F.IsConst == ref.IsConst, matchRes); + MRDOCS_CHECK_OR(F.IsVolatile == ref.IsVolatile, matchRes); + matchRes = MatchLevel::Qualifiers; + + // Noexcept match + MRDOCS_CHECK_OR(F.Noexcept.Implicit == ref.ExceptionSpec.Implicit, matchRes); + matchRes = MatchLevel::NoExceptDefinition; + MRDOCS_CHECK_OR(F.Noexcept.Kind == ref.ExceptionSpec.Kind, matchRes); + matchRes = MatchLevel::NoExceptKind; + MRDOCS_CHECK_OR(F.Noexcept.Operand == ref.ExceptionSpec.Operand, matchRes); + matchRes = MatchLevel::NoExceptOperand; + return matchRes; + }); + if (memberMatchLevel > matchLevel) + { + res = &member; + matchLevel = memberMatchLevel; + // Early exit if the matchMatchLevel is the highest possible + // for the component and the parsed reference + if (matchLevel >= highestMatchLevel) + { + break; + } + } } - // Fallback to members of resolved typedefs - if (context.isTypedef()) + // If we found a match, return it + if (matchLevel != MatchLevel::None) { - auto* TI = dynamic_cast(&context); - return lookupImpl(TI->Type->namedSymbol(), c, s, checkParameters); + return res; } - // Fallback to transparent contexts - Info const* r = visit(context, [&]( - InfoTy const& I) -> Info const* + // Else, fallback to transparent contexts + report::trace(" Looking up in transparent contexts"); + for (SymbolID const& memberID : memberIDs) { - if constexpr (InfoParent) + Info const* memberPtr = find(memberID); + MRDOCS_CHECK_OR_CONTINUE(memberPtr); + Info const& member = *memberPtr; + MRDOCS_CHECK_OR_CONTINUE(isTransparent(member)); + if (Info const* r = lookupImpl(member.id, component, ref, checkParameters)) { - for (SymbolID const& MId : allMembers(I)) - { - Info const* memberPtr = find(MId); - MRDOCS_CHECK_OR(memberPtr, nullptr); - Info const& member = *memberPtr; - if (isTransparent(member)) - { - if (auto* r1 = lookupImpl(MId, c, s, checkParameters)) - { - return r1; - } - } - } + return r; } - return nullptr; - }); - if (r) - { - return r; } + // If we didn't find a match, return nullptr return nullptr; } @@ -420,11 +517,11 @@ lookupCacheGet( void CorpusImpl:: lookupCacheSet( - SymbolID const& context, + SymbolID const& contextId, std::string_view name, Info const* info) { - lookupCache_[context][std::string(name)] = info; + lookupCache_[contextId][std::string(name)] = info; } diff --git a/src/lib/Lib/CorpusImpl.hpp b/src/lib/Lib/CorpusImpl.hpp index d3a1b8a0ce..a068eaeb2a 100644 --- a/src/lib/Lib/CorpusImpl.hpp +++ b/src/lib/Lib/CorpusImpl.hpp @@ -117,6 +117,30 @@ class CorpusImpl final : public Corpus std::views::common; } + /** Return a range of constant Info objects for the specified Symbol IDs. + */ + template R> + auto + find(R&& range) const + { + return + std::views::transform( + range, + [this](SymbolID const& id) -> Info const* + { + return this->find(id); + }) | + std::views::filter([](Info const* info) + { + return info != nullptr; + }) | + std::views::transform([](Info const* info) -> Info const& + { + return *info; + }) | + std::views::common; + } + Expected> lookup(SymbolID const& context, std::string_view name) const override; @@ -170,7 +194,7 @@ class CorpusImpl final : public Corpus Expected> lookupImpl( Self&& self, - SymbolID const& context, + SymbolID const& contextId, std::string_view name); template @@ -179,15 +203,15 @@ class CorpusImpl final : public Corpus lookupImpl( Self&& self, SymbolID const& context, - ParsedRef const& s, + ParsedRef const& ref, std::string_view name, bool cache); Info const* lookupImpl( SymbolID const& contextId, - ParsedRefComponent const& c, - ParsedRef const& s, + ParsedRefComponent const& component, + ParsedRef const& ref, bool checkParameters) const; std::pair diff --git a/src/lib/Metadata/Finalizers/JavadocFinalizer.cpp b/src/lib/Metadata/Finalizers/JavadocFinalizer.cpp index 82ec5ec3ef..2ce05a3585 100644 --- a/src/lib/Metadata/Finalizers/JavadocFinalizer.cpp +++ b/src/lib/Metadata/Finalizers/JavadocFinalizer.cpp @@ -22,6 +22,14 @@ operator()(InfoTy& I) MRDOCS_CHECK_OR(!finalized_.contains(&I)); finalized_.emplace(&I); + if constexpr (InfoTy::isOverloads()) + { + if (!I.javadoc) + { + populateOverloadJavadocs(I); + } + } + report::trace( "Finalizing javadoc for '{}'", corpus_.Corpus::qualifiedName(I)); @@ -320,11 +328,12 @@ copyBriefAndDetails(Javadoc& javadoc) { auto resPrimaryLoc = getPrimaryLocation(res); this->warn( - "{}: Failed to copy documentation from '{}' (no documentation available).\n" + "{}: Failed to copy documentation from {} '{}' (no documentation available).\n" " No documentation available.\n" " {}:{}\n" " Note: No documentation available for '{}'.", corpus_.Corpus::qualifiedName(*current_context_), + toString(res.Kind), copied->string, resPrimaryLoc->FullPath, resPrimaryLoc->LineNumber, @@ -647,19 +656,6 @@ checkExists(SymbolID const& id) const MRDOCS_ASSERT(corpus_.info_.contains(id)); } -void -JavadocFinalizer:: -generateOverloadJavadocs() -{ - for (auto& I: corpus_.info_) - { - if (auto* O = dynamic_cast(I.get())) - { - populateOverloadJavadocs(*O); - } - } -} - namespace { template bool @@ -1107,6 +1103,15 @@ populateOverloadJavadocs(OverloadsInfo& I) return *dynamic_cast(infoPtr); }); + // Ensure all the members are initialized + for (FunctionInfo const& function: functions) + { + if (!finalized_.contains(&function)) + { + operator()(const_cast(function)); + } + } + I.javadoc.emplace(); // blocks: we do not copy javadoc detail blocks because // it's impossible to guarantee that the details for diff --git a/src/lib/Metadata/Finalizers/JavadocFinalizer.hpp b/src/lib/Metadata/Finalizers/JavadocFinalizer.hpp index 1883b23660..09683c8349 100644 --- a/src/lib/Metadata/Finalizers/JavadocFinalizer.hpp +++ b/src/lib/Metadata/Finalizers/JavadocFinalizer.hpp @@ -91,7 +91,6 @@ class JavadocFinalizer MRDOCS_CHECK_OR_CONTINUE(I->Extraction != ExtractionMode::Dependency); visit(*I, *this); } - generateOverloadJavadocs(); emitWarnings(); } @@ -203,9 +202,6 @@ class JavadocFinalizer })); } - void - generateOverloadJavadocs(); - void populateOverloadJavadocs(OverloadsInfo&); diff --git a/src/lib/Metadata/Type.cpp b/src/lib/Metadata/Type.cpp index 2397071b7e..7db9df5cdf 100644 --- a/src/lib/Metadata/Type.cpp +++ b/src/lib/Metadata/Type.cpp @@ -324,16 +324,6 @@ operator<=>(NamedTypeInfo const& other) const { return br; } - if (auto const br = IsConst <=> other.IsConst; - !std::is_eq(br)) - { - return br; - } - if (auto const br = IsVolatile <=> other.IsVolatile; - !std::is_eq(br)) - { - return br; - } return Name <=> other.Name; } @@ -487,11 +477,13 @@ operator<=>(Polymorphic const& lhs, Polymorphic const& rhs) { if (lhs && rhs) { - if (lhs->Kind == rhs->Kind) + auto& lhsRef = *lhs; + auto& rhsRef = *rhs; + if (lhsRef.Kind == rhsRef.Kind) { - return visit(*lhs, detail::VisitCompareFn(*rhs)); + return visit(lhsRef, detail::VisitCompareFn(rhsRef)); } - return lhs->Kind <=> rhs->Kind; + return lhsRef.Kind <=> rhsRef.Kind; } return !lhs ? std::strong_ordering::less : std::strong_ordering::greater; diff --git a/test-files/golden-tests/javadoc/copydoc/decay-params.adoc b/test-files/golden-tests/javadoc/copydoc/decay-params.adoc new file mode 100644 index 0000000000..4712a5f0b5 --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/decay-params.adoc @@ -0,0 +1,227 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + + +=== Functions + +[cols=2] +|=== +| Name +| Description + +| <> +| Brief from `foo()` + +| <> +| `foo` overloads + +|=== + +[#bar] +== bar + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<decay‐params.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +bar(int* a); +---- + +=== Description + + +This is the function original documentation for the foo function with an array parameter. + + + +=== Return Value + + +A boolean value. + +=== Parameters + + +|=== +| Name | Description + +| *a* +| An array of integers. + +|=== + +[#foo-05] +== foo + + +`foo` overloads + +=== Synopses + + +Declared in `<decay‐params.cpp>` + +We should not copy this doc + + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +void +<>(); +---- + +[.small]#<># + +We should not copy this doc + + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +void +<>(int a); +---- + +[.small]#<># + +Brief from `foo()` + + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +<>(int a[3]); +---- + +[.small]#<># + +=== Return Value + + +A boolean value. + +=== Parameters + + +|=== +| Name | Description + +| *a* +| An integer. + +|=== + +[#foo-0c] +== foo + + +We should not copy this doc + +=== Synopsis + + +Declared in `<decay‐params.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +void +foo(); +---- + +=== Description + + +`bar` should not copy this documentation just because it has the same name and is simpler. + + + +[#foo-01] +== foo + + +We should not copy this doc + +=== Synopsis + + +Declared in `<decay‐params.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +void +foo(int a); +---- + +=== Description + + +`bar` should not copy this documentation just because it has the same number of parameters. + + + +=== Parameters + + +|=== +| Name | Description + +| *a* +| An integer. + +|=== + +[#foo-0e] +== foo + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<decay‐params.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +foo(int a[3]); +---- + +=== Description + + +This is the function original documentation for the foo function with an array parameter. + + + +=== Return Value + + +A boolean value. + +=== Parameters + + +|=== +| Name | Description + +| *a* +| An array of integers. + +|=== + + + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/javadoc/copydoc/decay-params.cpp b/test-files/golden-tests/javadoc/copydoc/decay-params.cpp new file mode 100644 index 0000000000..cefddff08a --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/decay-params.cpp @@ -0,0 +1,37 @@ +/** We should not copy this doc + + `bar` should not copy this documentation + just because it has the same name and is + simpler. + */ +void +foo(); + +/** We should not copy this doc + + `bar` should not copy this documentation + just because it has the same number of + parameters. + + @param a An integer. + */ +void +foo(int a); + +/** Brief from `foo()` + + This is the function original documentation + for the foo function with an array parameter. + + @param a An array of integers. + @return A boolean value. +*/ +constexpr +bool +foo(int a[3]); + +/** @copydoc foo(int*) + */ +constexpr +bool +bar(int *a); diff --git a/test-files/golden-tests/javadoc/copydoc/decay-params.html b/test-files/golden-tests/javadoc/copydoc/decay-params.html new file mode 100644 index 0000000000..0c95af19e6 --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/decay-params.html @@ -0,0 +1,290 @@ + + +Reference + + +
+

Reference

+
+
+

Global namespace

+
+

Functions

+ + + + + + + + + + + + + + +
NameDescription
bar Brief from foo() +
foo foo overloads +
+
+
+
+

bar

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <decay-params.cpp>
+
+
+constexpr
+bool
+bar(int* a);
+
+
+
+
+

Description

+

This is the function original documentation for the foo function with an array parameter.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
a

An array of integers.

+
+
+
+
+
+

foo

+
+foo overloads + + +
+
+
+

Synopses

+
+Declared in <decay-params.cpp>
+

+ We should not copy this doc + +

+ + +
+
+void
+foo();
+
+
» more... + +

+ We should not copy this doc + +

+ + +
+
+void
+foo(int a);
+
+
» more... + +

+ Brief from foo() + +

+ + +
+
+constexpr
+bool
+foo(int a[3]);
+
+
» more... + + +
+
+

Return Value

+

A boolean value.

+ +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
a

An integer.

+
+
+
+
+
+

foo

+
+We should not copy this doc + + +
+
+
+

Synopsis

+
+Declared in <decay-params.cpp>
+
+
+void
+foo();
+
+
+
+
+

Description

+

bar should not copy this documentation just because it has the same name and is simpler.

+ + +
+
+
+
+

foo

+
+We should not copy this doc + + +
+
+
+

Synopsis

+
+Declared in <decay-params.cpp>
+
+
+void
+foo(int a);
+
+
+
+
+

Description

+

bar should not copy this documentation just because it has the same number of parameters.

+ + +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
a

An integer.

+
+
+
+
+
+

foo

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <decay-params.cpp>
+
+
+constexpr
+bool
+foo(int a[3]);
+
+
+
+
+

Description

+

This is the function original documentation for the foo function with an array parameter.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
a

An array of integers.

+
+
+
+ +
+
+

Created with MrDocs

+
+ + \ No newline at end of file diff --git a/test-files/golden-tests/javadoc/copydoc/decay-params.xml b/test-files/golden-tests/javadoc/copydoc/decay-params.xml new file mode 100644 index 0000000000..bc59afe8b7 --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/decay-params.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + Brief from + foo() + + + This is the function original documentation for the foo function with an array parameter. + + + A boolean value. + + + An array of integers. + + + + + + + + We should not copy this doc + + + bar + should not copy this documentation just because it has the same name and is simpler. + + + + + + + + + + + We should not copy this doc + + + bar + should not copy this documentation just because it has the same number of parameters. + + + An integer. + + + + + + + + + + + + + + + + + Brief from + foo() + + + This is the function original documentation for the foo function with an array parameter. + + + A boolean value. + + + An array of integers. + + + + + diff --git a/test-files/golden-tests/javadoc/copydoc/no-param.adoc b/test-files/golden-tests/javadoc/copydoc/no-param.adoc new file mode 100644 index 0000000000..1d36c6313d --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/no-param.adoc @@ -0,0 +1,212 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + + +=== Functions + +[cols=2] +|=== +| Name +| Description + +| <> +| Brief from `foo()` + +| <> +| Brief from `foo()` + +| <> +| Brief from `foo()` + +|=== + +[#copyFromNoParam] +== copyFromNoParam + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<no‐param.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +copyFromNoParam(); +---- + +=== Description + + +This is the function original documentation for the foo function with no parameters. + +This documentation is copied from the page containing the foo overload with no parameters. + + + +=== Return Value + + +A boolean value. + +[#copyfromOverloads] +== copyfromOverloads + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<no‐param.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +copyfromOverloads(); +---- + +=== Description + + +This documentation is copied from the page containing all overloads of foo. + + + +=== Return Value + + +A boolean value. + +[#foo-05] +== foo + + +Brief from `foo()` + +=== Synopses + + +Declared in `<no‐param.cpp>` + +Brief from `foo()` + + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +<>(); +---- + +[.small]#<># + +Brief from `foo()` + + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +<>(char ch); +---- + +[.small]#<># + +=== Return Value + + +A boolean value. + +=== Parameters + + +|=== +| Name | Description + +| *ch* +| A character. + +|=== + +[#foo-0c] +== foo + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<no‐param.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +foo(); +---- + +=== Description + + +This is the function original documentation for the foo function with no parameters. + + + +=== Return Value + + +A boolean value. + +[#foo-0a] +== foo + + +Brief from `foo()` + +=== Synopsis + + +Declared in `<no‐param.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +constexpr +bool +foo(char ch); +---- + +=== Description + + +This is the function original documentation for the foo function with no parameters. + + + +=== Return Value + + +A boolean value. + +=== Parameters + + +|=== +| Name | Description + +| *ch* +| A character. + +|=== + + + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/javadoc/copydoc/no-param.cpp b/test-files/golden-tests/javadoc/copydoc/no-param.cpp new file mode 100644 index 0000000000..cacdba9dab --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/no-param.cpp @@ -0,0 +1,38 @@ +/** Brief from `foo()` + + This is the function original documentation + for the foo function with no parameters. + + @return A boolean value. +*/ +constexpr +bool +foo(); + +/** @copydoc foo() + + @param ch A character. + */ +constexpr +bool +foo(char ch); + +/** @copydoc foo() + + This documentation is copied from the + page containing the foo overload with + no parameters. + */ +constexpr +bool +copyFromNoParam(); + +/** @copydoc foo + + This documentation is copied from the + page containing all overloads of foo. + + */ +constexpr +bool +copyfromOverloads(); \ No newline at end of file diff --git a/test-files/golden-tests/javadoc/copydoc/no-param.html b/test-files/golden-tests/javadoc/copydoc/no-param.html new file mode 100644 index 0000000000..b84360c7e1 --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/no-param.html @@ -0,0 +1,258 @@ + + +Reference + + +
+

Reference

+
+
+

Global namespace

+
+

Functions

+ + + + + + + + + + + + + + + + +
NameDescription
copyFromNoParam Brief from foo() +
copyfromOverloads Brief from foo() +
foo Brief from foo() +
+
+
+
+

copyFromNoParam

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <no-param.cpp>
+
+
+constexpr
+bool
+copyFromNoParam();
+
+
+
+
+

Description

+

This is the function original documentation for the foo function with no parameters.

+

This documentation is copied from the page containing the foo overload with no parameters.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+
+
+

copyfromOverloads

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <no-param.cpp>
+
+
+constexpr
+bool
+copyfromOverloads();
+
+
+
+
+

Description

+

This documentation is copied from the page containing all overloads of foo.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+
+
+

foo

+
+Brief from foo() + + +
+
+
+

Synopses

+
+Declared in <no-param.cpp>
+

+ Brief from foo() + +

+ + +
+
+constexpr
+bool
+foo();
+
+
» more... + +

+ Brief from foo() + +

+ + +
+
+constexpr
+bool
+foo(char ch);
+
+
» more... + + +
+
+

Return Value

+

A boolean value.

+ +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
ch

A character.

+
+
+
+
+
+

foo

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <no-param.cpp>
+
+
+constexpr
+bool
+foo();
+
+
+
+
+

Description

+

This is the function original documentation for the foo function with no parameters.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+
+
+

foo

+
+Brief from foo() + + +
+
+
+

Synopsis

+
+Declared in <no-param.cpp>
+
+
+constexpr
+bool
+foo(char ch);
+
+
+
+
+

Description

+

This is the function original documentation for the foo function with no parameters.

+ + +
+
+

Return Value

+

A boolean value.

+ +
+
+

Parameters

+ + + + + + + + + + + + + +
NameDescription
ch

A character.

+
+
+
+ +
+
+

Created with MrDocs

+
+ + \ No newline at end of file diff --git a/test-files/golden-tests/javadoc/copydoc/no-param.xml b/test-files/golden-tests/javadoc/copydoc/no-param.xml new file mode 100644 index 0000000000..c99df570f5 --- /dev/null +++ b/test-files/golden-tests/javadoc/copydoc/no-param.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + Brief from + foo() + + + This is the function original documentation for the foo function with no parameters. + + + This documentation is copied from the page containing the foo overload with no parameters. + + + A boolean value. + + + + + + + + + + + + Brief from + foo() + + + This documentation is copied from the page containing all overloads of foo. + + + A boolean value. + + + + + + + + + + + + Brief from + foo() + + + This is the function original documentation for the foo function with no parameters. + + + A boolean value. + + + + + + + + + + + + + + + Brief from + foo() + + + This is the function original documentation for the foo function with no parameters. + + + A boolean value. + + + A character. + + + + + diff --git a/test-files/golden-tests/javadoc/ref/operator-param.adoc b/test-files/golden-tests/javadoc/copydoc/operator-param.adoc similarity index 90% rename from test-files/golden-tests/javadoc/ref/operator-param.adoc rename to test-files/golden-tests/javadoc/copydoc/operator-param.adoc index d968773684..4ce9329a70 100644 --- a/test-files/golden-tests/javadoc/ref/operator-param.adoc +++ b/test-files/golden-tests/javadoc/copydoc/operator-param.adoc @@ -54,6 +54,7 @@ Return true if ch is in the character set. Declared in `<operator‐param.cpp>` +Return true if ch is in the character set. [source,cpp,subs="verbatim,replacements,macros,-callouts"] @@ -97,6 +98,8 @@ True if ch is in the set, otherwise false. == <>::operator() +Return true if ch is in the character set. + === Synopsis @@ -109,6 +112,13 @@ bool operator()(char ch) const noexcept; ---- +=== Description + + +This function returns true if the character is in the set, otherwise it returns false. + + + === Return Value diff --git a/test-files/golden-tests/javadoc/ref/operator-param.cpp b/test-files/golden-tests/javadoc/copydoc/operator-param.cpp similarity index 100% rename from test-files/golden-tests/javadoc/ref/operator-param.cpp rename to test-files/golden-tests/javadoc/copydoc/operator-param.cpp diff --git a/test-files/golden-tests/javadoc/ref/operator-param.html b/test-files/golden-tests/javadoc/copydoc/operator-param.html similarity index 91% rename from test-files/golden-tests/javadoc/ref/operator-param.html rename to test-files/golden-tests/javadoc/copydoc/operator-param.html index 1bb741a61c..f63ab4b21e 100644 --- a/test-files/golden-tests/javadoc/ref/operator-param.html +++ b/test-files/golden-tests/javadoc/copydoc/operator-param.html @@ -68,6 +68,10 @@

A::operator()

Synopses

Declared in <operator-param.cpp>
+

+ Return true if ch is in the character set. + +

@@ -121,6 +125,11 @@ 

Parameters

A::operator()

+
+Return true if ch is in the character set. + + +

Synopsis

@@ -133,6 +142,12 @@

Synopsis

operator()(char ch) const noexcept;
+ +
+

Description

+

This function returns true if the character is in the set, otherwise it returns false.

+ +

Return Value

diff --git a/test-files/golden-tests/javadoc/ref/operator-param.xml b/test-files/golden-tests/javadoc/copydoc/operator-param.xml similarity index 89% rename from test-files/golden-tests/javadoc/ref/operator-param.xml rename to test-files/golden-tests/javadoc/copydoc/operator-param.xml index b38c14b977..40b24cea35 100644 --- a/test-files/golden-tests/javadoc/ref/operator-param.xml +++ b/test-files/golden-tests/javadoc/copydoc/operator-param.xml @@ -16,6 +16,12 @@ + + Return true if ch is in the character set. + + + This function returns true if the character is in the set, otherwise it returns false. + True if ch is in the set, otherwise false.