Skip to content
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

Improve {@inheritdoc} behavior #4686 #4846

Merged
merged 2 commits into from
Oct 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,17 @@ static final class PHPDocExtractor {
private static final Pattern DESC_HEADER_PATTERN = Pattern.compile("(\r?\n)*(.*?((\r?\n){2,}|\\.\\s*\r?\n)|.*)", Pattern.DOTALL); // NOI18N
private static final Pattern INLINE_INHERITDOC_PATTERN = Pattern.compile("\\{@inheritdoc *\\}", Pattern.CASE_INSENSITIVE); // NOI18N
private static final ArrayList<String> LINK_TAGS = new ArrayList<>();
// see: https://pear.php.net/package/PhpDocumentor/docs/latest/phpDocumentor/tutorial_tags.inlineinheritdoc.pkg.html
// phpdocumentor separates a doc comment into a header and description.
// only description is replaced.
// e.g.
// /**
// * Header.
// * Description.
// */
// /** {@inheritdoc} */ -> /** Description. */
private static final boolean INHERITDOC_FOR_PHPDOCUMENTOR = Boolean.getBoolean("nb.php.editor.inheritDocForPhpdocumentor"); // NOI18N
static volatile boolean UNIT_TEST_INHERITDOC_FOR_PHPDOCUMENTER = false; // for unit tests

static {
LINK_TAGS.add("@link"); // NOI18N
Expand Down Expand Up @@ -633,12 +644,15 @@ private String replaceInheritdocForDescription(@NullAllowed String description,
if (description == null) {
return parentDescription;
}
if (description != null && hasInlineInheritdoc(description)) {
if (hasInlineInheritdoc(description)) {
if (parentDescription != null && !parentDescription.trim().isEmpty()) {
if (INLINE_INHERITDOC_PATTERN.matcher(description.trim()).matches()) {
return parentDescription;
}
String inheritdoc = removeDescriptionHeader(parentDescription);
String inheritdoc = parentDescription;
if (INHERITDOC_FOR_PHPDOCUMENTOR || UNIT_TEST_INHERITDOC_FOR_PHPDOCUMENTER) {
inheritdoc = removeDescriptionHeader(parentDescription);
}
return replaceInlineInheritdoc(description, inheritdoc);
}
}
Expand Down Expand Up @@ -811,6 +825,12 @@ private List<PhpElement> getInheritedElements() {
} else if (indexedElement instanceof InterfaceElement) {
InterfaceElement interfaceElement = (InterfaceElement) indexedElement;
inheritedElements.addAll(getAllInheritedInterfaces(interfaceElement));
} else if (indexedElement instanceof FieldElement) {
FieldElement fieldElement = (FieldElement) indexedElement;
inheritedElements.addAll(getAllOverriddenFields(fieldElement));
} else if (indexedElement instanceof TypeConstantElement) {
TypeConstantElement constElement = (TypeConstantElement) indexedElement;
inheritedElements.addAll(getAllOverriddenConstants(constElement));
}
return inheritedElements;
}
Expand Down Expand Up @@ -975,6 +995,62 @@ private static Set<MethodElement> getInheritedMethods(MethodElement method) {
return index.getInheritedMethods(type);
}

private static List<FieldElement> getAllOverriddenFields(FieldElement field) {
List<FieldElement> fields = new ArrayList<>();
getOverriddenFields(field, fields);
return fields;
}

private static void getOverriddenFields(FieldElement field, List<FieldElement> fields) {
Set<FieldElement> overriddenFields = getOverriddenFields(field);
fields.addAll(overriddenFields);
for (FieldElement overriddenField : overriddenFields) {
getOverriddenFields(overriddenField, fields);
}
}

private static Set<FieldElement> getOverriddenFields(FieldElement field) {
ElementFilter fieldNameFilter = ElementFilter.forName(NameKind.exact(field.getName()));
return fieldNameFilter.filter(getInheritedFields(field));
}

private static Set<FieldElement> getInheritedFields(FieldElement field) {
Index index = getIndex(field);
TypeElement type = field.getType();
if (type == null) {
return Collections.emptySet();
}
return index.getInheritedFields(type);
}

private static List<TypeConstantElement> getAllOverriddenConstants(TypeConstantElement constant) {
List<TypeConstantElement> constants = new ArrayList<>();
getOverriddenConstants(constant, constants);
return constants;
}

private static void getOverriddenConstants(TypeConstantElement constant, List<TypeConstantElement> constants) {
Set<TypeConstantElement> overriddenConstants = getOverriddenConstants(constant);
constants.addAll(overriddenConstants);
for (TypeConstantElement overriddenConstant : overriddenConstants) {
getOverriddenConstants(overriddenConstant, constants);
}
}

private static Set<TypeConstantElement> getOverriddenConstants(TypeConstantElement constant) {
ElementFilter constantNameFilter = ElementFilter.forName(NameKind.exact(constant.getName()));
return constantNameFilter.filter(getInheritedConstants(constant));
}

private static Set<TypeConstantElement> getInheritedConstants(TypeConstantElement constant) {
Index index = getIndex(constant);
TypeElement type = constant.getType();
if (type == null) {
return Collections.emptySet();
}
return index.getInheritedTypeConstants(type);
}

@CheckForNull
private PHPDocBlock getPhpDocBlock(final PhpElement phpElement) {
if (!canBeProcessed(phpElement)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,68 @@
*/
class BaseClass {

/**
* The summary of BaseClass CONSTANT.
*/
public const CONSTANT_SINGLE_SENTENCE = 0;

/**
* The summary of BaseClass CONSTANT.
*
* Description of BaseClass CONSTANT.
*/
public const CONSTANT_ONLY_TAG = 0;

/**
* The summary of BaseClass CONSTANT.
*
* Description of BaseClass CONSTANT.
*/
public const CONSTANT_INLINE_TAG = 0;

/**
* The summary of BaseClass CONSTANT.
*
* Description of BaseClass CONSTANT.
*/
public const CONSTANT_WITHOUT_PHPDOC = 0;

/**
* The summary of BaseClass $field.
* @var int
*/
public int $fieldSingleSentence = 0;

/**
* The summary of BaseClass $field.
*
* Description of BaseClass $field.
* @var int
*/
public int $fieldOnlyTag = 0;

/**
* The summary of BaseClass $field.
*
* Description of BaseClass $field.
* @var int
*/
public int $fieldInlineTag = 0;

/**
* The summary of BaseClass $field.
*
* Description of BaseClass $field.
* @var int
*/
public int $fieldWithoutPHPDoc = 0;

/**
* testSingleSentence method of BaseClass.
*/
public function testSingleSentence() {
}

/**
* testOnlyTag method of BaseClass.
*
Expand Down Expand Up @@ -70,6 +132,54 @@ public function testNoDoc() {
*/
class ChildClass extends BaseClass {

/**
* {@inheritDoc} Description of ChildClass CONSTANT.
*/
public const CONSTANT_SINGLE_SENTENCE = 0;

/**
* {@inheritDoc}
*/
public const CONSTANT_ONLY_TAG = 0;

/**
* The summary of ChildClass CONSTANT.
*
* {@inheritDoc} Description of ChildClass CONSTANT.
*/
public const CONSTANT_INLINE_TAG = 0;

public const CONSTANT_WITHOUT_PHPDOC = 0;

/**
* {@inheritDoc} Description of ChildClass $field.
* @var int
*/
public int $fieldSingleSentence = 0;

/**
* {@inheritDoc}
*/
public int $fieldOnlyTag = 0;

/**
* The summary of ChildClass $field.
*
* {@inheritDoc} Description of ChildClass $field.
* @var int
*/
public int $fieldInlineTag = 0;

public int $fieldWithoutPHPDoc = 0;

/**
* testSingleSentence method of ChildClass.
*
* {@inheritDoc} Description of ChildClass.
*/
public function testSingleSentence() {
}

/**
* {@inheritdoc }
*/
Expand Down Expand Up @@ -181,6 +291,15 @@ public function childInterfaceMethod() {
}

$childClass = new ChildClass();
ChildClass::CONSTANT_SINGLE_SENTENCE;
ChildClass::CONSTANT_ONLY_TAG;
ChildClass::CONSTANT_INLINE_TAG;
ChildClass::CONSTANT_WITHOUT_PHPDOC;
$childClass->fieldSingleSentence;
$childClass->fieldOnlytag;
$childClass->fieldInlineTag;
$childClass->fieldWithoutPhpDoc;
$childClass->testSingleSentence();
$childClass->testOnlyTag($param1, $param2);
$childClass->testMissingParam($param1);
$childClass->testNoDoc();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
$childClass->testSingle|Sentence();
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
METHOD testSingleSentence() [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>testSingleSentence</b><br/><br/>
testSingleSentence method of ChildClass.<br><br>testSingleSentence method of BaseClass.
Description of ChildClass.
<br />
</body></html>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CLASS ChildInlineTagClass [PUBLIC] inheritdoc.php
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>ChildInlineTagClass</b><br/><br/>
The summary of ChildInlineTagClass.<br><br>Description of BaseClass. Description of ChildInlineTagClass.
The summary of ChildInlineTagClass.<br><br>The summary of BaseClass.<br><br>Description of BaseClass. Description of ChildInlineTagClass.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html><body>
<pre>Code completion result for source line:
class GrandchildInlineTagClass extends ChildInlineTagC|lass {
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CLASS ChildInlineTagClass [PUBLIC] inheritdoc.php
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>ChildInlineTagClass</b><br/><br/>
The summary of ChildInlineTagClass.<br><br>Description of BaseClass. Description of ChildInlineTagClass.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
ChildClass::CONSTANT_INLIN|E_TAG;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CONSTANT CONSTANT_INLINE_TAG 0 [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>CONSTANT_INLINE_TAG</b> = 0<br/><br/>
The summary of ChildClass CONSTANT.<br><br>The summary of BaseClass CONSTANT.<br><br>Description of BaseClass CONSTANT.
Description of ChildClass CONSTANT.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
ChildClass::CONSTANT_INLIN|E_TAG;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CONSTANT CONSTANT_INLINE_TAG 0 [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>CONSTANT_INLINE_TAG</b> = 0<br/><br/>
The summary of ChildClass CONSTANT.<br><br>Description of BaseClass CONSTANT.
Description of ChildClass CONSTANT.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html><body>
<pre>Code completion result for source line:
ChildClass::CONSTANT_ONL|Y_TAG;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CONSTANT CONSTANT_ONLY_TAG 0 [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>CONSTANT_ONLY_TAG</b> = 0<br/><br/>
The summary of BaseClass CONSTANT.<br><br>Description of BaseClass CONSTANT.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html><body>
<pre>Code completion result for source line:
ChildClass::CONSTANT_SINGLE_|SENTENCE;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CONSTANT CONSTANT_SINGLE_SENTENCE 0 [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>CONSTANT_SINGLE_SENTENCE</b> = 0<br/><br/><br><br>The summary of BaseClass CONSTANT.
Description of ChildClass CONSTANT.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html><body>
<pre>Code completion result for source line:
ChildClass::CONSTANT_WITHOUT_PH|PDOC;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CONSTANT CONSTANT_WITHOUT_PHPDOC 0 [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>CONSTANT_WITHOUT_PHPDOC</b> = 0<br/><br/>
The summary of BaseClass CONSTANT.<br><br>Description of BaseClass CONSTANT.
<br />
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
$childClass->fieldInli|neTag;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
VARIABLE int fieldInlineTag [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>$fieldInlineTag</b><br/><br/>
The summary of ChildClass $field.<br><br>The summary of BaseClass $field.<br><br>Description of BaseClass $field. Description of ChildClass $field.<br />
<table>
<tr><th align="left">Type:</th><td>int</td></tr></table>
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
$childClass->fieldInlineT|ag;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
VARIABLE int fieldInlineTag [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>$fieldInlineTag</b><br/><br/>
The summary of ChildClass $field.<br><br>Description of BaseClass $field. Description of ChildClass $field.<br />
<table>
<tr><th align="left">Type:</th><td>int</td></tr></table>
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
$childClass->fieldOnl|ytag;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
VARIABLE int fieldOnlyTag [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>$fieldOnlyTag</b><br/><br/>
The summary of BaseClass $field.<br><br>Description of BaseClass $field.<br />
<table>
<tr><th align="left">Type:</th><td>int</td></tr></table>
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html><body>
<pre>Code completion result for source line:
$childClass->fieldSingle|Sentence;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
VARIABLE int fieldSingleSentence [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>$fieldSingleSentence</b><br/><br/><br><br>The summary of BaseClass $field. Description of ChildClass $field.<br />
<table>
<tr><th align="left">Type:</th><td>int</td></tr></table>
</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html><body>
<pre>Code completion result for source line:
$childClass->fieldWithoutP|hpDoc;
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
VARIABLE int fieldWithoutPHPDoc [PUBLIC] ChildClass
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>$fieldWithoutPHPDoc</b><br/><br/>
The summary of BaseClass $field.<br><br>Description of BaseClass $field.<br />
<table>
<tr><th align="left">Type:</th><td>int</td></tr></table>
</body></html>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
(QueryType=COMPLETION, prefixSearch=false, caseSensitive=true)
CLASS ChildInlineTagInterface [PUBLIC] inheritdoc.php
</pre><h2>Documentation:</h2><div align="right"><font size=-1></font></div><b>ChildInlineTagInterface</b><br/><br/>
The summary of ChildInlineTagInterface.<br><br>Description of BaseInterface. Description of ChildInlineTagInterface.
The summary of ChildInlineTagInterface.<br><br>The summary of BaseInterface.<br><br>Description of BaseInterface. Description of ChildInlineTagInterface.
<br />
</body></html>
Loading