mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Cleanup (javadoc inspection logic separation)
This commit is contained in:
+269
-906
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -75,7 +75,7 @@ public class JavaDocReferenceInspectionBase extends BaseJavaBatchLocalInspectio
|
||||
final PsiDocTag[] tags = tag.getContainingComment().getTags();
|
||||
final Set<String> unboundParams = new HashSet<String>();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!JavaDocLocalInspectionBase.isFound(tags, parameter)) {
|
||||
if (!JavadocHighlightUtil.hasTagForParameter(tags, parameter)) {
|
||||
unboundParams.add(parameter.getName());
|
||||
}
|
||||
}
|
||||
|
||||
+492
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.javaDoc;
|
||||
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.reference.RefJavaUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
|
||||
import com.intellij.psi.javadoc.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class JavadocHighlightUtil {
|
||||
private static final String[] TAGS_TO_CHECK = {"author", "version", "since"};
|
||||
private static final Set<String> UNIQUE_TAGS = ContainerUtil.newHashSet("return", "deprecated", "serial", "serialData");
|
||||
|
||||
public interface ProblemHolder {
|
||||
Project project();
|
||||
JavaDocLocalInspectionBase inspection();
|
||||
|
||||
void problem(@NotNull PsiElement toHighlight, @NotNull @Nls String message, @Nullable LocalQuickFix fix);
|
||||
void eolProblem(@NotNull PsiElement toHighlight, @NotNull @Nls String message, @Nullable LocalQuickFix fix);
|
||||
|
||||
LocalQuickFix addJavadocFix(@NotNull PsiElement nameIdentifier);
|
||||
LocalQuickFix addMissingTagFix(@NotNull String tag, @NotNull String value);
|
||||
LocalQuickFix addMissingParamTagFix(@NotNull String name);
|
||||
LocalQuickFix registerTagFix(@NotNull String tag);
|
||||
}
|
||||
|
||||
static boolean isJavaDocRequired(@NotNull JavaDocLocalInspectionBase inspection, @NotNull PsiModifierListOwner element) {
|
||||
int actualAccess = getAccessNumber(RefJavaUtil.getInstance().getAccessModifier(element));
|
||||
|
||||
if (element instanceof PsiPackage) {
|
||||
return 1 <= getAccessNumber(inspection.PACKAGE_OPTIONS);
|
||||
}
|
||||
|
||||
if (element instanceof PsiClass) {
|
||||
boolean isInner = PsiTreeUtil.getParentOfType(element, PsiClass.class) != null;
|
||||
return actualAccess <= getAccessNumber(isInner ? inspection.INNER_CLASS_OPTIONS : inspection.TOP_LEVEL_CLASS_OPTIONS);
|
||||
}
|
||||
|
||||
if (element instanceof PsiMethod) {
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
while (element != null) {
|
||||
actualAccess = Math.max(actualAccess, getAccessNumber(RefJavaUtil.getInstance().getAccessModifier(element)));
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
}
|
||||
|
||||
return actualAccess <= getAccessNumber(inspection.METHOD_OPTIONS);
|
||||
}
|
||||
|
||||
if (element instanceof PsiField) {
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
while (element != null) {
|
||||
actualAccess = Math.max(actualAccess, getAccessNumber(RefJavaUtil.getInstance().getAccessModifier(element)));
|
||||
element = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
}
|
||||
|
||||
return actualAccess <= getAccessNumber(inspection.FIELD_OPTIONS);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getAccessNumber(JavaDocLocalInspectionBase.Options options) {
|
||||
return getAccessNumber(options.ACCESS_JAVADOC_REQUIRED_FOR);
|
||||
}
|
||||
|
||||
private static int getAccessNumber(String accessModifier) {
|
||||
if (accessModifier.startsWith("none")) return 0;
|
||||
if (accessModifier.startsWith("public")) return 1;
|
||||
if (accessModifier.startsWith("protected")) return 2;
|
||||
if (accessModifier.startsWith("package")) return 3;
|
||||
if (accessModifier.startsWith("private")) return 4;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static void reportMissingTag(@NotNull PsiElement toHighlight, @NotNull ProblemHolder holder) {
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.descriptor");
|
||||
holder.problem(toHighlight, message, holder.addJavadocFix(toHighlight));
|
||||
}
|
||||
|
||||
static void checkRequiredTags(@NotNull PsiDocTag[] tags,
|
||||
@NotNull Predicate<String> tagRequired,
|
||||
@NotNull PsiElement toHighlight,
|
||||
@NotNull ProblemHolder holder) {
|
||||
boolean[] isTagRequired = new boolean[TAGS_TO_CHECK.length];
|
||||
boolean[] isTagPresent = new boolean[TAGS_TO_CHECK.length];
|
||||
boolean someTagsAreRequired = false;
|
||||
|
||||
for (int i = 0; i < TAGS_TO_CHECK.length; i++) {
|
||||
someTagsAreRequired |= (isTagRequired[i] = tagRequired.test(TAGS_TO_CHECK[i]));
|
||||
}
|
||||
|
||||
if (!someTagsAreRequired) return;
|
||||
|
||||
for (PsiDocTag tag : tags) {
|
||||
int p = ArrayUtil.find(TAGS_TO_CHECK, tag.getName());
|
||||
if (p >= 0) isTagPresent[p] = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < TAGS_TO_CHECK.length; i++) {
|
||||
if (isTagRequired[i] && !isTagPresent[i]) {
|
||||
String tagName = TAGS_TO_CHECK[i];
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@" + tagName + "</code>");
|
||||
holder.problem(toHighlight, message, holder.addMissingTagFix(tagName, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkRequiredTagDescriptions(@NotNull PsiDocTag[] tags, @NotNull ProblemHolder holder) {
|
||||
for (PsiDocTag tag : tags) {
|
||||
String tagName = tag.getName();
|
||||
if (ArrayUtil.find(TAGS_TO_CHECK, tagName) >= 0 && emptyTag(tag)) {
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag.description", StringUtil.capitalize(tagName), tagName);
|
||||
holder.problem(tag.getNameElement(), message, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkTagValues(@NotNull PsiDocTag[] tags, @Nullable PsiElement context, @NotNull ProblemHolder holder) {
|
||||
JavadocManager docManager = JavadocManager.SERVICE.getInstance(holder.project());
|
||||
for (PsiDocTag tag : tags) {
|
||||
String tagName = tag.getName();
|
||||
JavadocTagInfo tagInfo = docManager.getTagInfo(tagName);
|
||||
|
||||
if (tagInfo == null || !tagInfo.isValidInContext(context)) {
|
||||
if (checkTagInfo(tag, tagInfo, holder)) continue;
|
||||
}
|
||||
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (tagInfo != null && !tagInfo.isValidInContext(context)) continue;
|
||||
String message = tagInfo == null ? null : tagInfo.checkTagValue(value);
|
||||
|
||||
PsiReference reference = value != null ? value.getReference() : null;
|
||||
if (message == null && reference != null) {
|
||||
PsiElement element = reference.resolve();
|
||||
if (element == null) {
|
||||
int textOffset = value.getTextOffset();
|
||||
if (textOffset == value.getTextRange().getEndOffset()) {
|
||||
holder.eolProblem(tag, InspectionsBundle.message("inspection.javadoc.problem.name.expected"), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement == null) {
|
||||
String tagText = "<code>" + tag.getName() + "</code>";
|
||||
holder.problem(tag, InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", tagText), null);
|
||||
}
|
||||
else {
|
||||
holder.problem(valueElement, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
checkInlineTags(tag.getDataElements(), holder);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkInlineTags(@NotNull PsiElement[] elements, @NotNull ProblemHolder holder) {
|
||||
JavadocManager docManager = JavadocManager.SERVICE.getInstance(holder.project());
|
||||
for (PsiElement element : elements) {
|
||||
if (element instanceof PsiInlineDocTag) {
|
||||
PsiInlineDocTag tag = (PsiInlineDocTag)element;
|
||||
if (docManager.getTagInfo(tag.getName()) == null) {
|
||||
checkTagInfo(tag, null, holder);
|
||||
}
|
||||
if (!holder.inspection().IGNORE_POINT_TO_ITSELF) {
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (value != null) {
|
||||
PsiReference reference = value.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement target = reference.resolve();
|
||||
if (target != null) {
|
||||
if (PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class) ==
|
||||
PsiTreeUtil.getParentOfType(target, PsiDocCommentOwner.class, false)) {
|
||||
PsiElement nameElement = tag.getNameElement();
|
||||
if (nameElement != null) {
|
||||
holder.problem(nameElement, InspectionsBundle.message("inspection.javadoc.problem.pointing.to.itself"), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkTagInfo(PsiDocTag tag, JavadocTagInfo tagInfo, ProblemHolder holder) {
|
||||
String tagName = tag.getName();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(holder.inspection().myAdditionalJavadocTags, ", ");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
if (Comparing.strEqual(tagName, tokenizer.nextToken())) return true;
|
||||
}
|
||||
|
||||
PsiElement nameElement = tag.getNameElement();
|
||||
if (nameElement != null) {
|
||||
String key = tagInfo == null ? "inspection.javadoc.problem.wrong.tag" : "inspection.javadoc.problem.disallowed.tag";
|
||||
holder.problem(nameElement, InspectionsBundle.message(key, "<code>" + tagName + "</code>"), holder.registerTagFix(tagName));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void checkForPeriod(@NotNull PsiDocComment docComment, @Nullable PsiElement context, @NotNull ProblemHolder holder) {
|
||||
int dotIndex = docComment.getText().indexOf('.'), tagOffset = 0;
|
||||
if (dotIndex >= 0) { // need to find first valid tag
|
||||
for (PsiDocTag tag : docComment.getTags()) {
|
||||
String tagName = tag.getName();
|
||||
JavadocTagInfo tagInfo = JavadocManager.SERVICE.getInstance(tag.getProject()).getTagInfo(tagName);
|
||||
if (tagInfo != null && tagInfo.isValidInContext(context) && !tagInfo.isInline()) {
|
||||
tagOffset = tag.getTextOffset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dotIndex == -1 || tagOffset > 0 && dotIndex + docComment.getTextOffset() > tagOffset) {
|
||||
holder.problem(docComment.getFirstChild(), InspectionsBundle.message("inspection.javadoc.problem.descriptor1"), null);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkDuplicateTags(@NotNull PsiDocTag[] tags, @NotNull ProblemHolder holder) {
|
||||
Set<String> documentedParamNames = null;
|
||||
Set<String> documentedExceptions = null;
|
||||
Set<String> uniqueTags = null;
|
||||
|
||||
for (PsiDocTag tag : tags) {
|
||||
if ("param".equals(tag.getName())) {
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (value instanceof PsiDocParamRef) {
|
||||
PsiReference reference = value.getReference();
|
||||
if (reference != null) {
|
||||
String paramName = reference.getCanonicalText();
|
||||
documentedParamNames = set(documentedParamNames);
|
||||
if (documentedParamNames.contains(paramName)) {
|
||||
holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.duplicate.param", paramName), null);
|
||||
}
|
||||
documentedParamNames.add(paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!holder.inspection().isIgnoreDuplicatedThrows() && ("throws".equals(tag.getName()) || "exception".equals(tag.getName()))) {
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (value != null) {
|
||||
PsiElement firstChild = value.getFirstChild();
|
||||
if (firstChild != null && firstChild.getFirstChild() instanceof PsiJavaCodeReferenceElement) {
|
||||
PsiJavaCodeReferenceElement refElement = (PsiJavaCodeReferenceElement)firstChild.getFirstChild();
|
||||
PsiElement element = refElement.resolve();
|
||||
if (element instanceof PsiClass) {
|
||||
String fqName = ((PsiClass)element).getQualifiedName();
|
||||
documentedExceptions = set(documentedExceptions);
|
||||
if (documentedExceptions.contains(fqName)) {
|
||||
holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.duplicate.throws", fqName), null);
|
||||
}
|
||||
documentedExceptions.add(fqName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (UNIQUE_TAGS.contains(tag.getName())) {
|
||||
uniqueTags = set(uniqueTags);
|
||||
if (uniqueTags.contains(tag.getName())) {
|
||||
holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.duplicate.tag", tag.getName()), null);
|
||||
}
|
||||
uniqueTags.add(tag.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkForBadCharacters(@NotNull PsiDocComment docComment, @NotNull ProblemHolder holder) {
|
||||
docComment.accept(new PsiRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
super.visitElement(element);
|
||||
ASTNode node = element.getNode();
|
||||
if (node != null && node.getElementType() == JavaDocTokenType.DOC_COMMENT_BAD_CHARACTER) {
|
||||
holder.problem(element, InspectionsBundle.message("inspection.illegal.character"), null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void checkMissingTypeParamTags(@NotNull PsiClass psiClass,
|
||||
@NotNull PsiDocTag[] tags,
|
||||
@NotNull PsiElement toHighlight,
|
||||
@NotNull ProblemHolder holder) {
|
||||
if (psiClass.hasTypeParameters()) {
|
||||
List<PsiTypeParameter> absentParameters = null;
|
||||
|
||||
for (PsiTypeParameter typeParameter : psiClass.getTypeParameters()) {
|
||||
if (!hasTagForParameter(tags, typeParameter)) {
|
||||
(absentParameters = list(absentParameters)).add(typeParameter);
|
||||
}
|
||||
}
|
||||
|
||||
if (absentParameters != null) {
|
||||
for (PsiTypeParameter typeParameter : absentParameters) {
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@param</code>");
|
||||
holder.problem(toHighlight, message, holder.addMissingTagFix("param", "<" + typeParameter.getName() + ">"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkMissingReturnTag(@NotNull PsiDocTag[] tags,
|
||||
@NotNull PsiMethod psiMethod,
|
||||
@NotNull PsiElement toHighlight,
|
||||
@NotNull ProblemHolder holder) {
|
||||
if (!psiMethod.isConstructor() && !PsiType.VOID.equals(psiMethod.getReturnType())) {
|
||||
boolean hasReturnTag = Stream.of(tags).anyMatch(tag -> "return".equals(tag.getName()));
|
||||
if (!hasReturnTag) {
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@" + "return" + "</code>");
|
||||
holder.problem(toHighlight, message, holder.addMissingTagFix("return", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkMissingParamTags(@NotNull PsiDocTag[] tags,
|
||||
@NotNull PsiMethod psiMethod,
|
||||
@NotNull PsiElement toHighlight,
|
||||
@NotNull ProblemHolder holder) {
|
||||
List<PsiParameter> absentParameters = null;
|
||||
|
||||
for (PsiParameter param : psiMethod.getParameterList().getParameters()) {
|
||||
if (!hasTagForParameter(tags, param)) {
|
||||
(absentParameters = list(absentParameters)).add(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (absentParameters != null) {
|
||||
for (PsiParameter parameter : absentParameters) {
|
||||
String name = parameter.getName();
|
||||
if (name != null) {
|
||||
String tagText = "<code>" + name + "</code>";
|
||||
String message = InspectionsBundle.message("inspection.javadoc.method.problem.missing.param.tag", tagText);
|
||||
holder.problem(toHighlight, message, holder.addMissingParamTagFix(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkMissingThrowsTags(@NotNull PsiDocTag[] tags,
|
||||
@NotNull PsiMethod psiMethod,
|
||||
@NotNull PsiElement toHighlight,
|
||||
@NotNull ProblemHolder holder) {
|
||||
PsiClassType[] thrownTypes = psiMethod.getThrowsList().getReferencedTypes();
|
||||
if (thrownTypes.length <= 0) return;
|
||||
|
||||
Map<PsiClassType, PsiClass> declaredExceptions = ContainerUtil.newLinkedHashMap();
|
||||
|
||||
for (PsiClassType classType : thrownTypes) {
|
||||
PsiClass psiClass = classType.resolve();
|
||||
if (psiClass != null) {
|
||||
declaredExceptions.put(classType, psiClass);
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiDocTag tag : tags) {
|
||||
if ("throws".equals(tag.getName()) || "exception".equals(tag.getName())) {
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (value != null) {
|
||||
PsiElement firstChild = value.getFirstChild();
|
||||
if (firstChild != null) {
|
||||
PsiElement psiElement = firstChild.getFirstChild();
|
||||
if ((psiElement instanceof PsiJavaCodeReferenceElement)) {
|
||||
PsiElement target = ((PsiJavaCodeReferenceElement)psiElement).resolve();
|
||||
if (target instanceof PsiClass) {
|
||||
for (Iterator<PsiClassType> it = declaredExceptions.keySet().iterator(); it.hasNext(); ) {
|
||||
PsiClass psiClass = declaredExceptions.get(it.next());
|
||||
if (InheritanceUtil.isInheritorOrSelf((PsiClass)target, psiClass, true)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiClassType declaredException : declaredExceptions.keySet()) {
|
||||
String tagText = "<code>@throws</code> " + declaredException.getCanonicalText();
|
||||
String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", tagText);
|
||||
String firstDeclaredException = declaredException.getCanonicalText();
|
||||
holder.problem(toHighlight, message, holder.addMissingTagFix("throws", firstDeclaredException));
|
||||
}
|
||||
}
|
||||
|
||||
static void checkEmptyMethodTagsDescription(@NotNull PsiDocTag[] tags, @NotNull ProblemHolder holder) {
|
||||
for (PsiDocTag tag : tags) {
|
||||
if ("return".equals(tag.getName())) {
|
||||
if (emptyTag(tag)) {
|
||||
String tagText = "<code>@return</code>";
|
||||
holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", tagText), null);
|
||||
}
|
||||
}
|
||||
else if ("throws".equals(tag.getName()) || "exception".equals(tag.getName())) {
|
||||
if (emptyThrowsTag(tag)) {
|
||||
String tagText = "<code>" + tag.getName() + "</code>";
|
||||
holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", tagText), null);
|
||||
}
|
||||
}
|
||||
else if ("param".equals(tag.getName())) {
|
||||
PsiDocTagValue valueElement = tag.getValueElement();
|
||||
if (valueElement != null && emptyParamTag(tag, valueElement)) {
|
||||
String tagText = "<code>@param " + valueElement.getText() + "</code>";
|
||||
holder.problem(valueElement, InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", tagText), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Set<T> set(Set<T> set) {
|
||||
return set != null ? set : ContainerUtil.newHashSet();
|
||||
}
|
||||
|
||||
private static <T> List<T> list(List<T> list) {
|
||||
return list != null ? list : ContainerUtil.newSmartList();
|
||||
}
|
||||
|
||||
private static boolean emptyTag(PsiDocTag tag) {
|
||||
return Stream.of(tag.getChildren())
|
||||
.filter(e -> e instanceof PsiDocToken && ((PsiDocToken)e).getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA ||
|
||||
e instanceof PsiDocTagValue ||
|
||||
e instanceof PsiInlineDocTag)
|
||||
.allMatch(JavadocHighlightUtil::empty);
|
||||
}
|
||||
|
||||
private static boolean emptyThrowsTag(PsiDocTag tag) {
|
||||
return Stream.of(tag.getChildren())
|
||||
.filter(e -> e instanceof PsiDocToken && ((PsiDocToken)e).getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA)
|
||||
.allMatch(JavadocHighlightUtil::empty);
|
||||
}
|
||||
|
||||
private static boolean emptyParamTag(PsiDocTag tag, PsiDocTagValue valueElement) {
|
||||
PsiElement[] dataElements = tag.getDataElements();
|
||||
return dataElements.length < 2 || Stream.of(dataElements)
|
||||
.filter(e -> e != valueElement)
|
||||
.allMatch(JavadocHighlightUtil::empty);
|
||||
}
|
||||
|
||||
private static boolean empty(PsiElement e) {
|
||||
return e.getText().chars().allMatch(c -> c <= ' ');
|
||||
}
|
||||
|
||||
public static boolean hasTagForParameter(@NotNull PsiDocTag[] tags, PsiElement param) {
|
||||
for (PsiDocTag tag : tags) {
|
||||
if ("param".equals(tag.getName())) {
|
||||
PsiDocTagValue value = tag.getValueElement();
|
||||
if (value instanceof PsiDocParamRef) {
|
||||
PsiReference psiReference = value.getReference();
|
||||
if (psiReference != null && psiReference.isReferenceTo(param)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.SuppressionUtilCore;
|
||||
import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection;
|
||||
import com.intellij.codeInspection.javaDoc.JavaDocLocalInspectionBase;
|
||||
import com.intellij.codeInspection.javaDoc.JavadocHighlightUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -342,7 +343,7 @@ public class JavaDocCompletionContributor extends CompletionContributor {
|
||||
if (psiMethod != null) {
|
||||
PsiDocTag[] tags = comment.getTags();
|
||||
for (PsiParameter param : psiMethod.getParameterList().getParameters()) {
|
||||
if (!JavaDocLocalInspectionBase.isFound(tags, param)) {
|
||||
if (!JavadocHighlightUtil.hasTagForParameter(tags, param)) {
|
||||
result.add(tagName + " " + param.getName());
|
||||
}
|
||||
}
|
||||
|
||||
+321
-177
@@ -3,24 +3,28 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.javaDoc;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.intention.impl.AddJavadocIntention;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.FieldPanel;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.javadoc.PsiDocTagValue;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -31,50 +35,100 @@ import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class JavaDocLocalInspection extends JavaDocLocalInspectionBase {
|
||||
private static final Logger LOG = Logger.getInstance("com.intellij.codeInspection.javaDoc.JavaDocLocalInspection");
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new OptionsPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalQuickFix createAddJavadocFix(@NotNull final PsiElement nameIdentifier, boolean isOnTheFly) {
|
||||
if (isOnTheFly) {
|
||||
final AddJavadocIntention intention = new AddJavadocIntention();
|
||||
return new LocalQuickFixAndIntentionActionOnPsiElement(nameIdentifier) {
|
||||
@Override
|
||||
public void invoke(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable("is null when called from inspection") Editor editor,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
intention.invoke(project, editor, startElement);
|
||||
}
|
||||
protected LocalQuickFix createAddJavadocFix(@NotNull PsiElement nameIdentifier, boolean isOnTheFly) {
|
||||
return isOnTheFly ? new AddJavadocFix(nameIdentifier) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return intention.getText();
|
||||
}
|
||||
@Override
|
||||
protected LocalQuickFix createAddMissingTagFix(@NotNull String tag, @NotNull String value, boolean isOnTheFly) {
|
||||
return new AddMissingTagFix(tag, value);
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return intention.getFamilyName();
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
protected LocalQuickFix createAddMissingParamTagFix(@NotNull String name, boolean isOnTheFly) {
|
||||
return new AddMissingParamTagFix(name);
|
||||
}
|
||||
|
||||
return super.createAddJavadocFix(nameIdentifier, false);
|
||||
@Override
|
||||
protected LocalQuickFix createRegisterTagFix(@NotNull String tag, boolean isOnTheFly) {
|
||||
return new AddUnknownTagToCustoms(this, tag);
|
||||
}
|
||||
|
||||
private class OptionsPanel extends JPanel {
|
||||
public OptionsPanel() {
|
||||
super(new GridBagLayout());
|
||||
GridBagConstraints gc =
|
||||
new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(0, 0, 0, 0), 0, 0);
|
||||
|
||||
String title = InspectionsBundle.message("inspection.javadoc.dialog.title");
|
||||
FieldPanel additionalTagsPanel = new FieldPanel(InspectionsBundle.message("inspection.javadoc.label.text"), title, null, null);
|
||||
additionalTagsPanel.setPreferredSize(new Dimension(150, additionalTagsPanel.getPreferredSize().height));
|
||||
additionalTagsPanel.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
Document document = e.getDocument();
|
||||
try {
|
||||
String text = document.getText(0, document.getLength());
|
||||
if (text != null) {
|
||||
myAdditionalJavadocTags = text.trim();
|
||||
}
|
||||
}
|
||||
catch (BadLocationException ex) {
|
||||
Logger.getInstance(JavaDocLocalInspection.class).error(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
additionalTagsPanel.setText(myAdditionalJavadocTags);
|
||||
add(additionalTagsPanel, gc);
|
||||
|
||||
JTabbedPane tabs = new JBTabbedPane(SwingConstants.BOTTOM);
|
||||
String[] tags = {"@author", "@version", "@since"};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.package"),
|
||||
createOptionsPanel(new String[]{NONE, PUBLIC}, tags, PACKAGE_OPTIONS));
|
||||
tags = new String[]{"@author", "@version", "@since", "@param"};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title"),
|
||||
createOptionsPanel(new String[]{NONE, PUBLIC, PACKAGE_LOCAL}, tags, TOP_LEVEL_CLASS_OPTIONS));
|
||||
tags = new String[]{"@return", "@param", InspectionsBundle.message("inspection.javadoc.throws.or.exception.option")};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.method"),
|
||||
createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE}, tags, METHOD_OPTIONS));
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.field"),
|
||||
createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE}, null, FIELD_OPTIONS));
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.inner.class"),
|
||||
createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE}, null, INNER_CLASS_OPTIONS));
|
||||
add(tabs, gc);
|
||||
|
||||
JCheckBox checkBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.deprecated"), IGNORE_DEPRECATED);
|
||||
checkBox.addActionListener(e -> IGNORE_DEPRECATED = checkBox.isSelected());
|
||||
gc.gridwidth = 1;
|
||||
add(checkBox, gc);
|
||||
|
||||
JCheckBox periodCheckBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.period"), IGNORE_JAVADOC_PERIOD);
|
||||
periodCheckBox.addActionListener(e -> IGNORE_JAVADOC_PERIOD = periodCheckBox.isSelected());
|
||||
add(periodCheckBox, gc);
|
||||
|
||||
JCheckBox ignoreDuplicateThrowsCheckBox = new JCheckBox("Ignore duplicate throws tag", isIgnoreDuplicatedThrows());
|
||||
ignoreDuplicateThrowsCheckBox.addActionListener(e -> setIgnoreDuplicatedThrows(ignoreDuplicateThrowsCheckBox.isSelected()));
|
||||
add(ignoreDuplicateThrowsCheckBox, gc);
|
||||
|
||||
JCheckBox ignorePointToItselfCheckBox = new JCheckBox("Ignore javadoc pointing to itself", IGNORE_POINT_TO_ITSELF);
|
||||
ignorePointToItselfCheckBox.addActionListener(e -> IGNORE_POINT_TO_ITSELF = ignorePointToItselfCheckBox.isSelected());
|
||||
add(ignorePointToItselfCheckBox, gc);
|
||||
|
||||
JCheckBox ignoreSimpleAccessorsCheckBox = new JCheckBox("Ignore simple property accessors", isIgnoreSimpleAccessors());
|
||||
ignoreSimpleAccessorsCheckBox.addActionListener(e -> setIgnoreSimpleAccessors(ignoreSimpleAccessorsCheckBox.isSelected()));
|
||||
add(ignoreSimpleAccessorsCheckBox, gc);
|
||||
}
|
||||
|
||||
private JPanel createOptionsPanel(String[] modifiers, String[] tags, Options options) {
|
||||
JPanel pane = new JPanel(new GridLayout(1, tags == null ? 1 : 2));
|
||||
|
||||
@@ -88,11 +142,50 @@ public class JavaDocLocalInspection extends JavaDocLocalInspectionBase {
|
||||
return pane;
|
||||
}
|
||||
|
||||
private JPanel createScopePanel(String[] modifiers, Options options) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(
|
||||
IdeBorderFactory.createTitledBorder(InspectionsBundle.message("inspection.scope.for.title"), true),
|
||||
BorderFactory.createEmptyBorder(0, 3, 3, 3)));
|
||||
|
||||
@SuppressWarnings("UseOfObsoleteCollectionType") Hashtable<Integer, JComponent> sliderLabels = new Hashtable<>();
|
||||
for (int i = 0; i < modifiers.length; i++) {
|
||||
sliderLabels.put(i + 1, new JLabel(modifiers[i]));
|
||||
}
|
||||
|
||||
JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, modifiers.length, 1);
|
||||
slider.setLabelTable(sliderLabels);
|
||||
slider.putClientProperty(UIUtil.JSLIDER_ISFILLED, Boolean.TRUE);
|
||||
slider.setPreferredSize(JBUI.size(80, 50));
|
||||
slider.setPaintLabels(true);
|
||||
slider.setSnapToTicks(true);
|
||||
slider.addChangeListener(e -> {
|
||||
int value = slider.getValue();
|
||||
options.ACCESS_JAVADOC_REQUIRED_FOR = modifiers[value - 1];
|
||||
for (Integer key : sliderLabels.keySet()) {
|
||||
sliderLabels.get(key).setForeground(key.intValue() <= value ? JBColor.BLACK : Gray._100);
|
||||
}
|
||||
});
|
||||
|
||||
Color fore = JBColor.BLACK;
|
||||
for (int i = 0; i < modifiers.length; i++) {
|
||||
sliderLabels.get(i + 1).setForeground(fore);
|
||||
if (modifiers[i].equals(options.ACCESS_JAVADOC_REQUIRED_FOR)) {
|
||||
slider.setValue(i + 1);
|
||||
fore = Gray._100;
|
||||
}
|
||||
}
|
||||
|
||||
panel.add(slider, BorderLayout.WEST);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createTagsPanel(String[] tags, Options options) {
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(IdeBorderFactory.createTitledBorder(
|
||||
InspectionsBundle.message("inspection.javadoc.required.tags.option.title"), true),
|
||||
BorderFactory.createEmptyBorder(0, 3, 3, 3)));
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(
|
||||
IdeBorderFactory.createTitledBorder(InspectionsBundle.message("inspection.javadoc.required.tags.option.title"), true),
|
||||
BorderFactory.createEmptyBorder(0, 3, 3, 3)));
|
||||
|
||||
GridBagConstraints gc = new GridBagConstraints();
|
||||
gc.weightx = 1;
|
||||
@@ -100,7 +193,6 @@ public class JavaDocLocalInspection extends JavaDocLocalInspectionBase {
|
||||
gc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gc.anchor = GridBagConstraints.NORTHWEST;
|
||||
|
||||
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
JCheckBox box = new JCheckBox(tags[i]);
|
||||
gc.gridy = i;
|
||||
@@ -115,8 +207,8 @@ public class JavaDocLocalInspection extends JavaDocLocalInspectionBase {
|
||||
|
||||
private class MyChangeListener implements ChangeListener {
|
||||
private final JCheckBox myCheckBox;
|
||||
private final Options myOptions;
|
||||
private final String myTagName;
|
||||
private final Options myOptions;
|
||||
private final String myTagName;
|
||||
|
||||
public MyChangeListener(JCheckBox checkBox, Options options, String tagName) {
|
||||
myCheckBox = checkBox;
|
||||
@@ -136,144 +228,196 @@ public class JavaDocLocalInspection extends JavaDocLocalInspectionBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JPanel createScopePanel(final String[] modifiers, final Options options) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(IdeBorderFactory.createTitledBorder(
|
||||
InspectionsBundle.message("inspection.scope.for.title"), true),
|
||||
BorderFactory.createEmptyBorder(0, 3, 3, 3)));
|
||||
/*
|
||||
* Fixes
|
||||
*/
|
||||
|
||||
final Hashtable<Integer, JComponent> sliderLabels = new Hashtable<Integer, JComponent>();
|
||||
for (int i = 0; i < modifiers.length; i++) {
|
||||
sliderLabels.put(i + 1, new JLabel(modifiers[i]));
|
||||
}
|
||||
private static class AddJavadocFix extends LocalQuickFixAndIntentionActionOnPsiElement {
|
||||
private final AddJavadocIntention myIntention;
|
||||
|
||||
final JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, modifiers.length, 1);
|
||||
|
||||
slider.setLabelTable(sliderLabels);
|
||||
slider.putClientProperty(UIUtil.JSLIDER_ISFILLED, Boolean.TRUE);
|
||||
slider.setPreferredSize(JBUI.size(80, 50));
|
||||
slider.setPaintLabels(true);
|
||||
slider.setSnapToTicks(true);
|
||||
slider.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
int value = slider.getValue();
|
||||
options.ACCESS_JAVADOC_REQUIRED_FOR = modifiers[value - 1];
|
||||
for (Integer key : sliderLabels.keySet()) {
|
||||
sliderLabels.get(key).setForeground(key.intValue() <= value ? Color.black : Gray._100);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Color fore = Color.black;
|
||||
for (int i = 0; i < modifiers.length; i++) {
|
||||
sliderLabels.get(i + 1).setForeground(fore);
|
||||
|
||||
if (modifiers[i].equals(options.ACCESS_JAVADOC_REQUIRED_FOR)) {
|
||||
slider.setValue(i + 1);
|
||||
fore = Gray._100;
|
||||
}
|
||||
}
|
||||
|
||||
panel.add(slider, BorderLayout.WEST);
|
||||
|
||||
return panel;
|
||||
public AddJavadocFix(PsiElement nameIdentifier) {
|
||||
super(nameIdentifier);
|
||||
myIntention = new AddJavadocIntention();
|
||||
}
|
||||
|
||||
public OptionsPanel() {
|
||||
super(new GridBagLayout());
|
||||
GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0),0,0 );
|
||||
add(createAdditionalJavadocTagsPanel(), gc);
|
||||
JTabbedPane tabs = new JBTabbedPane(SwingConstants.BOTTOM);
|
||||
@NonNls String[] tags = new String[]{"@author", "@version", "@since"};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.package"), createOptionsPanel(new String[]{NONE, PUBLIC},
|
||||
tags,PACKAGE_OPTIONS));
|
||||
|
||||
tags = new String[]{"@author", "@version", "@since", "@param"};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title"), createOptionsPanel(new String[]{NONE, PUBLIC, PACKAGE_LOCAL},
|
||||
tags,
|
||||
TOP_LEVEL_CLASS_OPTIONS));
|
||||
tags = new String[]{"@return", "@param", InspectionsBundle.message("inspection.javadoc.throws.or.exception.option")};
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.method"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
|
||||
tags,
|
||||
METHOD_OPTIONS));
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.field"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
|
||||
null,
|
||||
FIELD_OPTIONS));
|
||||
tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.inner.class"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
|
||||
null,
|
||||
INNER_CLASS_OPTIONS));
|
||||
add(tabs, gc);
|
||||
|
||||
final JCheckBox checkBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.deprecated"),
|
||||
IGNORE_DEPRECATED);
|
||||
checkBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
IGNORE_DEPRECATED = checkBox.isSelected();
|
||||
}
|
||||
});
|
||||
gc.gridwidth = 1;
|
||||
add(checkBox, gc);
|
||||
final JCheckBox periodCheckBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.period"),
|
||||
IGNORE_JAVADOC_PERIOD);
|
||||
periodCheckBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
IGNORE_JAVADOC_PERIOD = periodCheckBox.isSelected();
|
||||
}
|
||||
});
|
||||
add(periodCheckBox, gc);
|
||||
|
||||
final JCheckBox ignoreDuplicateThrowsCheckBox = new JCheckBox("Ignore duplicate throws tag",
|
||||
getIgnoreDuplicatedThrows());
|
||||
ignoreDuplicateThrowsCheckBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setIgnoreDuplicatedThrows(ignoreDuplicateThrowsCheckBox.isSelected());
|
||||
}
|
||||
});
|
||||
add(ignoreDuplicateThrowsCheckBox, gc);
|
||||
|
||||
final JCheckBox ignorePointToItselfCheckBox = new JCheckBox("Ignore javadoc pointing to itself", IGNORE_POINT_TO_ITSELF);
|
||||
ignorePointToItselfCheckBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
IGNORE_POINT_TO_ITSELF = ignorePointToItselfCheckBox.isSelected();
|
||||
}
|
||||
});
|
||||
add(ignorePointToItselfCheckBox, gc);
|
||||
final JCheckBox ignoreSimpleAccessorsCheckBox = new JCheckBox("Ignore simple property accessors", myIgnoreSimpleAccessors);
|
||||
ignoreSimpleAccessorsCheckBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myIgnoreSimpleAccessors = ignoreSimpleAccessorsCheckBox.isSelected();
|
||||
}
|
||||
});
|
||||
add(ignoreSimpleAccessorsCheckBox, gc);
|
||||
@Override
|
||||
public void invoke(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable("is null when called from inspection") Editor editor,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
myIntention.invoke(project, editor, startElement);
|
||||
}
|
||||
|
||||
public FieldPanel createAdditionalJavadocTagsPanel(){
|
||||
FieldPanel additionalTagsPanel = new FieldPanel(InspectionsBundle.message("inspection.javadoc.label.text"), InspectionsBundle.message("inspection.javadoc.dialog.title"), null, null);
|
||||
additionalTagsPanel.setPreferredSize(new Dimension(150, additionalTagsPanel.getPreferredSize().height));
|
||||
additionalTagsPanel.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
final Document document = e.getDocument();
|
||||
try {
|
||||
final String text = document.getText(0, document.getLength());
|
||||
if (text != null) {
|
||||
myAdditionalJavadocTags = text.trim();
|
||||
}
|
||||
}
|
||||
catch (BadLocationException e1) {
|
||||
LOG.error(e1);
|
||||
}
|
||||
}
|
||||
});
|
||||
additionalTagsPanel.setText(myAdditionalJavadocTags);
|
||||
return additionalTagsPanel;
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
//noinspection DialogTitleCapitalization
|
||||
return myIntention.getText();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return myIntention.getFamilyName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddMissingTagFix implements LocalQuickFix {
|
||||
private final String myTag;
|
||||
private final String myValue;
|
||||
|
||||
public AddMissingTagFix(@NotNull String tag, @NotNull String value) {
|
||||
myTag = tag;
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiDocComment docComment = PsiTreeUtil.getParentOfType(descriptor.getEndElement(), PsiDocComment.class);
|
||||
if (docComment != null) {
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(docComment)) return;
|
||||
|
||||
PsiDocTag tag = JavaPsiFacade.getInstance(project).getElementFactory().createDocTagFromText("@" + myTag + " " + myValue);
|
||||
|
||||
PsiElement addedTag;
|
||||
PsiElement anchor = getAnchor(descriptor);
|
||||
if (anchor != null) {
|
||||
addedTag = docComment.addBefore(tag, anchor);
|
||||
}
|
||||
else {
|
||||
addedTag = docComment.add(tag);
|
||||
}
|
||||
moveCaretAfter(addedTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiElement getAnchor(ProblemDescriptor descriptor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void moveCaretAfter(PsiElement newCaretPosition) {
|
||||
PsiElement sibling = newCaretPosition.getNextSibling();
|
||||
if (sibling != null) {
|
||||
((Navigatable)sibling).navigate(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("inspection.javadoc.problem.add.tag", myTag, myValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
//noinspection DialogTitleCapitalization
|
||||
return InspectionsBundle.message("inspection.javadoc.problem.add.tag.family");
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddMissingParamTagFix extends AddMissingTagFix {
|
||||
private final String myName;
|
||||
|
||||
public AddMissingParamTagFix(String name) {
|
||||
super("param", name);
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected PsiElement getAnchor(ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getPsiElement();
|
||||
PsiElement parent = element == null ? null : element.getParent();
|
||||
if (!(parent instanceof PsiDocComment)) return null;
|
||||
final PsiDocComment docComment = (PsiDocComment)parent;
|
||||
final PsiDocCommentOwner owner = docComment.getOwner();
|
||||
if (!(owner instanceof PsiMethod)) return null;
|
||||
PsiParameter[] parameters = ((PsiMethod)owner).getParameterList().getParameters();
|
||||
PsiParameter myParam = ContainerUtil.find(parameters, new Condition<PsiParameter>() {
|
||||
@Override
|
||||
public boolean value(PsiParameter psiParameter) {
|
||||
return myName.equals(psiParameter.getName());
|
||||
}
|
||||
});
|
||||
if (myParam == null) return null;
|
||||
|
||||
PsiDocTag[] tags = docComment.findTagsByName("param");
|
||||
if (tags.length == 0) { //insert as first tag or append to description
|
||||
tags = docComment.getTags();
|
||||
if (tags.length == 0) return null;
|
||||
return tags[0];
|
||||
}
|
||||
|
||||
PsiParameter nextParam = PsiTreeUtil.getNextSiblingOfType(myParam, PsiParameter.class);
|
||||
while (nextParam != null) {
|
||||
for (PsiDocTag tag : tags) {
|
||||
if (matches(nextParam, tag)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
nextParam = PsiTreeUtil.getNextSiblingOfType(nextParam, PsiParameter.class);
|
||||
}
|
||||
|
||||
PsiParameter prevParam = PsiTreeUtil.getPrevSiblingOfType(myParam, PsiParameter.class);
|
||||
while (prevParam != null) {
|
||||
for (PsiDocTag tag : tags) {
|
||||
if (matches(prevParam, tag)) {
|
||||
return PsiTreeUtil.getNextSiblingOfType(tag, PsiDocTag.class);
|
||||
}
|
||||
}
|
||||
prevParam = PsiTreeUtil.getPrevSiblingOfType(prevParam, PsiParameter.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean matches(PsiParameter param, PsiDocTag tag) {
|
||||
PsiDocTagValue valueElement = tag.getValueElement();
|
||||
String name = param.getName();
|
||||
return valueElement != null && name != null && valueElement.getText().trim().startsWith(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
//noinspection DialogTitleCapitalization
|
||||
return InspectionsBundle.message("inspection.javadoc.problem.add.param.tag", myName);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AddUnknownTagToCustoms implements LocalQuickFix {
|
||||
private final JavaDocLocalInspectionBase myInspection;
|
||||
private final String myTag;
|
||||
|
||||
public AddUnknownTagToCustoms(@NotNull JavaDocLocalInspectionBase inspection, @NotNull String tag) {
|
||||
myInspection = inspection;
|
||||
myTag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
myInspection.registerAdditionalTag(myTag);
|
||||
InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
InspectionProfileManager.getInstance().fireProfileChanged(profile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return QuickFixBundle.message("add.docTag.to.custom.tags", myTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
//noinspection DialogTitleCapitalization
|
||||
return QuickFixBundle.message("fix.javadoc.family");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,16 +270,14 @@ inspection.javadoc.required.tags.option.title=Required Tags
|
||||
inspection.javadoc.problem.descriptor=Required Javadoc is absent
|
||||
inspection.javadoc.problem.descriptor1=Period in the documentation is missing. The period is used by the Javadoc tool to generate the comment for the overview page
|
||||
inspection.javadoc.problem.missing.tag=Required tag {0} is missing
|
||||
inspection.javadoc.problem.missing.author.description=Author is missing after @author tag
|
||||
inspection.javadoc.problem.missing.version.description=Version is missing after @version tag
|
||||
inspection.javadoc.problem.missing.since.description=Since is missing after @since tag
|
||||
inspection.javadoc.problem.missing.tag.description={0} is missing after @{1} tag
|
||||
inspection.javadoc.problem.cannot.resolve=Cannot resolve symbol {0}
|
||||
inspection.javadoc.problem.name.expected=Name expected
|
||||
inspection.javadoc.problem.wrong.tag=Wrong tag {0}
|
||||
inspection.javadoc.problem.disallowed.tag=Tag ''{0}'' is not allowed here
|
||||
inspection.javadoc.method.problem.descriptor=Description is missing in {0} tag for parameter {1}
|
||||
inspection.javadoc.method.problem.missing.tag.description={0} tag description is missing
|
||||
inspection.javadoc.method.problem.missing.param.tag=Required tag {0} is missing for parameter {1}
|
||||
inspection.javadoc.method.problem.missing.param.tag=Required tag <code>@param</code> is missing for parameter {0}
|
||||
inspection.javadoc.problem.duplicate.param=Duplicate @param tag for parameter ''{0}''
|
||||
inspection.javadoc.problem.duplicate.throws=Duplicate @throws or @exception tag for exception ''{0}''
|
||||
inspection.javadoc.problem.duplicate.tag=Duplicate @{0} tag
|
||||
@@ -688,6 +686,8 @@ detach.library.quickfix.name=Detach library
|
||||
detach.library.roots.quickfix.name=Detach unused library roots
|
||||
inspection.javadoc.problem.pointing.to.itself=Javadoc pointing to itself
|
||||
|
||||
inspection.illegal.character=Illegal character
|
||||
|
||||
inspection.redirect.template=<html><body>Injected element has problem: {0} (in <a href=\"#navigation/{1}:{2}\">{3}</a>). </body></html>
|
||||
nothing.found=Nothing found
|
||||
special.annotations.list.annotation.pattern=Add Annotations Pattern
|
||||
|
||||
Reference in New Issue
Block a user