/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.ext.java.jdt.internal.text.correction; import org.eclipse.che.ide.ext.java.jdt.Images; import org.eclipse.che.ide.ext.java.jdt.JavaUIStatus; import org.eclipse.che.ide.ext.java.jdt.codeassistant.api.IProblemLocation; import org.eclipse.che.ide.ext.java.jdt.core.JavaCore; import org.eclipse.che.ide.ext.java.jdt.core.compiler.IProblem; import org.eclipse.che.ide.ext.java.jdt.core.dom.AST; import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode; import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.BodyDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit; import org.eclipse.che.ide.ext.java.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.FieldDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.IBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.IMethodBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.Javadoc; import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.Name; import org.eclipse.che.ide.ext.java.jdt.core.dom.PrimitiveType; import org.eclipse.che.ide.ext.java.jdt.core.dom.SimpleName; import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.che.ide.ext.java.jdt.core.dom.TagElement; import org.eclipse.che.ide.ext.java.jdt.core.dom.TextElement; import org.eclipse.che.ide.ext.java.jdt.core.dom.Type; import org.eclipse.che.ide.ext.java.jdt.core.dom.TypeDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.TypeParameter; import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ASTResolving; import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.StubUtility; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ASTNodes; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.Bindings; import org.eclipse.che.ide.ext.java.jdt.internal.corext.util.Strings; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.ASTRewriteCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.CUCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.LinkedCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.quickassist.api.InvocationContext; import org.eclipse.che.ide.ext.java.jdt.text.Document; import org.eclipse.che.ide.ext.java.jdt.text.TextUtilities; import org.eclipse.che.ide.ext.java.jdt.text.edits.InsertEdit; import org.eclipse.che.ide.ext.java.jdt.text.edits.TextEdit; import org.eclipse.che.ide.ext.java.jdt.text.edits.TextEditGroup; import org.eclipse.che.ide.runtime.Assert; import org.eclipse.che.ide.runtime.CoreException; import org.eclipse.che.ide.runtime.IStatus; import org.eclipse.che.ide.api.text.BadLocationException; import org.eclipse.che.ide.api.text.Region; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * */ public class JavadocTagsSubProcessor { private static final class AddJavadocCommentProposal extends CUCorrectionProposal { private final int fInsertPosition; private final String fComment; private AddJavadocCommentProposal(String name, int relevance, Document document, int insertPosition, String comment) { super(name, relevance, document, Images.javadoc); fInsertPosition = insertPosition; fComment = comment; } @Override protected void addEdits(Document document, TextEdit rootEdit) throws CoreException { try { String lineDelimiter = TextUtilities.getDefaultLineDelimiter(document); // final IJavaProject project = getCompilationUnit().getJavaProject(); Region region = document.getLineInformationOfOffset(fInsertPosition); String lineContent = document.get(region.getOffset(), region.getLength()); String indentString = Strings.getIndentString(lineContent); String str = Strings.changeIndent(fComment, 0, indentString, lineDelimiter); InsertEdit edit = new InsertEdit(fInsertPosition, str); rootEdit.addChild(edit); if (fComment.charAt(fComment.length() - 1) != '\n') { rootEdit.addChild(new InsertEdit(fInsertPosition, lineDelimiter)); rootEdit.addChild(new InsertEdit(fInsertPosition, indentString)); } } catch (BadLocationException e) { throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e)); } } } private static final class AddMissingJavadocTagProposal extends LinkedCorrectionProposal { private final BodyDeclaration fBodyDecl; // MethodDecl or TypeDecl private final ASTNode fMissingNode; public AddMissingJavadocTagProposal(String label, BodyDeclaration methodDecl, ASTNode missingNode, int relevance, Document document) { super(label, null, relevance, document, Images.javadoc); fBodyDecl = methodDecl; fMissingNode = missingNode; } @Override protected ASTRewrite getRewrite() throws CoreException { AST ast = fBodyDecl.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); insertMissingJavadocTag(rewrite, fMissingNode, fBodyDecl); return rewrite; } private void insertMissingJavadocTag(ASTRewrite rewrite, ASTNode missingNode, BodyDeclaration bodyDecl) { AST ast = bodyDecl.getAST(); Javadoc javadoc = bodyDecl.getJavadoc(); if (javadoc == null) { javadoc = ast.newJavadoc(); rewrite.set(bodyDecl, bodyDecl.getJavadocProperty(), javadoc, null); } ListRewrite tagsRewriter = rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY); StructuralPropertyDescriptor location = missingNode.getLocationInParent(); TagElement newTag; if (location == SingleVariableDeclaration.NAME_PROPERTY) { // normal parameter SingleVariableDeclaration decl = (SingleVariableDeclaration)missingNode.getParent(); String name = ((SimpleName)missingNode).getIdentifier(); newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_PARAM); newTag.fragments().add(ast.newSimpleName(name)); MethodDeclaration methodDeclaration = (MethodDeclaration)bodyDecl; List<SingleVariableDeclaration> params = methodDeclaration.parameters(); Set<String> sameKindLeadingNames = getPreviousParamNames(params, decl); List<TypeParameter> typeParams = methodDeclaration.typeParameters(); for (int i = 0; i < typeParams.size(); i++) { String curr = '<' + typeParams.get(i).getName().getIdentifier() + '>'; sameKindLeadingNames.add(curr); } insertTag(tagsRewriter, newTag, sameKindLeadingNames); } else if (location == TypeParameter.NAME_PROPERTY) { // type parameter TypeParameter typeParam = (TypeParameter)missingNode.getParent(); String name = '<' + ((SimpleName)missingNode).getIdentifier() + '>'; newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_PARAM); TextElement text = ast.newTextElement(); text.setText(name); newTag.fragments().add(text); List<TypeParameter> params; if (bodyDecl instanceof TypeDeclaration) { params = ((TypeDeclaration)bodyDecl).typeParameters(); } else { params = ((MethodDeclaration)bodyDecl).typeParameters(); } insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(params, typeParam)); } else if (location == MethodDeclaration.RETURN_TYPE2_PROPERTY) { newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_RETURN); insertTag(tagsRewriter, newTag, null); } else if (location == MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY) { newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_THROWS); TextElement excNode = ast.newTextElement(); excNode.setText(ASTNodes.asString(missingNode)); newTag.fragments().add(excNode); List<Name> exceptions = ((MethodDeclaration)bodyDecl).thrownExceptions(); insertTag(tagsRewriter, newTag, getPreviousExceptionNames(exceptions, missingNode)); } else { Assert.isTrue(false, "AddMissingJavadocTagProposal: unexpected node location"); //$NON-NLS-1$ return; } TextElement textElement = ast.newTextElement(); textElement.setText(""); //$NON-NLS-1$ newTag.fragments().add(textElement); // addLinkedPosition(rewrite.track(textElement), false, "comment_start"); //$NON-NLS-1$ if (bodyDecl.getJavadoc() == null) { // otherwise the linked position spans over a line delimiter newTag.fragments().add(ast.newTextElement()); } } } private static final class AddAllMissingJavadocTagsProposal extends LinkedCorrectionProposal { private final BodyDeclaration fBodyDecl; public AddAllMissingJavadocTagsProposal(String label, BodyDeclaration bodyDecl, int relevance, Document document) { super(label, null, relevance, document, Images.javadoc); fBodyDecl = bodyDecl; } @Override protected ASTRewrite getRewrite() throws CoreException { ASTRewrite rewrite = ASTRewrite.create(fBodyDecl.getAST()); if (fBodyDecl instanceof MethodDeclaration) { insertAllMissingMethodTags(rewrite, (MethodDeclaration)fBodyDecl); } else { insertAllMissingTypeTags(rewrite, (TypeDeclaration)fBodyDecl); } return rewrite; } private void insertAllMissingMethodTags(ASTRewrite rewriter, MethodDeclaration methodDecl) { AST ast = methodDecl.getAST(); Javadoc javadoc = methodDecl.getJavadoc(); ListRewrite tagsRewriter = rewriter.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY); List<TypeParameter> typeParams = methodDecl.typeParameters(); ASTNode root = methodDecl.getRoot(); if (root instanceof CompilationUnit) { ASTNode typeRoot = ((CompilationUnit)root).getParent(); if (typeRoot != null && !StubUtility.shouldGenerateMethodTypeParameterTags()) typeParams = Collections.emptyList(); } List<String> typeParamNames = new ArrayList<String>(); for (int i = typeParams.size() - 1; i >= 0; i--) { TypeParameter decl = typeParams.get(i); String name = '<' + decl.getName().getIdentifier() + '>'; if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) { TagElement newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_PARAM); TextElement text = ast.newTextElement(); text.setText(name); newTag.fragments().add(text); insertTabStop(rewriter, newTag.fragments(), "typeParam" + i); //$NON-NLS-1$ insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(typeParams, decl)); } typeParamNames.add(name); } List<SingleVariableDeclaration> params = methodDecl.parameters(); for (int i = params.size() - 1; i >= 0; i--) { SingleVariableDeclaration decl = params.get(i); String name = decl.getName().getIdentifier(); if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) { TagElement newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_PARAM); newTag.fragments().add(ast.newSimpleName(name)); insertTabStop(rewriter, newTag.fragments(), "methParam" + i); //$NON-NLS-1$ Set<String> sameKindLeadingNames = getPreviousParamNames(params, decl); sameKindLeadingNames.addAll(typeParamNames); insertTag(tagsRewriter, newTag, sameKindLeadingNames); } } if (!methodDecl.isConstructor()) { Type type = methodDecl.getReturnType2(); if (!type.isPrimitiveType() || (((PrimitiveType)type).getPrimitiveTypeCode() != PrimitiveType.VOID)) { if (findTag(javadoc, TagElement.TAG_RETURN, null) == null) { TagElement newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_RETURN); insertTabStop(rewriter, newTag.fragments(), "return"); //$NON-NLS-1$ insertTag(tagsRewriter, newTag, null); } } } List<Name> thrownExceptions = methodDecl.thrownExceptions(); for (int i = thrownExceptions.size() - 1; i >= 0; i--) { Name exception = thrownExceptions.get(i); ITypeBinding binding = exception.resolveTypeBinding(); if (binding != null) { String name = binding.getName(); if (findThrowsTag(javadoc, name) == null) { TagElement newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_THROWS); TextElement excNode = ast.newTextElement(); excNode.setText(ASTNodes.asString(exception)); newTag.fragments().add(excNode); insertTabStop(rewriter, newTag.fragments(), "exception" + i); //$NON-NLS-1$ insertTag(tagsRewriter, newTag, getPreviousExceptionNames(thrownExceptions, exception)); } } } } private void insertAllMissingTypeTags(ASTRewrite rewriter, TypeDeclaration typeDecl) { AST ast = typeDecl.getAST(); Javadoc javadoc = typeDecl.getJavadoc(); ListRewrite tagsRewriter = rewriter.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY); List<TypeParameter> typeParams = typeDecl.typeParameters(); for (int i = typeParams.size() - 1; i >= 0; i--) { TypeParameter decl = typeParams.get(i); String name = '<' + decl.getName().getIdentifier() + '>'; if (findTag(javadoc, TagElement.TAG_PARAM, name) == null) { TagElement newTag = ast.newTagElement(); newTag.setTagName(TagElement.TAG_PARAM); TextElement text = ast.newTextElement(); text.setText(name); newTag.fragments().add(text); insertTabStop(rewriter, newTag.fragments(), "typeParam" + i); //$NON-NLS-1$ insertTag(tagsRewriter, newTag, getPreviousTypeParamNames(typeParams, decl)); } } } private void insertTabStop(ASTRewrite rewriter, List<ASTNode> fragments, String linkedName) { TextElement textElement = rewriter.getAST().newTextElement(); textElement.setText(""); //$NON-NLS-1$ fragments.add(textElement); // addLinkedPosition(rewriter.track(textElement), false, linkedName); } } public static void getMissingJavadocTagProposals(InvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { ASTNode node = problem.getCoveringNode(context.getASTRoot()); if (node == null) { return; } node = ASTNodes.getNormalizedNode(node); BodyDeclaration bodyDeclaration = ASTResolving.findParentBodyDeclaration(node); if (bodyDeclaration == null) { return; } Javadoc javadoc = bodyDeclaration.getJavadoc(); if (javadoc == null) { return; } String label; StructuralPropertyDescriptor location = node.getLocationInParent(); if (location == SingleVariableDeclaration.NAME_PROPERTY) { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_paramtag_description(); if (node.getParent().getLocationInParent() != MethodDeclaration.PARAMETERS_PROPERTY) { return; // paranoia checks } } else if (location == TypeParameter.NAME_PROPERTY) { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_paramtag_description(); StructuralPropertyDescriptor parentLocation = node.getParent().getLocationInParent(); if (parentLocation != MethodDeclaration.TYPE_PARAMETERS_PROPERTY && parentLocation != TypeDeclaration.TYPE_PARAMETERS_PROPERTY) { return; // paranoia checks } } else if (location == MethodDeclaration.RETURN_TYPE2_PROPERTY) { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_returntag_description(); } else if (location == MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY) { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_throwstag_description(); } else { return; } ASTRewriteCorrectionProposal proposal = new AddMissingJavadocTagProposal(label, bodyDeclaration, node, 4, context.getDocument()); proposals.add(proposal); String label2 = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_allmissing_description(); ASTRewriteCorrectionProposal addAllMissing = new AddAllMissingJavadocTagsProposal(label2, bodyDeclaration, 5, context.getDocument()); proposals.add(addAllMissing); } public static void getUnusedAndUndocumentedParameterOrExceptionProposals(InvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { if (!JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT))) { return; } boolean isUnusedParam = problem.getProblemId() == IProblem.ArgumentIsNeverUsed; String key = isUnusedParam ? JavaCore.COMPILER_PB_UNUSED_PARAMETER_INCLUDE_DOC_COMMENT_REFERENCE : JavaCore.COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION_INCLUDE_DOC_COMMENT_REFERENCE; if (!JavaCore.ENABLED.equals(JavaCore.getOption(key))) { return; } ASTNode node = problem.getCoveringNode(context.getASTRoot()); if (node == null) { return; } MethodDeclaration methodDecl = (MethodDeclaration)ASTNodes.getParent(node, ASTNode.METHOD_DECLARATION); if (methodDecl == null || methodDecl.resolveBinding() == null) { return; } String label; if (isUnusedParam) { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_document_parameter_description(); } else { label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_document_exception_description(); } ASTRewriteCorrectionProposal proposal = new AddMissingJavadocTagProposal(label, methodDecl, node, 1, context.getDocument()); proposals.add(proposal); } public static void getMissingJavadocCommentProposals(InvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { ASTNode node = problem.getCoveringNode(context.getASTRoot()); if (node == null) { return; } BodyDeclaration declaration = ASTResolving.findParentBodyDeclaration(node); if (declaration == null) { return; } ITypeBinding binding = Bindings.getBindingOfParentType(declaration); if (binding == null) { return; } if (declaration instanceof MethodDeclaration) { MethodDeclaration methodDecl = (MethodDeclaration)declaration; IMethodBinding methodBinding = methodDecl.resolveBinding(); IMethodBinding overridden = null; if (methodBinding != null) { overridden = Bindings.findOverriddenMethod(methodBinding, true); } String string = LinkedCorrectionProposal.getMethodComment(binding.getName(), methodDecl, overridden, String.valueOf('\n')); // CodeGeneration.getMethodComment(cu, binding.getName(), methodDecl, overridden, ); if (string != null) { String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_method_description(); proposals.add(new AddJavadocCommentProposal(label, 1, context.getDocument(), declaration.getStartPosition(), string)); } } else if (declaration instanceof AbstractTypeDeclaration) { String typeQualifiedName = Bindings.getTypeQualifiedName(binding); String[] typeParamNames; if (declaration instanceof TypeDeclaration) { List<TypeParameter> typeParams = ((TypeDeclaration)declaration).typeParameters(); typeParamNames = new String[typeParams.size()]; for (int i = 0; i < typeParamNames.length; i++) { typeParamNames[i] = (typeParams.get(i)).getName().getIdentifier(); } } else { typeParamNames = new String[0]; } String string = StubUtility.getTypeComment(typeQualifiedName, typeParamNames, String.valueOf('\n')); if (string != null) { String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_type_description(); proposals.add(new AddJavadocCommentProposal(label, 1, context.getDocument(), declaration.getStartPosition(), string)); } } else if (declaration instanceof FieldDeclaration) { String comment = "/**\n *\n */\n"; //$NON-NLS-1$ List<VariableDeclarationFragment> fragments = ((FieldDeclaration)declaration).fragments(); if (fragments != null && fragments.size() > 0) { VariableDeclaration decl = fragments.get(0); String fieldName = decl.getName().getIdentifier(); String typeName = binding.getName(); comment = StubUtility.getFieldComment(typeName, fieldName, String.valueOf('\n')); } if (comment != null) { String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_field_description(); proposals.add(new AddJavadocCommentProposal(label, 1, context.getDocument(), declaration.getStartPosition(), comment)); } } else if (declaration instanceof EnumConstantDeclaration) { EnumConstantDeclaration enumDecl = (EnumConstantDeclaration)declaration; String id = enumDecl.getName().getIdentifier(); String comment = StubUtility.getFieldComment(binding.getName(), id, String.valueOf('\n')); String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_addjavadoc_enumconst_description(); proposals.add(new AddJavadocCommentProposal(label, 1, context.getDocument(), declaration.getStartPosition(), comment)); } } public static Set<String> getPreviousTypeParamNames(List<TypeParameter> typeParams, ASTNode missingNode) { Set<String> previousNames = new HashSet<String>(); for (int i = 0; i < typeParams.size(); i++) { TypeParameter curr = typeParams.get(i); if (curr == missingNode) { return previousNames; } previousNames.add('<' + curr.getName().getIdentifier() + '>'); } return previousNames; } private static Set<String> getPreviousParamNames(List<SingleVariableDeclaration> params, ASTNode missingNode) { Set<String> previousNames = new HashSet<String>(); for (int i = 0; i < params.size(); i++) { SingleVariableDeclaration curr = params.get(i); if (curr == missingNode) { return previousNames; } previousNames.add(curr.getName().getIdentifier()); } return previousNames; } private static Set<String> getPreviousExceptionNames(List<Name> list, ASTNode missingNode) { Set<String> previousNames = new HashSet<String>(); for (int i = 0; i < list.size() && missingNode != list.get(i); i++) { Name curr = list.get(i); previousNames.add(ASTNodes.getSimpleNameIdentifier(curr)); } return previousNames; } public static TagElement findTag(Javadoc javadoc, String name, String arg) { List<TagElement> tags = javadoc.tags(); int nTags = tags.size(); for (int i = 0; i < nTags; i++) { TagElement curr = tags.get(i); if (name.equals(curr.getTagName())) { if (arg != null) { String argument = getArgument(curr); if (arg.equals(argument)) { return curr; } } else { return curr; } } } return null; } public static TagElement findParamTag(Javadoc javadoc, String arg) { List<TagElement> tags = javadoc.tags(); int nTags = tags.size(); for (int i = 0; i < nTags; i++) { TagElement curr = tags.get(i); String currName = curr.getTagName(); if (TagElement.TAG_PARAM.equals(currName)) { String argument = getArgument(curr); if (arg.equals(argument)) { return curr; } } } return null; } public static TagElement findThrowsTag(Javadoc javadoc, String arg) { List<TagElement> tags = javadoc.tags(); int nTags = tags.size(); for (int i = 0; i < nTags; i++) { TagElement curr = tags.get(i); String currName = curr.getTagName(); if (TagElement.TAG_THROWS.equals(currName) || TagElement.TAG_EXCEPTION.equals(currName)) { String argument = getArgument(curr); if (arg.equals(argument)) { return curr; } } } return null; } public static void insertTag(ListRewrite rewriter, TagElement newElement, Set<String> sameKindLeadingNames) { insertTag(rewriter, newElement, sameKindLeadingNames, null); } public static void insertTag(ListRewrite rewriter, TagElement newElement, Set<String> sameKindLeadingNames, TextEditGroup groupDescription) { List<? extends ASTNode> tags = rewriter.getRewrittenList(); String insertedTagName = newElement.getTagName(); ASTNode after = null; int tagRanking = getTagRanking(insertedTagName); for (int i = tags.size() - 1; i >= 0; i--) { TagElement curr = (TagElement)tags.get(i); String tagName = curr.getTagName(); if (tagName == null || tagRanking > getTagRanking(tagName)) { after = curr; break; } if (sameKindLeadingNames != null && isSameTag(insertedTagName, tagName)) { String arg = getArgument(curr); if (arg != null && sameKindLeadingNames.contains(arg)) { after = curr; break; } } } if (after != null) { rewriter.insertAfter(newElement, after, groupDescription); } else { rewriter.insertFirst(newElement, groupDescription); } } private static boolean isSameTag(String insertedTagName, String tagName) { if (insertedTagName.equals(tagName)) { return true; } if (TagElement.TAG_EXCEPTION.equals(tagName)) { return TagElement.TAG_THROWS.equals(insertedTagName); } return false; } private static String[] TAG_ORDER = { // see http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#orderoftags TagElement.TAG_AUTHOR, TagElement.TAG_VERSION, TagElement.TAG_PARAM, TagElement.TAG_RETURN, TagElement.TAG_THROWS, // synonym to TAG_EXCEPTION TagElement.TAG_SEE, TagElement.TAG_SINCE, TagElement.TAG_SERIAL, TagElement.TAG_DEPRECATED}; private static int getTagRanking(String tagName) { if (tagName.equals(TagElement.TAG_EXCEPTION)) { tagName = TagElement.TAG_THROWS; } for (int i = 0; i < TAG_ORDER.length; i++) { if (tagName.equals(TAG_ORDER[i])) { return i; } } return TAG_ORDER.length; } private static String getArgument(TagElement curr) { List<? extends ASTNode> fragments = curr.fragments(); if (!fragments.isEmpty()) { Object first = fragments.get(0); if (first instanceof Name) { return ASTNodes.getSimpleNameIdentifier((Name)first); } else if (first instanceof TextElement && TagElement.TAG_PARAM.equals(curr.getTagName())) { String text = ((TextElement)first).getText(); if ("<".equals(text) && fragments.size() >= 3) { //$NON-NLS-1$ Object second = fragments.get(1); Object third = fragments.get(2); if (second instanceof Name && third instanceof TextElement && ">".equals(((TextElement)third).getText())) { //$NON-NLS-1$ return '<' + ASTNodes.getSimpleNameIdentifier((Name)second) + '>'; } } else if (text.startsWith(String.valueOf('<')) && text.endsWith(String.valueOf('>')) && text.length() > 2) { return text.substring(1, text.length() - 1); } } } return null; } public static void getRemoveJavadocTagProposals(InvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { ASTNode node = problem.getCoveringNode(context.getASTRoot()); while (node != null && !(node instanceof TagElement)) { node = node.getParent(); } if (node == null) { return; } ASTRewrite rewrite = ASTRewrite.create(node.getAST()); rewrite.remove(node, null); String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_removetag_description(); Images image = Images.delete_obj; proposals.add(new ASTRewriteCorrectionProposal(label, rewrite, 5, context.getDocument(), image)); } public static void getInvalidQualificationProposals(InvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { ASTNode node = problem.getCoveringNode(context.getASTRoot()); if (!(node instanceof Name)) { return; } Name name = (Name)node; IBinding binding = name.resolveBinding(); if (!(binding instanceof ITypeBinding)) { return; } ITypeBinding typeBinding = (ITypeBinding)binding; AST ast = node.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); rewrite.replace(name, ast.newName(typeBinding.getQualifiedName()), null); String label = CorrectionMessages.INSTANCE.JavadocTagsSubProcessor_qualifylinktoinner_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 5, context.getDocument(), image); proposals.add(proposal); } }