@@ -110,34 +110,34 @@ operator()(InfoTy& I)
110110
111111void
112112JavadocFinalizer::
113- finalize (doc::Reference& ref)
113+ finalize (doc::Reference& ref, bool const emitWarning )
114114{
115- Info const * res = corpus_. lookup (current_context_-> id , ref. string );
116- if (res )
115+ if (Expected< Info const *> res
116+ = corpus_. lookup (current_context_-> id , ref. string ) )
117117 {
118- ref.id = res->id ;
118+ Info const * resPtr = *res;
119+ MRDOCS_ASSERT (resPtr);
120+ ref.id = resPtr->id ;
119121 }
120- if (res == nullptr &&
122+ else if (
123+ emitWarning &&
121124 corpus_.config ->warnings &&
122125 corpus_.config ->warnBrokenRef &&
123126 // Only warn once per reference
124- !warned_ .contains ({ref.string , current_context_->Name }) &&
127+ !refWarned_ .contains ({ref.string , current_context_->Name }) &&
125128 // Ignore std:: references
126129 !ref.string .starts_with (" std::" ) &&
127130 // Ignore other reference types that can't be replaced by `...`
128131 ref.Kind == doc::NodeKind::reference)
129132 {
130133 MRDOCS_ASSERT (current_context_);
131- if (auto primaryLoc = getPrimaryLocation (*current_context_))
132- {
133- this ->warn (
134- " {}:{}\n {}: Failed to resolve reference to '{}'" ,
135- primaryLoc->FullPath ,
136- primaryLoc->LineNumber ,
137- corpus_.Corpus ::qualifiedName (*current_context_),
138- ref.string );
139- }
140- warned_.insert ({ref.string , current_context_->Name });
134+ this ->warn (
135+ " {}: Failed to resolve reference to '{}'\n "
136+ " {}" ,
137+ corpus_.Corpus ::qualifiedName (*current_context_),
138+ ref.string ,
139+ res.error ().reason ());
140+ refWarned_.insert ({ref.string , current_context_->Name });
141141 }
142142}
143143
@@ -154,11 +154,11 @@ finalize(doc::Node& node)
154154
155155 if constexpr (std::same_as<NodeTy, doc::Reference>)
156156 {
157- finalize (dynamic_cast <doc::Reference&>(N));
157+ finalize (dynamic_cast <doc::Reference&>(N), true );
158158 }
159159 else if constexpr (std::same_as<NodeTy, doc::Throws>)
160160 {
161- finalize (dynamic_cast <doc::Throws&>(N).exception );
161+ finalize (dynamic_cast <doc::Throws&>(N).exception , false );
162162 }
163163 });
164164}
@@ -280,62 +280,55 @@ copyBriefAndDetails(Javadoc& javadoc)
280280 }
281281
282282 // Find the node to copy from
283- Info const * res = corpus_.lookup (current_context_->id , copied->string );
284- if (!res)
283+ Expected< Info const *> res = corpus_.lookup (current_context_->id , copied->string );
284+ if (!res || !*res )
285285 {
286286 if (corpus_.config ->warnings &&
287287 corpus_.config ->warnBrokenRef &&
288- !warned_ .contains ({copied->string , current_context_->Name }))
288+ !refWarned_ .contains ({copied->string , current_context_->Name }))
289289 {
290- MRDOCS_ASSERT (current_context_);
291- auto primaryLoc = getPrimaryLocation (*current_context_);
292290 this ->warn (
293- " {}:{}\n "
294- " {}: Failed to copy documentation from '{}'\n "
295- " Note: Symbol '{}' not found." ,
296- primaryLoc->FullPath ,
297- primaryLoc->LineNumber ,
291+ " {}: Failed to copy documentation from '{}' (symbol not found)\n "
292+ " {}" ,
298293 corpus_.Corpus ::qualifiedName (*current_context_),
299294 copied->string ,
300- copied-> string );
295+ res. error (). reason () );
301296 }
302297 continue ;
303298 }
304299
305300 // Ensure the source node is finalized
306- if (!finalized_.contains (res))
301+ Info const * resPtr = *res;
302+ MRDOCS_ASSERT (resPtr);
303+ if (!finalized_.contains (resPtr))
307304 {
308- operator ()(const_cast <Info&>(*res ));
305+ operator ()(const_cast <Info&>(*resPtr ));
309306 }
310- if (!res ->javadoc )
307+ if (!resPtr ->javadoc )
311308 {
312309 if (corpus_.config ->warnings &&
313310 corpus_.config ->warnBrokenRef &&
314- !warned_ .contains ({copied->string , current_context_->Name }))
311+ !refWarned_ .contains ({copied->string , current_context_->Name }))
315312 {
316- auto ctxPrimaryLoc = getPrimaryLocation (*current_context_);
317- auto resPrimaryLoc = getPrimaryLocation (*res);
313+ auto resPrimaryLoc = getPrimaryLocation (*resPtr);
318314 this ->warn (
319- " {}:{}\n "
320- " {}: Failed to copy documentation from '{}'.\n "
321- " No documentation available.\n "
322- " {}:{}\n "
323- " Note: No documentation available for '{}'." ,
324- ctxPrimaryLoc->FullPath ,
325- ctxPrimaryLoc->LineNumber ,
315+ " {}: Failed to copy documentation from '{}' (no documentation available).\n "
316+ " No documentation available.\n "
317+ " {}:{}\n "
318+ " Note: No documentation available for '{}'." ,
326319 corpus_.Corpus ::qualifiedName (*current_context_),
327320 copied->string ,
328321 resPrimaryLoc->FullPath ,
329322 resPrimaryLoc->LineNumber ,
330- corpus_.Corpus ::qualifiedName (*res ));
323+ corpus_.Corpus ::qualifiedName (*resPtr ));
331324 }
332325 continue ;
333326 }
334327
335328 // Copy brief and details
336329 bool const copyBrief = copied->parts == doc::Parts::all || copied->parts == doc::Parts::brief;
337330 bool const copyDetails = copied->parts == doc::Parts::all || copied->parts == doc::Parts::description;
338- Javadoc const & src = *res ->javadoc ;
331+ Javadoc const & src = *resPtr ->javadoc ;
339332 if (copyBrief && !javadoc.brief )
340333 {
341334 javadoc.brief = src.brief ;
@@ -648,34 +641,54 @@ checkExists(SymbolID const& id) const
648641
649642void
650643JavadocFinalizer::
651- emitWarnings () const
644+ emitWarnings ()
652645{
653646 MRDOCS_CHECK_OR (corpus_.config ->warnings );
654647 warnUndocumented ();
655648 warnDocErrors ();
656649 warnNoParamDocs ();
657650 warnUndocEnumValues ();
651+
652+ // Print to the console
653+ auto const level = !corpus_.config ->warnAsError ? report::Level::warn : report::Level::error;
654+ for (auto const & [loc, msgs] : warnings_)
655+ {
656+ std::string locWarning = fmt::format (
657+ " {}:{}\n " ,
658+ loc.FullPath ,
659+ loc.LineNumber );
660+ for (auto const & msg : msgs)
661+ {
662+ locWarning += fmt::format (" {}\n " , msg);
663+ }
664+ report::log (level, locWarning);
665+ }
658666}
659667
660668void
661669JavadocFinalizer::
662- warnUndocumented () const
670+ warnUndocumented ()
663671{
664672 MRDOCS_CHECK_OR (corpus_.config ->warnIfUndocumented );
665- for (auto & [id, name] : corpus_.undocumented_ )
673+ for (auto & undocI : corpus_.undocumented_ )
666674 {
667- if (Info const * I = corpus_.find (id))
675+ if (Info const * I = corpus_.find (undocI. id ))
668676 {
669- MRDOCS_CHECK_OR (!I->javadoc || I->Extraction == ExtractionMode::Regular);
677+ MRDOCS_CHECK_OR (
678+ !I->javadoc || I->Extraction == ExtractionMode::Regular);
670679 }
671- this ->warn (" {}: Symbol is undocumented" , name);
680+ bool const prefer_definition = undocI.kind == InfoKind::Record
681+ || undocI.kind == InfoKind::Enum;
682+ this ->warn (
683+ *getPrimaryLocation (undocI, prefer_definition),
684+ " {}: Symbol is undocumented" , undocI.name );
672685 }
673686 corpus_.undocumented_ .clear ();
674687}
675688
676689void
677690JavadocFinalizer::
678- warnDocErrors () const
691+ warnDocErrors ()
679692{
680693 MRDOCS_CHECK_OR (corpus_.config ->warnIfDocError );
681694 for (auto const & I : corpus_.info_ )
@@ -713,7 +726,7 @@ getJavadocParamNames(Javadoc const& javadoc)
713726
714727void
715728JavadocFinalizer::
716- warnParamErrors (FunctionInfo const & I) const
729+ warnParamErrors (FunctionInfo const & I)
717730{
718731 MRDOCS_CHECK_OR (I.javadoc );
719732
@@ -723,15 +736,12 @@ warnParamErrors(FunctionInfo const& I) const
723736 auto [firstDup, lastUnique] = std::ranges::unique (javadocParamNames);
724737 auto duplicateParamNames = std::ranges::subrange (firstDup, lastUnique);
725738 auto [firstDupDup, _] = std::ranges::unique (duplicateParamNames);
726- for (auto uniqueDuplicateParamNames = std::ranges::subrange (firstDup, firstDupDup);
739+ for (auto const uniqueDuplicateParamNames = std::ranges::subrange (firstDup, firstDupDup);
727740 std::string_view duplicateParamName: uniqueDuplicateParamNames)
728741 {
729- auto primaryLoc = getPrimaryLocation (I);
730742 this ->warn (
731- " {}:{} \n "
743+ * getPrimaryLocation (I),
732744 " {}: Duplicate parameter documentation for '{}'" ,
733- primaryLoc->FullPath ,
734- primaryLoc->LineNumber ,
735745 corpus_.Corpus ::qualifiedName (I),
736746 duplicateParamName);
737747 }
@@ -745,12 +755,9 @@ warnParamErrors(FunctionInfo const& I) const
745755 {
746756 if (std::ranges::find (paramNames, javadocParamName) == paramNames.end ())
747757 {
748- auto primaryLoc = getPrimaryLocation (I);
749758 this ->warn (
750- " {}:{} \n "
759+ * getPrimaryLocation (I),
751760 " {}: Documented parameter '{}' does not exist" ,
752- primaryLoc->FullPath ,
753- primaryLoc->LineNumber ,
754761 corpus_.Corpus ::qualifiedName (I),
755762 javadocParamName);
756763 }
@@ -760,7 +767,7 @@ warnParamErrors(FunctionInfo const& I) const
760767
761768void
762769JavadocFinalizer::
763- warnNoParamDocs () const
770+ warnNoParamDocs ()
764771{
765772 MRDOCS_CHECK_OR (corpus_.config ->warnNoParamdoc );
766773 for (auto const & I : corpus_.info_ )
@@ -774,8 +781,9 @@ warnNoParamDocs() const
774781
775782void
776783JavadocFinalizer::
777- warnNoParamDocs (FunctionInfo const & I) const
784+ warnNoParamDocs (FunctionInfo const & I)
778785{
786+ MRDOCS_CHECK_OR (!I.IsDeleted );
779787 // Check for function parameters that are not documented in javadoc
780788 auto javadocParamNames = getJavadocParamNames (*I.javadoc );
781789 auto paramNames =
@@ -785,12 +793,9 @@ warnNoParamDocs(FunctionInfo const& I) const
785793 {
786794 if (std::ranges::find (javadocParamNames, paramName) == javadocParamNames.end ())
787795 {
788- auto primaryLoc = getPrimaryLocation (I);
789796 this ->warn (
790- " {}:{} \n "
797+ * getPrimaryLocation (I),
791798 " {}: Missing documentation for parameter '{}'" ,
792- primaryLoc->FullPath ,
793- primaryLoc->LineNumber ,
794799 corpus_.Corpus ::qualifiedName (I),
795800 paramName);
796801 }
@@ -810,33 +815,27 @@ warnNoParamDocs(FunctionInfo const& I) const
810815 };
811816 if (!isVoid (*I.ReturnType ))
812817 {
813- auto primaryLoc = getPrimaryLocation (I);
814818 this ->warn (
815- " {}:{} \n "
819+ * getPrimaryLocation (I),
816820 " {}: Missing documentation for return type" ,
817- primaryLoc->FullPath ,
818- primaryLoc->LineNumber ,
819821 corpus_.Corpus ::qualifiedName (I));
820822 }
821823 }
822824}
823825
824826void
825827JavadocFinalizer::
826- warnUndocEnumValues () const
828+ warnUndocEnumValues ()
827829{
828830 MRDOCS_CHECK_OR (corpus_.config ->warnIfUndocEnumVal );
829831 for (auto const & I : corpus_.info_ )
830832 {
831833 MRDOCS_CHECK_OR_CONTINUE (I->isEnumConstant ());
832834 MRDOCS_CHECK_OR_CONTINUE (I->Extraction == ExtractionMode::Regular);
833835 MRDOCS_CHECK_OR_CONTINUE (!I->javadoc );
834- auto primaryLoc = getPrimaryLocation (*I);
835836 this ->warn (
836- " {}:{} \n "
837+ * getPrimaryLocation (*I),
837838 " {}: Missing documentation for enum value" ,
838- primaryLoc->FullPath ,
839- primaryLoc->LineNumber ,
840839 corpus_.Corpus ::qualifiedName (*I));
841840 }
842841}
0 commit comments