Skip to content

Commit 10c6669

Browse files
authored
Completion does not offer record components from Javadoc (eclipse-jdt#4169)
Add missing resolution and completion code for records inside Javadoc. Refactor and reuse the existing code that resolves @param tags on method's Javadoc for resolution of the same on record declarations.
1 parent 4486817 commit 10c6669

5 files changed

Lines changed: 337 additions & 124 deletions

File tree

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Javadoc.java

Lines changed: 74 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*******************************************************************************/
1717
package org.eclipse.jdt.internal.compiler.ast;
1818

19+
import java.util.function.Function;
1920
import org.eclipse.jdt.core.compiler.CharOperation;
2021
import org.eclipse.jdt.internal.compiler.ASTVisitor;
2122
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -241,6 +242,7 @@ public void resolve(ClassScope scope) {
241242
JavadocSingleNameReference param = this.paramReferences[i];
242243
scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
243244
}
245+
resolveParamTags(scope, true);
244246
resolveTypeParameterTags(scope, true);
245247

246248
// @return tags
@@ -542,9 +544,32 @@ else if (reference instanceof JavadocSingleTypeReference && reference.resolvedTy
542544
scope.problemReporter().javadocInvalidReference(reference.sourceStart, reference.sourceEnd);
543545
}
544546
}
545-
546547
/*
547-
* Resolve @param tags while method scope
548+
* Resolve @param tags for records
549+
*/
550+
private void resolveParamTags(ClassScope scope, boolean reportMissing) {
551+
TypeDeclaration typeDecl = scope.referenceContext;
552+
if (!typeDecl.isRecord())
553+
return;
554+
Function<JavadocSingleNameReference, Binding> resolveNameRef =
555+
(nameRef) -> {
556+
nameRef.resolve(scope);
557+
return nameRef.binding;
558+
};
559+
Function<AbstractVariableDeclaration, Binding> resolveArgumentOrComponent =
560+
(arg) -> {
561+
return typeDecl.binding.getField(arg.name, false);
562+
};
563+
resolveParamTags(typeDecl.initializerScope,
564+
reportMissing,
565+
typeDecl.recordComponents,
566+
true,
567+
typeDecl.modifiers, // not used
568+
resolveNameRef,
569+
resolveArgumentOrComponent);
570+
}
571+
/*
572+
* Resolve @param tags for methods
548573
*/
549574
private void resolveParamTags(MethodScope scope, boolean reportMissing, boolean considerParamRefAsUsage) {
550575
AbstractMethodDeclaration methodDecl = scope.referenceMethod();
@@ -558,36 +583,62 @@ private void resolveParamTags(MethodScope scope, boolean reportMissing, boolean
558583
}
559584
return;
560585
}
586+
Function<JavadocSingleNameReference, Binding> resolveNameRef =
587+
(nameRef) -> {
588+
nameRef.resolve(scope, true, considerParamRefAsUsage);
589+
return nameRef.binding;
590+
};
591+
Function<AbstractVariableDeclaration, Binding> resolveArgumentOrComponent =
592+
(arg) -> {
593+
return arg instanceof Argument argument ? argument.binding : scope.findVariable(arg.name);
594+
};
595+
resolveParamTags(scope,
596+
reportMissing,
597+
methodDecl.arguments(),
598+
!methodDecl.isCompactConstructor(),
599+
methodDecl.binding.modifiers,
600+
resolveNameRef,
601+
resolveArgumentOrComponent);
602+
}
603+
private void resolveParamTags(MethodScope scope,
604+
boolean reportMissing,
605+
AbstractVariableDeclaration[] arguments,
606+
boolean reportAllUndocumented,
607+
int modifiers,
608+
Function<JavadocSingleNameReference, Binding> resolveNameRef,
609+
Function<AbstractVariableDeclaration, Binding> resolveArgumentOrComponent) {
561610

611+
int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
562612
// If no param tags then report a problem for each method argument
563-
AbstractVariableDeclaration [] arguments = methodDecl.arguments(true);
564613
int argumentsSize = arguments == null ? 0 : arguments.length;
565614
if (paramTagsSize == 0) {
566-
if (reportMissing && !methodDecl.isCompactConstructor()) {
615+
if (reportMissing && reportAllUndocumented) {
567616
for (int i = 0; i < argumentsSize; i++) {
568617
AbstractVariableDeclaration arg = arguments[i];
569-
scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers);
618+
scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, modifiers);
570619
}
571620
}
621+
return;
572622
} else {
573-
LocalVariableBinding[] bindings = new LocalVariableBinding[paramTagsSize];
623+
VariableBinding[] bindings = new VariableBinding[paramTagsSize];
574624
int maxBindings = 0;
575625

576626
// Scan all @param tags
577627
for (int i = 0; i < paramTagsSize; i++) {
578628
JavadocSingleNameReference param = this.paramReferences[i];
579-
param.resolve(scope, true, considerParamRefAsUsage);
580-
if (param.binding != null && param.binding.isValidBinding()) {
629+
630+
Binding lBinding = resolveNameRef.apply(param);
631+
if (lBinding instanceof VariableBinding varBinding) {
581632
// Verify duplicated tags
582633
boolean found = false;
583634
for (int j = 0; j < maxBindings && !found; j++) {
584635
if (bindings[j] == param.binding) {
585-
scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, methodDecl.binding.modifiers);
636+
scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
586637
found = true;
587638
}
588639
}
589640
if (!found) {
590-
bindings[maxBindings++] = (LocalVariableBinding) param.binding;
641+
bindings[maxBindings++] = varBinding;
591642
}
592643
}
593644
}
@@ -596,17 +647,19 @@ private void resolveParamTags(MethodScope scope, boolean reportMissing, boolean
596647
if (reportMissing) {
597648
for (int i = 0; i < argumentsSize; i++) {
598649
AbstractVariableDeclaration arg = arguments[i];
599-
LocalVariableBinding argBinding = arg instanceof Argument argument ? argument.binding : scope.findVariable(arg.name);
600-
boolean found = false;
601-
for (int j = 0; j < maxBindings; j++) {
602-
LocalVariableBinding binding = bindings[j];
603-
if (argBinding == binding) {
604-
found = true;
605-
break;
650+
Binding lBinding = resolveArgumentOrComponent.apply(arg);
651+
if (lBinding instanceof VariableBinding argBinding) {
652+
boolean found = false;
653+
for (int j = 0; j < maxBindings; j++) {
654+
VariableBinding binding = bindings[j];
655+
if (argBinding == binding) {
656+
found = true;
657+
break;
658+
}
659+
}
660+
if (!found) {
661+
scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, modifiers);
606662
}
607-
}
608-
if (!found) {
609-
scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers);
610663
}
611664
}
612665
}
@@ -760,12 +813,10 @@ private void resolveProvidesTags(BlockScope scope, boolean reportMissing) {
760813
*/
761814
private void resolveTypeParameterTags(Scope scope, boolean reportMissing) {
762815
int paramTypeParamLength = this.paramTypeParameters == null ? 0 : this.paramTypeParameters.length;
763-
int paramReferencesLength = this.paramReferences == null ? 0 : this.paramReferences.length;
764816

765817
// Get declaration infos
766818
TypeParameter[] parameters = null;
767819
TypeVariableBinding[] typeVariables = null;
768-
RecordComponent[] recordParameters = null;
769820
int modifiers = -1;
770821
switch (scope.kind) {
771822
case Scope.METHOD_SCOPE:
@@ -787,81 +838,17 @@ private void resolveTypeParameterTags(Scope scope, boolean reportMissing) {
787838
parameters = typeDeclaration.typeParameters;
788839
typeVariables = typeDeclaration.binding.typeVariables;
789840
modifiers = typeDeclaration.binding.modifiers;
790-
recordParameters = typeDeclaration.recordComponents;
791841
break;
792842
}
793843

794844
// If no type variables then report a problem for each param type parameter tag
795-
if ((recordParameters == null || recordParameters.length == 0)
796-
&& (typeVariables == null || typeVariables.length == 0)) {
845+
if ((typeVariables == null || typeVariables.length == 0)) {
797846
for (int i = 0; i < paramTypeParamLength; i++) {
798847
JavadocSingleTypeReference param = this.paramTypeParameters[i];
799848
scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
800849
}
801850
return;
802851
}
803-
804-
// If no param tags then report a problem for each record parameter
805-
if (recordParameters != null) {
806-
int recordParametersLength = recordParameters.length;
807-
String argNames[] = new String[paramReferencesLength];
808-
if (paramReferencesLength == 0) {
809-
if (reportMissing) {
810-
for (int i = 0, l=recordParametersLength; i<l; i++) {
811-
scope.problemReporter().javadocMissingParamTag(recordParameters[i].name, recordParameters[i].sourceStart, recordParameters[i].sourceEnd, modifiers);
812-
}
813-
}
814-
} else {
815-
// Otherwise verify that all param tags match record args
816-
// Scan all @param tags
817-
for (int i = 0; i < paramReferencesLength; ++i) {
818-
JavadocSingleNameReference param = this.paramReferences[i];
819-
String paramName = new String(param.getName()[0]);
820-
// Verify duplicated tags
821-
boolean duplicate = false;
822-
for (int j = 0; j < i && !duplicate; j++) {
823-
if (paramName.equals(argNames[j])) {
824-
scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
825-
duplicate = true;
826-
}
827-
}
828-
if (!duplicate) {
829-
argNames[i] = paramName;
830-
}
831-
}
832-
// Look for undocumented arguments
833-
if (reportMissing) {
834-
for (RecordComponent component : recordParameters) {
835-
boolean found = false;
836-
for (int j = 0; j < paramReferencesLength && !found; j++) {
837-
JavadocSingleNameReference param = this.paramReferences[j];
838-
String paramName = new String(param.getName()[0]);
839-
if (paramName.equals(new String(component.name))) {
840-
found = true;
841-
}
842-
}
843-
if (!found) {
844-
scope.problemReporter().javadocMissingParamTag(component.name, component.sourceStart, component.sourceEnd, modifiers);
845-
}
846-
}
847-
}
848-
// Look for param tags that specify non-existent arguments
849-
for (int i = 0; i < paramReferencesLength; i++) {
850-
JavadocSingleNameReference param = this.paramReferences[i];
851-
String paramName = new String(param.getName()[0]);
852-
boolean found = false;
853-
for (RecordComponent component : recordParameters) {
854-
if (paramName.equals(new String(component.name))) {
855-
found = true;
856-
}
857-
}
858-
if (!found) {
859-
scope.problemReporter().javadocInvalidParamTagName(param.sourceStart, param.sourceEnd);
860-
}
861-
}
862-
}
863-
}
864-
865852
// If no param tags then report a problem for each declaration type parameter
866853
if (parameters != null) {
867854
int typeParametersLength = parameters.length;

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.eclipse.jdt.internal.compiler.ASTVisitor;
1717
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
1818
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
19+
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
1920
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
2021
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
2122
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
@@ -31,6 +32,25 @@ public JavadocSingleNameReference(char[] source, long pos, int tagStart, int tag
3132
this.bits |= InsideJavadoc;
3233
}
3334

35+
public void resolve(ClassScope scope) {
36+
TypeDeclaration type = scope.referenceContext;
37+
if (type != null && type.isRecord()) {
38+
FieldBinding field = type.binding.getField(this.token, false);
39+
if (field != null && field.isValidBinding()) {
40+
this.binding = field;
41+
return;
42+
}
43+
if (scope.compilerOptions().reportUnusedParameterIncludeDocCommentReference) {
44+
try {
45+
scope.problemReporter().javadocUndeclaredParamTagName(this.token, this.sourceStart, this.sourceEnd, type.modifiers);
46+
}
47+
catch (Exception e) {
48+
scope.problemReporter().javadocUndeclaredParamTagName(this.token, this.sourceStart, this.sourceEnd, -1);
49+
}
50+
}
51+
}
52+
}
53+
3454
@Override
3555
public void resolve(BlockScope scope) {
3656
resolve(scope, true, scope.compilerOptions().reportUnusedParameterIncludeDocCommentReference);

0 commit comments

Comments
 (0)