blob: 8af44754859b24923e504899b0f6be2b5d2d3400 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.codeassist.complete;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.parser.JavadocTagConstants;
public class CompletionOnJavadocTag extends JavadocSingleNameReference implements JavadocTagConstants, CompletionOnJavadoc {
public int completionFlags = JAVADOC;
public final static char[][][] NO_CHAR_CHAR_CHAR = new char[0][][];
private char[][][] possibleTags = NO_CHAR_CHAR_CHAR;
public CompletionOnJavadocTag(char[] source, long pos, int tagStart, int tagEnd, char[][][] possibleTags, boolean orphan) {
super(source, pos, tagStart, tagEnd);
this.possibleTags = possibleTags;
if (orphan) this.completionFlags |= ALL_POSSIBLE_TAGS;
}
@Override
public void addCompletionFlags(int flags) {
this.completionFlags |= flags;
}
@Override
public int getCompletionFlags() {
return this.completionFlags;
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output) {
output.append("<CompleteOnJavadocTag:"); //$NON-NLS-1$
output.append('@');
if (this.token != null) super.printExpression(indent, output);
// Print block tags
char[][] blockTags = this.possibleTags[BLOCK_IDX];
if (blockTags != null) {
int length=blockTags.length;
if (length > 0) {
output.append("\npossible block tags:"); //$NON-NLS-1$
for (int i=0; i<length; i++) {
output.append("\n - "); //$NON-NLS-1$
output.append(blockTags[i]);
}
output.append('\n');
}
}
// Print inline tags
char[][] inlineTags = this.possibleTags[INLINE_IDX];
if (inlineTags != null) {
int length=inlineTags.length;
if (length > 0) {
output.append("\npossible inline tags:"); //$NON-NLS-1$
for (int i=0; i<length; i++) {
output.append("\n - "); //$NON-NLS-1$
output.append(inlineTags[i]);
}
output.append('\n');
}
}
// Print snippet tags
char[][] snipTags = this.possibleTags[SNIPPET_IDX];
if (snipTags != null) {
int length=snipTags.length;
if (length > 0) {
output.append("\npossible snippet tags:"); //$NON-NLS-1$
for (int i=0; i<length; i++) {
output.append("\n - "); //$NON-NLS-1$
output.append(snipTags[i]);
}
output.append('\n');
}
}
return output.append('>');
}
public void filterPossibleTags(Scope scope) {
if (this.possibleTags == null || this.possibleTags.length == 0 || (this.completionFlags & ALL_POSSIBLE_TAGS) != 0) {
return;
}
int kind = scope.kind;
char[][] specifiedTags = null;
switch (kind) {
case Scope.COMPILATION_UNIT_SCOPE:
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=255752
// Check for FAKE_TYPE_NAME to allow proposals (@see CompletionParser#consumeCompilationUnit)
CompilationUnitDeclaration compilationUnit = scope.referenceCompilationUnit();
if(compilationUnit != null && compilationUnit.isModuleInfo() ) {
specifiedTags = MODULE_TAGS;
break;
}
if (compilationUnit != null &&
(compilationUnit.types.length > 0 && compilationUnit.types[0].name == CompletionParser.FAKE_TYPE_NAME)) {
specifiedTags = CLASS_TAGS;
} else {
specifiedTags = COMPILATION_UNIT_TAGS;
}
break;
case Scope.CLASS_SCOPE:
specifiedTags = CLASS_TAGS;
break;
case Scope.METHOD_SCOPE:
MethodScope methodScope = (MethodScope) scope;
if (methodScope.referenceMethod() == null) {
if (methodScope.initializedField == null) {
specifiedTags = PACKAGE_TAGS;
} else {
specifiedTags = FIELD_TAGS;
}
} else {
specifiedTags = METHOD_TAGS;
}
break;
default:
return;
}
int kinds = this.possibleTags.length;
for (int k=0; k<kinds; k++) {
int length = this.possibleTags[k].length;
int specLenth = specifiedTags.length;
char[][] filteredTags = new char[length][];
int size = 0;
for (int i=0; i<length; i++) {
char[] possibleTag = this.possibleTags[k][i];
for (int j=0; j<specLenth; j++) {
if (possibleTag[0] == specifiedTags[j][0] && CharOperation.equals(possibleTag, specifiedTags[j])) {
if (possibleTag == TAG_PARAM) {
switch (scope.kind) {
case Scope.CLASS_SCOPE:
if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
TypeDeclaration typeDecl = ((ClassScope)scope).referenceContext;
boolean isRecordWithComponent = typeDecl.isRecord() && typeDecl.nRecordComponents >0 ;
if (((ClassScope)scope).referenceContext.binding.isGenericType() || isRecordWithComponent) {
filteredTags[size++] = possibleTag;
}
}
break;
case Scope.COMPILATION_UNIT_SCOPE:
if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
filteredTags[size++] = possibleTag;
}
break;
default:
filteredTags[size++] = possibleTag;
break;
}
} else {
filteredTags[size++] = possibleTag;
}
break;
}
}
}
if (size<length) {
System.arraycopy(filteredTags, 0, this.possibleTags[k] = new char[size][], 0, size);
}
}
}
/**
* Return possible block tags
*
* @return char[][]
*/
public char[][] getPossibleBlockTags() {
return this.possibleTags[BLOCK_IDX];
}
/**
* Return possible inline tags
*
* @return char[][]
*/
public char[][] getPossibleInlineTags() {
return this.possibleTags[INLINE_IDX];
}
public char[][] getPossibleInSnippetTags() {
return this.possibleTags[SNIPPET_IDX];
}
}