blob: f5a8253ab5ab5929c7c522793cae67fbbcfe8d0c [file] [log] [blame]
/*
* Copyright 2000-2010 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.codeInsight.completion;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.filters.FilterPositionUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
/**
* @author peter
*/
class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceElement> {
static final InsertHandler<JavaPsiClassReferenceElement> JAVA_CLASS_INSERT_HANDLER = new JavaClassNameInsertHandler();
@Override
public void handleInsert(final InsertionContext context, final JavaPsiClassReferenceElement item) {
int offset = context.getTailOffset() - 1;
final PsiFile file = context.getFile();
if (PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiImportStatementBase.class, false) != null) {
final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiJavaCodeReferenceElement.class, false);
final String qname = item.getQualifiedName();
if (qname != null && (ref == null || !qname.equals(ref.getCanonicalText()))) {
AllClassesGetter.INSERT_FQN.handleInsert(context, item);
}
return;
}
PsiElement position = file.findElementAt(offset);
PsiJavaCodeReferenceElement ref = position != null && position.getParent() instanceof PsiJavaCodeReferenceElement ?
(PsiJavaCodeReferenceElement) position.getParent() : null;
PsiClass psiClass = item.getObject();
final Project project = context.getProject();
final Editor editor = context.getEditor();
final char c = context.getCompletionChar();
if (c == '#') {
context.setLaterRunnable(new Runnable() {
@Override
public void run() {
new CodeCompletionHandlerBase(CompletionType.BASIC).invokeCompletion(project, editor);
}
});
} else if (c == '.' && PsiTreeUtil.getParentOfType(position, PsiParameterList.class) == null) {
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
}
if (PsiTreeUtil.getParentOfType(position, PsiDocComment.class, false) != null &&
CodeStyleSettingsManager.getSettings(project).USE_FQ_CLASS_NAMES_IN_JAVADOC) {
AllClassesGetter.INSERT_FQN.handleInsert(context, item);
return;
}
if (ref != null && PsiTreeUtil.getParentOfType(position, PsiDocTag.class) != null && ref.isReferenceTo(psiClass)) {
return;
}
OffsetKey refEnd = context.trackOffset(context.getTailOffset(), false);
boolean fillTypeArgs = context.getCompletionChar() == '<';
if (fillTypeArgs) {
context.setAddCompletionChar(false);
}
if (ref == null || !ref.isQualified()) {
PsiTypeLookupItem.addImportForItem(context, psiClass);
}
if (context.getOffset(refEnd) < 0) {
return;
}
context.setTailOffset(context.getOffset(refEnd));
context.commitDocument();
if (item.getUserData(JavaChainLookupElement.CHAIN_QUALIFIER) == null &&
shouldInsertParentheses(file.findElementAt(context.getTailOffset() - 1))) {
if (ConstructorInsertHandler.insertParentheses(context, item, psiClass, false)) {
fillTypeArgs |= psiClass.hasTypeParameters() && PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5);
}
}
else if (insertingAnnotationWithParameters(context, item)) {
JavaCompletionUtil.insertParentheses(context, item, false, true);
}
if (fillTypeArgs && context.getCompletionChar() != '(') {
JavaCompletionUtil.promptTypeArgs(context, context.getOffset(refEnd));
}
}
private static boolean shouldInsertParentheses(PsiElement position) {
final PsiJavaCodeReferenceElement ref = PsiTreeUtil.getParentOfType(position, PsiJavaCodeReferenceElement.class);
if (ref == null) {
return false;
}
final PsiReferenceParameterList parameterList = ref.getParameterList();
if (parameterList != null && parameterList.getTextLength() > 0) {
return false;
}
final PsiElement prevElement = FilterPositionUtil.searchNonSpaceNonCommentBack(ref);
if (prevElement != null && prevElement.getParent() instanceof PsiNewExpression) {
for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiExpression)prevElement.getParent(), true)) {
if (info.getType() instanceof PsiArrayType) {
return false;
}
}
return true;
}
return false;
}
private static boolean insertingAnnotationWithParameters(InsertionContext context, LookupElement item) {
final Object obj = item.getObject();
if (!(obj instanceof PsiClass) || !((PsiClass)obj).isAnnotationType()) return false;
PsiElement leaf = context.getFile().findElementAt(context.getStartOffset());
if (psiElement(PsiIdentifier.class).withParents(PsiJavaCodeReferenceElement.class, PsiAnnotation.class).accepts(leaf)) {
return shouldHaveAnnotationParameters((PsiClass)obj);
}
return false;
}
static boolean shouldHaveAnnotationParameters(PsiClass annoClass) {
for (PsiMethod m : annoClass.getMethods()) {
if (!PsiUtil.isAnnotationMethod(m)) continue;
if (((PsiAnnotationMethod)m).getDefaultValue() == null) return true;
}
return false;
}
}