update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / completion / JavaDocCompletionContributor.java
blob67fa7e096bb3b283b9406214bdadf9a77ba5597b
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.completion;
18 import com.intellij.codeInsight.completion.scope.CompletionElement;
19 import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
20 import com.intellij.codeInsight.lookup.*;
21 import com.intellij.codeInspection.InspectionProfile;
22 import com.intellij.codeInspection.InspectionProfileEntry;
23 import com.intellij.codeInspection.SuppressionUtil;
24 import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
25 import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.editor.CaretModel;
28 import com.intellij.openapi.editor.Editor;
29 import com.intellij.openapi.editor.EditorModificationUtil;
30 import com.intellij.openapi.editor.ScrollType;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.patterns.PsiJavaPatterns;
33 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
34 import com.intellij.psi.*;
35 import com.intellij.psi.codeStyle.CodeStyleSettings;
36 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
37 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
38 import com.intellij.psi.filters.TrueFilter;
39 import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
40 import com.intellij.psi.javadoc.*;
41 import com.intellij.psi.util.PsiTreeUtil;
42 import com.intellij.psi.util.TypeConversionUtil;
43 import com.intellij.util.IncorrectOperationException;
44 import com.intellij.util.ProcessingContext;
45 import com.intellij.util.text.CharArrayUtil;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.util.StringTokenizer;
53 /**
54 * Created by IntelliJ IDEA.
55 * User: ik
56 * Date: 05.03.2003
57 * Time: 21:40:11
58 * To change this template use Options | File Templates.
60 public class JavaDocCompletionContributor extends CompletionContributor {
61 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaDocCompletionContributor");
62 private static final @NonNls String VALUE_TAG = "value";
63 private static final @NonNls String LINK_TAG = "link";
65 public JavaDocCompletionContributor() {
66 extend(CompletionType.BASIC, PsiJavaPatterns.psiElement(PsiDocToken.DOC_TAG_NAME), new TagChooser());
68 extend(CompletionType.BASIC, PsiJavaPatterns.psiElement().inside(PsiDocTagValue.class), new CompletionProvider<CompletionParameters>(
69 true) {
70 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
71 final PsiElement position = parameters.getPosition();
72 boolean isArg = PsiJavaPatterns.psiElement().afterLeaf("(").accepts(position);
73 PsiDocTag tag = PsiTreeUtil.getParentOfType(position, PsiDocTag.class);
74 boolean onlyConstants = !isArg && tag != null && tag.getName().equals(VALUE_TAG);
76 final PsiReference ref = position.getContainingFile().findReferenceAt(parameters.getOffset());
77 if (ref instanceof PsiJavaReference) {
78 result.stopHere();
80 final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, false, null);
81 ((PsiJavaReference) ref).processVariants(processor);
83 for (final CompletionElement _item : processor.getResults()) {
84 LookupItem item = (LookupItem)LookupItemUtil.objectToLookupItem(_item.getElement());
85 if (onlyConstants) {
86 Object o = item.getObject();
87 if (!(o instanceof PsiField)) continue;
88 PsiField field = (PsiField) o;
89 if (!(field.hasModifierProperty(PsiModifier.STATIC) && field.getInitializer() != null &&
90 JavaConstantExpressionEvaluator.computeConstantExpression(field.getInitializer(), false) != null)) continue;
93 item.putUserData(LookupItem.FORCE_SHOW_SIGNATURE_ATTR, Boolean.TRUE);
94 if (isArg) {
95 item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
97 item.setInsertHandler(new MethodSignatureInsertHandler());
98 result.addElement(item);
105 @Override
106 public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) {
107 if (PsiJavaPatterns.psiElement(PsiDocToken.DOC_COMMENT_DATA).accepts(parameters.getPosition())) return;
109 super.fillCompletionVariants(parameters, result);
112 private static class TagChooser extends CompletionProvider<CompletionParameters> {
114 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
115 List<String> ret = new ArrayList<String>();
116 final PsiElement position = parameters.getPosition();
117 final PsiDocComment comment = PsiTreeUtil.getParentOfType(position, PsiDocComment.class);
118 final PsiElement parent = comment.getContext();
119 final boolean isInline = position.getContext() instanceof PsiInlineDocTag;
121 final JavadocManager manager = JavaPsiFacade.getInstance(position.getProject()).getJavadocManager();
122 final JavadocTagInfo[] infos = manager.getTagInfos(parent);
123 for (JavadocTagInfo info : infos) {
124 if (info.getName().equals(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) continue;
125 if (isInline != (info.isInline())) continue;
126 ret.add(info.getName());
129 InspectionProfile inspectionProfile =
130 InspectionProjectProfileManager.getInstance(position.getProject()).getInspectionProfile();
131 final InspectionProfileEntry inspectionTool = inspectionProfile.getInspectionTool(JavaDocLocalInspection.SHORT_NAME, position);
132 JavaDocLocalInspection inspection = (JavaDocLocalInspection)((LocalInspectionToolWrapper)inspectionTool).getTool();
133 final StringTokenizer tokenizer = new StringTokenizer(inspection.myAdditionalJavadocTags, ", ");
134 while (tokenizer.hasMoreTokens()) {
135 ret.add(tokenizer.nextToken());
137 for (final String s : ret) {
138 final LookupItem item = (LookupItem)LookupItemUtil.objectToLookupItem(s);
139 if (isInline) {
140 item.setInsertHandler(new InlineInsertHandler());
142 result.addElement(item);
146 @SuppressWarnings({"HardCodedStringLiteral"})
147 public String toString() {
148 return "javadoc-tag-chooser";
152 private static class InlineInsertHandler implements InsertHandler<LookupItem> {
153 public void handleInsert(InsertionContext context, LookupItem item) {
154 if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) {
155 final Project project = context.getProject();
156 PsiDocumentManager.getInstance(project).commitAllDocuments();
157 final Editor editor = context.getEditor();
158 final CaretModel caretModel = editor.getCaretModel();
159 final int offset = caretModel.getOffset();
160 final PsiElement element = context.getFile().findElementAt(offset - 1);
161 PsiDocTag tag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class);
163 for (PsiElement child = tag.getFirstChild(); child != null; child = child.getNextSibling()) {
164 if (child instanceof PsiDocToken) {
165 PsiDocToken token = (PsiDocToken)child;
166 if (token.getTokenType() == JavaDocTokenType.DOC_INLINE_TAG_END) return;
170 final String name = tag.getName();
172 final CharSequence chars = editor.getDocument().getCharsSequence();
173 final int currentOffset = caretModel.getOffset();
174 if (chars.charAt(currentOffset) == '}') {
175 caretModel.moveToOffset(offset + 1);
177 else if (chars.charAt(currentOffset + 1) == '}' && chars.charAt(currentOffset) == ' ') {
178 caretModel.moveToOffset(offset + 2);
180 else if (name.equals(LINK_TAG)) {
181 EditorModificationUtil.insertStringAtCaret(editor, " }");
182 caretModel.moveToOffset(offset + 1);
183 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
184 editor.getSelectionModel().removeSelection();
186 else {
187 EditorModificationUtil.insertStringAtCaret(editor, "}");
188 caretModel.moveToOffset(offset + 1);
194 private static class MethodSignatureInsertHandler implements InsertHandler<LookupItem> {
195 public void handleInsert(InsertionContext context, LookupItem item) {
196 if (!(item.getObject() instanceof PsiMethod)) {
197 return;
199 PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getEditor().getDocument());
200 final Editor editor = context.getEditor();
201 final PsiMethod method = (PsiMethod)((LookupItem)item).getObject();
203 final PsiParameter[] parameters = method.getParameterList().getParameters();
204 final StringBuffer buffer = new StringBuffer();
206 final CharSequence chars = editor.getDocument().getCharsSequence();
207 int endOffset = editor.getCaretModel().getOffset();
208 final Project project = context.getProject();
209 int afterSharp = CharArrayUtil.shiftBackwardUntil(chars, endOffset - 1, "#") + 1;
210 int signatureOffset = afterSharp;
212 PsiElement element = context.getFile().findElementAt(signatureOffset - 1);
213 final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(element.getProject());
214 PsiDocTag tag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class);
215 if (context.getCompletionChar() == Lookup.REPLACE_SELECT_CHAR) {
216 final PsiDocTagValue valueElement = tag.getValueElement();
217 endOffset = valueElement.getTextRange().getEndOffset();
219 editor.getDocument().deleteString(afterSharp, endOffset);
220 editor.getCaretModel().moveToOffset(signatureOffset);
221 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
222 editor.getSelectionModel().removeSelection();
223 buffer.append(method.getName() + "(");
224 final int afterParenth = afterSharp + buffer.length();
225 for (int i = 0; i < parameters.length; i++) {
226 final PsiType type = TypeConversionUtil.erasure(parameters[i].getType());
227 buffer.append(type.getCanonicalText());
229 if (i < parameters.length - 1) {
230 buffer.append(",");
231 if (styleSettings.SPACE_AFTER_COMMA) buffer.append(" ");
234 buffer.append(")");
235 if (!(tag instanceof PsiInlineDocTag)) {
236 buffer.append(" ");
238 else {
239 final int currentOffset = editor.getCaretModel().getOffset();
240 if (chars.charAt(currentOffset) == '}') {
241 afterSharp++;
243 else {
244 buffer.append("} ");
247 String insertString = buffer.toString();
248 EditorModificationUtil.insertStringAtCaret(editor, insertString);
249 editor.getCaretModel().moveToOffset(afterSharp + buffer.length());
250 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
251 PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
253 shortenReferences(project, editor, context, afterParenth);
256 private static void shortenReferences(final Project project, final Editor editor, InsertionContext context, int offset) {
257 PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
258 final PsiElement element = context.getFile().findElementAt(offset);
259 final PsiDocTagValue tagValue = PsiTreeUtil.getParentOfType(element, PsiDocTagValue.class);
260 if (tagValue != null) {
261 try {
262 JavaCodeStyleManager.getInstance(project).shortenClassReferences(tagValue);
264 catch (IncorrectOperationException e) {
265 LOG.error(e);
268 PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();