Merge
This commit is contained in:
commit
a50161b750
@ -154,19 +154,19 @@ static void print_message(outputStream* output, oop content, TRAPS) {
|
||||
}
|
||||
|
||||
static void log(oop content, TRAPS) {
|
||||
LogMessage(jfr,startup) msg;
|
||||
objArrayOop lines = objArrayOop(content);
|
||||
assert(lines != NULL, "invariant");
|
||||
assert(lines->is_array(), "must be array");
|
||||
const int length = lines->length();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
|
||||
if (text == NULL) {
|
||||
// An oome has been thrown and is pending.
|
||||
break;
|
||||
}
|
||||
msg.info("%s", text);
|
||||
LogMessage(jfr,startup) msg;
|
||||
objArrayOop lines = objArrayOop(content);
|
||||
assert(lines != NULL, "invariant");
|
||||
assert(lines->is_array(), "must be array");
|
||||
const int length = lines->length();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
const char* text = JfrJavaSupport::c_str(lines->obj_at(i), THREAD);
|
||||
if (text == NULL) {
|
||||
// An oome has been thrown and is pending.
|
||||
break;
|
||||
}
|
||||
msg.info("%s", text);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_dcmd_result(outputStream* output,
|
||||
@ -215,6 +215,8 @@ static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) {
|
||||
return args->result()->get_oop();
|
||||
}
|
||||
|
||||
JfrDCmd::JfrDCmd(outputStream* output, bool heap, int num_arguments) : DCmd(output, heap), _args(NULL), _num_arguments(num_arguments), _delimiter('\0') {}
|
||||
|
||||
void JfrDCmd::invoke(JfrJavaArguments& method, TRAPS) const {
|
||||
JavaValue constructor_result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&constructor_result);
|
||||
@ -274,6 +276,20 @@ void JfrDCmd::print_help(const char* name) const {
|
||||
handle_dcmd_result(output(), result.get_oop(), DCmd_Source_MBean, thread);
|
||||
}
|
||||
|
||||
static void initialize_dummy_descriptors(GrowableArray<DCmdArgumentInfo*>* array) {
|
||||
assert(array != NULL, "invariant");
|
||||
DCmdArgumentInfo * const dummy = new DCmdArgumentInfo(NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
true, // a DcmdFramework "option"
|
||||
false);
|
||||
for (int i = 0; i < array->max_length(); ++i) {
|
||||
array->append(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
// Since the DcmdFramework does not support dynamically allocated strings,
|
||||
// we keep them in a thread local arena. The arena is reset between invocations.
|
||||
static THREAD_LOCAL Arena* dcmd_arena = NULL;
|
||||
@ -340,16 +356,29 @@ static DCmdArgumentInfo* create_info(oop argument, TRAPS) {
|
||||
GrowableArray<DCmdArgumentInfo*>* JfrDCmd::argument_info_array() const {
|
||||
static const char signature[] = "()[Ljdk/jfr/internal/dcmd/Argument;";
|
||||
JavaThread* thread = JavaThread::current();
|
||||
GrowableArray<DCmdArgumentInfo*>* const array = new GrowableArray<DCmdArgumentInfo*>(_num_arguments);
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments getArgumentInfos(&result, javaClass(), "getArgumentInfos", signature, thread);
|
||||
invoke(getArgumentInfos, thread);
|
||||
if (thread->has_pending_exception()) {
|
||||
// Most likely an OOME, but the DCmdFramework is not the best place to handle it.
|
||||
// We handle it locally by clearing the exception and returning an array with dummy descriptors.
|
||||
// This lets the MBean server initialization routine complete successfully,
|
||||
// but this particular command will have no argument descriptors exposed.
|
||||
// Hence we postpone, or delegate, handling of OOME's to code that is better suited.
|
||||
log_debug(jfr, system)("Exception in DCmd getArgumentInfos");
|
||||
thread->clear_pending_exception();
|
||||
initialize_dummy_descriptors(array);
|
||||
assert(array->length() == _num_arguments, "invariant");
|
||||
return array;
|
||||
}
|
||||
objArrayOop arguments = objArrayOop(result.get_oop());
|
||||
assert(arguments != NULL, "invariant");
|
||||
assert(arguments->is_array(), "must be array");
|
||||
GrowableArray<DCmdArgumentInfo*>* const array = new GrowableArray<DCmdArgumentInfo*>();
|
||||
const int length = arguments->length();
|
||||
const int num_arguments = arguments->length();
|
||||
assert(num_arguments == _num_arguments, "invariant");
|
||||
prepare_dcmd_string_arena();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
for (int i = 0; i < num_arguments; ++i) {
|
||||
DCmdArgumentInfo* const dai = create_info(arguments->obj_at(i), thread);
|
||||
assert(dai != NULL, "invariant");
|
||||
array->append(dai);
|
||||
|
@ -31,23 +31,23 @@ class JfrJavaArguments;
|
||||
class JfrDCmd : public DCmd {
|
||||
private:
|
||||
const char* _args;
|
||||
const int _num_arguments;
|
||||
char _delimiter;
|
||||
protected:
|
||||
JfrDCmd(outputStream* output, bool heap, int num_arguments);
|
||||
virtual const char* javaClass() const = 0;
|
||||
void invoke(JfrJavaArguments& method, TRAPS) const;
|
||||
public:
|
||||
JfrDCmd(outputStream* output, bool heap) : DCmd(output,heap), _args(NULL), _delimiter('\0') {}
|
||||
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
virtual void print_help(const char* name) const;
|
||||
virtual GrowableArray<const char*>* argument_name_array() const;
|
||||
virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() const;
|
||||
virtual void parse(CmdLine* line, char delim, TRAPS);
|
||||
protected:
|
||||
virtual const char* javaClass() const = 0;
|
||||
void invoke(JfrJavaArguments& method, TRAPS) const;
|
||||
};
|
||||
|
||||
class JfrStartFlightRecordingDCmd : public JfrDCmd {
|
||||
public:
|
||||
JfrStartFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
|
||||
JfrStartFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
|
||||
|
||||
static const char* name() {
|
||||
return "JFR.start";
|
||||
@ -72,7 +72,7 @@ class JfrStartFlightRecordingDCmd : public JfrDCmd {
|
||||
|
||||
class JfrDumpFlightRecordingDCmd : public JfrDCmd {
|
||||
public:
|
||||
JfrDumpFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
|
||||
JfrDumpFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
|
||||
|
||||
static const char* name() {
|
||||
return "JFR.dump";
|
||||
@ -97,7 +97,7 @@ class JfrDumpFlightRecordingDCmd : public JfrDCmd {
|
||||
|
||||
class JfrCheckFlightRecordingDCmd : public JfrDCmd {
|
||||
public:
|
||||
JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
|
||||
JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
|
||||
|
||||
static const char* name() {
|
||||
return "JFR.check";
|
||||
@ -122,7 +122,7 @@ class JfrCheckFlightRecordingDCmd : public JfrDCmd {
|
||||
|
||||
class JfrStopFlightRecordingDCmd : public JfrDCmd {
|
||||
public:
|
||||
JfrStopFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap) {}
|
||||
JfrStopFlightRecordingDCmd(outputStream* output, bool heap) : JfrDCmd(output, heap, num_arguments()) {}
|
||||
|
||||
static const char* name() {
|
||||
return "JFR.stop";
|
||||
|
@ -335,7 +335,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
|
||||
: HtmlLinkInfo.Kind.MEMBER,
|
||||
te, element, typeContent);
|
||||
Content desc = new ContentBuilder();
|
||||
writer.addSummaryLinkComment(this, element, desc);
|
||||
writer.addSummaryLinkComment(element, desc);
|
||||
useTable.addRow(summaryType, typeContent, desc);
|
||||
}
|
||||
contentTree.add(useTable);
|
||||
@ -363,7 +363,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
|
||||
addSummaryLink(tElement, member, summaryLink);
|
||||
rowContents.add(summaryLink);
|
||||
Content desc = new ContentBuilder();
|
||||
writer.addSummaryLinkComment(this, member, firstSentenceTrees, desc);
|
||||
writer.addSummaryLinkComment(member, firstSentenceTrees, desc);
|
||||
rowContents.add(desc);
|
||||
table.addRow(member, rowContents);
|
||||
}
|
||||
|
@ -1162,7 +1162,7 @@ public class HtmlDocletWriter {
|
||||
public void addInlineComment(Element element, DocTree tag, Content htmltree) {
|
||||
CommentHelper ch = utils.getCommentHelper(element);
|
||||
List<? extends DocTree> description = ch.getDescription(tag);
|
||||
addCommentTags(element, tag, description, false, false, false, htmltree);
|
||||
addCommentTags(element, description, false, false, false, htmltree);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1249,22 +1249,6 @@ public class HtmlDocletWriter {
|
||||
*/
|
||||
private void addCommentTags(Element element, List<? extends DocTree> tags, boolean depr,
|
||||
boolean first, boolean inSummary, Content htmltree) {
|
||||
addCommentTags(element, null, tags, depr, first, inSummary, htmltree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the comment tags.
|
||||
*
|
||||
* @param element for which the comment tags will be generated
|
||||
* @param holderTag the block tag context for the inline tags
|
||||
* @param tags the first sentence tags for the doc
|
||||
* @param depr true if it is deprecated
|
||||
* @param first true if the first sentence tags should be added
|
||||
* @param inSummary true if the comment tags are added into the summary section
|
||||
* @param htmltree the documentation tree to which the comment tags will be added
|
||||
*/
|
||||
private void addCommentTags(Element element, DocTree holderTag, List<? extends DocTree> tags, boolean depr,
|
||||
boolean first, boolean inSummary, Content htmltree) {
|
||||
if (options.noComment()) {
|
||||
return;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
|
||||
@ -136,25 +135,22 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
|
||||
/**
|
||||
* Add the summary link for the member.
|
||||
*
|
||||
* @param mw the writer for the member being documented
|
||||
* @param member the member to be documented
|
||||
* @param contentTree the content tree to which the link will be added
|
||||
*/
|
||||
public void addSummaryLinkComment(AbstractMemberWriter mw, Element member, Content contentTree) {
|
||||
public void addSummaryLinkComment(Element member, Content contentTree) {
|
||||
List<? extends DocTree> tags = utils.getFirstSentenceTrees(member);
|
||||
addSummaryLinkComment(mw, member, tags, contentTree);
|
||||
addSummaryLinkComment(member, tags, contentTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the summary link comment.
|
||||
*
|
||||
* @param mw the writer for the member being documented
|
||||
* @param member the member being documented
|
||||
* @param firstSentenceTags the first sentence tags for the member to be documented
|
||||
* @param tdSummary the content tree to which the comment will be added
|
||||
*/
|
||||
public void addSummaryLinkComment(AbstractMemberWriter mw,
|
||||
Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
|
||||
public void addSummaryLinkComment(Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
|
||||
addIndexComment(member, firstSentenceTags, tdSummary);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,6 @@ public class InheritDocTaglet extends BaseTaglet {
|
||||
if (!inheritedDoc.inlineTags.isEmpty()) {
|
||||
replacement = writer.commentTagsToOutput(inheritedDoc.holder, inheritedDoc.holderTag,
|
||||
inheritedDoc.inlineTags, isFirstSentence);
|
||||
ch.setOverrideElement(inheritedDoc.holder);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -206,9 +206,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
||||
String lname = kind != ParamKind.TYPE_PARAMETER
|
||||
? utils.getSimpleName(e)
|
||||
: utils.getTypeName(e.asType(), false);
|
||||
CommentHelper ch = utils.getCommentHelper(holder);
|
||||
ch.setOverrideElement(inheritedDoc.holder);
|
||||
Content content = processParamTag(holder, kind, writer,
|
||||
Content content = processParamTag(inheritedDoc.holder, kind, writer,
|
||||
(ParamTree) inheritedDoc.holderTag,
|
||||
lname,
|
||||
alreadyDocumented.isEmpty());
|
||||
|
@ -121,9 +121,7 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
||||
Input input = new DocFinder.Input(utils, holder, this);
|
||||
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
|
||||
if (inheritedDoc.holderTag != null) {
|
||||
CommentHelper ch = utils.getCommentHelper(input.element);
|
||||
ch.setOverrideElement(inheritedDoc.holder);
|
||||
return writer.returnTagOutput(holder, (ReturnTree) inheritedDoc.holderTag, false);
|
||||
return writer.returnTagOutput(inheritedDoc.holder, (ReturnTree) inheritedDoc.holderTag, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -165,26 +165,8 @@ public class CommentHelper {
|
||||
}
|
||||
return configuration.docEnv.getTypeUtils().asElement(symbol);
|
||||
}
|
||||
// case A: the element contains no comments associated and
|
||||
// the comments need to be copied from ancestor
|
||||
// case B: the element has @inheritDoc, then the ancestral comment
|
||||
// as appropriate has to be copied over.
|
||||
|
||||
// Case A.
|
||||
if (dcTree == null && overriddenElement != null) {
|
||||
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
|
||||
return ovch.getElement(rtree);
|
||||
}
|
||||
if (dcTree == null) {
|
||||
return null;
|
||||
}
|
||||
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
|
||||
DocTreePath docTreePath = getDocTreePath(rtree);
|
||||
if (docTreePath == null) {
|
||||
// Case B.
|
||||
if (overriddenElement != null) {
|
||||
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
|
||||
return ovch.getElement(rtree);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
DocTrees doctrees = configuration.docEnv.getDocTrees();
|
||||
@ -192,10 +174,7 @@ public class CommentHelper {
|
||||
}
|
||||
|
||||
public TypeMirror getType(ReferenceTree rtree) {
|
||||
// Workaround for JDK-8269706
|
||||
if (path == null || dcTree == null || rtree == null)
|
||||
return null;
|
||||
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
|
||||
DocTreePath docTreePath = getDocTreePath(rtree);
|
||||
if (docTreePath != null) {
|
||||
DocTrees doctrees = configuration.docEnv.getDocTrees();
|
||||
return doctrees.getType(docTreePath);
|
||||
@ -700,9 +679,18 @@ public class CommentHelper {
|
||||
}
|
||||
|
||||
public DocTreePath getDocTreePath(DocTree dtree) {
|
||||
if (path == null || dcTree == null || dtree == null)
|
||||
if (dcTree == null && overriddenElement != null) {
|
||||
// This is an inherited comment, return path from ancestor.
|
||||
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
|
||||
} else if (path == null || dcTree == null || dtree == null) {
|
||||
return null;
|
||||
return DocTreePath.getPath(path, dcTree, dtree);
|
||||
}
|
||||
DocTreePath dtPath = DocTreePath.getPath(path, dcTree, dtree);
|
||||
if (dtPath == null && overriddenElement != null) {
|
||||
// The overriding element has a doc tree, but it doesn't contain what we're looking for.
|
||||
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
|
||||
}
|
||||
return dtPath;
|
||||
}
|
||||
|
||||
public Element getOverriddenElement() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -74,6 +74,7 @@ public class JsrRewriting {
|
||||
className);
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotHaveExitValue(0);
|
||||
String[] expectedMsgs = {
|
||||
"java.lang.LinkageError",
|
||||
"java.lang.NoSuchMethodError",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -73,6 +73,7 @@ public class OomWhileParsingRepeatedJsr {
|
||||
className );
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotHaveExitValue(0);
|
||||
output.shouldContain("Cannot reserve enough memory");
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public class TestAbortOnVMOperationTimeout {
|
||||
if (shouldPass) {
|
||||
output.shouldHaveExitValue(0);
|
||||
} else {
|
||||
output.shouldMatch("VM operation took too long");
|
||||
output.shouldContain("VM operation took too long");
|
||||
output.shouldNotHaveExitValue(0);
|
||||
}
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ public class TestAbortVMOnSafepointTimeout {
|
||||
);
|
||||
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldMatch("Timed out while spinning to reach a safepoint.");
|
||||
output.shouldContain("Timed out while spinning to reach a safepoint.");
|
||||
if (Platform.isWindows()) {
|
||||
output.shouldMatch("Safepoint sync time longer than");
|
||||
output.shouldContain("Safepoint sync time longer than");
|
||||
} else {
|
||||
output.shouldMatch("SIGILL");
|
||||
output.shouldContain("SIGILL");
|
||||
if (Platform.isLinux()) {
|
||||
output.shouldMatch("(sent by kill)");
|
||||
output.shouldContain("(sent by kill)");
|
||||
}
|
||||
}
|
||||
output.shouldNotHaveExitValue(0);
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8269722
|
||||
* @bug 8269722 8270866
|
||||
* @summary NPE in HtmlDocletWriter, reporting errors on inherited tags
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
@ -67,6 +67,14 @@ public class TestInherited extends JavadocTester {
|
||||
"-Xdoclint:-missing", "-XDdoe",
|
||||
src.resolve("BadParam.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
checkOutput("BadParam.Base.html", true, """
|
||||
<dt>Parameters:</dt>
|
||||
<dd><code>i</code> - a < b</dd>
|
||||
""");
|
||||
checkOutput("BadParam.Sub.html", true, """
|
||||
<dt>Parameters:</dt>
|
||||
<dd><code>i</code> - a < b</dd>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -91,5 +99,64 @@ public class TestInherited extends JavadocTester {
|
||||
"-Xdoclint:-missing",
|
||||
src.resolve("BadReturn.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
checkOutput("BadReturn.Base.html", true, """
|
||||
<dt>Returns:</dt>
|
||||
<dd>a < b</dd>
|
||||
""");
|
||||
checkOutput("BadReturn.Sub.html", true, """
|
||||
<dt>Returns:</dt>
|
||||
<dd>a < b</dd>
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadInheritedReference(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
public class BadReference {
|
||||
public interface Intf {
|
||||
/**
|
||||
* {@link NonExistingClass}
|
||||
*/
|
||||
public void m();
|
||||
}
|
||||
|
||||
public static class Impl1 implements Intf {
|
||||
public void m() { }
|
||||
}
|
||||
|
||||
public static class Impl2 implements Intf {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void m() { }
|
||||
}
|
||||
|
||||
// subclass has doc comment but inherits main description
|
||||
public static class Impl3 implements Intf {
|
||||
/**
|
||||
* @since 1
|
||||
*/
|
||||
public void m() { }
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"-Xdoclint:-reference",
|
||||
src.resolve("BadReference.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
checkOutput("BadReference.Intf.html", true, """
|
||||
<div class="block"><code>NonExistingClass</code></div>
|
||||
""");
|
||||
checkOutput("BadReference.Impl1.html", true, """
|
||||
<div class="block"><code>NonExistingClass</code></div>
|
||||
""");
|
||||
checkOutput("BadReference.Impl2.html", true, """
|
||||
<div class="block"><code>NonExistingClass</code></div>
|
||||
""");
|
||||
checkOutput("BadReference.Impl3.html", true, """
|
||||
<div class="block"><code>NonExistingClass</code></div>
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user