diff options
author | Tor Norbye <tnorbye@google.com> | 2013-08-07 11:11:08 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-08-07 11:11:08 -0700 |
commit | 6739a8f0977b70ddc8a8283b169902da3f2eecb3 (patch) | |
tree | 5c5573c2ac01544f02d9318671aa558769726289 /java/java-impl/src/com/intellij | |
parent | c1ace1f7e1e49c81bb4b75377c99f07be340abfe (diff) | |
download | idea-6739a8f0977b70ddc8a8283b169902da3f2eecb3.tar.gz |
Snapshot af729d01433bb5bbd6ca93c0fdf9778b36d624ce from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: I214dd066d0d27444a26166c0eae1a5aaf3705d49
Diffstat (limited to 'java/java-impl/src/com/intellij')
209 files changed, 7379 insertions, 7366 deletions
diff --git a/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java b/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java index d82d51f56b6e..e7d0082155db 100644 --- a/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java +++ b/java/java-impl/src/com/intellij/application/options/ImportLayoutPanel.java @@ -18,7 +18,6 @@ package com.intellij.application.options; import com.intellij.ide.highlighter.JavaHighlightingColors; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.editor.SyntaxHighlighterColors; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.psi.codeStyle.PackageEntry; import com.intellij.psi.codeStyle.PackageEntryTable; diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 6a3d3f69df01..89b606e85324 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -940,7 +940,7 @@ public class ExpectedTypesProvider { } ParameterTypeInferencePolicy policy = forCompletion ? CompletionParameterTypeInferencePolicy.INSTANCE : DefaultParameterTypeInferencePolicy.INSTANCE; - + Set<ExpectedTypeInfo> array = new LinkedHashSet<ExpectedTypeInfo>(); for (CandidateInfo candidateInfo : methodCandidates) { PsiMethod method = (PsiMethod)candidateInfo.getElement(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index ac8297def978..1bdedafa4219 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -140,9 +140,10 @@ public class AllClassesGetter { } }; - public static void processJavaClasses(final CompletionParameters parameters, - final PrefixMatcher prefixMatcher, final boolean filterByScope, - final Consumer<PsiClass> consumer) { + public static void processJavaClasses(@NotNull final CompletionParameters parameters, + @NotNull final PrefixMatcher prefixMatcher, + final boolean filterByScope, + @NotNull final Consumer<PsiClass> consumer) { final PsiElement context = parameters.getPosition(); final Project project = context.getProject(); final GlobalSearchScope scope = filterByScope ? context.getContainingFile().getResolveScope() : GlobalSearchScope.allScope(project); @@ -167,10 +168,10 @@ public class AllClassesGetter { processJavaClasses(prefixMatcher, project, scope, processor); } - public static void processJavaClasses(final PrefixMatcher prefixMatcher, - Project project, - GlobalSearchScope scope, - Processor<PsiClass> processor) { + public static void processJavaClasses(@NotNull final PrefixMatcher prefixMatcher, + @NotNull Project project, + @NotNull GlobalSearchScope scope, + @NotNull Processor<PsiClass> processor) { AllClassesSearch.search(scope, project, new Condition<String>() { @Override public boolean value(String s) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java index 0440a33aed22..bc00fa223385 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java @@ -16,13 +16,13 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.daemon.impl.actions.AddImportAction; -import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupActionProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementAction; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import org.jetbrains.annotations.Nullable; @@ -39,12 +39,12 @@ public class ExcludeFromCompletionLookupActionProvider implements LookupActionPr } else if (o instanceof PsiMethod) { final PsiMethod method = (PsiMethod)o; if (method.hasModifierProperty(PsiModifier.STATIC)) { - addExcludes(consumer, method, StaticImportMethodFix.getMemberQualifiedName(method)); + addExcludes(consumer, method, PsiUtil.getMemberQualifiedName(method)); } } else if (o instanceof PsiField) { final PsiField field = (PsiField)o; if (field.hasModifierProperty(PsiModifier.STATIC)) { - addExcludes(consumer, field, StaticImportMethodFix.getMemberQualifiedName(field)); + addExcludes(consumer, field, PsiUtil.getMemberQualifiedName(field)); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java index eb19c574c872..f7140fea80eb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java @@ -17,7 +17,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.*; import com.intellij.diagnostic.LogMessageEx; -import com.intellij.diagnostic.errordialog.Attachment; +import com.intellij.diagnostic.AttachmentFactory; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.ClassConditionKey; @@ -120,7 +120,7 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement "atTail=" + atTail + "\n" + "offset=" + context.getTailOffset() + "\n" + DebugUtil.currentStackTrace(), - new Attachment(context.getDocument()))); + AttachmentFactory.createAttachment(context.getDocument()))); } document.replaceString(context.getTailOffset() - 1, context.getTailOffset(), "."); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index a25001065d11..71360e7ba348 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -30,9 +30,11 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.lang.java.JavaLanguage; import com.intellij.patterns.PsiJavaPatterns; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; public class JavaCharFilter extends CharFilter { @@ -67,9 +69,16 @@ public class JavaCharFilter extends CharFilter { if (c == ':') { PsiFile file = lookup.getPsiFile(); PsiDocumentManager.getInstance(file.getProject()).commitDocument(lookup.getEditor().getDocument()); - PsiElement element = lookup.getPsiElement(); - if (PsiTreeUtil.getParentOfType(element, PsiSwitchLabelStatement.class) != null || - PsiTreeUtil.getParentOfType(element, PsiConditionalExpression.class) != null) { + PsiElement leaf = file.findElementAt(lookup.getEditor().getCaretModel().getOffset() - 1); + if (PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_8)) { + PsiStatement statement = PsiTreeUtil.getParentOfType(leaf, PsiStatement.class); + if (statement == null || + statement.getTextRange().getStartOffset() != leaf.getTextRange().getStartOffset()) { // not typing a statement label + return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + } + } + if (PsiTreeUtil.getParentOfType(leaf, PsiSwitchLabelStatement.class) != null || + PsiTreeUtil.getParentOfType(leaf, PsiConditionalExpression.class) != null) { return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } return Result.HIDE_LOOKUP; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index d1166c749091..df113a5a77a1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -30,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.TrueFilter; +import com.intellij.psi.filters.classes.AnnotationTypeFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -78,14 +79,16 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { return false; } - public static void addAllClasses(CompletionParameters parameters, + public static void addAllClasses(@NotNull CompletionParameters parameters, final boolean filterByScope, @NotNull final PrefixMatcher matcher, @NotNull final Consumer<LookupElement> consumer) { final PsiElement insertedElement = parameters.getPosition(); final ElementFilter filter = - IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : TrueFilter.INSTANCE; + IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : + JavaCompletionContributor.ANNOTATION_NAME.accepts(insertedElement) ? new AnnotationTypeFilter() : + TrueFilter.INSTANCE; final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; final boolean afterNew = AFTER_NEW.accepts(insertedElement); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 083649aeb1a6..3ce6050837b7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -39,6 +39,7 @@ import com.intellij.patterns.PsiNameValuePairPattern; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.filters.*; +import com.intellij.psi.filters.classes.AnnotationTypeFilter; import com.intellij.psi.filters.classes.AssignableFromContextFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; import com.intellij.psi.filters.element.ModifierFilter; @@ -75,6 +76,9 @@ public class JavaCompletionContributor extends CompletionContributor { ourCompletionData.put(LanguageLevel.JDK_1_3, new JavaCompletionData()); } + public static final ElementPattern<PsiElement> ANNOTATION_NAME = psiElement(). + withParents(PsiJavaCodeReferenceElement.class, PsiAnnotation.class).afterLeaf("@"); + private static JavaCompletionData getCompletionData(LanguageLevel level) { final Set<Map.Entry<LanguageLevel, JavaCompletionData>> entries = ourCompletionData.entrySet(); for (Map.Entry<LanguageLevel, JavaCompletionData> entry : entries) { @@ -113,6 +117,10 @@ public class JavaCompletionContributor extends CompletionContributor { return new AndFilter(ElementClassFilter.CLASS, new NotFilter(new AssignableFromContextFilter())); } + if (ANNOTATION_NAME.accepts(position)) { + return new AnnotationTypeFilter(); + } + if (JavaCompletionData.DECLARATION_START.accepts(position) || JavaCompletionData.isInsideParameterList(position) || psiElement().inside(psiElement(PsiJavaCodeReferenceElement.class).withParent(psiAnnotation())).accepts(position)) { @@ -223,10 +231,10 @@ public class JavaCompletionContributor extends CompletionContributor { result.addElement(LookupElementBuilder.create("*")); } - Set<String> usedWords = addReferenceVariants(parameters, result, inheritors); - addKeywords(parameters, result); + Set<String> usedWords = addReferenceVariants(parameters, result, inheritors); + if (psiElement().inside(PsiLiteralExpression.class).accepts(position)) { PsiReference reference = position.getContainingFile().findReferenceAt(parameters.getOffset()); if (reference == null || reference.isSoft()) { @@ -234,7 +242,7 @@ public class JavaCompletionContributor extends CompletionContributor { } } - JavaOverrideCompletionContributor.fillCompletionVariants(parameters, result); + JavaGenerateMemberCompletionContributor.fillCompletionVariants(parameters, result); addAllClasses(parameters, result, inheritors); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index 1de9f59cc67a..f9405ad0afc8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -68,7 +68,7 @@ public class JavaCompletionSorting { CompletionSorter sorter = CompletionSorter.defaultSorter(parameters, result.getPrefixMatcher()); if (!smart && afterNew) { sorter = sorter.weighBefore("liftShorter", new PreferExpected(true, expectedTypes)); - } else { + } else if (PsiTreeUtil.getParentOfType(position, PsiReferenceList.class) == null) { sorter = ((CompletionSorterImpl)sorter).withClassifier("liftShorterClasses", true, new LiftShorterClasses(position)); } if (smart) { @@ -124,7 +124,7 @@ public class JavaCompletionSorting { public Comparable weigh(@NotNull LookupElement element) { final Object o = element.getObject(); if (o instanceof PsiKeyword) return -3; - if (!(o instanceof PsiMember) || element.getUserData(JavaOverrideCompletionContributor.OVERRIDE_ELEMENT) != null) { + if (!(o instanceof PsiMember) || element.getUserData(JavaGenerateMemberCompletionContributor.GENERATE_ELEMENT) != null) { return 0; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 163b2c6ca3bf..6dc59284748f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.completion.scope.CompletionElement; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; -import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix; import com.intellij.codeInsight.guess.GuessManager; import com.intellij.codeInsight.lookup.*; import com.intellij.lang.StdLanguages; @@ -125,7 +124,7 @@ public class JavaCompletionUtil { } public static boolean isInExcludedPackage(@NotNull final PsiMember member, boolean allowInstanceInnerClasses) { - final String name = StaticImportMethodFix.getMemberQualifiedName(member); + final String name = PsiUtil.getMemberQualifiedName(member); if (name == null) return false; if (!member.hasModifierProperty(PsiModifier.STATIC)) { @@ -362,6 +361,7 @@ public class JavaCompletionUtil { PsiElement ctx = createContextWithXxxVariable(element, composite); javaReference = (PsiReferenceExpression) JavaPsiFacade.getElementFactory(element.getProject()).createExpressionFromText("xxx.xxx", ctx); qualifierType = runtimeQualifier; + processor.setQualifierType(qualifierType); } javaReference.processVariants(processor); @@ -620,6 +620,9 @@ public class JavaCompletionUtil { if (element instanceof PsiJavaCodeReferenceElement) { return mayHaveSideEffects(((PsiJavaCodeReferenceElement)element).getQualifier()); } + if (element instanceof PsiParenthesizedExpression) { + return mayHaveSideEffects(((PsiParenthesizedExpression)element).getExpression()); + } return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index 9e18f7bf8448..2259d2bcf23c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -18,16 +18,15 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.scope.CompletionElement; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; +import com.intellij.codeInsight.editorActions.wordSelection.DocTagSelectioner; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.SuppressionUtil; import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorModificationUtil; -import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiJavaPatterns; @@ -38,20 +37,20 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; +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.psi.util.TypeConversionUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ProcessingContext; -import com.intellij.util.Processor; -import com.intellij.util.SystemProperties; +import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.StringTokenizer; /** @@ -113,13 +112,80 @@ public class JavaDocCompletionContributor extends CompletionContributor { }); } + private static PsiParameter getDocTagParam(PsiElement tag) { + if (tag instanceof PsiDocTag && "param".equals(((PsiDocTag)tag).getName())) { + PsiDocTagValue value = ((PsiDocTag)tag).getValueElement(); + if (value instanceof PsiDocParamRef) { + final PsiReference psiReference = value.getReference(); + PsiElement target = psiReference != null ? psiReference.resolve() : null; + if (target instanceof PsiParameter) { + return (PsiParameter)target; + } + } + } + return null; + } + @Override public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) { - if (PsiJavaPatterns.psiElement(JavaDocTokenType.DOC_COMMENT_DATA).accepts(parameters.getPosition())) return; + + PsiElement position = parameters.getPosition(); + if (PsiJavaPatterns.psiElement(JavaDocTokenType.DOC_COMMENT_DATA).accepts(position)) { + final PsiParameter param = getDocTagParam(position.getParent()); + if (param != null) { + suggestSimilarParameterDescriptions(result, position, param); + } + + return; + } super.fillCompletionVariants(parameters, result); } + private static void suggestSimilarParameterDescriptions(CompletionResultSet result, PsiElement position, final PsiParameter param) { + final Set<String> descriptions = ContainerUtil.newHashSet(); + position.getContainingFile().accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + PsiParameter param1 = getDocTagParam(element); + if (param1 != null && param1 != param && + Comparing.equal(param1.getName(), param.getName()) && Comparing.equal(param1.getType(), param.getType())) { + String text = ""; + for (PsiElement psiElement : ((PsiDocTag)element).getDataElements()) { + if (psiElement != ((PsiDocTag)element).getValueElement()) { + text += psiElement.getText(); + } + } + text = text.trim(); + if (text.contains(" ")) { + descriptions.add(text); + } + } + + super.visitElement(element); + } + }); + for (String description : descriptions) { + result.addElement(LookupElementBuilder.create(description).withInsertHandler(new InsertHandler<LookupElement>() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + if (context.getCompletionChar() != Lookup.REPLACE_SELECT_CHAR) return; + + context.commitDocument(); + PsiDocTag docTag = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiDocTag.class, false); + if (docTag != null) { + Document document = context.getDocument(); + int tagEnd = DocTagSelectioner.getDocTagRange(docTag, document.getCharsSequence(), 0).getEndOffset(); + int tail = context.getTailOffset(); + if (tail < tagEnd) { + document.deleteString(tail, tagEnd); + } + } + } + })); + } + } + private static class TagChooser extends CompletionProvider<CompletionParameters> { @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaOverrideCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java index 7467edc91687..ee7a96a1dd4f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaOverrideCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.generation.PsiGenerationInfo; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.Key; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; @@ -29,7 +30,10 @@ import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.ui.RowIcon; import com.intellij.util.VisibilityUtil; +import com.intellij.util.containers.ContainerUtil; +import javax.swing.*; +import java.util.Arrays; import java.util.List; import static com.intellij.patterns.PlatformPatterns.psiElement; @@ -37,8 +41,8 @@ import static com.intellij.patterns.PlatformPatterns.psiElement; /** * @author peter */ -public class JavaOverrideCompletionContributor { - static final Key<Boolean> OVERRIDE_ELEMENT = Key.create("OVERRIDE_ELEMENT"); +public class JavaGenerateMemberCompletionContributor { + static final Key<Boolean> GENERATE_ELEMENT = Key.create("GENERATE_ELEMENT"); public static void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { if (parameters.getCompletionType() != CompletionType.BASIC && parameters.getCompletionType() != CompletionType.SMART) { @@ -51,6 +55,7 @@ public class JavaOverrideCompletionContributor { andNot(psiElement().afterLeaf(psiElement().inside(PsiModifierList.class))).accepts(position)) { final PsiClass parent = CompletionUtil.getOriginalElement((PsiClass)position.getParent().getParent().getParent()); if (parent != null) { + addGetterSetterElements(result, parent); addSuperSignatureElements(parent, true, result); addSuperSignatureElements(parent, false, result); } @@ -58,9 +63,38 @@ public class JavaOverrideCompletionContributor { } + private static void addGetterSetterElements(CompletionResultSet result, PsiClass parent) { + List<PsiMethod> prototypes = ContainerUtil.newArrayList(); + for (PsiField field : parent.getFields()) { + if (!(field instanceof PsiEnumConstant)) { + prototypes.add(GenerateMembersUtil.generateGetterPrototype(field)); + prototypes.add(GenerateMembersUtil.generateSetterPrototype(field)); + } + } + for (final PsiMethod prototype : prototypes) { + if (parent.findMethodBySignature(prototype, false) == null) { + Icon icon = prototype.getIcon(Iconable.ICON_FLAG_VISIBILITY); + result.addElement(createGenerateMethodElement(prototype, PsiSubstitutor.EMPTY, icon, "", new InsertHandler<LookupElement>() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + removeLookupString(context); + + insertGenerationInfos(context, Arrays.asList(new PsiGenerationInfo<PsiMethod>(prototype))); + } + })); + } + } + } + + private static void removeLookupString(InsertionContext context) { + context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); + context.commitDocument(); + } + private static void addSuperSignatureElements(final PsiClass parent, boolean implemented, CompletionResultSet result) { for (CandidateInfo candidate : OverrideImplementExploreUtil.getMethodsToOverrideImplement(parent, implemented)) { PsiMethod baseMethod = (PsiMethod)candidate.getElement(); + assert baseMethod != null; PsiClass baseClass = baseMethod.getContainingClass(); if (!baseMethod.isConstructor() && baseClass != null) { result.addElement(createOverridingLookupElement(parent, implemented, baseMethod, baseClass, candidate.getSubstitutor())); @@ -72,39 +106,48 @@ public class JavaOverrideCompletionContributor { boolean implemented, final PsiMethod baseMethod, PsiClass baseClass, PsiSubstitutor substitutor) { - String methodName = baseMethod.getName(); - - String visibility = VisibilityUtil.getVisibilityModifier(baseMethod.getModifierList()); - String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " "); - PsiType type = substitutor.substitute(baseMethod.getReturnType()); - String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName; - - String parameters = PsiFormatUtil.formatMethod(baseMethod, substitutor, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME); + RowIcon icon = new RowIcon(2); + icon.setIcon(baseMethod.getIcon(0), 0); + icon.setIcon(implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod, 1); - InsertHandler<LookupElement> insertHandler = new InsertHandler<LookupElement>() { + return createGenerateMethodElement(baseMethod, substitutor, icon, baseClass.getName(), new InsertHandler<LookupElement>() { @Override public void handleInsert(InsertionContext context, LookupElement item) { - context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); - context.commitDocument(); + removeLookupString(context); List<PsiMethod> prototypes = OverrideImplementUtil.overrideOrImplementMethod(parent, baseMethod, false); - List<PsiGenerationInfo<PsiMethod>> infos = OverrideImplementUtil.convert2GenerationInfos(prototypes); - List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil.insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos); - if (!newInfos.isEmpty()) { - newInfos.get(0).positionCaret(context.getEditor(), true); - } + insertGenerationInfos(context, OverrideImplementUtil.convert2GenerationInfos(prototypes)); } - }; + }); + } - RowIcon icon = new RowIcon(2); - icon.setIcon(baseMethod.getIcon(0), 0); - icon.setIcon(implemented ? AllIcons.Gutter.ImplementingMethod : AllIcons.Gutter.OverridingMethod, 1); + private static void insertGenerationInfos(InsertionContext context, List<PsiGenerationInfo<PsiMethod>> infos) { + List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil + .insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos); + if (!newInfos.isEmpty()) { + newInfos.get(0).positionCaret(context.getEditor(), true); + } + } + + private static LookupElementBuilder createGenerateMethodElement(PsiMethod prototype, + PsiSubstitutor substitutor, + Icon icon, + String typeText, InsertHandler<LookupElement> insertHandler) { + String methodName = prototype.getName(); + + String visibility = VisibilityUtil.getVisibilityModifier(prototype.getModifierList()); + String modifiers = (visibility == PsiModifier.PACKAGE_LOCAL ? "" : visibility + " "); + + PsiType type = substitutor.substitute(prototype.getReturnType()); + String signature = modifiers + (type == null ? "" : type.getPresentableText() + " ") + methodName; + + String parameters = PsiFormatUtil.formatMethod(prototype, substitutor, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME); - LookupElementBuilder element = LookupElementBuilder.create(baseMethod, signature).withLookupString(methodName). + LookupElementBuilder element = LookupElementBuilder.create(prototype, signature).withLookupString(methodName). withLookupString(signature).withInsertHandler(insertHandler). - appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(baseClass.getName()).withIcon(icon); - element.putUserData(OVERRIDE_ELEMENT, true); + appendTailText(parameters, false).appendTailText(" {...}", true).withTypeText(typeText).withIcon(icon); + element.putUserData(GENERATE_ELEMENT, true); return element; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java index b2896f336a9a..d995a9e3d475 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.lookup.*; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -66,6 +67,10 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { return; } + if (parameters.getInvocationCount() == 0 && TemplateManagerImpl.getTemplateState(parameters.getEditor()) != null) { + return; + } + PsiElement position = parameters.getPosition(); final Set<LookupElement> lookupSet = new THashSet<LookupElement>(); if (psiElement(PsiIdentifier.class).andNot(INSIDE_TYPE_PARAMS_PATTERN).withParent( diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index e099338792e3..c28c80767326 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -51,14 +51,13 @@ public class JavaNoVariantsDelegator extends CompletionContributor { if (empty) { delegate(parameters, JavaCompletionSorting.addJavaSorting(parameters, result)); - } else if (Registry.is("ide.completion.show.all.classes") || Registry.is("ide.completion.show.better.matching.classes")) { - if (parameters.getInvocationCount() <= 1 && + } else if (Registry.is("ide.completion.show.better.matching.classes")) { + if (parameters.getCompletionType() == CompletionType.BASIC && + parameters.getInvocationCount() <= 1 && JavaCompletionContributor.mayStartClassName(result) && JavaCompletionContributor.isClassNamePossible(parameters) && !JavaSmartCompletionContributor.AFTER_NEW.accepts(parameters.getPosition())) { - if (Registry.is("ide.completion.show.better.matching.classes")) { - result = result.withPrefixMatcher(new BetterPrefixMatcher(result.getPrefixMatcher(), BetterPrefixMatcher.getBestMatchingDegree(plainResults))); - } + result = result.withPrefixMatcher(new BetterPrefixMatcher(result.getPrefixMatcher(), BetterPrefixMatcher.getBestMatchingDegree(plainResults))); suggestNonImportedClasses(parameters, result); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 5e7af80e7d0d..9710f7550c99 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -474,10 +474,10 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return; } if (parent instanceof PsiParenthesizedExpression) { - context.setDummyIdentifier("xxx)yyy "); // to handle type cast + context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + ")" + CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + " "); // to handle type cast return; } } - context.setDummyIdentifier("xxx"); + context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index f316b0a92ed2..f4adccc7140d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -284,7 +284,9 @@ public class ReferenceExpressionCompletionContributor { final PsiType expectedType = parameters.getExpectedType(); if (!OBJECT_METHOD_PATTERN.accepts(object) || allowGetClass(object, parameters)) { if (parameters.getParameters().getInvocationCount() >= 3 || !itemType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { - addChainedCallVariants(element, baseItem, result, itemType, expectedType, parameters); + if (!(object instanceof PsiMethod && ((PsiMethod)object).getParameterList().getParametersCount() > 0)) { + addChainedCallVariants(element, baseItem, result, itemType, expectedType, parameters); + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/ChainCompletionStringUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/ChainCompletionStringUtil.java new file mode 100644 index 000000000000..688fadaf613c --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/ChainCompletionStringUtil.java @@ -0,0 +1,94 @@ +package com.intellij.codeInsight.completion.methodChains; + +import com.intellij.openapi.util.text.StringUtilRt; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public final class ChainCompletionStringUtil { + private ChainCompletionStringUtil() {} + + public static boolean isPrimitiveOrArray(final @Nullable String typeQName) { + return typeQName != null && (typeQName.endsWith("[]") || PRIMITIVES_NAMES.contains(typeQName)); + } + + /** + * CAUTION: isPrimitiveOrArrayOfPrimitives("java.lang.String") == true, + * isPrimitiveOrArrayOfPrimitives("java.lang.Object") == true + * isPrimitiveOrArrayOfPrimitives("java.lang.Class") == true + */ + public static boolean isPrimitiveOrArrayOfPrimitives(final String typeQName) { + if (typeQName == null) { + return false; + } + return PRIMITIVES_NAMES.contains(deleteArraySigns(typeQName)); + } + + public static boolean isShortNamePrimitiveOrArrayOfPrimitives(final @Nullable String shortName) { + if (shortName == null) { + return false; + } + return PRIMITIVES_SHORT_NAMES.contains(deleteArraySigns(shortName)); + } + + private static String deleteArraySigns(final @NotNull String typeName) { + String nameWithoutArraySign = typeName; + while (nameWithoutArraySign.endsWith("[]")) { + nameWithoutArraySign = nameWithoutArraySign.substring(0, nameWithoutArraySign.length() - 2); + } + return nameWithoutArraySign; + } + + private static final Set<String> PRIMITIVES_NAMES = new HashSet<String>(); + + static { + fillPrimitivesNames(PsiType.BOOLEAN); + fillPrimitivesNames(PsiType.INT); + fillPrimitivesNames(PsiType.LONG); + fillPrimitivesNames(PsiType.DOUBLE); + fillPrimitivesNames(PsiType.FLOAT); + fillPrimitivesNames(PsiType.SHORT); + fillPrimitivesNames(PsiType.CHAR); + fillPrimitivesNames(PsiType.BYTE); + fillPrimitivesNames(PsiType.VOID); + PRIMITIVES_NAMES.add(CommonClassNames.JAVA_LANG_STRING); + PRIMITIVES_NAMES.add(CommonClassNames.JAVA_LANG_OBJECT); + PRIMITIVES_NAMES.add(CommonClassNames.JAVA_LANG_CLASS); + } + + private static void fillPrimitivesNames(final PsiPrimitiveType type) { + PRIMITIVES_NAMES.add(type.getBoxedTypeName()); + PRIMITIVES_NAMES.add(type.getCanonicalText()); + } + + private static final Set<String> PRIMITIVES_SHORT_NAMES = new HashSet<String>(); + + static { + fillPrimitivesShortNames(PsiType.BOOLEAN); + fillPrimitivesShortNames(PsiType.INT); + fillPrimitivesShortNames(PsiType.LONG); + fillPrimitivesShortNames(PsiType.DOUBLE); + fillPrimitivesShortNames(PsiType.FLOAT); + fillPrimitivesShortNames(PsiType.SHORT); + fillPrimitivesShortNames(PsiType.CHAR); + fillPrimitivesShortNames(PsiType.BYTE); + fillPrimitivesShortNames(PsiType.VOID); + PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(CommonClassNames.JAVA_LANG_STRING)); + PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(CommonClassNames.JAVA_LANG_OBJECT)); + PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(CommonClassNames.JAVA_LANG_CLASS)); + } + + private static void fillPrimitivesShortNames(final PsiPrimitiveType type) { + PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(type.getBoxedTypeName())); + PRIMITIVES_SHORT_NAMES.add(type.getCanonicalText()); + } + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/Constants.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/Constants.java new file mode 100644 index 000000000000..7a326a70d4c7 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/Constants.java @@ -0,0 +1,20 @@ +package com.intellij.codeInsight.completion.methodChains; + +/** + * @author Dmitry Batkovich + */ +public final class Constants { + + private Constants() { + } + + /** + * magic numbers + */ + public static final int SINGLETON_MAGIC_RATIO = 100; + + public static final int SINGLETON_MAGIC_RATIO2 = 5; + + public static final int CHAIN_SEARCH_MAGIC_RATIO = 12; + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/CompletionContributorPatternUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/CompletionContributorPatternUtil.java new file mode 100644 index 000000000000..f020afa18141 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/CompletionContributorPatternUtil.java @@ -0,0 +1,33 @@ +package com.intellij.codeInsight.completion.methodChains.completion; + +import com.intellij.codeInsight.completion.CompletionInitializationContext; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl; + +import static com.intellij.patterns.PsiJavaPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.or; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public final class CompletionContributorPatternUtil { + + private CompletionContributorPatternUtil() {} + + @SuppressWarnings("unchecked") + public static ElementPattern<PsiElement> patternForVariableAssignment() { + final ElementPattern<PsiElement> patternForParent = or(psiElement().withText(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED) + .afterSiblingSkipping(psiElement(PsiWhiteSpace.class), + psiElement(PsiJavaToken.class).withText("="))); + + return psiElement().withParent(patternForParent).withSuperParent(2, or(psiElement(PsiAssignmentExpression.class), + psiElement(PsiLocalVariable.class) + .inside(PsiDeclarationStatement.class))) + .inside(PsiMethod.class); + } + + public static ElementPattern<PsiElement> patternForMethodParameter() { + return psiElement().withSuperParent(3, PsiMethodCallExpressionImpl.class); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java new file mode 100644 index 000000000000..27c63a0c2a50 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java @@ -0,0 +1,206 @@ +package com.intellij.codeInsight.completion.methodChains.completion; + +import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext; +import com.intellij.codeInsight.completion.methodChains.completion.context.ContextUtil; +import com.intellij.codeInsight.completion.methodChains.search.ChainsSearcher; +import com.intellij.codeInsight.completion.methodChains.search.MethodChainsSearchService; +import com.intellij.codeInsight.completion.methodChains.search.MethodsChain; +import com.intellij.codeInsight.completion.methodChains.search.MethodsChainLookupRangingHelper; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.searches.DirectClassInheritorsSearch; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ProcessingContext; +import com.intellij.util.Processor; +import com.intellij.util.SmartList; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +import static com.intellij.patterns.PsiJavaPatterns.or; + +/** + * @author Dmitry Batkovich + */ +public class MethodsChainsCompletionContributor extends CompletionContributor { + public static final int INVOCATIONS_THRESHOLD = 3; + + private final static int MAX_SEARCH_RESULT_SIZE = 20; + private final static int MAX_CHAIN_SIZE = 4; + private final static int FILTER_RATIO = 10; + + @Override + public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) { + if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD && CompilerOutputIndexer.getInstance(parameters.getPosition().getProject()).isEnabled()) { + super.fillCompletionVariants(parameters, result); + if (ApplicationManager.getApplication().isUnitTestMode()) { + result.stopHere(); + } + } + } + + @SuppressWarnings("unchecked") + public MethodsChainsCompletionContributor() { + final ElementPattern<PsiElement> pattern = + or(CompletionContributorPatternUtil.patternForMethodParameter(), CompletionContributorPatternUtil.patternForVariableAssignment()); + extend(CompletionType.BASIC, pattern, new CompletionProvider<CompletionParameters>() { + @Override + protected void addCompletions(final @NotNull CompletionParameters parameters, + final ProcessingContext context, + final @NotNull CompletionResultSet result) { + + final ChainCompletionContext completionContext = extractContext(parameters); + if (completionContext == null) return; + + + final String targetClassQName = completionContext.getTargetQName(); + final Set<String> contextTypesKeysSet = completionContext.getContextTypes(); + final Set<String> contextRelevantTypes = new HashSet<String>(contextTypesKeysSet.size() + 1); + for (final String type : contextTypesKeysSet) { + if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) { + contextRelevantTypes.add(type); + } + } + contextRelevantTypes.remove(targetClassQName); + + final List<LookupElement> foundedElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext); + result.addAllElements(foundedElements); + } + }); + } + + private static List<LookupElement> searchForLookups(final String targetClassQName, + final Set<String> contextRelevantTypes, + final ChainCompletionContext completionContext) { + final MethodChainsSearchService searchService = new MethodChainsSearchService(completionContext.getProject()); + final List<MethodsChain> searchResult = + searchChains(targetClassQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, searchService); + if (searchResult.size() < MAX_SEARCH_RESULT_SIZE) { + final PsiClass aClass = JavaPsiFacade.getInstance(completionContext.getProject()) + .findClass(targetClassQName, GlobalSearchScope.allScope(completionContext.getProject())); + if (aClass != null) { + DirectClassInheritorsSearch.search(aClass).forEach(new Processor<PsiClass>() { + @Override + public boolean process(final PsiClass psiClass) { + final String inheritorQName = psiClass.getQualifiedName(); + if (!StringUtil.isEmpty(inheritorQName)) { + final List<MethodsChain> inheritorFilteredSearchResult = new SmartList<MethodsChain>(); + //noinspection ConstantConditions + for (final MethodsChain chain : searchChains(inheritorQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, + completionContext, searchService)) { + boolean insert = true; + for (final MethodsChain baseChain : searchResult) { + if (baseChain.weakContains(chain)) { + insert = false; + break; + } + } + if (insert) { + inheritorFilteredSearchResult.add(chain); + } + } + searchResult.addAll(inheritorFilteredSearchResult); + } + return true; + } + }); + } + } + return MethodsChainLookupRangingHelper.chainsToWeightableLookupElements(filterTailAndGetSumLastMethodOccurrence(searchResult), + completionContext); + } + + @SuppressWarnings("unchecked") + @Nullable + private static ChainCompletionContext extractContext(final CompletionParameters parameters) { + final PsiElement parent = PsiTreeUtil + .getParentOfType(parameters.getPosition(), PsiAssignmentExpression.class, PsiLocalVariable.class, PsiMethodCallExpression.class); + if (parent == null) { + return null; + } + + if (parent instanceof PsiAssignmentExpression) { + return tryExtractContextFromAssignment((PsiAssignmentExpression)parent); + } + if (parent instanceof PsiLocalVariable) { + final PsiLocalVariable localVariable = (PsiLocalVariable)parent; + return ContextUtil.createContext(localVariable.getType(), localVariable.getName(), + PsiTreeUtil.getParentOfType(parent, PsiDeclarationStatement.class)); + } + final PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod(); + if (method == null) return null; + final PsiExpression expression = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpression.class); + final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpressionList.class); + if (expressionList == null) return null; + final int exprPosition = Arrays.asList(expressionList.getExpressions()).indexOf(expression); + final PsiParameter[] methodParameters = method.getParameterList().getParameters(); + if (exprPosition < methodParameters.length) { + final PsiParameter methodParameter = methodParameters[exprPosition]; + return ContextUtil + .createContext(methodParameter.getType(), null, PsiTreeUtil.getParentOfType(expression, PsiDeclarationStatement.class)); + } + return null; + } + + @Nullable + private static ChainCompletionContext tryExtractContextFromAssignment(final PsiAssignmentExpression assignmentExpression) { + final PsiType type = assignmentExpression.getLExpression().getType(); + final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(assignmentExpression.getLExpression(), PsiIdentifier.class); + if (identifier == null) return null; + final String identifierText = identifier.getText(); + return ContextUtil.createContext(type, identifierText, assignmentExpression); + } + + private static List<MethodsChain> filterTailAndGetSumLastMethodOccurrence(final List<MethodsChain> chains) { + int maxWeight = 0; + for (final MethodsChain chain : chains) { + final int chainWeight = chain.getChainWeight(); + if (chainWeight > maxWeight) { + maxWeight = chainWeight; + } + } + + final List<MethodsChain> filteredResult = new ArrayList<MethodsChain>(); + for (final MethodsChain chain : chains) { + final int chainWeight = chain.getChainWeight(); + if (chainWeight * FILTER_RATIO >= maxWeight) { + filteredResult.add(chain); + } + } + return filteredResult; + } + + private static List<MethodsChain> searchChains(final String targetQName, + final Set<String> contextVarsQNames, + final int maxResultSize, + final int maxChainSize, + final ChainCompletionContext context, + final MethodChainsSearchService searchService) { + return ChainsSearcher.search(searchService, targetQName, contextVarsQNames, maxResultSize, maxChainSize, + createNotDeprecatedMethodsResolver(JavaPsiFacade.getInstance(context.getProject()), + context.getResolveScope()), + context.getExcludedQNames(), context.getContextMethodName()); + } + + private static FactoryMap<MethodIncompleteSignature, PsiMethod[]> createNotDeprecatedMethodsResolver(final JavaPsiFacade javaPsiFacade, + final GlobalSearchScope scope) { + return new FactoryMap<MethodIncompleteSignature, PsiMethod[]>() { + @Nullable + @Override + protected PsiMethod[] create(final MethodIncompleteSignature signature) { + return signature.resolveNotDeprecated(javaPsiFacade, scope); + } + }; + } + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsWeigher.java new file mode 100644 index 000000000000..57293cae1e12 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsWeigher.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 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.methodChains.completion; + +import com.intellij.codeInsight.completion.CompletionLocation; +import com.intellij.codeInsight.completion.CompletionWeigher; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.WeightableChainLookupElement; +import com.intellij.codeInsight.completion.methodChains.search.ChainRelevance; +import com.intellij.codeInsight.lookup.LookupElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public class MethodsChainsWeigher extends CompletionWeigher { + @Override + public Comparable weigh(@NotNull final LookupElement element, @NotNull final CompletionLocation location) { + if (element instanceof WeightableChainLookupElement) { + return ((WeightableChainLookupElement)element).getChainRelevance(); + } + return ChainRelevance.LOWEST; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContext.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContext.java new file mode 100644 index 000000000000..bb8d92d0839f --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContext.java @@ -0,0 +1,156 @@ +package com.intellij.codeInsight.completion.methodChains.completion.context; + +import com.intellij.codeInsight.completion.methodChains.search.CachedRelevantStaticMethodSearcher; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiVariable; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class ChainCompletionContext { + private final NotNullLazyValue<String> myContextMethodName = new NotNullLazyValue<String>() { + @NotNull + @Override + protected String compute() { + return myContextMethod.getName(); + } + }; + private final PsiMethod myContextMethod; + private final String myTargetQName; + private final Set<String> myContainingClassQNames; + private final MultiMap<String, PsiVariable> myContextVars; + private final MultiMap<String, PsiMethod> myContainingClassGetters; + private final MultiMap<String, ContextRelevantVariableGetter> myContextVarsGetters; + private final Map<String, PsiVariable> myStringVars; + private final CachedRelevantStaticMethodSearcher myStaticMethodSearcher; + private final Set<String> myExcludedQNames; + private final GlobalSearchScope myResolveScope; + private final Project myProject; + + private final NotNullLazyValue<Set<String>> contextTypesQNames = new NotNullLazyValue<Set<String>>() { + @SuppressWarnings("unchecked") + @NotNull + @Override + protected Set<String> compute() { + return unionToHashSet(myContainingClassQNames, myContextVars.keySet(), myContainingClassGetters.keySet(), + myContextVarsGetters.keySet()); + } + }; + + public Set<String> getExcludedQNames() { + return myExcludedQNames; + } + + ChainCompletionContext(final PsiMethod contextMethod, + final String targetQName, + final Set<String> containingClassQNames, + final MultiMap<String, PsiVariable> contextVars, + final MultiMap<String, PsiMethod> containingClassGetters, + final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters, + final Map<String, PsiVariable> stringVars, + final Set<String> excludedQNames, + final Project project, + final GlobalSearchScope resolveScope) { + myContextMethod = contextMethod; + myTargetQName = targetQName; + myContainingClassQNames = containingClassQNames; + myContextVars = contextVars; + myContainingClassGetters = containingClassGetters; + myContextVarsGetters = contextVarsGetters; + myStringVars = stringVars; + myExcludedQNames = excludedQNames; + myResolveScope = resolveScope; + myProject = project; + myStaticMethodSearcher = new CachedRelevantStaticMethodSearcher(project, resolveScope); + } + + public PsiMethod getContextMethod() { + return myContextMethod; + } + + public String getContextMethodName() { + return myContextMethodName.getValue(); + } + + public String getTargetQName() { + return myTargetQName; + } + + @Nullable + public PsiVariable findRelevantStringInContext(@Nullable final String stringParamName) { + if (stringParamName == null) { + return null; + } + for (final Map.Entry<String, PsiVariable> e : myStringVars.entrySet()) { + if (ChainCompletionContextStringUtil.isSimilar(e.getKey(), stringParamName)) { + return e.getValue(); + } + } + return null; + } + + public Set<String> getContainingClassQNames() { + return myContainingClassQNames; + } + + public Collection<PsiVariable> getVariables(final String typeQName) { + return myContextVars.get(typeQName); + } + + public Collection<PsiMethod> getContainingClassMethods(final String typeQName) { + return myContainingClassGetters.get(typeQName); + } + + public Collection<ContextRelevantStaticMethod> getRelevantStaticMethods(final String typeQName, final int weight) { + return myStaticMethodSearcher.getRelevantStaticMethods(typeQName, weight, this); + } + + public Collection<ContextRelevantVariableGetter> getRelevantVariablesGetters(final String typeQName) { + return myContextVarsGetters.get(typeQName); + } + + public Collection<?> getContextRefElements(final String typeQName) { + final Collection<PsiVariable> variables = getVariables(typeQName); + final Collection<PsiMethod> containingClassMethods = getContainingClassMethods(typeQName); + final Collection<UserDataHolder> refElements = new ArrayList<UserDataHolder>(variables.size() + containingClassMethods.size()); + refElements.addAll(variables); + refElements.addAll(containingClassMethods); + for (final ContextRelevantVariableGetter contextRelevantVariableGetter : getRelevantVariablesGetters(typeQName)) { + refElements.add(contextRelevantVariableGetter.createLookupElement()); + } + return refElements; + } + + public boolean contains(@Nullable final String typeQualifierName) { + return typeQualifierName != null && contextTypesQNames.getValue().contains(typeQualifierName); + } + + public Set<String> getContextTypes() { + return contextTypesQNames.getValue(); + } + + public GlobalSearchScope getResolveScope() { + return myResolveScope; + } + + public Project getProject() { + return myProject; + } + + private static <T> HashSet<T> unionToHashSet(final Collection<T>... collections) { + final HashSet<T> res = new HashSet<T>(); + for (final Collection<T> set : collections) { + res.addAll(set); + } + return res; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContextStringUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContextStringUtil.java new file mode 100644 index 000000000000..a9b1903ea803 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ChainCompletionContextStringUtil.java @@ -0,0 +1,36 @@ +package com.intellij.codeInsight.completion.methodChains.completion.context; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +class ChainCompletionContextStringUtil { + + private ChainCompletionContextStringUtil(){} + + private final static int COMMON_PART_MIN_LENGTH = 3; + + public static boolean isSimilar(@NotNull final String varName, + @NotNull final String parameterName) { + final String sanitizedParamName = sanitizedToLowerCase(parameterName); + if (StringUtil.commonPrefix(varName, sanitizedParamName).length() >= COMMON_PART_MIN_LENGTH) { + return true; + } + final String suffix = StringUtil.commonSuffix(varName, sanitizedParamName); + return suffix.length() >= COMMON_PART_MIN_LENGTH; + } + + @NotNull + public static String sanitizedToLowerCase(@NotNull final String name) { + final StringBuilder result = new StringBuilder(); + for (int i = 0; i < name.length(); i++) { + final char ch = name.charAt(i); + if (Character.isLetter(ch)) { + result.append(Character.toLowerCase(ch)); + } + } + return result.toString(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantStaticMethod.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantStaticMethod.java new file mode 100644 index 000000000000..23b1c26be7f4 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantStaticMethod.java @@ -0,0 +1,45 @@ +package com.intellij.codeInsight.completion.methodChains.completion.context; + +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.StaticMethodSubLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.SubLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.VariableSubLookupElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiVariable; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TIntObjectProcedure; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class ContextRelevantStaticMethod { + private final PsiMethod psiMethod; + @Nullable + private final TIntObjectHashMap<SubLookupElement> parameters; + + public ContextRelevantStaticMethod(final PsiMethod psiMethod, @Nullable final TIntObjectHashMap<PsiVariable> parameters) { + this.psiMethod = psiMethod; + if (parameters == null) { + this.parameters = null; + } else { + this.parameters = new TIntObjectHashMap<SubLookupElement>(parameters.size()); + parameters.forEachEntry(new TIntObjectProcedure<PsiVariable>() { + @SuppressWarnings("ConstantConditions") + @Override + public boolean execute(final int pos, final PsiVariable var) { + ContextRelevantStaticMethod.this.parameters.put(pos, new VariableSubLookupElement(var)); + return false; + } + }); + } + } + + private SubLookupElement cachedLookupElement; + + public SubLookupElement createLookupElement() { + if (cachedLookupElement == null) { + cachedLookupElement = new StaticMethodSubLookupElement(psiMethod, parameters); + } + return cachedLookupElement; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantVariableGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantVariableGetter.java new file mode 100644 index 000000000000..fec1cfd6b61e --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextRelevantVariableGetter.java @@ -0,0 +1,31 @@ +package com.intellij.codeInsight.completion.methodChains.completion.context; + +import com.intellij.codeInsight.completion.JavaChainLookupElement; +import com.intellij.codeInsight.completion.JavaMethodCallElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.GetterLookupSubLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.SubLookupElement; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.VariableLookupItem; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiVariable; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class ContextRelevantVariableGetter { + private final PsiVariable myVariable; + private final PsiMethod myMethod; + + public ContextRelevantVariableGetter(final PsiVariable variable, final PsiMethod method) { + myVariable = variable; + myMethod = method; + } + + public SubLookupElement createSubLookupElement() { + return new GetterLookupSubLookupElement(myVariable.getName(), myMethod.getName()); + } + + public LookupElement createLookupElement() { + return new JavaChainLookupElement(new VariableLookupItem(myVariable), new JavaMethodCallElement(myMethod)); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextUtil.java new file mode 100644 index 000000000000..481c5f87ac63 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/context/ContextUtil.java @@ -0,0 +1,245 @@ +package com.intellij.codeInsight.completion.methodChains.completion.context; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.SmartList; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class ContextUtil { + @Nullable + public static ChainCompletionContext createContext(final @Nullable PsiType variableType, + final @Nullable String variableName, + final @Nullable PsiElement containingElement) { + if (variableType == null || containingElement == null) { + return null; + } + if (variableType instanceof PsiClassType) { + final PsiClass aClass = ((PsiClassType)variableType).resolve(); + if (aClass != null) { + if (aClass.hasTypeParameters()) { + return null; + } + } + else { + return null; + } + } + + final String targetQName = variableType.getCanonicalText(); + if (targetQName == null || targetQName.endsWith("[]")) { + return null; + } + + final PsiMethod method = PsiTreeUtil.getParentOfType(containingElement, PsiMethod.class); + if (method == null) { + return null; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return null; + } + final Set<String> containingClassQNames = resolveSupersNamesRecursively(aClass); + + final List<PsiVariable> contextVars = new SmartList<PsiVariable>(); + for (final PsiField field : aClass.getFields()) { + final PsiClass containingClass = field.getContainingClass(); + if (containingClass != null) { + if ((field.hasModifierProperty(PsiModifier.PUBLIC) || + field.hasModifierProperty(PsiModifier.PROTECTED) || + ((field.hasModifierProperty(PsiModifier.PRIVATE) || field.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) && + aClass.isEquivalentTo(containingClass))) && !field.getName().equals(variableName)) { + contextVars.add(field); + } + } + } + Collections.addAll(contextVars, method.getParameterList().getParameters()); + + final PsiCodeBlock methodBody = method.getBody(); + assert methodBody != null; + boolean processMethodTail = false; + final List<PsiElement> afterElements = new ArrayList<PsiElement>(); + for (final PsiElement element : methodBody.getChildren()) { + if (element.isEquivalentTo(containingElement)) { + if (variableType instanceof PsiClassType) { + processMethodTail = true; + continue; + } + else { + break; + } + } + if (element instanceof PsiDeclarationStatement) { + if (processMethodTail) { + afterElements.add(element); + } + else { + for (final PsiElement declaredElement : ((PsiDeclarationStatement)element).getDeclaredElements()) { + if (declaredElement instanceof PsiLocalVariable && + (variableName == null || !variableName.equals(((PsiLocalVariable)declaredElement).getName()))) { + contextVars.add((PsiVariable)declaredElement); + } + } + } + } + } + + final Set<String> excludedQNames = processMethodTail + ? generateExcludedQNames(afterElements, ((PsiClassType)variableType).resolve(), variableName, + contextVars) + : Collections.<String>emptySet(); + + final List<PsiMethod> contextMethods = new ArrayList<PsiMethod>(); + for (final PsiMethod psiMethod : aClass.getMethods()) { + if ((psiMethod.hasModifierProperty(PsiModifier.PROTECTED) || psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) && + psiMethod.getParameterList().getParametersCount() == 0) { + contextMethods.add(psiMethod); + } + } + + return create(method, targetQName, contextVars, contextMethods, containingClassQNames, containingElement.getProject(), + containingElement.getResolveScope(), excludedQNames); + } + + private static Set<String> generateExcludedQNames(final List<PsiElement> tailElements, + final @Nullable PsiClass psiClass, + final @Nullable String varName, + final List<PsiVariable> contextVars) { + if (psiClass == null) { + return Collections.emptySet(); + } + final String classQName = psiClass.getQualifiedName(); + if (classQName == null) { + return Collections.emptySet(); + } + + final Set<String> excludedQNames = new HashSet<String>(); + if (!tailElements.isEmpty()) { + final Set<String> contextVarTypes = new HashSet<String>(); + final Map<String, PsiVariable> contextVarNamesToVar = new HashMap<String, PsiVariable>(); + for (final PsiVariable var : contextVars) { + contextVarTypes.add(var.getType().getCanonicalText()); + contextVarNamesToVar.put(var.getName(), var); + } + for (final PsiElement element : tailElements) { + final Collection<PsiMethodCallExpression> methodCallExpressions = + PsiTreeUtil.findChildrenOfType(element, PsiMethodCallExpression.class); + for (final PsiMethodCallExpression methodCallExpression : methodCallExpressions) { + final PsiExpressionList args = methodCallExpression.getArgumentList(); + final PsiMethod resolvedMethod = methodCallExpression.resolveMethod(); + if (resolvedMethod != null) { + final PsiType returnType = resolvedMethod.getReturnType(); + if (returnType != null) { + final String returnTypeAsString = returnType.getCanonicalText(); + for (final PsiExpression expression : args.getExpressions()) { + final String qVarName = expression.getText(); + if (qVarName != null) { + if (contextVarNamesToVar.containsKey(qVarName) || qVarName.equals(varName)) { + excludedQNames.add(returnTypeAsString); + } + } + } + if (!contextVarTypes.contains(returnTypeAsString)) { + excludedQNames.add(returnTypeAsString); + } + } + } + } + } + } + + return excludedQNames; + } + + @Nullable + private static ChainCompletionContext create(final PsiMethod contextMethod, + final String targetQName, + final List<PsiVariable> contextVars, + final List<PsiMethod> contextMethods, + final Set<String> containingClassQNames, + final Project project, + final GlobalSearchScope resolveScope, + final Set<String> excludedQNames) { + final MultiMap<String, PsiVariable> classQNameToVariable = new MultiMap<String, PsiVariable>(); + final MultiMap<String, PsiMethod> containingClassGetters = new MultiMap<String, PsiMethod>(); + final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters = new MultiMap<String, ContextRelevantVariableGetter>(); + final Map<String, PsiVariable> stringVars = new HashMap<String, PsiVariable>(); + + for (final PsiMethod method : contextMethods) { + final String returnTypeQName = method.getReturnType().getCanonicalText(); + if (returnTypeQName != null) { + containingClassGetters.putValue(returnTypeQName, method); + } + } + + for (final PsiVariable var : contextVars) { + final PsiType type = var.getType(); + final Set<String> classQNames = new HashSet<String>(); + if (type instanceof PsiClassType) { + if (JAVA_LANG_STRING_SHORT_NAME.equals(((PsiClassType)type).getClassName())) { + final String varName = var.getName(); + if (varName != null) { + stringVars.put(ChainCompletionContextStringUtil.sanitizedToLowerCase(varName), var); + continue; + } + } + + final PsiClass aClass = ((PsiClassType)type).resolve(); + if (aClass != null) { + final String classQName = type.getCanonicalText(); + if (!targetQName.equals(classQName)) { + classQNames.add(classQName); + classQNames.addAll(resolveSupersNamesRecursively(aClass)); + for (final PsiMethod method : aClass.getAllMethods()) { + if (method.getParameterList().getParametersCount() == 0 && method.getName().startsWith("get")) { + final String getterReturnTypeQName = method.getReturnType().getCanonicalText(); + if (getterReturnTypeQName != null) { + contextVarsGetters.putValue(getterReturnTypeQName, new ContextRelevantVariableGetter(var, method)); + } + } + } + } + } + } + else { + final String classQName = type.getCanonicalText(); + if (classQName != null) { + classQNames.add(classQName); + } + } + for (final String qName : classQNames) { + classQNameToVariable.putValue(qName, var); + } + } + return new ChainCompletionContext(contextMethod, targetQName, containingClassQNames, classQNameToVariable, containingClassGetters, + contextVarsGetters, stringVars, excludedQNames, project, resolveScope); + } + + @NotNull + private static Set<String> resolveSupersNamesRecursively(@Nullable final PsiClass psiClass) { + final Set<String> result = new HashSet<String>(); + if (psiClass != null) { + for (final PsiClass superClass : psiClass.getSupers()) { + final String qualifiedName = superClass.getQualifiedName(); + if (!CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) { + if (qualifiedName != null) { + result.add(qualifiedName); + } + result.addAll(resolveSupersNamesRecursively(superClass)); + } + } + } + return result; + } + + private final static String JAVA_LANG_STRING_SHORT_NAME = StringUtil.getShortName(CommonClassNames.JAVA_LANG_STRING); +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionLookupElementUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionLookupElementUtil.java new file mode 100644 index 000000000000..65be8928c5d9 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionLookupElementUtil.java @@ -0,0 +1,53 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup; + +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.SubLookupElement; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.psi.PsiKeyword; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiParameter; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public final class ChainCompletionLookupElementUtil { + private ChainCompletionLookupElementUtil() { + } + + public static LookupElement createLookupElement(final PsiMethod method, + final @Nullable TIntObjectHashMap<SubLookupElement> replaceElements) { + if (method.isConstructor()) { + //noinspection ConstantConditions + return LookupElementBuilder.create(String.format("%s %s", PsiKeyword.NEW, method.getContainingClass().getName())); + } else if (method.hasModifierProperty(PsiModifier.STATIC)) { + return new ChainCompletionMethodCallLookupElement(method, replaceElements, false, true); + } else { + return new ChainCompletionMethodCallLookupElement(method, replaceElements); + } + } + + public static String fillMethodParameters(final PsiMethod method, @Nullable final TIntObjectHashMap<SubLookupElement> replaceElements) { + final TIntObjectHashMap<SubLookupElement> notNullReplaceElements = replaceElements == null ? + new TIntObjectHashMap<SubLookupElement>(0) : + replaceElements; + + final PsiParameter[] parameters = method.getParameterList().getParameters(); + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parameters.length; i++) { + if (i != 0) { + sb.append(", "); + } + final PsiParameter parameter = parameters[i]; + final SubLookupElement replaceElement = notNullReplaceElements.get(i); + if (replaceElement != null) { + sb.append(replaceElement.getInsertString()); + } else { + sb.append(parameter.getName()); + } + } + return sb.toString(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionMethodCallLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionMethodCallLookupElement.java new file mode 100644 index 000000000000..f7a62d6ccc02 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionMethodCallLookupElement.java @@ -0,0 +1,88 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup; + +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.completion.JavaMethodCallElement; +import com.intellij.codeInsight.completion.StaticallyImportable; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.SubLookupElement; +import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiMethod; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TObjectProcedure; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class ChainCompletionMethodCallLookupElement extends JavaMethodCallElement implements StaticallyImportable { + public static final String PROP_METHODS_CHAIN_COMPLETION_AUTO_COMPLETION = "methods.chain.completion.autoCompletion"; + + private final PsiMethod myMethod; + @Nullable + private final TIntObjectHashMap<SubLookupElement> myReplaceElements; + private final boolean myMergedOverloads; + + public ChainCompletionMethodCallLookupElement(final PsiMethod method, + final @Nullable TIntObjectHashMap<SubLookupElement> replaceElements, + final boolean shouldImportStatic, + final boolean mergedOverloads) { + super(method, shouldImportStatic, mergedOverloads); + myMethod = method; + myReplaceElements = replaceElements; + myMergedOverloads = mergedOverloads; + configureAutoCompletionPolicy(); + } + + public ChainCompletionMethodCallLookupElement(final PsiMethod method, + final @Nullable TIntObjectHashMap<SubLookupElement> replaceElements) { + super(method); + myMethod = method; + myReplaceElements = replaceElements; + myMergedOverloads = true; + configureAutoCompletionPolicy(); + } + + private void configureAutoCompletionPolicy() { + if (ApplicationManager.getApplication().isUnitTestMode()) { + if (PropertiesComponent.getInstance(myMethod.getProject()).getBoolean(PROP_METHODS_CHAIN_COMPLETION_AUTO_COMPLETION, false)) { + setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE); + } + } + } + + @Override + public void handleInsert(final InsertionContext context) { + super.handleInsert(context); + if (!myMergedOverloads || isUniqueMethod(myMethod)) { + context.commitDocument(); + context.getDocument() + .insertString(context.getTailOffset() - 1, ChainCompletionLookupElementUtil.fillMethodParameters(myMethod, myReplaceElements)); + final PsiFile file = context.getFile(); + assert file instanceof PsiJavaFile; + final PsiJavaFile javaFile = (PsiJavaFile)file; + if (myReplaceElements != null) { + myReplaceElements.forEachValue(new TObjectProcedure<SubLookupElement>() { + @Override + public boolean execute(final SubLookupElement subLookupElement) { + subLookupElement.doImport(javaFile); + return true; + } + }); + } + context.commitDocument(); + context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); + context.commitDocument(); + } + } + + + private static boolean isUniqueMethod(@NotNull final PsiMethod method) { + final PsiClass containingClass = method.getContainingClass(); + return containingClass == null || containingClass.findMethodsByName(method.getName(), true).length == 1; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java new file mode 100644 index 000000000000..53dc9bc9eed5 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java @@ -0,0 +1,79 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup; + +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.codeInsight.lookup.LookupItem; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class ChainCompletionNewVariableLookupElement extends LookupItem<PsiClass> { + + private final PsiClass psiClass; + private final String newVarName; + + public ChainCompletionNewVariableLookupElement(final PsiClass psiClass, final String newVarName) { + super(psiClass, newVarName); + this.newVarName = newVarName; + this.psiClass = psiClass; + } + + public static ChainCompletionNewVariableLookupElement create(final PsiClass psiClass) { + final Project project = psiClass.getProject(); + final SuggestedNameInfo suggestedNameInfo = JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, JavaPsiFacade .getElementFactory( project).createType(psiClass)); + return new ChainCompletionNewVariableLookupElement(psiClass, chooseLongest(suggestedNameInfo.names)); + } + + @Override + public void handleInsert(final InsertionContext context) { + final PsiFile file = context.getFile(); + ((PsiJavaFile) file).importClass(psiClass); + final PsiStatement statement = PsiTreeUtil.getParentOfType(file.findElementAt(context.getEditor().getCaretModel().getOffset()), PsiStatement.class); + final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(statement, PsiCodeBlock.class); + assert codeBlock != null; + final Project project = context.getProject(); + new WriteCommandAction.Simple(project, file) { + @Override + protected void run() throws Throwable { + codeBlock.addBefore( + JavaPsiFacade.getElementFactory( + project). + createStatementFromText(String.format("%s %s = null;", psiClass.getName(), newVarName), null), statement); + } + }.execute(); + PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(context.getDocument()); + } + + @NotNull + @Override + public String getLookupString() { + return newVarName; + } + + @Override + public void renderElement(final LookupElementPresentation presentation) { + super.renderElement(presentation); + presentation.setItemText(newVarName); + } + + private static String chooseLongest(final String[] names) { + String longestWord = names[0]; + int maxLength = longestWord.length(); + for (int i = 1; i < names.length; i++) { + final int length = names[i].length(); + if (length > maxLength) { + maxLength = length; + longestWord = names[i]; + } + } + return longestWord; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java new file mode 100644 index 000000000000..e58d2c84e7df --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java @@ -0,0 +1,22 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup; + +import com.intellij.codeInsight.completion.methodChains.search.ChainRelevance; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementDecorator; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public final class WeightableChainLookupElement extends LookupElementDecorator<LookupElement> { + private final ChainRelevance myChainRelevance; + + public WeightableChainLookupElement(final @NotNull LookupElement delegate, final ChainRelevance relevance) { + super(delegate); + myChainRelevance = relevance; + } + + public ChainRelevance getChainRelevance() { + return myChainRelevance; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/GetterLookupSubLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/GetterLookupSubLookupElement.java new file mode 100644 index 000000000000..e6b84107c6be --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/GetterLookupSubLookupElement.java @@ -0,0 +1,35 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup.sub; + +import com.intellij.psi.PsiJavaFile; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class GetterLookupSubLookupElement implements SubLookupElement { + private final String myVariableName; + private final String myMethodName; + + public GetterLookupSubLookupElement(final String methodName) { + this(null, methodName); + } + + public GetterLookupSubLookupElement(@Nullable final String variableName, final String methodName) { + myVariableName = variableName; + myMethodName = methodName; + } + + @Override + public void doImport(final PsiJavaFile javaFile) { + } + + @Override + public String getInsertString() { + final StringBuilder sb = new StringBuilder(); + if (myVariableName != null) { + sb.append(myVariableName).append("."); + } + sb.append(myMethodName).append("()"); + return sb.toString(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/StaticMethodSubLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/StaticMethodSubLookupElement.java new file mode 100644 index 000000000000..88d8b01529c0 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/StaticMethodSubLookupElement.java @@ -0,0 +1,51 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup.sub; + +import com.intellij.codeInsight.completion.methodChains.completion.lookup.ChainCompletionLookupElementUtil; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TObjectProcedure; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class StaticMethodSubLookupElement implements SubLookupElement { + + private final PsiMethod myMethod; + private final TIntObjectHashMap<SubLookupElement> myReplaceElements; + + public StaticMethodSubLookupElement(final PsiMethod method, @Nullable final TIntObjectHashMap<SubLookupElement> replaceElements) { + assert method.hasModifierProperty(PsiModifier.STATIC); + myReplaceElements = replaceElements; + myMethod = method; + } + + @Override + public void doImport(final PsiJavaFile javaFile) { + final PsiClass containingClass = myMethod.getContainingClass(); + if (containingClass != null) { + if (javaFile.findImportReferenceTo(containingClass) == null) { + javaFile.importClass(containingClass); + } + } + if (myReplaceElements != null) { + myReplaceElements.forEachValue(new TObjectProcedure<SubLookupElement>() { + @Override + public boolean execute(final SubLookupElement subLookupElement) { + subLookupElement.doImport(javaFile); + return false; + } + }); + } + } + + @Override + public String getInsertString() { + //noinspection ConstantConditions + return String.format("%s.%s(%s)", myMethod.getContainingClass().getName(), myMethod.getName(), + ChainCompletionLookupElementUtil.fillMethodParameters(myMethod, myReplaceElements)); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/SubLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/SubLookupElement.java new file mode 100644 index 000000000000..7046012d4017 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/SubLookupElement.java @@ -0,0 +1,13 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup.sub; + +import com.intellij.psi.PsiJavaFile; + +/** + * @author Dmitry Batkovich + */ +public interface SubLookupElement { + + void doImport(final PsiJavaFile javaFile); + + String getInsertString(); +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/VariableSubLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/VariableSubLookupElement.java new file mode 100644 index 000000000000..894f10b8d15d --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/sub/VariableSubLookupElement.java @@ -0,0 +1,25 @@ +package com.intellij.codeInsight.completion.methodChains.completion.lookup.sub; + +import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiVariable; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class VariableSubLookupElement implements SubLookupElement { + + private final String myVarName; + + public VariableSubLookupElement(final PsiVariable variable) { + myVarName = variable.getName(); + } + + @Override + public void doImport(final PsiJavaFile javaFile) { + } + + @Override + public String getInsertString() { + return myVarName; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java new file mode 100644 index 000000000000..018065a7ed56 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java @@ -0,0 +1,36 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.openapi.project.Project; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class CachedNotDeprecatedMethodsResolver { + private final Map<MethodIncompleteSignature, PsiMethod[]> myResolveLocalCache = new HashMap<MethodIncompleteSignature, PsiMethod[]>(); + private final JavaPsiFacade myJavaPsiFacade; + private final GlobalSearchScope myScope; + + public CachedNotDeprecatedMethodsResolver(final Project project, final GlobalSearchScope scope) { + myScope = scope; + myJavaPsiFacade = JavaPsiFacade.getInstance(project); + } + + @NotNull + public PsiMethod[] resolveNotDeprecated(@NotNull final MethodIncompleteSignature methodInvocation) { + final PsiMethod[] cached = myResolveLocalCache.get(methodInvocation); + if (cached != null) { + return cached; + } + final PsiMethod[] methods = methodInvocation.resolveNotDeprecated(myJavaPsiFacade, myScope); + myResolveLocalCache.put(methodInvocation, methods); + return methods; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedRelevantStaticMethodSearcher.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedRelevantStaticMethodSearcher.java new file mode 100644 index 000000000000..ef11e727c959 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedRelevantStaticMethodSearcher.java @@ -0,0 +1,122 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext; +import com.intellij.codeInsight.completion.methodChains.completion.context.ContextRelevantStaticMethod; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.MethodsUsageIndex; +import com.intellij.compilerOutputIndex.impl.UsageIndexValue; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class CachedRelevantStaticMethodSearcher { + private final HashMap<MethodIncompleteSignature, PsiMethod> myCachedResolveResults = new HashMap<MethodIncompleteSignature, PsiMethod>(); + private final MethodsUsageIndex myIndex; + private final JavaPsiFacade myJavaPsiFacade; + private final GlobalSearchScope myAllScope; + private final GlobalSearchScope myResolveScope; + + public CachedRelevantStaticMethodSearcher(final Project project, final GlobalSearchScope resolveScope) { + myIndex = MethodsUsageIndex.getInstance(project); + myJavaPsiFacade = JavaPsiFacade.getInstance(project); + myAllScope = GlobalSearchScope.allScope(project); + myResolveScope = resolveScope; + } + + @NotNull + public List<ContextRelevantStaticMethod> getRelevantStaticMethods(final String resultQualifiedClassName, + final int minOccurrence, + final ChainCompletionContext completionContext) { + if (resultQualifiedClassName == null || + ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(resultQualifiedClassName) || + completionContext.getTargetQName().equals(resultQualifiedClassName)) { + return Collections.emptyList(); + } + final TreeSet<UsageIndexValue> indexValues = myIndex.getValues(resultQualifiedClassName); + if (indexValues != null) { + int occurrences = 0; + final List<ContextRelevantStaticMethod> relevantMethods = new ArrayList<ContextRelevantStaticMethod>(); + for (final UsageIndexValue indexValue : extractStaticMethods(indexValues)) { + final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature(); + final PsiMethod method; + if (myCachedResolveResults.containsKey(methodInvocation)) { + method = myCachedResolveResults.get(methodInvocation); + } + else { + final PsiMethod[] methods = methodInvocation.resolveNotDeprecated(myJavaPsiFacade, myAllScope); + method = MethodChainsSearchUtil + .getMethodWithMinNotPrimitiveParameters(methods, Collections.singleton(completionContext.getTargetQName())); + myCachedResolveResults.put(methodInvocation, method); + if (method == null) { + return Collections.emptyList(); + } + } + if (method == null) { + return Collections.emptyList(); + } + if (method.hasModifierProperty(PsiModifier.PUBLIC)) { + if (isMethodValid(method, completionContext, resultQualifiedClassName)) { + occurrences += indexValue.getOccurrences(); + if (myResolveScope.contains(method.getContainingFile().getVirtualFile())) { + relevantMethods.add(new ContextRelevantStaticMethod(method, null)); + } + if (occurrences >= minOccurrence) { + return relevantMethods; + } + } + } + } + } + return Collections.emptyList(); + } + + private static List<UsageIndexValue> extractStaticMethods(final TreeSet<UsageIndexValue> indexValues) { + final List<UsageIndexValue> relevantStaticMethods = new SmartList<UsageIndexValue>(); + for (final UsageIndexValue indexValue : indexValues) { + if (indexValue.getMethodIncompleteSignature().isStatic()) { + relevantStaticMethods.add(indexValue); + } + } + return relevantStaticMethods; + } + + private static boolean isMethodValid(final @Nullable PsiMethod method, + final ChainCompletionContext completionContext, + final String targetTypeShortName) { + if (method == null) return false; + for (final PsiParameter parameter : method.getParameterList().getParameters()) { + final PsiType type = parameter.getType(); + final String shortClassName = typeAsString(type); + if (targetTypeShortName.equals(shortClassName)) return false; + if (!ChainCompletionStringUtil.isShortNamePrimitiveOrArrayOfPrimitives(shortClassName) && + !completionContext.contains(type.getCanonicalText())) { + return false; + } + } + return true; + } + + + @Nullable + public static String typeAsString(final PsiType type) { + if (type instanceof PsiClassType) + return ((PsiClassType) type).getClassName(); + else if (type instanceof PsiPrimitiveType) + return type.getCanonicalText(); + else if (type instanceof PsiArrayType) { + final String componentTypeAsString = typeAsString(((PsiArrayType) type).getComponentType()); + if (componentTypeAsString == null) return null; + return String.format("%s[]", componentTypeAsString); + } + return null; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java new file mode 100644 index 000000000000..09e008a7aa4b --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java @@ -0,0 +1,91 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class ChainRelevance implements Comparable<ChainRelevance> { + public static final ChainRelevance LOWEST = new ChainRelevance(Integer.MAX_VALUE, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, false, false); + + private final int myChainSize; + private final int myLastMethodOccurrences; + private final int myUnreachableParametersCount; + private final int myNotMatchedStringVars; + private final boolean myHasCallingVariableInContext; + private final boolean myFirstMethodStatic; + + public ChainRelevance(final int chainSize, + final int lastMethodOccurrences, + final int unreachableParametersCount, + final int notMatchedStringVars, + final boolean hasCallingVariableInContext, + final boolean firstMethodStatic) { + myChainSize = chainSize; + myLastMethodOccurrences = lastMethodOccurrences; + myUnreachableParametersCount = unreachableParametersCount; + myNotMatchedStringVars = notMatchedStringVars; + myHasCallingVariableInContext = hasCallingVariableInContext; + myFirstMethodStatic = firstMethodStatic; + } + + @TestOnly + public boolean hasCallingVariableInContext() { + return myHasCallingVariableInContext; + } + + @TestOnly + public int getChainSize() { + return myChainSize; + } + + @TestOnly + public int getLastMethodOccurrences() { + return myLastMethodOccurrences; + } + + @TestOnly + public int getUnreachableParametersCount() { + return myUnreachableParametersCount; + } + + @TestOnly + public int getNotMatchedStringVars() { + return myNotMatchedStringVars; + } + + @TestOnly + public boolean isFirstMethodStatic() { + return myFirstMethodStatic; + } + + @Override + public int compareTo(@NotNull final ChainRelevance that) { + if (myFirstMethodStatic && !that.myFirstMethodStatic) { + return -1; + } + if (that.myFirstMethodStatic && !myFirstMethodStatic) { + return 1; + } + if (myHasCallingVariableInContext && !that.myHasCallingVariableInContext) { + return 1; + } + if (that.myHasCallingVariableInContext && !myHasCallingVariableInContext) { + return -1; + } + int sub = myLastMethodOccurrences - that.myLastMethodOccurrences; + if (sub != 0) return sub; + sub = myUnreachableParametersCount - that.myUnreachableParametersCount; + if (sub != 0) return -sub; + return 0; + } + + @Override + public String toString() { + return (myFirstMethodStatic ? "1" : "0") + + (myHasCallingVariableInContext ? "1" : "0") + "_" + + myLastMethodOccurrences + "_" + + myUnreachableParametersCount; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java new file mode 100644 index 000000000000..b47095a096f4 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java @@ -0,0 +1,206 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.codeInsight.completion.methodChains.Constants; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.UsageIndexValue; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.psi.PsiMethod; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class ChainsSearcher { + + public static List<MethodsChain> search(final MethodChainsSearchService searchService, + final String targetQName, + final Set<String> contextQNames, + final int maxResultSize, + final int pathMaximalLength, + final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver, + final String contextMethodName) { + return search(searchService, targetQName, contextQNames, maxResultSize, pathMaximalLength, resolver, + Collections.<String>singleton(targetQName), contextMethodName); + } + + public static List<MethodsChain> search(final MethodChainsSearchService searchService, + final String targetQName, + final Set<String> contextQNames, + final int maxResultSize, + final int pathMaximalLength, + final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver, + final Set<String> excludedParamsTypesQNames, + final String contextMethodName) { + final SearchInitializer initializer = createInitializer(targetQName, resolver, searchService, excludedParamsTypesQNames); + final ArrayList<MethodsChain> methodsChains = new ArrayList<MethodsChain>(maxResultSize); + final MethodsChain firstBestMethodsChain = + search(searchService, initializer, contextQNames, Collections.<String>emptySet(), pathMaximalLength, resolver, targetQName, + excludedParamsTypesQNames, contextMethodName); + if (firstBestMethodsChain != null) { + methodsChains.add(firstBestMethodsChain); + Set<Set<String>> excludedCombinations = MethodsChain.edgeCombinations(Collections.<Set<String>>emptySet(), firstBestMethodsChain); + while (methodsChains.size() <= maxResultSize) { + final Set<Set<String>> localExcludedCombinations = excludedCombinations; + boolean allLocalsIsNull = true; + final int beforeStepChainsCount = methodsChains.size(); + for (final Set<String> excludedEdges : localExcludedCombinations) { + final MethodsChain local = + search(searchService, initializer, contextQNames, excludedEdges, pathMaximalLength, resolver, targetQName, + excludedParamsTypesQNames, contextMethodName); + if (local != null) { + allLocalsIsNull = false; + } + else { + continue; + } + boolean add = true; + for (int i = 0; i < methodsChains.size(); i++) { + final MethodsChain chain = methodsChains.get(i); + final MethodsChain.CompareResult compareResult = MethodsChain.compare(local, chain); + if (compareResult == MethodsChain.CompareResult.EQUAL || compareResult == MethodsChain.CompareResult.RIGHT_CONTAINS_LEFT) { + add = false; + break; + } + else if (compareResult == MethodsChain.CompareResult.LEFT_CONTAINS_RIGHT) { + methodsChains.set(i, local); + add = false; + break; + } + } + if (add) { + methodsChains.add(local); + if (methodsChains.size() >= maxResultSize) { + return methodsChains; + } + excludedCombinations = MethodsChain.edgeCombinations(excludedCombinations, local); + } + } + if (allLocalsIsNull || beforeStepChainsCount == methodsChains.size()) { + return methodsChains; + } + } + } + return methodsChains; + } + + private static SearchInitializer createInitializer(final String targetQName, + final FactoryMap<MethodIncompleteSignature, PsiMethod[]> context, + final MethodChainsSearchService searchService, + final Set<String> excludedParamsTypesQNames) { + return new SearchInitializer(searchService.getMethods(targetQName), context, targetQName, excludedParamsTypesQNames); + } + + @Nullable + private static MethodsChain search(final MethodChainsSearchService searchService, + final SearchInitializer initializer, + final Set<String> toSet, + final Set<String> excludedEdgeNames, + final int pathMaximalLength, + final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver, + final String targetQName, + final Set<String> excludedParamsTypesQNames, + final String contextMethodName) { + final Set<String> allExcludedNames = MethodChainsSearchUtil.unionToHashSet(excludedParamsTypesQNames, targetQName); + ProgressManager.checkCanceled(); + final SearchInitializer.InitResult initResult = initializer.init(excludedEdgeNames, toSet, searchService, contextMethodName); + final Map<MethodIncompleteSignature, MethodsChain> knownDistance = initResult.getChains(); + final PriorityQueue<WeightAware<MethodIncompleteSignature>> q = + new PriorityQueue<WeightAware<MethodIncompleteSignature>>(initResult.getVertexes()); + MethodsChain result = initResult.getCurrentBestTargetChain(); + + int maxWeight = 0; + for (final MethodsChain methodsChain : knownDistance.values()) { + if (methodsChain.getChainWeight() > maxWeight) { + maxWeight = methodsChain.getChainWeight(); + } + } + + final WeightAware<MethodIncompleteSignature> maxVertex = q.peek(); + final int maxDistance; + if (maxVertex != null) { + maxDistance = maxVertex.getWeight(); + } + else { + return null; + } + + while (!q.isEmpty()) { + final WeightAware<MethodIncompleteSignature> currentVertex = q.poll(); + final int currentVertexDistance = currentVertex.getWeight(); + if (currentVertexDistance * Constants.CHAIN_SEARCH_MAGIC_RATIO < maxDistance) { + return result; + } + final MethodIncompleteSignature currentVertexUnderlying = currentVertex.getUnderlying(); + final MethodsChain currentVertexMethodsChain = knownDistance.get(currentVertexUnderlying); + if (currentVertexDistance != currentVertexMethodsChain.getChainWeight()) { + continue; + } + final SortedSet<UsageIndexValue> bigrams = searchService.getBigram(currentVertexUnderlying); + int bigramsSumWeight = 0; + int maxUpdatedWeight = 0; + for (final UsageIndexValue indexValue : bigrams) { + final MethodIncompleteSignature vertex = indexValue.getMethodIncompleteSignature(); + final int occurrences = indexValue.getOccurrences(); + bigramsSumWeight += occurrences; + final boolean canBeResult = vertex.isStatic() || toSet.contains(vertex.getOwner()); + if (!vertex.getOwner().equals(targetQName) || canBeResult) { + final int vertexDistance = Math.min(currentVertexDistance, occurrences); + final MethodsChain knownVertexMethodsChain = knownDistance.get(vertex); + if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance) && + (result == null || result.getChainWeight() < vertexDistance)) { + if (occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO >= currentVertexMethodsChain.getChainWeight()) { + final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature(); + final PsiMethod[] psiMethods = resolver.get(methodInvocation); + + if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, allExcludedNames)) { + final MethodsChain newBestMethodsChain = currentVertexMethodsChain.addEdge(psiMethods); + if (canBeResult) { + result = newBestMethodsChain; + } + else if (newBestMethodsChain.size() < pathMaximalLength - 1) { + maxUpdatedWeight = Math.max(maxUpdatedWeight, newBestMethodsChain.getChainWeight()); + q.add(new WeightAware<MethodIncompleteSignature>(indexValue.getMethodIncompleteSignature(), + newBestMethodsChain.getChainWeight())); + } + knownDistance.put(vertex, newBestMethodsChain); + } + } + else if (!allExcludedNames.contains(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName()) && + searchService.isSingleton(currentVertexMethodsChain.getFirstQualifierClass(), contextMethodName) && + (searchService.isRelevantMethodForNotOverriden(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(), + currentVertexMethodsChain.getOneOfFirst().getName()) || + searchService.isRelevantMethodForField(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(), + currentVertexMethodsChain.getOneOfFirst().getName()))) { + result = currentVertexMethodsChain; + } + } + } + } + //if ((result == null || maxUpdatedWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO2 <= bigramsSumWeight) + // && bigramsSumWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO >= currentVertexMethodsChain.getChainWeight()) { + // return currentVertexMethodsChain; + //} + + if ((currentVertexMethodsChain.isStaticChain() || + !allExcludedNames.contains(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName())) && + bigramsSumWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO <= currentVertexDistance && + (result == null || result.getChainWeight() < currentVertexDistance) && + (currentVertexMethodsChain.isStaticChain() || + searchService.isSingleton(currentVertexMethodsChain.getFirstQualifierClass(), contextMethodName) && + (searchService.isRelevantMethodForNotOverriden(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(), + currentVertexMethodsChain.getOneOfFirst().getName()) || + searchService.isRelevantMethodForField(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(), + currentVertexMethodsChain.getOneOfFirst().getName())))) { + result = currentVertexMethodsChain; + } + } + + if (result != null && result.getChainWeight() * Constants.CHAIN_SEARCH_MAGIC_RATIO >= maxWeight) { + return result; + } + return null; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java new file mode 100644 index 000000000000..0bc1991c715a --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java @@ -0,0 +1,93 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.MethodsUsageIndex; +import com.intellij.compilerOutputIndex.impl.UsageIndexValue; +import com.intellij.compilerOutputIndex.impl.bigram.BigramMethodsUsageIndex; +import com.intellij.compilerOutputIndex.impl.callingLocation.MethodNameAndQualifier; +import com.intellij.codeInsight.completion.methodChains.search.service.OverridenMethodsService; +import com.intellij.codeInsight.completion.methodChains.search.service.SingletonService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodChainsSearchService { + private final static SortedSet EMPTY_SORTED_SET = new TreeSet(); + + private final MethodsUsageIndex myMethodsUsageIndex; + private final BigramMethodsUsageIndex myBigramMethodsUsageIndex; + private final SingletonService mySingletonService; + private final OverridenMethodsService myOverridenMethodsService; + private final Project myProject; + private final Map<String, Boolean> mySingletonLocalCache; + + public MethodChainsSearchService(final Project project) { + myOverridenMethodsService = new OverridenMethodsService(project); + myMethodsUsageIndex = MethodsUsageIndex.getInstance(project); + myBigramMethodsUsageIndex = BigramMethodsUsageIndex.getInstance(project); + mySingletonService = new SingletonService(project); + myProject = project; + + mySingletonLocalCache = new HashMap<String, Boolean>(); + mySingletonLocalCache.put(null, false); + } + + public Project getProject() { + return myProject; + } + + @NotNull + @SuppressWarnings("unchecked") + public SortedSet<UsageIndexValue> getBigram(final MethodIncompleteSignature methodIncompleteSignature) { + final TreeSet<UsageIndexValue> value = myBigramMethodsUsageIndex.getValues(methodIncompleteSignature); + if (value != null) { + return value; + } + return EMPTY_SORTED_SET; + } + + @NotNull + @SuppressWarnings("unchecked") + public SortedSet<UsageIndexValue> getMethods(final String targetQName) { + final TreeSet<UsageIndexValue> value = myMethodsUsageIndex.getValues(targetQName); + if (value != null) { + return value; + } + return EMPTY_SORTED_SET; + } + + public boolean isSingleton(@NotNull final PsiClass psiClass, final String contextMethodName) { + return isSingleton(psiClass.getQualifiedName(), contextMethodName); + } + + public boolean isSingleton(@Nullable final String typeQName, final String methodName) { + Boolean isSingleton = mySingletonLocalCache.get(typeQName); + if (isSingleton == null) { + isSingleton = mySingletonService.isSingleton(typeQName, methodName); + mySingletonLocalCache.put(typeQName, isSingleton); + } + return isSingleton; + } + + public boolean isRelevantMethodForField(@NotNull final String className, @NotNull final String methodName) { + final Pair<Integer, Integer> occurrences = + myOverridenMethodsService.getMethodUsageInFieldContext(new MethodNameAndQualifier(methodName, className)); + return occurrences.getFirst() > occurrences.getSecond(); + } + + public boolean isRelevantMethodForNotOverriden(@NotNull final String className, @NotNull final String methodName) { + final Pair<Integer, Integer> occurrences = + myOverridenMethodsService.getMethodsUsageInOverridenContext(new MethodNameAndQualifier(methodName, className)); + return occurrences.getFirst() < occurrences.getSecond(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchUtil.java new file mode 100644 index 000000000000..ae0df9554dc4 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchUtil.java @@ -0,0 +1,80 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiParameterList; +import com.intellij.psi.PsiPrimitiveType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public final class MethodChainsSearchUtil { + private MethodChainsSearchUtil() { + } + + @Nullable + public static PsiMethod getMethodWithMinNotPrimitiveParameters(final @NotNull PsiMethod[] methods, + final Set<String> excludedParamsQNames) { + PsiMethod minMethod = null; + int minParametersCount = Integer.MAX_VALUE; + for (final PsiMethod method : methods) { + final PsiParameterList parameterList = method.getParameterList(); + boolean doContinue = false; + int parametersCount = parameterList.getParametersCount(); + for (final PsiParameter p : parameterList.getParameters()) { + if (!(p.getType() instanceof PsiPrimitiveType)) { + if (excludedParamsQNames.contains(p.getType().getCanonicalText())) { + doContinue = true; + break; + } + parametersCount++; + } + } + if (doContinue) { + continue; + } + if (parametersCount < minParametersCount) { + if (parametersCount == 0) { + return method; + } + minParametersCount = parametersCount; + minMethod = method; + } + } + return minMethod; + } + + public static boolean checkParametersForTypesQNames(final PsiMethod[] psiMethods, final Set<String> excludedTypesQNames) { + if (psiMethods.length == 0) { + return true; + } + for (final PsiMethod method : psiMethods) { + boolean hasTargetInParams = false; + for (final PsiParameter param : method.getParameterList().getParameters()) { + final String paramType = param.getType().getCanonicalText(); + if (excludedTypesQNames.contains(paramType)) { + hasTargetInParams = true; + break; + } + } + if (!hasTargetInParams) { + return true; + } + } + return false; + } + + public static <T> HashSet<T> unionToHashSet(final Collection<T> collection, final T... items) { + final HashSet<T> result = new HashSet<T>(); + result.addAll(collection); + Collections.addAll(result, items); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java new file mode 100644 index 000000000000..c7f11c3af979 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java @@ -0,0 +1,160 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +import static com.intellij.util.containers.ContainerUtil.reverse; + +/** + * @author Dmitry Batkovich + */ +public class MethodsChain { + private final List<PsiMethod[]> myRevertedPath; + private final int myWeight; + + public MethodsChain(final PsiMethod[] methods, final int weight) { + this(ContainerUtil.<PsiMethod[]>newArrayList(methods), weight); + } + + public MethodsChain(final List<PsiMethod[]> revertedPath, final int weight) { + myRevertedPath = revertedPath; + myWeight = weight; + } + + public int size() { + return myRevertedPath.size(); + } + + public boolean isStaticChain() { + return myRevertedPath.get(myRevertedPath.size() - 1)[0].hasModifierProperty(PsiModifier.STATIC); + } + + @Nullable + public PsiClass getFirstQualifierClass() { + return myRevertedPath.isEmpty() ? null : myRevertedPath.get(myRevertedPath.size() - 1)[0].getContainingClass(); + } + + @Nullable + public PsiMethod getOneOfFirst() { + return (myRevertedPath.isEmpty() || myRevertedPath.get(0).length == 0) ? null : myRevertedPath.get(myRevertedPath.size() - 1)[0]; + } + + public List<PsiMethod[]> getPath() { + return reverse(myRevertedPath); + } + + public int getChainWeight() { + return myWeight; + } + + public MethodsChain addEdge(final PsiMethod[] psiMethods) { + final List<PsiMethod[]> newRevertedPath = new ArrayList<PsiMethod[]>(myRevertedPath.size() + 1); + newRevertedPath.addAll(myRevertedPath); + newRevertedPath.add(psiMethods); + return new MethodsChain(newRevertedPath, myWeight); + } + + /** + * checking only method names + */ + public boolean weakContains(final MethodsChain otherChain) { + if (otherChain.myRevertedPath.isEmpty()) { + return true; + } + if (myRevertedPath.isEmpty()) { + return false; + } + final Iterator<PsiMethod[]> otherChainIterator = otherChain.myRevertedPath.iterator(); + String otherChainCurrentName = otherChainIterator.next()[0].getName(); + boolean checkingStarted = false; + for (final PsiMethod[] methods : myRevertedPath) { + final String thisCurrentName = methods[0].getName(); + if (!checkingStarted && thisCurrentName.equals(otherChainCurrentName)) { + checkingStarted = true; + } + if (checkingStarted) { + if (otherChainIterator.hasNext()) { + otherChainCurrentName = otherChainIterator.next()[0].getName(); + if (!otherChainCurrentName.equals(thisCurrentName)) { + return false; + } + } else { + return false; + } + } + } + return !otherChainIterator.hasNext(); + } + + @Override + public String toString() { + return StringUtil.join(myRevertedPath, "<-"); + } + + public static Set<Set<String>> edgeCombinations(final Set<Set<String>> oldCombinations, + final MethodsChain methodsChain) { + if (oldCombinations.isEmpty()) { + final Set<Set<String>> result = new HashSet<Set<String>>(methodsChain.myRevertedPath.size()); + for (final PsiMethod[] e : methodsChain.myRevertedPath) { + final Set<String> set = new HashSet<String>(); + set.add(e[0].getName()); + result.add(set); + } + return result; + } else { + final Set<Set<String>> newTail = new HashSet<Set<String>>(oldCombinations.size() * methodsChain.size()); + for (final PsiMethod[] e : methodsChain.myRevertedPath) { + final String methodName = e[0].getName(); + for (final Set<String> tailSet : oldCombinations) { + final Set<String> newSet = new HashSet<String>(tailSet); + newSet.add(methodName); + if (!oldCombinations.contains(newSet)) { + newTail.add(newSet); + } + } + } + return newTail; + } + } + + @SuppressWarnings("ConstantConditions") + public static CompareResult compare(final MethodsChain left, final MethodsChain right) { + if (left.size() == 0) { + return CompareResult.RIGHT_CONTAINS_LEFT; + } + if (right.size() == 0) { + return CompareResult.LEFT_CONTAINS_RIGHT; + } + final Iterator<PsiMethod[]> leftIterator = left.myRevertedPath.iterator(); + final Iterator<PsiMethod[]> rightIterator = right.myRevertedPath.iterator(); + + final PsiManager psiManager = PsiManager.getInstance(left.getFirstQualifierClass().getProject()); + while (leftIterator.hasNext() && rightIterator.hasNext()) { + final PsiMethod thisNext = leftIterator.next()[0]; + final PsiMethod thatNext = rightIterator.next()[0]; + if (((thisNext.isConstructor() != thatNext.isConstructor())) + || !thisNext.getName().equals(thatNext.getName()) + || !psiManager.areElementsEquivalent(thisNext.getContainingClass(), thatNext.getContainingClass())) { + return CompareResult.NOT_EQUAL; + } + } + if (leftIterator.hasNext() && !rightIterator.hasNext()) { + return CompareResult.LEFT_CONTAINS_RIGHT; + } + if (!leftIterator.hasNext() && rightIterator.hasNext()) { + return CompareResult.RIGHT_CONTAINS_LEFT; + } + return CompareResult.EQUAL; + } + + public enum CompareResult { + LEFT_CONTAINS_RIGHT, + RIGHT_CONTAINS_LEFT, + EQUAL, + NOT_EQUAL + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java new file mode 100644 index 000000000000..58a76937b801 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java @@ -0,0 +1,230 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.codeInsight.completion.JavaChainLookupElement; +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext; +import com.intellij.codeInsight.completion.methodChains.completion.context.ContextRelevantStaticMethod; +import com.intellij.codeInsight.completion.methodChains.completion.context.ContextRelevantVariableGetter; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.ChainCompletionNewVariableLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.WeightableChainLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.GetterLookupSubLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.SubLookupElement; +import com.intellij.codeInsight.completion.methodChains.completion.lookup.sub.VariableSubLookupElement; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.VariableLookupItem; +import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static com.intellij.codeInsight.completion.methodChains.completion.lookup.ChainCompletionLookupElementUtil.createLookupElement; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodsChainLookupRangingHelper { + + public static List<LookupElement> chainsToWeightableLookupElements(final List<MethodsChain> chains, + final ChainCompletionContext context) { + final List<LookupElement> lookupElements = new ArrayList<LookupElement>(chains.size()); + for (final MethodsChain chain : chains) { + final LookupElement lookupElement = chainToWeightableLookupElement(chain, context); + if (lookupElement != null) { + lookupElements.add(lookupElement); + } + } + return lookupElements; + } + + @SuppressWarnings("ConstantConditions") + @Nullable + private static WeightableChainLookupElement chainToWeightableLookupElement(final MethodsChain chain, + final ChainCompletionContext context) { + final int chainSize = chain.size(); + assert chainSize != 0; + final int lastMethodWeight = chain.getChainWeight(); + int unreachableParametersCount = 0; + int notMatchedStringVars = 0; + Boolean isFirstMethodStatic = null; + Boolean hasCallingVariableInContext = null; + LookupElement chainLookupElement = null; + + final NullableNotNullManager nullableNotNullManager = NullableNotNullManager.getInstance(context.getProject()); + + for (final PsiMethod[] psiMethods : chain.getPath()) { + final PsiMethod method = + MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters(psiMethods, Collections.singleton(context.getTargetQName())); + if (method == null) { + return null; + } + if (isFirstMethodStatic == null) { + isFirstMethodStatic = psiMethods[0].hasModifierProperty(PsiModifier.STATIC); + } + final MethodProcResult procResult = + processMethod(method, context, lastMethodWeight, chainLookupElement == null, nullableNotNullManager); + if (procResult == null) { + return null; + } + if (hasCallingVariableInContext == null) { + hasCallingVariableInContext = procResult.hasCallingVariableInContext(); + } + unreachableParametersCount += procResult.getUnreachableParametersCount(); + notMatchedStringVars += procResult.getNotMatchedStringVars(); + chainLookupElement = chainLookupElement == null + ? procResult.getLookupElement() + : new JavaChainLookupElement(chainLookupElement, procResult.getLookupElement()); + } + + final ChainRelevance relevance = new ChainRelevance(chainSize, + lastMethodWeight, + unreachableParametersCount, + notMatchedStringVars, + hasCallingVariableInContext, + isFirstMethodStatic); + + return new WeightableChainLookupElement(chainLookupElement, relevance); + } + + + private static MethodProcResult processMethod(@NotNull final PsiMethod method, + final ChainCompletionContext context, + final int weight, + final boolean isHeadMethod, + final NullableNotNullManager nullableNotNullManager) { + int unreachableParametersCount = 0; + int notMatchedStringVars = 0; + boolean hasCallingVariableInContext = false; + final PsiParameterList parameterList = method.getParameterList(); + final TIntObjectHashMap<SubLookupElement> parametersMap = new TIntObjectHashMap<SubLookupElement>(parameterList.getParametersCount()); + final PsiParameter[] parameters = parameterList.getParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final String typeQName = parameter.getType().getCanonicalText(); + if (typeQName != null) { + if (JAVA_LANG_STRING.equals(typeQName)) { + final PsiVariable relevantStringVar = context.findRelevantStringInContext(parameter.getName()); + if (relevantStringVar == null) { + notMatchedStringVars++; + } + else { + parametersMap.put(i, new VariableSubLookupElement(relevantStringVar)); + } + } + else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(typeQName)) { + final Collection<PsiVariable> contextVariables = context.getVariables(typeQName); + final PsiVariable contextVariable = ContainerUtil.getFirstItem(contextVariables, null); + if (contextVariable != null) { + if (contextVariables.size() == 1) parametersMap.put(i, new VariableSubLookupElement(contextVariable)); + continue; + } + final Collection<ContextRelevantVariableGetter> relevantVariablesGetters = context.getRelevantVariablesGetters(typeQName); + final ContextRelevantVariableGetter contextVariableGetter = ContainerUtil.getFirstItem(relevantVariablesGetters, null); + if (contextVariableGetter != null) { + if (relevantVariablesGetters.size() == 1) parametersMap.put(i, contextVariableGetter.createSubLookupElement()); + continue; + } + final Collection<PsiMethod> containingClassMethods = context.getContainingClassMethods(typeQName); + final PsiMethod contextRelevantGetter = ContainerUtil.getFirstItem(containingClassMethods, null); + if (contextRelevantGetter != null) { + if (containingClassMethods.size() == 1) parametersMap.put(i, new GetterLookupSubLookupElement(method.getName())); + continue; + } + final ContextRelevantStaticMethod contextRelevantStaticMethod = + ContainerUtil.getFirstItem(context.getRelevantStaticMethods(typeQName, weight), null); + if (contextRelevantStaticMethod != null) { + // + // In most cases it is not really relevant + // + //parametersMap.put(i, contextRelevantStaticMethod.createLookupElement()); + continue; + } + if (!nullableNotNullManager.isNullable(parameter, true)) { + unreachableParametersCount++; + } + } + } + } + final LookupElement lookupElement; + if (isHeadMethod) { + if (method.hasModifierProperty(PsiModifier.STATIC)) { + lookupElement = createLookupElement(method, parametersMap); + } + else if (method.isConstructor()) { + return null; + } + else { + final PsiClass containingClass = method.getContainingClass(); + final String classQName = containingClass.getQualifiedName(); + if (classQName == null) return null; + final Object e = ContainerUtil.getFirstItem(context.getContextRefElements(classQName), null); + if (e != null) { + final LookupElement firstChainElement; + if (e instanceof PsiVariable) { + hasCallingVariableInContext = true; + firstChainElement = new VariableLookupItem((PsiVariable)e); + } + else if (e instanceof PsiMethod) { + firstChainElement = createLookupElement((PsiMethod)e, null); + } + else if (e instanceof LookupElement) { + firstChainElement = (LookupElement)e; + } + else { + throw new AssertionError(); + } + lookupElement = new JavaChainLookupElement(firstChainElement, createLookupElement(method, parametersMap)); + } + else lookupElement = context.getContainingClassQNames().contains(classQName) + ? createLookupElement(method, parametersMap) + : new JavaChainLookupElement(ChainCompletionNewVariableLookupElement.create(containingClass), + createLookupElement(method, parametersMap)); + } + } + else { + lookupElement = createLookupElement(method, parametersMap); + } + return new MethodProcResult(lookupElement, unreachableParametersCount, notMatchedStringVars, hasCallingVariableInContext); + } + + private static class MethodProcResult { + private final LookupElement myMethodLookup; + private final int myUnreachableParametersCount; + private final int myNotMatchedStringVars; + private final boolean myHasCallingVariableInContext; + + private MethodProcResult(final LookupElement methodLookup, + final int unreachableParametersCount, + final int notMatchedStringVars, + final boolean hasCallingVariableInContext) { + myMethodLookup = methodLookup; + myUnreachableParametersCount = unreachableParametersCount; + myNotMatchedStringVars = notMatchedStringVars; + myHasCallingVariableInContext = hasCallingVariableInContext; + } + + private boolean hasCallingVariableInContext() { + return myHasCallingVariableInContext; + } + + private LookupElement getLookupElement() { + return myMethodLookup; + } + + private int getUnreachableParametersCount() { + return myUnreachableParametersCount; + } + + private int getNotMatchedStringVars() { + return myNotMatchedStringVars; + } + } +} + diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java new file mode 100644 index 000000000000..1f9831361299 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java @@ -0,0 +1,128 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import com.intellij.codeInsight.completion.methodChains.Constants; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.UsageIndexValue; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.util.containers.FactoryMap; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class SearchInitializer { + private final List<WeightAware<MethodIncompleteSignature>> myVertexes; + private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains; + private final Map<MethodIncompleteSignature, Integer> myOccurrencesMap; + private final FactoryMap<MethodIncompleteSignature, PsiMethod[]> myResolver; + + public SearchInitializer(final SortedSet<UsageIndexValue> indexValues, + final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver, + final String targetQName, + final Set<String> excludedParamsTypesQNames) { + myResolver = resolver; + final int size = indexValues.size(); + myVertexes = new ArrayList<WeightAware<MethodIncompleteSignature>>(size); + myChains = new LinkedHashMap<MethodIncompleteSignature, MethodsChain>(size); + myOccurrencesMap = new HashMap<MethodIncompleteSignature, Integer>(size); + add(indexValues, MethodChainsSearchUtil.unionToHashSet(excludedParamsTypesQNames, targetQName)); + } + + private void add(final Collection<UsageIndexValue> indexValues, final Set<String> excludedParamsTypesQNames) { + int bestOccurrences = -1; + for (final UsageIndexValue indexValue : indexValues) { + if (add(indexValue, excludedParamsTypesQNames)) { + final int occurrences = indexValue.getOccurrences(); + if (bestOccurrences == -1) { + bestOccurrences = occurrences; + } else if (bestOccurrences > occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO) { + return; + } + } + } + } + + private boolean add(final UsageIndexValue indexValue, final Set<String> excludedParamsTypesQNames) { + final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature(); + final PsiMethod[] psiMethods = myResolver.get(methodInvocation); + if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, excludedParamsTypesQNames)) { + final int occurrences = indexValue.getOccurrences(); + final MethodsChain methodsChain = new MethodsChain(psiMethods, occurrences); + myChains.put(methodInvocation, methodsChain); + myVertexes.add(new WeightAware<MethodIncompleteSignature>(methodInvocation, occurrences)); + myOccurrencesMap.put(methodInvocation, occurrences); + return true; + } + return false; + } + + public InitResult init(final Set<String> excludedEdgeNames, + final Set<String> contextQNames, + final MethodChainsSearchService searchService, + final String contextMethodName) { + final int size = myVertexes.size(); + int bestOccurrences = 0; + MethodsChain bestTargetMethodChain = null; + final List<WeightAware<MethodIncompleteSignature>> initedVertexes = new ArrayList<WeightAware<MethodIncompleteSignature>>(size); + final LinkedHashMap<MethodIncompleteSignature, MethodsChain> initedChains = new LinkedHashMap<MethodIncompleteSignature, MethodsChain>(size); + final Iterator<Map.Entry<MethodIncompleteSignature, MethodsChain>> chainsIterator = myChains.entrySet().iterator(); + for (final WeightAware<MethodIncompleteSignature> vertex : myVertexes) { + final Map.Entry<MethodIncompleteSignature, MethodsChain> chainEntry = chainsIterator.next(); + final MethodIncompleteSignature method = vertex.getUnderlying(); + if (!excludedEdgeNames.contains(method.getName())) { + initedVertexes.add(vertex); + final MethodsChain methodsChain = chainEntry.getValue(); + initedChains.put(chainEntry.getKey(), methodsChain); + if (contextQNames.contains(method.getOwner())) { + final Integer occurrences = myOccurrencesMap.get(method); + if (occurrences > bestOccurrences) { + final PsiMethod oneOfFirst = methodsChain.getOneOfFirst(); + if (oneOfFirst != null && oneOfFirst.hasModifierProperty(PsiModifier.STATIC)) { + bestTargetMethodChain = methodsChain; + bestOccurrences = occurrences; + continue; + } + final PsiClass firstQualifierClass = methodsChain.getFirstQualifierClass(); + if (firstQualifierClass != null && (searchService.isSingleton(firstQualifierClass, contextMethodName) + || contextQNames.contains(firstQualifierClass.getQualifiedName()))) { + bestTargetMethodChain = methodsChain; + bestOccurrences = occurrences; + } + } + } + } + } + return new InitResult(initedVertexes, initedChains, bestTargetMethodChain); + } + + public static class InitResult { + private final List<WeightAware<MethodIncompleteSignature>> myVertexes; + private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains; + private final MethodsChain myCurrentBestTargetChain; + + private InitResult(final List<WeightAware<MethodIncompleteSignature>> vertexes, + final LinkedHashMap<MethodIncompleteSignature, MethodsChain> chains, + final @Nullable MethodsChain currentBestTargetChain) { + this.myVertexes = vertexes; + this.myChains = chains; + this.myCurrentBestTargetChain = currentBestTargetChain; + } + + public List<WeightAware<MethodIncompleteSignature>> getVertexes() { + return myVertexes; + } + + public LinkedHashMap<MethodIncompleteSignature, MethodsChain> getChains() { + return myChains; + } + + @Nullable + public MethodsChain getCurrentBestTargetChain() { + return myCurrentBestTargetChain; + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java new file mode 100644 index 000000000000..617053d57baf --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java @@ -0,0 +1,29 @@ +package com.intellij.codeInsight.completion.methodChains.search; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public class WeightAware<V> implements Comparable<WeightAware<V>> { + private final V myUnderlying; + private final int myWeight; + + public WeightAware(final V underlying, final int weight) { + myUnderlying = underlying; + myWeight = weight; + } + + public V getUnderlying() { + return myUnderlying; + } + + public int getWeight() { + return myWeight; + } + + @Override + public int compareTo(@NotNull final WeightAware<V> that) { + return -getWeight() + that.getWeight(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java new file mode 100644 index 000000000000..f310a463b49c --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java @@ -0,0 +1,65 @@ +package com.intellij.codeInsight.completion.methodChains.search.service; + +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.callingLocation.CallingLocation; +import com.intellij.compilerOutputIndex.impl.callingLocation.MethodCallingLocationIndex; +import com.intellij.compilerOutputIndex.impl.callingLocation.MethodNameAndQualifier; +import com.intellij.compilerOutputIndex.impl.callingLocation.VariableType; +import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickInheritanceIndex; +import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickMethodsIndex; +import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickOverrideUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; + +/** + * @author Dmitry Batkovich + */ +public class OverridenMethodsService { + + private final QuickMethodsIndex myQuickMethodsIndex; + private final QuickInheritanceIndex myQuickInheritanceIndex; + private final MethodCallingLocationIndex myMethodCallingLocationIndex; + + public OverridenMethodsService(final Project project) { + myQuickInheritanceIndex = QuickInheritanceIndex.getInstance(project); + myQuickMethodsIndex = QuickMethodsIndex.getInstance(project); + myMethodCallingLocationIndex = MethodCallingLocationIndex.getInstance(project); + } + + public boolean isMethodOverriden(final String classQName, final String methodName) { + return QuickOverrideUtil.isMethodOverriden(classQName, methodName, myQuickInheritanceIndex, myQuickMethodsIndex); + } + + public Pair<Integer, Integer> getMethodsUsageInOverridenContext(final MethodNameAndQualifier method) { + final Multiset<MethodIncompleteSignature> locationsAsParam = myMethodCallingLocationIndex.getLocationsAsParam(method); + int overridenOccurrences = 0; + int nonOverridenOccurrences = 0; + for (final Multiset.Entry<MethodIncompleteSignature> e : locationsAsParam.entrySet()) { + final MethodIncompleteSignature sign = e.getElement(); + final boolean methodOverriden = isMethodOverriden(sign.getOwner(), sign.getName()); + if (methodOverriden) { + overridenOccurrences++; + } + else { + nonOverridenOccurrences++; + } + } + + return Pair.create(overridenOccurrences, nonOverridenOccurrences); + } + + public Pair<Integer, Integer> getMethodUsageInFieldContext(final MethodNameAndQualifier method) { + int asField = 0; + int notField = 0; + for (final CallingLocation callingLocation : myMethodCallingLocationIndex.getAllLocations(method)) { + if (callingLocation.getVariableType().equals(VariableType.FIELD)) { + asField++; + } + else { + notField++; + } + } + return Pair.create(asField, notField); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java new file mode 100644 index 000000000000..4f27ad24cf1f --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java @@ -0,0 +1,89 @@ +package com.intellij.codeInsight.completion.methodChains.search.service; + +import com.intellij.codeInsight.completion.methodChains.Constants; +import com.intellij.compilerOutputIndex.impl.singleton.MethodShortSignatureWithWeight; +import com.intellij.compilerOutputIndex.impl.singleton.ParamsInMethodOccurrencesIndex; +import com.intellij.compilerOutputIndex.impl.singleton.TwinVariablesIndex; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Dmitry Batkovich + */ +public class SingletonService { + private final TwinVariablesIndex myTwinVariablesIndex; + private final ParamsInMethodOccurrencesIndex myParamsInMethodOccurrencesIndex; + private final GlobalSearchScope myAllScope; + private final JavaPsiFacade myJavaPsiFacade; + + private final Map<String, Boolean> myLocalCache; + + public SingletonService(final Project project) { + myTwinVariablesIndex = TwinVariablesIndex.getInstance(project); + myParamsInMethodOccurrencesIndex = ParamsInMethodOccurrencesIndex.getInstance(project); + myAllScope = GlobalSearchScope.allScope(project); + myJavaPsiFacade = JavaPsiFacade.getInstance(project); + + myLocalCache = new HashMap<String, Boolean>(); + myLocalCache.put(null, false); + } + + public boolean isSingleton(@Nullable final String typeQName, final @NotNull String contextMethodName) { + final Boolean isSingletonCached = myLocalCache.get(typeQName); + if (isSingletonCached == null) { + assert typeQName != null; + final PsiClass aClass = myJavaPsiFacade.findClass(typeQName, myAllScope); + if (aClass == null) { + myLocalCache.put(typeQName, false); + return false; + } + for (final PsiClass psiClass : aClass.getInterfaces()) { + final String qualifiedName = psiClass.getQualifiedName(); + if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName) || !isSingleton(qualifiedName, contextMethodName)) { + myLocalCache.put(typeQName, false); + return false; + } + } + final boolean isSingleton = hasTwinsFeature(typeQName) && isSuitableTypeFor(typeQName, contextMethodName); + myLocalCache.put(typeQName, isSingleton); + return isSingleton; + } + return isSingletonCached; + } + + public boolean hasTwinsFeature(final String typeQName) { + final List<Integer> twinInfo = myTwinVariablesIndex.getTwinInfo(typeQName); + if (twinInfo.isEmpty()) { + return false; + } + int ones = 0; + for (final int i : twinInfo) { + if (i == 1) { + ones++; + } + } + return (twinInfo.size() - ones) * Constants.SINGLETON_MAGIC_RATIO < twinInfo.size(); + } + + private boolean isSuitableTypeFor(final String typeName, final String methodName) { + final Pair<List<MethodShortSignatureWithWeight>, Integer> parameterOccurrences = + myParamsInMethodOccurrencesIndex.getParameterOccurrences(typeName); + if (parameterOccurrences.getSecond() == 0) { + return true; + } + final List<MethodShortSignatureWithWeight> contextMethods = parameterOccurrences.getFirst(); + final MethodShortSignatureWithWeight last = contextMethods.get(contextMethods.size() - 1); + return last.getMethodShortSignature().getName().equals(methodName) || last.getWeight() * Constants.SINGLETON_MAGIC_RATIO2 <= parameterOccurrences.getSecond(); + } + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 16fad58d214a..2ec4c4888d53 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -95,8 +95,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme } } else if (qualifier != null) { - myQualifierType = qualifier.getType(); - myQualifierClass = PsiUtil.resolveClassInType(myQualifierType); + setQualifierType(qualifier.getType()); if (myQualifierType == null && qualifier instanceof PsiJavaCodeReferenceElement) { final PsiElement target = ((PsiJavaCodeReferenceElement)qualifier).resolve(); if (target instanceof PsiClass) { @@ -256,6 +255,11 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme return false; } + public void setQualifierType(@Nullable PsiType qualifierType) { + myQualifierType = qualifierType; + myQualifierClass = PsiUtil.resolveClassInClassTypeOnly(qualifierType); + } + @Nullable public PsiType getQualifierType() { return myQualifierType; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index 43a7037397ff..10de8bf533bf 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -27,8 +27,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.*; import com.intellij.codeInsight.intention.EmptyIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionManager; -import com.intellij.codeInspection.InspectionProfile; -import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.ex.InspectionManagerEx; import com.intellij.codeInspection.reference.UnusedDeclarationFixProvider; @@ -36,8 +35,8 @@ import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection; import com.intellij.codeInspection.unusedParameters.UnusedParametersInspection; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.codeInspection.util.SpecialAnnotationsUtilBase; +import com.intellij.diagnostic.AttachmentFactory; import com.intellij.diagnostic.LogMessageEx; -import com.intellij.diagnostic.errordialog.Attachment; import com.intellij.find.FindManager; import com.intellij.find.findUsages.*; import com.intellij.find.impl.FindManagerImpl; @@ -83,6 +82,8 @@ import org.jetbrains.annotations.PropertyKey; import java.util.*; +import static com.intellij.psi.search.PsiSearchHelper.SearchCostResult.*; + public class PostHighlightingPass extends TextEditorHighlightingPass { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.PostHighlightingPass"); private RefCountHolder myRefCountHolder; @@ -211,7 +212,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { String afterText = file.getText(); if (Comparing.strEqual(beforeText, afterText)) { LOG.error(LogMessageEx.createEvent("Import optimizer hasn't optimized any imports", file.getViewProvider().getVirtualFile().getPath(), - new Attachment(file.getViewProvider().getVirtualFile()))); + AttachmentFactory.createAttachment(file.getViewProvider().getVirtualFile()))); } } } @@ -312,7 +313,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { return processField((PsiField)parent, identifier, progress, helper); } if (parent instanceof PsiParameter && myUnusedSymbolInspection.PARAMETER) { - if (InspectionManagerEx.isSuppressed(identifier, UnusedParametersInspection.SHORT_NAME)) return null; + if (SuppressionUtil.isSuppressed(identifier, UnusedParametersInspection.SHORT_NAME)) return null; return processParameter((PsiParameter)parent, identifier, progress); } if (parent instanceof PsiMethod && myUnusedSymbolInspection.METHOD) { @@ -499,10 +500,11 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { if (UnusedSymbolLocalInspection.isInjected(method)) return null; HighlightInfo highlightInfo = checkUnusedParameter(parameter, identifier, progress); if (highlightInfo != null) { - final ArrayList<IntentionAction> options = new ArrayList<IntentionAction>(); + List<IntentionAction> options = new ArrayList<IntentionAction>(); options.addAll(IntentionManager.getInstance().getStandardIntentionOptions(myUnusedSymbolKey, myFile)); if (myUnusedParametersInspection != null) { - Collections.addAll(options, myUnusedParametersInspection.getSuppressActions(parameter)); + SuppressQuickFix[] batchSuppressActions = myUnusedParametersInspection.getBatchSuppressActions(parameter); + Collections.addAll(options, SuppressManagerImpl.convertBatchToSuppressIntentionActions(batchSuppressActions)); } //need suppress from Unused Parameters but settings from Unused Symbol QuickFixAction.registerQuickFixAction(highlightInfo, new RemoveUnusedParameterFix(parameter), @@ -623,16 +625,28 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { useScope = GlobalSearchScope.projectScope(project).uniteWith((GlobalSearchScope)useScope); } - PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(project).isCheapEnoughToSearch(name, (GlobalSearchScope)useScope, - helper.isCurrentFileAlreadyChecked() ? member.getContainingFile() : null, - progress); - if (cheapEnough == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES) return false; + PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(project); + PsiFile file = member.getContainingFile(); + PsiFile ignoreFile = helper.isCurrentFileAlreadyChecked() ? file : null; + PsiSearchHelper.SearchCostResult cheapEnough = searchHelper.isCheapEnoughToSearch(name, (GlobalSearchScope)useScope, ignoreFile, progress); + if (cheapEnough == TOO_MANY_OCCURRENCES) return false; //search usages if it cheap //if count is 0 there is no usages since we've called myRefCountHolder.isReferenced() before - if (cheapEnough == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) { + if (cheapEnough == ZERO_OCCURRENCES) { if (!canBeReferencedViaWeirdNames(member)) return true; } + + if (member instanceof PsiMethod) { + String propertyName = PropertyUtil.getPropertyName(member); + if (propertyName != null && file != null) { + SearchScope fileScope = file.getUseScope(); + if (fileScope instanceof GlobalSearchScope && + searchHelper.isCheapEnoughToSearch(propertyName, (GlobalSearchScope)fileScope, ignoreFile, progress) == TOO_MANY_OCCURRENCES) { + return false; + } + } + } } FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager(); FindUsagesHandler handler = new JavaFindUsagesHandler(member, new JavaFindUsagesHandlerFactory(project)); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java deleted file mode 100644 index a473befa0b31..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RemoveSuppressWarningAction.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2000-2009 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.daemon.impl; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.SuppressManager; -import com.intellij.codeInspection.SuppressionUtil; -import com.intellij.openapi.diagnostic.Logger; -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.javadoc.PsiDocComment; -import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class RemoveSuppressWarningAction implements LocalQuickFix { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.RemoveSuppressWarningAction"); - - private final String myID; - private final String myProblemLine; - - public RemoveSuppressWarningAction(final String ID, final String problemLine) { - myID = ID; - myProblemLine = problemLine; - } - - public RemoveSuppressWarningAction(String id) { - final int idx = id.indexOf(";"); - if (idx > -1) { - myID = id.substring(0, idx); - myProblemLine = id.substring(idx); - } - else { - myID = id; - myProblemLine = null; - } - } - - @Override - @NotNull - public String getFamilyName() { - return QuickFixBundle.message("remove.suppression.action.family"); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - try { - if (element instanceof PsiIdentifier) { - if (!FileModificationService.getInstance().prepareFileForWrite(element.getContainingFile())) return; - final PsiIdentifier identifier = (PsiIdentifier)element; - final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(identifier, PsiDocCommentOwner.class); - if (commentOwner != null) { - final PsiElement psiElement = SuppressManager.getInstance().getElementMemberSuppressedIn(commentOwner, myID); - if (psiElement instanceof PsiAnnotation) { - removeFromAnnotation((PsiAnnotation)psiElement); - } else if (psiElement instanceof PsiDocComment) { - removeFromJavaDoc((PsiDocComment)psiElement); - } else { //try to remove from all comments - final Set<PsiComment> comments = new HashSet<PsiComment>(); - commentOwner.accept(new PsiRecursiveElementWalkingVisitor() { - @Override public void visitComment(final PsiComment comment) { - super.visitComment(comment); - if (comment.getText().contains(myID)) { - comments.add(comment); - } - } - }); - for (PsiComment comment : comments) { - try { - removeFromComment(comment, comments.size() > 1); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - } - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - @Override - @NotNull - public String getName() { - return QuickFixBundle.message("remove.suppression.action.name", myID); - } - - private void removeFromComment(final PsiComment comment, final boolean checkLine) throws IncorrectOperationException { - if (checkLine) { - final PsiStatement statement = PsiTreeUtil.getNextSiblingOfType(comment, PsiStatement.class); - if (statement != null && !Comparing.strEqual(statement.getText(), myProblemLine)) return; - } - String newText = removeFromElementText(comment); - if (newText != null) { - if (newText.length() == 0) { - comment.delete(); - } - else { - PsiComment newComment = JavaPsiFacade.getInstance(comment.getProject()).getElementFactory() - .createCommentFromText("// " + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME+" "+newText, comment); - comment.replace(newComment); - } - } - } - - private void removeFromJavaDoc(PsiDocComment docComment) throws IncorrectOperationException { - PsiDocTag tag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME); - if (tag == null) return; - String newText = removeFromElementText(tag.getDataElements()); - if (newText != null && newText.length() == 0) { - tag.delete(); - } - else if (newText != null) { - newText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + newText; - PsiDocTag newTag = JavaPsiFacade.getInstance(tag.getProject()).getElementFactory().createDocTagFromText(newText); - tag.replace(newTag); - } - } - - @Nullable - private String removeFromElementText(final PsiElement... elements) { - String text = ""; - for (PsiElement element : elements) { - text += StringUtil.trimStart(element.getText(), "//").trim(); - } - text = StringUtil.trimStart(text, "@").trim(); - text = StringUtil.trimStart(text, SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME).trim(); - List<String> ids = StringUtil.split(text, ","); - int i = ArrayUtil.find(ids.toArray(), myID); - if (i==-1) return null; - ids.remove(i); - return StringUtil.join(ids, ","); - } - - private void removeFromAnnotation(final PsiAnnotation annotation) throws IncorrectOperationException { - PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); - for (PsiNameValuePair attribute : attributes) { - PsiAnnotationMemberValue value = attribute.getValue(); - if (value instanceof PsiArrayInitializerMemberValue) { - PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers(); - for (PsiAnnotationMemberValue initializer : initializers) { - if (removeFromValue(annotation, initializer, initializers.length==1)) return; - } - } - if (removeFromValue(annotation, value, attributes.length==1)) return; - } - } - - private boolean removeFromValue(final PsiAnnotationMemberValue parent, final PsiAnnotationMemberValue value, final boolean removeParent) throws IncorrectOperationException { - String text = value.getText(); - text = StringUtil.trimStart(text, "\""); - text = StringUtil.trimEnd(text, "\""); - if (myID.equals(text)) { - if (removeParent) { - parent.delete(); - } - else { - value.delete(); - } - return true; - } - return false; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index b1cbfe05c3b2..6c9723698a8d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -27,6 +27,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.patterns.ElementPattern; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.PsiClassReferenceType; @@ -295,7 +296,7 @@ public class AnnotationsHighlightUtil { ); @Nullable - public static HighlightInfo checkApplicability(@NotNull PsiAnnotation annotation) { + public static HighlightInfo checkApplicability(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) { return null; } @@ -311,7 +312,7 @@ public class AnnotationsHighlightUtil { } if (!(owner instanceof PsiModifierList)) { - HighlightInfo info = HighlightUtil.checkTypeAnnotationFeature(annotation); + HighlightInfo info = HighlightUtil.checkTypeAnnotationFeature(annotation, languageLevel,containingFile); if (info != null) return info; } @@ -465,23 +466,23 @@ public class AnnotationsHighlightUtil { LOG.assertTrue(aClass.isAnnotationType()); PsiType type = typeElement.getType(); final Set<PsiClass> checked = new HashSet<PsiClass>(); - if (cyclicDependencies(aClass, type, checked)) { + if (cyclicDependencies(aClass, type, checked, aClass.getManager())) { String description = JavaErrorMessages.message("annotation.cyclic.element.type"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create(); } return null; } - private static boolean cyclicDependencies(PsiClass aClass, PsiType type, Set<PsiClass> checked) { + private static boolean cyclicDependencies(PsiClass aClass, PsiType type, @NotNull Set<PsiClass> checked,@NotNull PsiManager manager) { final PsiClass resolvedClass = PsiUtil.resolveClassInType(type); if (resolvedClass != null && resolvedClass.isAnnotationType()) { if (aClass == resolvedClass) { return true; } - if (!checked.add(resolvedClass) || !resolvedClass.getManager().isInProject(resolvedClass)) return false; + if (!checked.add(resolvedClass) || !manager.isInProject(resolvedClass)) return false; final PsiMethod[] methods = resolvedClass.getMethods(); for (PsiMethod method : methods) { - if (cyclicDependencies(aClass, method.getReturnType(), checked)) return true; + if (cyclicDependencies(aClass, method.getReturnType(), checked,manager)) return true; } } return false; @@ -572,10 +573,10 @@ public class AnnotationsHighlightUtil { } @Nullable - public static HighlightInfo checkFunctionalInterface(PsiAnnotation annotation) { - final String errorMessage = LambdaUtil.checkFunctionalInterface(annotation); + public static HighlightInfo checkFunctionalInterface(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel) { + final String errorMessage = LambdaUtil.checkFunctionalInterface(annotation, languageLevel); if (errorMessage != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(errorMessage).create(); + return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(annotation).descriptionAndTooltip(errorMessage).create(); } return null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 48e10ee31035..55990a6ffd0f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -68,7 +68,7 @@ public class GenericsHighlightUtil { for (PsiClassType type : extendsTypes) { PsiType extendsType = substitutor.substitute(type); if (substituted instanceof PsiWildcardType) { - if (!((PsiWildcardType)substituted).isExtends()) { + if (((PsiWildcardType)substituted).isSuper()) { continue; } final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound(); @@ -110,17 +110,19 @@ public class GenericsHighlightUtil { @Nullable public static HighlightInfo checkParameterizedReferenceTypeArguments(final PsiElement resolved, final PsiJavaCodeReferenceElement referenceElement, - final PsiSubstitutor substitutor) { + final PsiSubstitutor substitutor, + @NotNull JavaSdkVersion javaSdkVersion) { if (!(resolved instanceof PsiTypeParameterListOwner)) return null; final PsiTypeParameterListOwner typeParameterListOwner = (PsiTypeParameterListOwner)resolved; - return checkReferenceTypeArgumentList(typeParameterListOwner, referenceElement.getParameterList(), substitutor, true); + return checkReferenceTypeArgumentList(typeParameterListOwner, referenceElement.getParameterList(), substitutor, true, javaSdkVersion); } @Nullable public static HighlightInfo checkReferenceTypeArgumentList(final PsiTypeParameterListOwner typeParameterListOwner, final PsiReferenceParameterList referenceParameterList, final PsiSubstitutor substitutor, - boolean registerIntentions) { + boolean registerIntentions, + @NotNull JavaSdkVersion javaSdkVersion) { PsiDiamondType.DiamondInferenceResult inferenceResult = null; PsiTypeElement[] referenceElements = null; if (referenceParameterList != null) { @@ -150,7 +152,7 @@ public class GenericsHighlightUtil { if (targetParametersNum == 0) { if (PsiTreeUtil.getParentOfType(referenceParameterList, PsiCall.class) != null && typeParameterListOwner instanceof PsiMethod && - JavaVersionService.getInstance().isAtLeast(referenceParameterList, JavaSdkVersion.JDK_1_7)) { + javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7)) { description = null; } else { @@ -388,7 +390,8 @@ public class GenericsHighlightUtil { public static HighlightInfo checkElementInTypeParameterExtendsList(@NotNull PsiReferenceList referenceList, @NotNull PsiClass aClass, @NotNull JavaResolveResult resolveResult, - @NotNull PsiElement element) { + @NotNull PsiElement element, + @NotNull LanguageLevel languageLevel) { final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements(); PsiClass extendFrom = (PsiClass)resolveResult.getElement(); if (extendFrom == null) return null; @@ -408,7 +411,7 @@ public class GenericsHighlightUtil { IntentionAction fix = QUICK_FIX_FACTORY.createExtendsListFix(aClass, type, false); QuickFixAction.registerQuickFixAction(errorResult, fix, null); } - if (errorResult == null && JavaVersionService.getInstance().isAtLeast(referenceList, JavaSdkVersion.JDK_1_7) && + if (errorResult == null && languageLevel.isAtLeast(LanguageLevel.JDK_1_7) && referenceElements.length > 1) { //todo suppress erased methods which come from the same class return checkOverrideEquivalentMethods(aClass); @@ -736,7 +739,7 @@ public class GenericsHighlightUtil { //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 @Nullable - public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(PsiReferenceExpression expr, JavaResolveResult result) { + public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(@NotNull PsiReferenceExpression expr, @NotNull JavaResolveResult result) { final PsiElement resolved = result.getElement(); if (!(resolved instanceof PsiField)) return null; @@ -806,10 +809,10 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkTypeParametersList(PsiTypeParameterList parameterList) { + public static HighlightInfo checkTypeParametersList(PsiTypeParameterList parameterList, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { PsiTypeParameter[] typeParameters = parameterList.getTypeParameters(); if (typeParameters.length == 0) return null; - HighlightInfo info = HighlightUtil.checkGenericsFeature(parameterList, typeParameters.length); + HighlightInfo info = HighlightUtil.checkGenericsFeature(parameterList, typeParameters.length, languageLevel, containingFile); if (info != null) return info; final PsiElement parent = parameterList.getParent(); @@ -839,7 +842,7 @@ public class GenericsHighlightUtil { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeParameter2).descriptionAndTooltip(message).create(); } } - if (!JavaVersionService.getInstance().isAtLeast(parameterList, JavaSdkVersion.JDK_1_7)) { + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) { for (PsiJavaCodeReferenceElement referenceElement : typeParameter1.getExtendsList().getReferenceElements()) { final PsiElement resolve = referenceElement.resolve(); if (resolve instanceof PsiTypeParameter && ArrayUtilRt.find(typeParameters, resolve) > i) { @@ -941,7 +944,7 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkOverrideAnnotation(PsiMethod method) { + public static HighlightInfo checkOverrideAnnotation(PsiMethod method, final LanguageLevel languageLevel) { PsiModifierList list = method.getModifierList(); final PsiAnnotation overrideAnnotation = list.findAnnotation("java.lang.Override"); if (overrideAnnotation == null) { @@ -962,7 +965,6 @@ public class GenericsHighlightUtil { PullAsAbstractUpFix.registerQuickFix(highlightInfo, method); return highlightInfo; } - LanguageLevel languageLevel = PsiUtil.getLanguageLevel(method); PsiClass superClass = superMethod.getMethod().getContainingClass(); if (languageLevel.equals(LanguageLevel.JDK_1_5) && superClass != null && @@ -1023,7 +1025,9 @@ public class GenericsHighlightUtil { } } - static void checkEnumConstantForConstructorProblems(PsiEnumConstant enumConstant, final HighlightInfoHolder holder) { + static void checkEnumConstantForConstructorProblems(PsiEnumConstant enumConstant, + final HighlightInfoHolder holder, + @NotNull JavaSdkVersion javaSdkVersion) { PsiClass containingClass = enumConstant.getContainingClass(); if (enumConstant.getInitializingClass() == null) { HighlightInfo highlightInfo = HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier()); @@ -1040,7 +1044,7 @@ public class GenericsHighlightUtil { } PsiClassType type = JavaPsiFacade.getInstance(holder.getProject()).getElementFactory().createType(containingClass); - HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder); + HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion); } @Nullable @@ -1061,12 +1065,12 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkVarArgParameterIsLast(PsiParameter parameter) { + public static HighlightInfo checkVarArgParameterIsLast(@NotNull PsiParameter parameter, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { PsiElement declarationScope = parameter.getDeclarationScope(); if (declarationScope instanceof PsiMethod) { PsiParameter[] params = ((PsiMethod)declarationScope).getParameterList().getParameters(); if (parameter.isVarArgs()) { - HighlightInfo info = HighlightUtil.checkVarargFeature(parameter); + HighlightInfo info = HighlightUtil.checkVarargFeature(parameter, languageLevel,containingFile); if (info != null) return info; if (params[params.length - 1] != parameter) { @@ -1097,8 +1101,9 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) { - HighlightInfo info = HighlightUtil.checkGenericsFeature(refParamList, refParamList.getTypeParameterElements().length); + public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + HighlightInfo info = HighlightUtil.checkGenericsFeature(refParamList, refParamList.getTypeParameterElements().length, + languageLevel, containingFile); if (info != null) return info; if (refParamList.getTextLength() != 0) { @@ -1148,7 +1153,7 @@ public class GenericsHighlightUtil { if (qualifier instanceof PsiReferenceExpression){ final PsiClass typeParameter = PsiUtil.resolveClassInType(((PsiReferenceExpression)qualifier).getType()); if (typeParameter instanceof PsiTypeParameter) { - if (JavaVersionService.getInstance().isAtLeast(element, JavaSdkVersion.JDK_1_7)) return null; + if (JavaVersionService.getInstance().isAtLeast(containingClass, JavaSdkVersion.JDK_1_7)) return null; for (PsiClassType classType : typeParameter.getExtendsListTypes()) { final PsiClass resolve = classType.resolve(); if (resolve != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index ae32b61b8e45..449df8e09b16 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -377,7 +377,7 @@ public class HighlightClassUtil { .parent(PsiMatchers.hasClass(PsiModifierList.class)) .parent(PsiMatchers.hasClass(parentClass)) .parent(PsiMatchers.hasClass(PsiClass.class)) - .dot(PsiMatchers.hasModifier(PsiModifier.STATIC, false)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, false)) .parent(PsiMatchers.hasClass(PsiClass.class, PsiDeclarationStatement.class, PsiNewExpression.class, PsiEnumConstant.class)) .getElement(); } @@ -387,9 +387,9 @@ public class HighlightClassUtil { // keyword points to 'class' or 'interface' or 'enum' if (new PsiMatcherImpl(keyword) .parent(PsiMatchers.hasClass(PsiClass.class)) - .dot(PsiMatchers.hasModifier(PsiModifier.STATIC, true)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, true)) .parent(PsiMatchers.hasClass(PsiClass.class)) - .dot(PsiMatchers.hasModifier(PsiModifier.STATIC, false)) + .dot(JavaMatchers.hasModifier(PsiModifier.STATIC, false)) .parent(PsiMatchers.hasClass(PsiClass.class, PsiDeclarationStatement.class, PsiNewExpression.class, PsiEnumConstant.class)) .getElement() == null) { return null; @@ -626,7 +626,7 @@ public class HighlightClassUtil { } @Nullable - public static HighlightInfo checkExtendsDuplicate(PsiJavaCodeReferenceElement element, PsiElement resolved) { + public static HighlightInfo checkExtendsDuplicate(PsiJavaCodeReferenceElement element, PsiElement resolved, @NotNull PsiFile containingFile) { if (!(element.getParent() instanceof PsiReferenceList)) return null; PsiReferenceList list = (PsiReferenceList)element.getParent(); if (!(list.getParent() instanceof PsiClass)) return null; @@ -634,9 +634,10 @@ public class HighlightClassUtil { PsiClass aClass = (PsiClass)resolved; PsiClassType[] referencedTypes = list.getReferencedTypes(); int dupCount = 0; + PsiManager manager = containingFile.getManager(); for (PsiClassType referencedType : referencedTypes) { PsiClass resolvedElement = referencedType.resolve(); - if (resolvedElement != null && list.getManager().areElementsEquivalent(resolvedElement, aClass)) { + if (resolvedElement != null && manager.areElementsEquivalent(resolvedElement, aClass)) { dupCount++; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 5a0f156c5bbd..f74f6f9d6214 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -29,8 +29,6 @@ import com.intellij.psi.controlFlow.*; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiMatcherImpl; -import com.intellij.psi.util.PsiMatchers; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; @@ -141,7 +139,7 @@ public class HighlightControlFlowUtil { for (PsiMethod constructor : constructors) { PsiCodeBlock ctrBody = constructor.getBody(); if (ctrBody == null) return false; - final List<PsiMethod> redirectedConstructors = getChainedConstructors(constructor); + final List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); final PsiCodeBlock body = redirectedConstructor.getBody(); @@ -170,21 +168,9 @@ public class HighlightControlFlowUtil { return false; } - /** - * return all constructors which are referred from this constructor by - * this (...) at the beginning of the constructor body - * @return referring constructor - */ - @Nullable public static List<PsiMethod> getChainedConstructors(PsiMethod constructor) { - final ConstructorVisitorInfo info = new ConstructorVisitorInfo(); - visitConstructorChain(constructor, info); - if (info.visitedConstructors != null) info.visitedConstructors.remove(constructor); - return info.visitedConstructors; - } - public static boolean isRecursivelyCalledConstructor(PsiMethod constructor) { - final ConstructorVisitorInfo info = new ConstructorVisitorInfo(); - visitConstructorChain(constructor, info); + final JavaHighlightUtil.ConstructorVisitorInfo info = new JavaHighlightUtil.ConstructorVisitorInfo(); + JavaHighlightUtil.visitConstructorChain(constructor, info); if (info.recursivelyCalledConstructor == null) return false; // our constructor is reached from some other constructor by constructor chain return info.visitedConstructors.indexOf(info.recursivelyCalledConstructor) <= @@ -214,42 +200,6 @@ public class HighlightControlFlowUtil { } } - private static class ConstructorVisitorInfo { - List<PsiMethod> visitedConstructors; - PsiMethod recursivelyCalledConstructor; - } - - private static void visitConstructorChain(PsiMethod constructor, ConstructorVisitorInfo info) { - while (true) { - if (constructor == null) return; - final PsiCodeBlock body = constructor.getBody(); - if (body == null) return; - final PsiStatement[] statements = body.getStatements(); - if (statements.length == 0) return; - final PsiStatement statement = statements[0]; - final PsiElement element = new PsiMatcherImpl(statement) - .dot(PsiMatchers.hasClass(PsiExpressionStatement.class)) - .firstChild(PsiMatchers.hasClass(PsiMethodCallExpression.class)) - .firstChild(PsiMatchers.hasClass(PsiReferenceExpression.class)) - .firstChild(PsiMatchers.hasClass(PsiKeyword.class)) - .dot(PsiMatchers.hasText(PsiKeyword.THIS)) - .parent(null) - .parent(null) - .getElement(); - if (element == null) return; - PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element; - PsiMethod method = methodCall.resolveMethod(); - if (method == null) return; - if (info.visitedConstructors != null && info.visitedConstructors.contains(method)) { - info.recursivelyCalledConstructor = method; - return; - } - if (info.visitedConstructors == null) info.visitedConstructors = new ArrayList<PsiMethod>(5); - info.visitedConstructors.add(method); - constructor = method; - } - } - /** * see JLS chapter 16 * @return true if variable assigned (maybe more than once) @@ -298,7 +248,7 @@ public class HighlightControlFlowUtil { @Nullable public static HighlightInfo checkVariableInitializedBeforeUsage(PsiReferenceExpression expression, PsiVariable variable, - Map<PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems) { + Map<PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems, @NotNull PsiFile containingFile) { if (variable instanceof ImplicitVariable) return null; if (!PsiUtil.isAccessedForReading(expression)) return null; final int startOffset = expression.getTextRange().getStartOffset(); @@ -326,18 +276,18 @@ public class HighlightControlFlowUtil { return null; } // access to final fields from inner classes always allowed - if (inInnerClass(expression, ((PsiField)variable).getContainingClass())) return null; + if (inInnerClass(expression, ((PsiField)variable).getContainingClass(),containingFile)) return null; if (topBlock == null) return null; final PsiElement parent = topBlock.getParent(); final PsiCodeBlock block; final PsiClass aClass; if (parent instanceof PsiMethod) { PsiMethod constructor = (PsiMethod)parent; - if (!parent.getManager().areElementsEquivalent(constructor.getContainingClass(), ((PsiField)variable).getContainingClass())) return null; + if (!containingFile.getManager().areElementsEquivalent(constructor.getContainingClass(), ((PsiField)variable).getContainingClass())) return null; // static variables already initialized in class initializers if (variable.hasModifierProperty(PsiModifier.STATIC)) return null; // as a last chance, field may be initialized in this() call - final List<PsiMethod> redirectedConstructors = getChainedConstructors(constructor); + final List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); // variable must be initialized before its usage @@ -353,7 +303,7 @@ public class HighlightControlFlowUtil { } else if (parent instanceof PsiClassInitializer) { final PsiClassInitializer classInitializer = (PsiClassInitializer)parent; - if (!parent.getManager().areElementsEquivalent(classInitializer.getContainingClass(), ((PsiField)variable).getContainingClass())) return null; + if (!containingFile.getManager().areElementsEquivalent(classInitializer.getContainingClass(), ((PsiField)variable).getContainingClass())) return null; block = classInitializer.getBody(); aClass = classInitializer.getContainingClass(); } @@ -377,7 +327,7 @@ public class HighlightControlFlowUtil { return null; } // as a last chance, field may be initialized in this() call - final List<PsiMethod> redirectedConstructors = getChainedConstructors(constructor); + final List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); // variable must be initialized before its usage @@ -435,9 +385,9 @@ public class HighlightControlFlowUtil { return null; } - private static boolean inInnerClass(PsiElement element, PsiClass containingClass) { + private static boolean inInnerClass(PsiElement element, PsiClass containingClass, @NotNull PsiFile containingFile) { while (element != null) { - if (element instanceof PsiClass) return !element.getManager().areElementsEquivalent(element, containingClass); + if (element instanceof PsiClass) return !containingFile.getManager().areElementsEquivalent(element, containingClass); element = element.getParent(); } return false; @@ -536,7 +486,7 @@ public class HighlightControlFlowUtil { final PsiMethod ctr = codeBlock.getParent() instanceof PsiMethod ? (PsiMethod)codeBlock.getParent() : null; // assignment to final field in several constructors threatens us only if these are linked (there is this() call in the beginning) - final List<PsiMethod> redirectedConstructors = ctr != null && ctr.isConstructor() ? getChainedConstructors(ctr) : null; + final List<PsiMethod> redirectedConstructors = ctr != null && ctr.isConstructor() ? JavaHighlightUtil.getChainedConstructors(ctr) : null; for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); if (redirectedConstructor.getBody() != null && @@ -593,7 +543,7 @@ public class HighlightControlFlowUtil { @Nullable - public static HighlightInfo checkCannotWriteToFinal(PsiExpression expression) { + public static HighlightInfo checkCannotWriteToFinal(PsiExpression expression, @NotNull PsiFile containingFile) { PsiReferenceExpression reference = null; if (expression instanceof PsiAssignmentExpression) { final PsiExpression left = ((PsiAssignmentExpression)expression).getLExpression(); @@ -618,7 +568,7 @@ public class HighlightControlFlowUtil { final PsiElement resolved = reference == null ? null : reference.resolve(); PsiVariable variable = resolved instanceof PsiVariable ? (PsiVariable)resolved : null; if (variable == null || !variable.hasModifierProperty(PsiModifier.FINAL)) return null; - if (!canWriteToFinal(variable, expression, reference)) { + if (!canWriteToFinal(variable, expression, reference,containingFile)) { final String name = variable.getName(); String description = JavaErrorMessages.message("assignment.to.final.variable", name); final HighlightInfo highlightInfo = @@ -637,7 +587,7 @@ public class HighlightControlFlowUtil { return null; } - private static boolean canWriteToFinal(PsiVariable variable, PsiExpression expression, final PsiReferenceExpression reference) { + private static boolean canWriteToFinal(PsiVariable variable, PsiExpression expression, final PsiReferenceExpression reference, @NotNull PsiFile containingFile) { if (variable.hasInitializer()) return false; if (variable instanceof PsiParameter) return false; PsiClass innerClass = getInnerClassVariableReferencedFrom(variable, expression); @@ -646,9 +596,9 @@ public class HighlightControlFlowUtil { if (HighlightUtil.findEnclosingFieldInitializer(expression) != null) return true; // assignment from within inner class is illegal always PsiField field = (PsiField)variable; - if (innerClass != null && !innerClass.getManager().areElementsEquivalent(innerClass, field.getContainingClass())) return false; + if (innerClass != null && !containingFile.getManager().areElementsEquivalent(innerClass, field.getContainingClass())) return false; final PsiMember enclosingCtrOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression); - return enclosingCtrOrInitializer != null && isSameField(variable, enclosingCtrOrInitializer, field, reference); + return enclosingCtrOrInitializer != null && isSameField(variable, enclosingCtrOrInitializer, field, reference,containingFile); } if (variable instanceof PsiLocalVariable) { boolean isAccessedFromOtherClass = innerClass != null; @@ -662,16 +612,18 @@ public class HighlightControlFlowUtil { private static boolean isSameField(final PsiVariable variable, final PsiMember enclosingCtrOrInitializer, final PsiField field, - final PsiReferenceExpression reference) { + final PsiReferenceExpression reference, @NotNull PsiFile containingFile) { - if (!variable.getManager().areElementsEquivalent(enclosingCtrOrInitializer.getContainingClass(), field.getContainingClass())) return false; + if (!containingFile.getManager().areElementsEquivalent(enclosingCtrOrInitializer.getContainingClass(), field.getContainingClass())) return false; PsiExpression qualifierExpression = reference.getQualifierExpression(); return qualifierExpression == null || qualifierExpression instanceof PsiThisExpression; } @Nullable - static HighlightInfo checkVariableMustBeFinal(PsiVariable variable, PsiJavaCodeReferenceElement context) { + static HighlightInfo checkVariableMustBeFinal(PsiVariable variable, + PsiJavaCodeReferenceElement context, + @NotNull LanguageLevel languageLevel) { if (variable.hasModifierProperty(PsiModifier.FINAL)) return null; final PsiClass innerClass = getInnerClassVariableReferencedFrom(variable, context); if (innerClass != null) { @@ -682,8 +634,7 @@ public class HighlightControlFlowUtil { return null; } } - if (PsiUtil.getLanguageLevel(variable).isAtLeast(LanguageLevel.JDK_1_8) && - isEffectivelyFinal(variable, innerClass, context)) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && isEffectivelyFinal(variable, innerClass, context)) { return null; } final String description = JavaErrorMessages.message("variable.must.be.final", context.getText()); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 2d1a4db5ff7d..96319603fc1e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -26,9 +26,11 @@ import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.codeInspection.LocalQuickFixOnPsiElementAsIntentionAdapter; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; @@ -312,7 +314,10 @@ public class HighlightMethodUtil { } @Nullable - static HighlightInfo checkMethodCall(PsiMethodCallExpression methodCall, PsiResolveHelper resolveHelper) { + static HighlightInfo checkMethodCall(@NotNull PsiMethodCallExpression methodCall, + @NotNull PsiResolveHelper resolveHelper, + @NotNull LanguageLevel languageLevel, + @NotNull JavaSdkVersion javaSdkVersion) { PsiExpressionList list = methodCall.getArgumentList(); PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression(); JavaResolveResult[] results = referenceToMethod.multiResolve(true); @@ -327,7 +332,7 @@ public class HighlightMethodUtil { if (resolved instanceof PsiMethod && resolveResult.isValidResult()) { TextRange fixRange = getFixRange(methodCall); highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); - if (highlightInfo == null && !LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)resolved, methodCall.getMethodExpression())) { + if (highlightInfo == null && !LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)resolved, methodCall.getMethodExpression(), languageLevel)) { highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Static method may be invoked on containing interface class only").range(fixRange).create(); } } @@ -364,7 +369,7 @@ public class HighlightMethodUtil { highlightInfo = GenericsHighlightUtil.checkInferredTypeArguments(resolvedMethod, methodCall, substitutor); } else { - highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, substitutor); + highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, methodExpression, substitutor, javaSdkVersion); } } } @@ -384,7 +389,8 @@ public class HighlightMethodUtil { } } if (highlightInfo == null) { - highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor); + highlightInfo = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor, + javaSdkVersion); } return highlightInfo; } @@ -860,7 +866,7 @@ public class HighlightMethodUtil { } @Nullable - static HighlightInfo checkMethodCanHaveBody(PsiMethod method) { + static HighlightInfo checkMethodCanHaveBody(PsiMethod method, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { PsiClass aClass = method.getContainingClass(); boolean hasNoBody = method.getBody() == null; boolean isInterface = aClass != null && aClass.isInterface(); @@ -887,7 +893,7 @@ public class HighlightMethodUtil { } } else if (isExtension) { - return HighlightUtil.checkExtensionMethodsFeature(method); + return HighlightUtil.checkExtensionMethodsFeature(method, languageLevel,containingFile); } } else if (isExtension) { @@ -983,7 +989,7 @@ public class HighlightMethodUtil { * @return error if static method overrides instance method or * instance method overrides static. see JLS 8.4.6.1, 8.4.6.2 */ - static HighlightInfo checkStaticMethodOverride(PsiMethod method) { + static HighlightInfo checkStaticMethodOverride(@NotNull PsiMethod method,@NotNull PsiFile containingFile) { // constructors are not members and therefor don't override class methods if (method.isConstructor()) { return null; @@ -997,7 +1003,7 @@ public class HighlightMethodUtil { : MethodSignatureUtil.findMethodBySignature(superClass, method, true); boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); - HighlightInfo highlightInfo = checkStaticMethodOverride(aClass, method, isStatic,superClass, superMethod); + HighlightInfo highlightInfo = checkStaticMethodOverride(aClass, method, isStatic,superClass, superMethod,containingFile); if (highlightInfo != null) return highlightInfo; if (!isStatic) { // all methods in interface are instance, so no possible errors in this case @@ -1007,15 +1013,15 @@ public class HighlightMethodUtil { for (PsiClass aInterfaces : interfaces) { superClass = aInterfaces; superMethod = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(aClass, superClass, method.getSignature(PsiSubstitutor.EMPTY), true); - highlightInfo = checkStaticMethodOverride(aClass, method, true, superClass, superMethod); + highlightInfo = checkStaticMethodOverride(aClass, method, true, superClass, superMethod,containingFile); if (highlightInfo != null) return highlightInfo; } return null; } - private static HighlightInfo checkStaticMethodOverride(PsiClass aClass, PsiMethod method, boolean isMethodStatic, PsiClass superClass, PsiMethod superMethod) { + private static HighlightInfo checkStaticMethodOverride(PsiClass aClass, PsiMethod method, boolean isMethodStatic, PsiClass superClass, PsiMethod superMethod,@NotNull PsiFile containingFile) { if (superMethod == null) return null; - PsiManager manager = superMethod.getManager(); + PsiManager manager = containingFile.getManager(); PsiModifierList superModifierList = superMethod.getModifierList(); PsiModifierList modifierList = method.getModifierList(); if (superModifierList.hasModifierProperty(PsiModifier.PRIVATE)) return null; @@ -1208,7 +1214,7 @@ public class HighlightMethodUtil { } - static void checkNewExpression(@NotNull PsiNewExpression expression, @NotNull HighlightInfoHolder holder) { + static void checkNewExpression(@NotNull PsiNewExpression expression, @NotNull HighlightInfoHolder holder, @NotNull JavaSdkVersion javaSdkVersion) { PsiType type = expression.getType(); if (!(type instanceof PsiClassType)) return; PsiClassType.ClassResolveResult typeResult = ((PsiClassType)type).resolveGenerics(); @@ -1222,15 +1228,16 @@ public class HighlightMethodUtil { } PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); - checkConstructorCall(typeResult, expression, type, classReference, holder); + checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion); } public static void checkConstructorCall(PsiClassType.ClassResolveResult typeResolveResult, - PsiConstructorCall constructorCall, - PsiType type, - PsiJavaCodeReferenceElement classReference, - final HighlightInfoHolder holder) { + PsiConstructorCall constructorCall, + PsiType type, + PsiJavaCodeReferenceElement classReference, + final HighlightInfoHolder holder, + @NotNull JavaSdkVersion javaSdkVersion) { PsiExpressionList list = constructorCall.getArgumentList(); if (list == null) return; PsiClass aClass = typeResolveResult.getElement(); @@ -1343,12 +1350,10 @@ public class HighlightMethodUtil { } else { if (constructorCall instanceof PsiNewExpression) { - HighlightInfo highlightInfo = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, - ((PsiNewExpression)constructorCall) - .getTypeArgumentList(), - result.getSubstitutor(), false); - if (highlightInfo != null) { - holder.add(highlightInfo); + PsiReferenceParameterList typeArgumentList = ((PsiNewExpression)constructorCall).getTypeArgumentList(); + HighlightInfo info = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, typeArgumentList, result.getSubstitutor(), false, javaSdkVersion); + if (info != null) { + holder.add(info); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightNamesUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightNamesUtil.java index dc8aaa969930..a8c041e4e829 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightNamesUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightNamesUtil.java @@ -28,6 +28,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.colors.TextAttributesScheme; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -51,14 +52,14 @@ public class HighlightNamesUtil { public static HighlightInfo highlightMethodName(@NotNull PsiMethod method, final PsiElement elementToHighlight, final boolean isDeclaration, - @NotNull EditorColorsScheme colorsScheme) { + @NotNull TextAttributesScheme colorsScheme) { return highlightMethodName(method, elementToHighlight, elementToHighlight.getTextRange(), colorsScheme, isDeclaration); } @Nullable public static HighlightInfo highlightMethodName(@NotNull PsiMethod method, final PsiElement elementToHighlight, - TextRange range, @NotNull EditorColorsScheme colorsScheme, final boolean isDeclaration) { + TextRange range, @NotNull TextAttributesScheme colorsScheme, final boolean isDeclaration) { boolean isInherited = false; if (!isDeclaration) { @@ -93,7 +94,7 @@ public class HighlightNamesUtil { private static TextAttributes mergeWithScopeAttributes(final PsiElement element, @NotNull HighlightInfoType type, - @NotNull EditorColorsScheme colorsScheme) { + @NotNull TextAttributesScheme colorsScheme) { TextAttributes regularAttributes = HighlightInfo.getAttributesByType(element, type, colorsScheme); if (element == null) return regularAttributes; TextAttributes scopeAttributes = getScopeAttributes(element, colorsScheme); @@ -101,7 +102,7 @@ public class HighlightNamesUtil { } @Nullable - public static HighlightInfo highlightClassName(PsiClass aClass, PsiElement elementToHighlight, @NotNull EditorColorsScheme colorsScheme) { + public static HighlightInfo highlightClassName(PsiClass aClass, PsiElement elementToHighlight, @NotNull TextAttributesScheme colorsScheme) { HighlightInfoType type = getClassNameHighlightType(aClass, elementToHighlight); if (elementToHighlight != null) { TextAttributes attributes = mergeWithScopeAttributes(aClass, type, colorsScheme); @@ -136,7 +137,7 @@ public class HighlightNamesUtil { @Nullable public static HighlightInfo highlightVariableName(final PsiVariable variable, final PsiElement elementToHighlight, - @NotNull EditorColorsScheme colorsScheme) { + @NotNull TextAttributesScheme colorsScheme) { HighlightInfoType varType = getVariableNameHighlightType(variable); if (varType != null) { if (variable instanceof PsiField) { @@ -154,7 +155,7 @@ public class HighlightNamesUtil { @Nullable public static HighlightInfo highlightClassNameInQualifier(final PsiJavaCodeReferenceElement element, - @NotNull EditorColorsScheme colorsScheme) { + @NotNull TextAttributesScheme colorsScheme) { PsiExpression qualifierExpression = null; if (element instanceof PsiReferenceExpression) { qualifierExpression = ((PsiReferenceExpression)element).getQualifierExpression(); @@ -228,7 +229,7 @@ public class HighlightNamesUtil { return null; } - private static TextAttributes getScopeAttributes(@NotNull PsiElement element, @NotNull EditorColorsScheme colorsScheme) { + private static TextAttributes getScopeAttributes(@NotNull PsiElement element, @NotNull TextAttributesScheme colorsScheme) { PsiFile file = element.getContainingFile(); if (file == null) return null; TextAttributes result = null; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index e7b3d6b4bbc9..3181bed81402 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -34,7 +34,6 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; -import com.intellij.openapi.projectRoots.JavaVersionService; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; @@ -46,7 +45,9 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; +import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl; +import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.jsp.JspFile; import com.intellij.psi.scope.processor.VariablesNotProcessor; @@ -336,7 +337,7 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable - static HighlightInfo checkAssignmentOperatorApplicable(@NotNull PsiAssignmentExpression assignment) { + static HighlightInfo checkAssignmentOperatorApplicable(@NotNull PsiAssignmentExpression assignment,@NotNull PsiFile containingFile) { PsiJavaToken operationSign = assignment.getOperationSign(); IElementType eqOpSign = operationSign.getTokenType(); IElementType opSign = TypeConversionUtil.convertEQtoOperation(eqOpSign); @@ -347,7 +348,7 @@ public class HighlightUtil extends HighlightUtilBase { final PsiType rType = rExpression.getType(); HighlightInfo errorResult = null; if (!TypeConversionUtil.isBinaryOperatorApplicable(opSign, lType, rType, true) || - PsiType.getJavaLangObject(assignment.getManager(), assignment.getResolveScope()).equals(lType)) { + PsiType.getJavaLangObject(containingFile.getManager(), assignment.getResolveScope()).equals(lType)) { String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1); String message = JavaErrorMessages.message("binary.operator.not.applicable", operatorText, JavaHighlightUtil.formatType(lType), @@ -621,6 +622,22 @@ public class HighlightUtil extends HighlightUtilBase { return null; } + @Nullable + public static HighlightInfo checkUnderscore(@NotNull PsiIdentifier identifier, @NotNull PsiVariable variable) { + if ("_".equals(variable.getName()) && PsiUtil.isLanguageLevel8OrHigher(variable)) { + if (variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiLambdaExpression) { + String message = JavaErrorMessages.message("underscore.lambda.identifier"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(message).create(); + } + else { + String message = JavaErrorMessages.message("underscore.identifier"); + return HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(identifier).descriptionAndTooltip(message).create(); + } + } + + return null; + } + @NotNull public static String formatClass(@NotNull PsiClass aClass) { return formatClass(aClass, true); @@ -845,7 +862,8 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - public static HighlightInfo checkLiteralExpressionParsingError(@NotNull final PsiLiteralExpression expression) { + public static HighlightInfo checkLiteralExpressionParsingError(@NotNull final PsiLiteralExpression expression, + @NotNull LanguageLevel languageLevel, @NotNull PsiFile containingFile) { PsiElement literal = expression.getFirstChild(); assert literal instanceof PsiJavaToken : literal; IElementType type = ((PsiJavaToken)literal).getTokenType(); @@ -860,19 +878,19 @@ public class HighlightUtil extends HighlightUtilBase { if (isFP) { if (text.startsWith(PsiLiteralExpressionImpl.HEX_PREFIX)) { - final HighlightInfo info = checkFeature(expression, Feature.HEX_FP_LITERALS); + final HighlightInfo info = checkFeature(expression, Feature.HEX_FP_LITERALS, languageLevel, containingFile); if (info != null) return info; } } if (isInt) { if (text.startsWith(PsiLiteralExpressionImpl.BIN_PREFIX)) { - final HighlightInfo info = checkFeature(expression, Feature.BIN_LITERALS); + final HighlightInfo info = checkFeature(expression, Feature.BIN_LITERALS, languageLevel, containingFile); if (info != null) return info; } } if (isInt || isFP) { if (text.contains("_")) { - HighlightInfo info = checkFeature(expression, Feature.UNDERSCORES); + HighlightInfo info = checkFeature(expression, Feature.UNDERSCORES, languageLevel, containingFile); if (info != null) return info; info = checkUnderscores(expression, text, isInt); if (info != null) return info; @@ -1176,7 +1194,7 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable static Collection<HighlightInfo> checkWithImprovedCatchAnalysis(@NotNull final PsiParameter parameter, - @NotNull final Collection<PsiClassType> thrownInTryStatement) { + @NotNull final Collection<PsiClassType> thrownInTryStatement,@NotNull PsiFile containingFile) { final PsiElement scope = parameter.getDeclarationScope(); if (!(scope instanceof PsiCatchSection)) return null; @@ -1186,8 +1204,10 @@ public class HighlightUtil extends HighlightUtilBase { if (idx <= 0) return null; final Collection<PsiClassType> thrownTypes = ContainerUtil.newHashSet(thrownInTryStatement); - thrownTypes.add(PsiType.getJavaLangError(parameter.getManager(), parameter.getResolveScope())); - thrownTypes.add(PsiType.getJavaLangRuntimeException(parameter.getManager(), parameter.getResolveScope())); + PsiManager manager = containingFile.getManager(); + GlobalSearchScope parameterResolveScope = parameter.getResolveScope(); + thrownTypes.add(PsiType.getJavaLangError(manager, parameterResolveScope)); + thrownTypes.add(PsiType.getJavaLangRuntimeException(manager, parameterResolveScope)); final Collection<HighlightInfo> result = ContainerUtil.newArrayList(); final List<PsiTypeElement> parameterTypeElements = PsiUtil.getParameterTypeElements(parameter); @@ -1805,7 +1825,9 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - public static HighlightInfo checkMemberReferencedBeforeConstructorCalled(@NotNull PsiElement expression, PsiElement resolved) { + public static HighlightInfo checkMemberReferencedBeforeConstructorCalled(@NotNull PsiElement expression, + PsiElement resolved, + @NotNull PsiFile containingFile) { PsiClass referencedClass; @NonNls String resolvedName; PsiType type; @@ -1903,13 +1925,14 @@ public class HighlightUtil extends HighlightUtilBase { return null; } if (referencedClass == null) return null; - return checkReferenceToOurInstanceInsideThisOrSuper(expression, referencedClass, resolvedName); + return checkReferenceToOurInstanceInsideThisOrSuper(expression, referencedClass, resolvedName, containingFile); } @Nullable private static HighlightInfo checkReferenceToOurInstanceInsideThisOrSuper(@NotNull final PsiElement expression, @NotNull PsiClass referencedClass, - final String resolvedName) { + final String resolvedName, + @NotNull PsiFile containingFile) { if (PsiTreeUtil.getParentOfType(expression, PsiReferenceParameterList.class) != null) return null; PsiElement element = expression.getParent(); while (element != null) { @@ -1919,7 +1942,7 @@ public class HighlightUtil extends HighlightUtilBase { .parent(PsiMatchers.hasClass(PsiExpressionStatement.class)) .parent(PsiMatchers.hasClass(PsiCodeBlock.class)) .parent(PsiMatchers.hasClass(PsiMethod.class)) - .dot(PsiMatchers.isConstructor(true)) + .dot(JavaMatchers.isConstructor(true)) .parent(PsiMatchers.hasClass(PsiClass.class)) .getElement(); if (parentClass == null) { @@ -1958,7 +1981,16 @@ public class HighlightUtil extends HighlightUtilBase { } if (element instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)element).resolve(); + final PsiElement resolve; + if (element instanceof PsiReferenceExpressionImpl) { + PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)element; + JavaResolveResult[] results = JavaResolveUtil + .resolveWithContainingFile(referenceExpression, PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, false, containingFile); + resolve = results.length == 1 ? results[0].getElement() : null; + } + else { + resolve = ((PsiReferenceExpression)element).resolve(); + } if (resolve instanceof PsiField && ((PsiField)resolve).hasModifierProperty(PsiModifier.STATIC)) { return null; } @@ -1976,8 +2008,8 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - public static HighlightInfo checkImplicitThisReferenceBeforeSuper(@NotNull PsiClass aClass) { - if (JavaVersionService.getInstance().isAtLeast(aClass, JavaSdkVersion.JDK_1_7)) return null; + public static HighlightInfo checkImplicitThisReferenceBeforeSuper(@NotNull PsiClass aClass, @NotNull JavaSdkVersion javaSdkVersion) { + if (javaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7)) return null; if (aClass instanceof PsiAnonymousClass || aClass instanceof PsiTypeParameter) return null; PsiClass superClass = aClass.getSuperClass(); if (superClass == null || !PsiUtil.isInnerClass(superClass)) return null; @@ -2205,13 +2237,13 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable - public static HighlightInfo checkSynchronizedExpressionType(@NotNull PsiExpression expression, @Nullable PsiType type) { + public static HighlightInfo checkSynchronizedExpressionType(@NotNull PsiExpression expression, @Nullable PsiType type,@NotNull PsiFile containingFile) { if (type == null) return null; if (expression.getParent() instanceof PsiSynchronizedStatement) { PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)expression.getParent(); if (expression == synchronizedStatement.getLockExpression() && (type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type))) { - PsiClassType objectType = PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope()); + PsiClassType objectType = PsiType.getJavaLangObject(containingFile.getManager(), expression.getResolveScope()); return createIncompatibleTypeHighlightInfo(objectType, type, expression.getTextRange(), 0); } } @@ -2308,14 +2340,14 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable public static HighlightInfo checkSingleImportClassConflict(@NotNull PsiImportStatement statement, - @NotNull Map<String, Pair<PsiImportStaticReferenceElement, PsiClass>> importedClasses) { + @NotNull Map<String, Pair<PsiImportStaticReferenceElement, PsiClass>> importedClasses,@NotNull PsiFile containingFile) { if (statement.isOnDemand()) return null; PsiElement element = statement.resolve(); if (element instanceof PsiClass) { String name = ((PsiClass)element).getName(); Pair<PsiImportStaticReferenceElement, PsiClass> imported = importedClasses.get(name); PsiClass importedClass = imported == null ? null : imported.getSecond(); - if (importedClass != null && !element.getManager().areElementsEquivalent(importedClass, element)) { + if (importedClass != null && !containingFile.getManager().areElementsEquivalent(importedClass, element)) { String description = JavaErrorMessages.message("single.import.class.conflict", formatClass(importedClass)); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create(); } @@ -2378,13 +2410,16 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable - static HighlightInfo checkReference(@NotNull final PsiJavaCodeReferenceElement ref, @NotNull final JavaResolveResult result) { + static HighlightInfo checkReference(@NotNull final PsiJavaCodeReferenceElement ref, + @NotNull final JavaResolveResult result, + @NotNull PsiFile containingFile, + @NotNull LanguageLevel languageLevel) { final PsiElement refName = ref.getReferenceNameElement(); if (!(refName instanceof PsiIdentifier) && !(refName instanceof PsiKeyword)) return null; final PsiElement resolved = result.getElement(); - HighlightInfo highlightInfo = checkMemberReferencedBeforeConstructorCalled(ref, resolved); + HighlightInfo highlightInfo = checkMemberReferencedBeforeConstructorCalled(ref, resolved, containingFile); if (highlightInfo != null) return highlightInfo; PsiElement refParent = ref.getParent(); @@ -2454,7 +2489,8 @@ public class HighlightUtil extends HighlightUtilBase { } } if ((resolved instanceof PsiLocalVariable || resolved instanceof PsiParameter) && !(resolved instanceof ImplicitVariable)) { - highlightInfo = HighlightControlFlowUtil.checkVariableMustBeFinal((PsiVariable)resolved, ref); + highlightInfo = HighlightControlFlowUtil.checkVariableMustBeFinal((PsiVariable)resolved, ref, + languageLevel); } else if (resolved instanceof PsiClass) { if (Comparing.strEqual(((PsiClass)resolved).getQualifiedName(), ((PsiClass)resolved).getName())) { @@ -2508,7 +2544,8 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable static HighlightInfo checkElementInReferenceList(@NotNull PsiJavaCodeReferenceElement ref, @NotNull PsiReferenceList referenceList, - @NotNull JavaResolveResult resolveResult) { + @NotNull JavaResolveResult resolveResult, + @NotNull LanguageLevel languageLevel) { PsiElement resolved = resolveResult.getElement(); HighlightInfo highlightInfo = null; PsiElement refGrandParent = referenceList.getParent(); @@ -2516,7 +2553,7 @@ public class HighlightUtil extends HighlightUtilBase { PsiClass aClass = (PsiClass)resolved; if (refGrandParent instanceof PsiClass) { if (refGrandParent instanceof PsiTypeParameter) { - highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, (PsiClass)refGrandParent, resolveResult, ref); + highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, (PsiClass)refGrandParent, resolveResult, ref, languageLevel); } else { highlightInfo = HighlightClassUtil.checkExtendsClassAndImplementsInterface(referenceList, resolveResult, ref); @@ -2630,8 +2667,11 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - private static HighlightInfo checkFeature(@Nullable final PsiElement element, @NotNull final Feature feature) { - if (element != null && element.getManager().isInProject(element) && !PsiUtil.getLanguageLevel(element).isAtLeast(feature.level)) { + private static HighlightInfo checkFeature(@NotNull final PsiElement element, + @NotNull Feature feature, + @NotNull LanguageLevel languageLevel, + @NotNull PsiFile containingFile) { + if (containingFile.getManager().isInProject(containingFile) && !languageLevel.isAtLeast(feature.level)) { String message = JavaErrorMessages.message("insufficient.language.level", JavaErrorMessages.message(feature.key)); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create(); QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(feature.level)); @@ -2643,62 +2683,69 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - public static HighlightInfo checkGenericsFeature(PsiElement parameterList, int listSize) { - return listSize > 0 ? checkFeature(parameterList, Feature.GENERICS) : null; + public static HighlightInfo checkGenericsFeature(@NotNull PsiElement parameterList, + int listSize, + @NotNull LanguageLevel languageLevel, + @NotNull PsiFile containingFile) { + return listSize > 0 ? checkFeature(parameterList, Feature.GENERICS, languageLevel, containingFile) : null; } @Nullable - public static HighlightInfo checkAnnotationFeature(PsiElement element) { - return checkFeature(element, Feature.ANNOTATIONS); + public static HighlightInfo checkAnnotationFeature(@NotNull PsiElement element, + @NotNull LanguageLevel languageLevel, + @NotNull PsiFile containingFile) { + return checkFeature(element, Feature.ANNOTATIONS, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkForEachFeature(PsiForeachStatement statement) { - return checkFeature(statement, Feature.FOR_EACH); + public static HighlightInfo checkForEachFeature(@NotNull PsiForeachStatement statement, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(statement, Feature.FOR_EACH, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkStaticImportFeature(PsiImportStaticStatement statement) { - return checkFeature(statement, Feature.STATIC_IMPORTS); + public static HighlightInfo checkStaticImportFeature(@NotNull PsiImportStaticStatement statement, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(statement, Feature.STATIC_IMPORTS, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkVarargFeature(PsiParameter parameter) { - return checkFeature(parameter, Feature.VARARGS); + public static HighlightInfo checkVarargFeature(@NotNull PsiParameter parameter, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(parameter, Feature.VARARGS, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkDiamondFeature(PsiTypeElement typeElement) { - return typeElement.getType() instanceof PsiDiamondType ? checkFeature(typeElement.getParent(), Feature.DIAMOND_TYPES) : null; + public static HighlightInfo checkDiamondFeature(@NotNull PsiTypeElement typeElement, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return typeElement.getType() instanceof PsiDiamondType ? checkFeature(typeElement.getParent(), Feature.DIAMOND_TYPES, + languageLevel, containingFile) : null; } @Nullable - public static HighlightInfo checkMultiCatchFeature(PsiParameter parameter) { - return parameter.getType() instanceof PsiDisjunctionType ? checkFeature(parameter, Feature.MULTI_CATCH) : null; + public static HighlightInfo checkMultiCatchFeature(@NotNull PsiParameter parameter, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return parameter.getType() instanceof PsiDisjunctionType ? checkFeature(parameter, Feature.MULTI_CATCH, + languageLevel, containingFile) : null; } @Nullable - public static HighlightInfo checkTryWithResourcesFeature(PsiResourceVariable resourceVariable) { - return checkFeature(resourceVariable.getParent(), Feature.TRY_WITH_RESOURCES); + public static HighlightInfo checkTryWithResourcesFeature(@NotNull PsiResourceVariable resourceVariable, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(resourceVariable.getParent(), Feature.TRY_WITH_RESOURCES, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkExtensionMethodsFeature(PsiMethod method) { - return checkFeature(method, Feature.EXTENSION_METHODS); + public static HighlightInfo checkExtensionMethodsFeature(@NotNull PsiMethod method, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(method, Feature.EXTENSION_METHODS, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkMethodReferencesFeature(PsiMethodReferenceExpression expression) { - return checkFeature(expression, Feature.METHOD_REFERENCES); + public static HighlightInfo checkMethodReferencesFeature(@NotNull PsiMethodReferenceExpression expression, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(expression, Feature.METHOD_REFERENCES, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkLambdaFeature(PsiLambdaExpression expression) { - return checkFeature(expression, Feature.LAMBDA_EXPRESSIONS); + public static HighlightInfo checkLambdaFeature(@NotNull PsiLambdaExpression expression, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(expression, Feature.LAMBDA_EXPRESSIONS, languageLevel, containingFile); } @Nullable - public static HighlightInfo checkTypeAnnotationFeature(PsiAnnotation annotation) { - return checkFeature(annotation, Feature.TYPE_ANNOTATIONS); + public static HighlightInfo checkTypeAnnotationFeature(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel,@NotNull PsiFile containingFile) { + return checkFeature(annotation, Feature.TYPE_ANNOTATIONS, languageLevel, containingFile); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index c705951fe395..4b8075da2503 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -23,24 +23,28 @@ import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; import com.intellij.codeInsight.daemon.impl.quickfix.SetupJDKFix; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesScheme; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; -import com.intellij.openapi.projectRoots.JavaVersionService; +import com.intellij.openapi.projectRoots.JavaSdkVersionUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; +import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.util.*; import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.MostlySingularMultiMap; import gnu.trove.THashMap; import gnu.trove.TObjectIntHashMap; @@ -81,6 +85,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } }; private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>>(); + private LanguageLevel myLanguageLevel; + private JavaSdkVersion myJavaSdkVersion; public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) { myResolveHelper = resolveHelper; @@ -92,6 +98,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (signatures == null) { signatures = new MostlySingularMultiMap<MethodSignature, PsiMethod>(); for (PsiMethod method : aClass.getMethods()) { + if (method instanceof ExternallyDefinedPsiElement) continue; // ignore aspectj-weaved methods; they are checked elsewhere MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); signatures.add(signature, method); } @@ -140,6 +147,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder = holder; boolean success = true; try { + myLanguageLevel = PsiUtil.getLanguageLevel(file); + myJavaSdkVersion = ObjectUtils.notNull(JavaSdkVersionUtil.getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel)); if (updateWholeFile) { Project project = file.getProject(); DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(project); @@ -192,14 +201,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitAnnotation(PsiAnnotation annotation) { super.visitAnnotation(annotation); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAnnotationFeature(annotation)); - if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkApplicability(annotation)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAnnotationFeature(annotation, myLanguageLevel, myFile)); + if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkApplicability(annotation, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkAnnotationType(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation)); - if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation)); + if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation)); } @@ -225,7 +234,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitAnnotationMethod(PsiAnnotationMethod method) { + @Override + public void visitAnnotationMethod(PsiAnnotationMethod method) { PsiType returnType = method.getReturnType(); PsiAnnotationMemberValue value = method.getDefaultValue(); if (returnType != null && value != null) { @@ -237,7 +247,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(AnnotationsHighlightUtil.checkClashesWithSuperMethods(method)); } - @Override public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { + @Override + public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { super.visitArrayInitializerExpression(expression); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkArrayInitializerApplicable(expression)); if (!(expression.getParent() instanceof PsiNewExpression)) { @@ -245,9 +256,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + @Override + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssignmentCompatibleTypes(assignment)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssignmentOperatorApplicable(assignment)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssignmentOperatorApplicable(assignment,myFile)); if (!myHolder.hasErrorResults()) visitExpression(assignment); } @@ -259,7 +271,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitLambdaExpression(PsiLambdaExpression expression) { - myHolder.add(HighlightUtil.checkLambdaFeature(expression)); + myHolder.add(HighlightUtil.checkLambdaFeature(expression, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) { if (LambdaUtil.isValidLambdaContext(expression.getParent())) { final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); @@ -354,11 +366,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkInterfaceMultipleInheritance(aClass)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkDuplicateTopLevelClass(aClass)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumMustNotBeLocal(aClass)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkImplicitThisReferenceBeforeSuper(aClass)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkImplicitThisReferenceBeforeSuper(aClass, myJavaSdkVersion)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassAndPackageConflict(aClass)); } - @Override public void visitClassInitializer(PsiClassInitializer initializer) { + @Override + public void visitClassInitializer(PsiClassInitializer initializer) { super.visitClassInitializer(initializer); if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkInitializerCompleteNormally(initializer)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(initializer.getBody())); @@ -367,25 +380,29 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { + @Override + public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { super.visitClassObjectAccessExpression(expression); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkClassObjectAccessExpression(expression)); } - @Override public void visitComment(PsiComment comment) { + @Override + public void visitComment(PsiComment comment) { super.visitComment(comment); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnclosedComment(comment)); if (myRefCountHolder != null && !myHolder.hasErrorResults()) registerReferencesFromInjectedFragments(comment); } - @Override public void visitContinueStatement(PsiContinueStatement statement) { + @Override + public void visitContinueStatement(PsiContinueStatement statement) { super.visitContinueStatement(statement); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findContinuedStatement())); } } - @Override public void visitJavaToken(PsiJavaToken token) { + @Override + public void visitJavaToken(PsiJavaToken token) { super.visitJavaToken(token); if (!myHolder.hasErrorResults() && token.getTokenType() == JavaTokenType.RBRACE @@ -398,28 +415,31 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh PsiMethod method = (PsiMethod)gParent; codeBlock = method.getBody(); returnType = method.getReturnType(); - } else if (gParent instanceof PsiLambdaExpression) { + } + else if (gParent instanceof PsiLambdaExpression) { final PsiElement body = ((PsiLambdaExpression)gParent).getBody(); if (!(body instanceof PsiCodeBlock)) return; codeBlock = (PsiCodeBlock)body; returnType = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)gParent); - } else { + } + else { return; } myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(codeBlock, returnType)); } - } - @Override public void visitDocComment(PsiDocComment comment) { + @Override + public void visitDocComment(PsiDocComment comment) { if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnclosedComment(comment)); } - @Override public void visitDocTagValue(PsiDocTagValue value) { + @Override + public void visitDocTagValue(PsiDocTagValue value) { PsiReference reference = value.getReference(); if (reference != null) { PsiElement element = reference.resolve(); - final EditorColorsScheme colorsScheme = myHolder.getColorsScheme(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); if (element instanceof PsiMethod) { myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)element, ((PsiDocMethodOrFieldRef)value).getNameElement(), false, colorsScheme)); @@ -430,13 +450,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitEnumConstant(PsiEnumConstant enumConstant) { + @Override + public void visitEnumConstant(PsiEnumConstant enumConstant) { super.visitEnumConstant(enumConstant); - if (!myHolder.hasErrorResults()) GenericsHighlightUtil.checkEnumConstantForConstructorProblems(enumConstant, myHolder); + if (!myHolder.hasErrorResults()) GenericsHighlightUtil.checkEnumConstantForConstructorProblems(enumConstant, myHolder, myJavaSdkVersion); if (!myHolder.hasErrorResults()) registerConstructorCall(enumConstant); } - @Override public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) { + @Override + public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) { super.visitEnumConstantInitializer(enumConstantInitializer); if (!myHolder.hasErrorResults()) { TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(enumConstantInitializer); @@ -444,29 +466,30 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitExpression(PsiExpression expression) { + @Override + public void visitExpression(PsiExpression expression) { ProgressManager.checkCanceled(); // visitLiteralExpression is invoked very often in array initializers super.visitExpression(expression); PsiType type = expression.getType(); if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression, type))) return; - if(expression instanceof PsiArrayAccessExpression) { + if (expression instanceof PsiArrayAccessExpression) { myHolder.add(HighlightUtil.checkValidArrayAccessExpression((PsiArrayAccessExpression)expression)); } if (expression.getParent() instanceof PsiNewExpression - && ((PsiNewExpression)expression.getParent()).getQualifier() != expression - && ((PsiNewExpression)expression.getParent()).getArrayInitializer() != expression) { + && ((PsiNewExpression)expression.getParent()).getQualifier() != expression + && ((PsiNewExpression)expression.getParent()).getArrayInitializer() != expression) { // like in 'new String["s"]' myHolder.add(HighlightUtil.checkAssignability(PsiType.INT, expression.getType(), expression, expression)); } - if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableExpected(expression)); if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkArrayInitializer(expression, type)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression, type)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression, type)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type)); if (!myHolder.hasErrorResults() && expression.getParent() instanceof PsiThrowStatement @@ -492,18 +515,19 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitForeachStatement(final PsiForeachStatement statement) { - myHolder.add(HighlightUtil.checkForEachFeature(statement)); + myHolder.add(HighlightUtil.checkForEachFeature(statement, myLanguageLevel, myFile)); } @Override public void visitImportStaticStatement(final PsiImportStaticStatement statement) { - myHolder.add(HighlightUtil.checkStaticImportFeature(statement)); + myHolder.add(HighlightUtil.checkStaticImportFeature(statement, myLanguageLevel, myFile)); } @Override public void visitIdentifier(final PsiIdentifier identifier) { + TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); + PsiElement parent = identifier.getParent(); - final EditorColorsScheme colorsScheme = myHolder.getColorsScheme(); if (parent instanceof PsiVariable) { PsiVariable variable = (PsiVariable)parent; myHolder.add(HighlightUtil.checkVariableAlreadyDefined(variable)); @@ -512,6 +536,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh final PsiElement child = variable.getLastChild(); if (child instanceof PsiErrorElement && child.getPrevSibling() == identifier) return; } + boolean isMethodParameter = variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiMethod; if (!isMethodParameter) { // method params are highlighted in visitMethod since we should make sure the method body was visited before if (HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems)) { @@ -524,11 +549,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh else { myReassignedParameters.put((PsiParameter)variable, 1); // mark param as present in current file } + + myHolder.add(HighlightUtil.checkUnderscore(identifier, variable)); } else if (parent instanceof PsiClass) { PsiClass aClass = (PsiClass)parent; if (aClass.isAnnotationType()) { - myHolder.add(HighlightUtil.checkAnnotationFeature(identifier)); + myHolder.add(HighlightUtil.checkAnnotationFeature(identifier, myLanguageLevel, myFile)); } myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier)); @@ -546,6 +573,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh else { visitParentReference(parent); } + super.visitIdentifier(identifier); } @@ -560,7 +588,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh catch (IndexNotReadyException e) { return; } - myHolder.add(HighlightUtil.checkReference(ref, result)); + myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); if (myRefCountHolder != null) { myRefCountHolder.registerReference(ref, result); } @@ -570,7 +598,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitImportStatement(final PsiImportStatement statement) { if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses)); + myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses,myFile)); } } @@ -624,13 +652,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { + @Override + public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { super.visitInstanceOfExpression(expression); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkInstanceOfApplicable(expression)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkInstanceOfGenericType(expression)); } - @Override public void visitKeyword(PsiKeyword keyword) { + @Override + public void visitKeyword(PsiKeyword keyword) { super.visitKeyword(keyword); PsiElement parent = keyword.getParent(); String text = keyword.getText(); @@ -668,25 +698,28 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitLabeledStatement(PsiLabeledStatement statement) { + @Override + public void visitLabeledStatement(PsiLabeledStatement statement) { super.visitLabeledStatement(statement); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkLabelWithoutStatement(statement)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkLabelAlreadyInUse(statement)); } - @Override public void visitLiteralExpression(PsiLiteralExpression expression) { + @Override + public void visitLiteralExpression(PsiLiteralExpression expression) { super.visitLiteralExpression(expression); if (myHolder.hasErrorResults()) return; - myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression)); + myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression, myLanguageLevel,myFile)); if (myRefCountHolder != null && !myHolder.hasErrorResults()) registerReferencesFromInjectedFragments(expression); } - @Override public void visitMethod(PsiMethod method) { + @Override + public void visitMethod(PsiMethod method) { super.visitMethod(method); if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(method.getBody())); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorHandleSuperClassExceptions(method)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkRecursiveConstructorInvocation(method)); - if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation(method)); + if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation(method, myLanguageLevel)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkSafeVarargsAnnotation(method)); if (!myHolder.hasErrorResults() && method.isConstructor()) { myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, method.getContainingClass())); @@ -694,7 +727,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh // method params are highlighted in visitMethod since we should make sure the method body was visited before PsiParameter[] parameters = method.getParameterList().getParameters(); - final EditorColorsScheme colorsScheme = myHolder.getColorsScheme(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); for (PsiParameter parameter : parameters) { int info = myReassignedParameters.get(parameter); @@ -713,7 +746,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (parent instanceof PsiReferenceExpression || parent instanceof PsiJavaCodeReferenceElement) { return; } - final EditorColorsScheme colorsScheme = myHolder.getColorsScheme(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); if (parent instanceof PsiMethodCallExpression) { PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod(); PsiElement methodNameElement = element.getReferenceNameElement(); @@ -751,13 +784,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumSuperConstructorCall(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkSuperQualifierType(myFile.getProject(), expression)); // in case of JSP synthetic method call, do not check - if (expression.getMethodExpression().isPhysical() && !myHolder.hasErrorResults()) { + if (myFile.isPhysical() && !myHolder.hasErrorResults()) { try { - myHolder.add(HighlightMethodUtil.checkMethodCall(expression, myResolveHelper)); + myHolder.add(HighlightMethodUtil.checkMethodCall(expression, myResolveHelper, myLanguageLevel,myJavaSdkVersion)); } catch (IndexNotReadyException ignored) { } @@ -772,7 +806,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh PsiElement parent = list.getParent(); if (parent instanceof PsiMethod) { PsiMethod method = (PsiMethod)parent; - if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodCanHaveBody(method)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodCanHaveBody(method, myLanguageLevel,myFile)); MethodSignatureBackedByPsiMethod methodSignature = MethodSignatureBackedByPsiMethod.create(method, PsiSubstitutor.EMPTY); if (!method.isConstructor()) { try { @@ -793,7 +827,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method,myFile)); } else if (parent instanceof PsiClass) { PsiClass aClass = (PsiClass)parent; @@ -818,7 +852,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitNameValuePair(PsiNameValuePair pair) { + @Override + public void visitNameValuePair(PsiNameValuePair pair) { myHolder.add(AnnotationsHighlightUtil.checkNameValuePair(pair)); if (!myHolder.hasErrorResults()) { PsiIdentifier nameId = pair.getNameIdentifier(); @@ -829,14 +864,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitNewExpression(PsiNewExpression expression) { + @Override + public void visitNewExpression(PsiNewExpression expression) { myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, null)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAnonymousInheritFinal(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkQualifiedNew(expression)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(expression)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression)); try { - if (!myHolder.hasErrorResults()) HighlightMethodUtil.checkNewExpression(expression, myHolder); + if (!myHolder.hasErrorResults()) HighlightMethodUtil.checkNewExpression(expression, myHolder, myJavaSdkVersion); } catch (IndexNotReadyException ignored) { } @@ -859,13 +895,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh final PsiElement parent = parameter.getParent(); if (parent instanceof PsiParameterList) { - if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter)); + if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter, + myLanguageLevel,myFile)); } else if (parent instanceof PsiForeachStatement) { if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkForeachLoopParameterType((PsiForeachStatement)parent)); } else if (parent instanceof PsiCatchSection) { - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkMultiCatchFeature(parameter)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkMultiCatchFeature(parameter, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter)); if (!myHolder.hasErrorResults()) myHolder.addAll(GenericsHighlightUtil.checkCatchParameterIsClass(parameter)); if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkCatchTypeIsDisjoint(parameter)); @@ -878,14 +915,16 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAnnotationMethodParameters(list)); } - @Override public void visitPostfixExpression(PsiPostfixExpression expression) { + @Override + public void visitPostfixExpression(PsiPostfixExpression expression) { super.visitPostfixExpression(expression); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); } } - @Override public void visitPrefixExpression(PsiPrefixExpression expression) { + @Override + public void visitPrefixExpression(PsiPrefixExpression expression) { super.visitPrefixExpression(expression); if (!myHolder.hasErrorResults()) { myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand())); @@ -910,7 +949,17 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh private JavaResolveResult doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) { JavaResolveResult result; try { - result = ref.advancedResolve(true); + if (ref instanceof PsiReferenceExpressionImpl) { + PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)ref; + JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(referenceExpression, + PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, + true, true, + myFile); + result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; + } + else { + result = ref.advancedResolve(true); + } } catch (IndexNotReadyException e) { return null; @@ -922,9 +971,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (myRefCountHolder != null) { myRefCountHolder.registerReference(ref, result); } - myHolder.add(HighlightUtil.checkReference(ref, result)); + myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); if (!myHolder.hasErrorResults() && resolved instanceof PsiTypeParameter) { - boolean cannotSelectFromTypeParameter = !JavaVersionService.getInstance().isAtLeast(ref, JavaSdkVersion.JDK_1_7); + boolean cannotSelectFromTypeParameter = !myJavaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7); if (!cannotSelectFromTypeParameter) { final PsiClass containingClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); if (containingClass != null) { @@ -940,17 +989,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAbstractInstantiation(ref, resolved)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassExtendsForeignInnerClass(ref, resolved)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkSelectStaticClassFromParameterizedType(resolved, ref)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, ref, - result.getSubstitutor())); + result.getSubstitutor(), + myJavaSdkVersion)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref)); if (resolved != null && parent instanceof PsiReferenceList) { if (!myHolder.hasErrorResults()) { PsiReferenceList referenceList = (PsiReferenceList)parent; - myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result)); + myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result, myLanguageLevel)); } } @@ -974,7 +1024,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myReassignedParameters.put((PsiParameter)variable, 2); } - final EditorColorsScheme colorsScheme = myHolder.getColorsScheme(); + final TextAttributesScheme colorsScheme = myHolder.getColorsScheme(); if (!variable.hasModifierProperty(PsiModifier.FINAL) && isReassigned(variable)) { myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, ref)); } @@ -1027,7 +1077,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh return result; } - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression); if (!myHolder.hasErrorResults()) { visitExpression(expression); @@ -1036,7 +1087,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh JavaResolveResult result; JavaResolveResult[] results; try { - results = expression.multiResolve(true); + if (expression instanceof PsiReferenceExpressionImpl) { + PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)expression; + results = JavaResolveUtil.resolveWithContainingFile(referenceExpression, + PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, true, + myFile); + } + else { + results = expression.multiResolve(true); + } result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; } catch (IndexNotReadyException e) { @@ -1046,7 +1105,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (resolved instanceof PsiVariable && resolved.getContainingFile() == expression.getContainingFile()) { if (!myHolder.hasErrorResults()) { try { - myHolder.add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, (PsiVariable)resolved, myUninitializedVarProblems)); + myHolder.add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, (PsiVariable)resolved, myUninitializedVarProblems,myFile)); } catch (IndexNotReadyException ignored) { } @@ -1089,7 +1148,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - myHolder.add(HighlightUtil.checkMethodReferencesFeature(expression)); + myHolder.add(HighlightUtil.checkMethodReferencesFeature(expression, myLanguageLevel,myFile)); JavaResolveResult result; try { result = expression.advancedResolve(true); @@ -1164,51 +1223,59 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitReferenceParameterList(PsiReferenceParameterList list) { - myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list)); + myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(list)); } - @Override public void visitReturnStatement(PsiReturnStatement statement) { + @Override + public void visitReturnStatement(PsiReturnStatement statement) { try { myHolder.add(HighlightUtil.checkReturnStatementType(statement)); } - catch (IndexNotReadyException ignore) { } + catch (IndexNotReadyException ignore) { + } } - @Override public void visitStatement(PsiStatement statement) { + @Override + public void visitStatement(PsiStatement statement) { super.visitStatement(statement); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkNotAStatement(statement)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkStatementPrependedWithCaseInsideSwitch(statement)); } - @Override public void visitSuperExpression(PsiSuperExpression expr) { + @Override + public void visitSuperExpression(PsiSuperExpression expr) { myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier())); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkAbstractMethodDirectCall(expr)); if (!myHolder.hasErrorResults()) visitExpression(expr); } - @Override public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { + @Override + public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) { super.visitSwitchLabelStatement(statement); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkCaseStatement(statement)); } - @Override public void visitSwitchStatement(PsiSwitchStatement statement) { + @Override + public void visitSwitchStatement(PsiSwitchStatement statement) { super.visitSwitchStatement(statement); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchSelectorType(statement)); } - @Override public void visitThisExpression(PsiThisExpression expr) { + @Override + public void visitThisExpression(PsiThisExpression expr) { myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier())); if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null)); + myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null, myFile)); } if (!myHolder.hasErrorResults()) { visitExpression(expr); } } - @Override public void visitThrowStatement(PsiThrowStatement statement) { + @Override + public void visitThrowStatement(PsiThrowStatement statement) { myHolder.add(HighlightUtil.checkUnhandledExceptions(statement, null)); if (!myHolder.hasErrorResults()) visitStatement(statement); } @@ -1224,7 +1291,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh added = myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter, thrownTypes)); } if (!added) { - myHolder.addAll(HighlightUtil.checkWithImprovedCatchAnalysis(parameter, thrownTypes)); + myHolder.addAll(HighlightUtil.checkWithImprovedCatchAnalysis(parameter, thrownTypes,myFile)); } } } @@ -1233,20 +1300,21 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitResourceVariable(final PsiResourceVariable resourceVariable) { visitVariable(resourceVariable); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryWithResourcesFeature(resourceVariable)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryWithResourcesFeature(resourceVariable, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resourceVariable)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resourceVariable)); } @Override public void visitTypeElement(final PsiTypeElement type) { - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkDiamondFeature(type)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkDiamondFeature(type, myLanguageLevel,myFile)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalType(type)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type)); } - @Override public void visitTypeCastExpression(PsiTypeCastExpression typeCast) { + @Override + public void visitTypeCastExpression(PsiTypeCastExpression typeCast) { super.visitTypeCastExpression(typeCast); try { if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkInconvertibleTypeCast(typeCast)); @@ -1255,11 +1323,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitTypeParameterList(PsiTypeParameterList list) { - myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list)); + @Override + public void visitTypeParameterList(PsiTypeParameterList list) { + myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list, myLanguageLevel,myFile)); } - @Override public void visitVariable(PsiVariable variable) { + @Override + public void visitVariable(PsiVariable variable) { super.visitVariable(variable); try { if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableInitializerType(variable)); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/BringVariableIntoScopeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/BringVariableIntoScopeFix.java index ff14d0c5bf5a..8212b039d100 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/BringVariableIntoScopeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/BringVariableIntoScopeFix.java @@ -145,7 +145,7 @@ public class BringVariableIntoScopeFix implements IntentionAction { myOutOfScopeVariable.delete(); } - if (HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(myUnresolvedReference, addedVar, new THashMap<PsiElement, Collection<PsiReferenceExpression>>()) != null) { + if (HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(myUnresolvedReference, addedVar, new THashMap<PsiElement, Collection<PsiReferenceExpression>>(),file) != null) { initialize(addedVar); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java index c12e9cb2c8c4..ac607483d723 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java @@ -18,7 +18,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; +import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil; import com.intellij.codeInsight.generation.PsiElementClassMember; import com.intellij.codeInsight.generation.PsiFieldMember; import com.intellij.codeInsight.generation.PsiMethodMember; @@ -316,7 +316,7 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { if (newParameters == parameters) return false; //user must have canceled dialog boolean created = false; // do not introduce assignment in chanined constructor - if (HighlightControlFlowUtil.getChainedConstructors(constructor) == null) { + if (JavaHighlightUtil.getChainedConstructors(constructor) == null) { for (PsiField field : fields.keySet()) { final String defaultParamName = fields.get(field); PsiParameter parameter = findParamByName(defaultParamName, field.getType(), newParameters, parameterInfos); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index 667143b2da35..491a5f6afe13 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -569,7 +569,7 @@ public class CreateFromUsageUtils { return result.toArray(new PsiVariable[result.size()]); } - private static void getExpectedInformation(PsiExpression expression, + private static void getExpectedInformation(final PsiExpression expression, List<ExpectedTypeInfo[]> types, List<String> expectedMethodNames, List<String> expectedFieldNames) { @@ -579,6 +579,12 @@ public class CreateFromUsageUtils { if (!(parent instanceof PsiReferenceExpression)) { ExpectedTypeInfo[] someExpectedTypes = ExpectedTypesProvider.getExpectedTypes(expr, false); if (someExpectedTypes.length > 0) { + Arrays.sort(someExpectedTypes, new Comparator<ExpectedTypeInfo>() { + @Override + public int compare(ExpectedTypeInfo o1, ExpectedTypeInfo o2) { + return compareExpectedTypes(o1, o2, expression); + } + }); types.add(someExpectedTypes); } continue; @@ -595,6 +601,12 @@ public class CreateFromUsageUtils { if (refName.equals("equals")) { ExpectedTypeInfo[] someExpectedTypes = equalsExpectedTypes((PsiMethodCallExpression)pparent); if (someExpectedTypes.length > 0) { + Arrays.sort(someExpectedTypes, new Comparator<ExpectedTypeInfo>() { + @Override + public int compare(ExpectedTypeInfo o1, ExpectedTypeInfo o2) { + return compareExpectedTypes(o1, o2, expression); + } + }); types.add(someExpectedTypes); } } @@ -609,6 +621,14 @@ public class CreateFromUsageUtils { } } + private static int compareExpectedTypes(ExpectedTypeInfo o1, ExpectedTypeInfo o2, PsiExpression expression) { + PsiClass c1 = PsiUtil.resolveClassInType(o1.getDefaultType()); + PsiClass c2 = PsiUtil.resolveClassInType(o2.getDefaultType()); + if (c1 == null && c2 == null) return 0; + if (c1 == null || c2 == null) return c1 == null ? -1 : 1; + return compareMembers(c1, c2, expression); + } + private static ExpectedTypeInfo[] equalsExpectedTypes(PsiMethodCallExpression methodCall) { final PsiType[] argumentTypes = methodCall.getArgumentList().getExpressionTypes(); if (argumentTypes.length != 1) { @@ -781,25 +801,7 @@ public class CreateFromUsageUtils { Arrays.sort(members, new Comparator<PsiMember>() { @Override public int compare(final PsiMember m1, final PsiMember m2) { - ProgressManager.checkCanceled(); - int result = JavaStatisticsManager.createInfo(null, m2).getUseCount() - JavaStatisticsManager.createInfo(null, m1).getUseCount(); - if (result != 0) return result; - final PsiClass aClass = m1.getContainingClass(); - final PsiClass bClass = m2.getContainingClass(); - if (aClass == null || bClass == null) return 0; - result = JavaStatisticsManager.createInfo(null, bClass).getUseCount() - JavaStatisticsManager.createInfo(null, aClass).getUseCount(); - if (result != 0) return result; - - WeighingComparable<PsiElement,ProximityLocation> proximity1 = PsiProximityComparator.getProximity(m1, expression); - WeighingComparable<PsiElement,ProximityLocation> proximity2 = PsiProximityComparator.getProximity(m2, expression); - if (proximity1 != null && proximity2 != null) { - result = proximity2.compareTo(proximity1); - if (result != 0) return result; - } - - String name1 = StaticImportMethodFix.getMemberQualifiedName(m1); - String name2 = StaticImportMethodFix.getMemberQualifiedName(m2); - return name1 == null || name2 == null ? 0 : name1.compareTo(name2); + return compareMembers(m1, m2, expression); } }); @@ -836,6 +838,29 @@ public class CreateFromUsageUtils { } } + private static int compareMembers(PsiMember m1, PsiMember m2, PsiExpression context) { + ProgressManager.checkCanceled(); + int result = JavaStatisticsManager.createInfo(null, m2).getUseCount() - JavaStatisticsManager.createInfo(null, m1).getUseCount(); + if (result != 0) return result; + final PsiClass aClass = m1.getContainingClass(); + final PsiClass bClass = m2.getContainingClass(); + if (aClass != null && bClass != null) { + result = JavaStatisticsManager.createInfo(null, bClass).getUseCount() - JavaStatisticsManager.createInfo(null, aClass).getUseCount(); + if (result != 0) return result; + } + + WeighingComparable<PsiElement,ProximityLocation> proximity1 = PsiProximityComparator.getProximity(m1, context); + WeighingComparable<PsiElement,ProximityLocation> proximity2 = PsiProximityComparator.getProximity(m2, context); + if (proximity1 != null && proximity2 != null) { + result = proximity2.compareTo(proximity1); + if (result != 0) return result; + } + + String name1 = PsiUtil.getMemberQualifiedName(m1); + String name2 = PsiUtil.getMemberQualifiedName(m2); + return name1 == null || name2 == null ? 0 : name1.compareTo(name2); + } + public static boolean isAccessedForWriting(final PsiExpression[] expressionOccurences) { for (PsiExpression expression : expressionOccurences) { if(PsiUtil.isAccessedForWriting(expression)) return true; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java index 3225968c3dd9..11bab8017903 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterOrSetterFix.java @@ -17,13 +17,13 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.QuickFixBundle; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -116,16 +116,12 @@ public class CreateGetterOrSetterFix implements IntentionAction, LowPriorityActi PsiClass aClass = myField.getContainingClass(); final List<PsiMethod> methods = new ArrayList<PsiMethod>(); if (myCreateGetter) { - methods.add(PropertyUtil.generateGetterPrototype(myField)); + methods.add(GenerateMembersUtil.generateGetterPrototype(myField)); } if (myCreateSetter) { - methods.add(PropertyUtil.generateSetterPrototype(myField)); + methods.add(GenerateMembersUtil.generateSetterPrototype(myField)); } for (PsiMethod method : methods) { - String modifier = PsiUtil.getMaximumModifierForMember(aClass); - if (modifier != null) { - PsiUtil.setModifierProperty(method, modifier, true); - } aClass.add(method); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java index eeae2b08c245..c5bd0289d4e3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateGetterSetterPropertyFromUsageFix.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.daemon.impl.quickfix; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; @@ -55,13 +56,13 @@ public class CreateGetterSetterPropertyFromUsageFix extends CreatePropertyFromUs @Override protected void beforeTemplateFinished(PsiClass aClass, PsiField field) { - PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(field); + PsiMethod getterPrototype = GenerateMembersUtil.generateGetterPrototype(field); if (aClass.findMethodsBySignature(getterPrototype, false).length == 0) { aClass.add(getterPrototype); } - PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(field); + PsiMethod setterPrototype = GenerateMembersUtil.generateSetterPrototype(field); if (aClass.findMethodsBySignature(setterPrototype, false).length == 0) { aClass.add(setterPrototype); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java index c61685914cce..6567a9a478cc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreatePropertyFromUsageFix.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.completion.JavaLookupElementBuilder; import com.intellij.codeInsight.daemon.QuickFixBundle; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.codeInsight.intention.impl.TypeExpression; import com.intellij.codeInsight.lookup.LookupElement; @@ -226,7 +227,7 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement PsiElement typeReference; PsiCodeBlock body; if (callText.startsWith(GET_PREFIX) || callText.startsWith(IS_PREFIX)) { - accessor = (PsiMethod)targetClass.add(PropertyUtil.generateGetterPrototype(field)); + accessor = (PsiMethod)targetClass.add(GenerateMembersUtil.generateGetterPrototype(field)); body = accessor.getBody(); LOG.assertTrue(body != null, accessor.getText()); fieldReference = ((PsiReturnStatement)body.getStatements()[0]).getReturnValue(); @@ -242,10 +243,6 @@ public class CreatePropertyFromUsageFix extends CreateFromUsageBaseFix implement } accessor.setName(callText); PsiUtil.setModifierProperty(accessor, PsiModifier.STATIC, isStatic); - final String modifier = PsiUtil.getMaximumModifierForMember(targetClass); - if (modifier != null) { - PsiUtil.setModifierProperty(accessor, modifier, true); - } TemplateBuilderImpl builder = new TemplateBuilderImpl(accessor); builder.replaceElement(typeReference, TYPE_VARIABLE, new TypeExpression(project, expectedTypes), true); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java index 2e23f7ef65e4..17871d103816 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java @@ -119,6 +119,9 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme return filterAssignableFrom(initializer.getType(), candidates); } } + if (var instanceof PsiParameter) { + return filterBySuperMethods((PsiParameter)var, candidates); + } } return super.filterByContext(candidates, ref); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index bfb7c45bf3c8..5de72527f379 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -43,7 +43,9 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -125,6 +127,18 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe } } + classList = filterByRequiredMemberName(classList); + + List<PsiClass> filtered = filterByContext(classList, myElement); + if (!filtered.isEmpty()) { + classList = filtered; + } + + filterAlreadyImportedButUnresolved(classList); + return classList; + } + + private List<PsiClass> filterByRequiredMemberName(List<PsiClass> classList) { final String memberName = getRequiredMemberName(myElement); if (memberName != null) { List<PsiClass> filtered = ContainerUtil.findAll(classList, new Condition<PsiClass>() { @@ -146,13 +160,6 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe classList = filtered; } } - - List<PsiClass> filtered = filterByContext(classList, myElement); - if (!filtered.isEmpty()) { - classList = filtered; - } - - filterAlreadyImportedButUnresolved(classList); return classList; } @@ -206,6 +213,41 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe return candidates; } + protected static List<PsiClass> filterBySuperMethods(PsiParameter parameter, List<PsiClass> candidates) { + PsiElement parent = parameter.getParent(); + if (parent instanceof PsiParameterList) { + PsiElement granny = parent.getParent(); + if (granny instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)granny; + if (method.getModifierList().findAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE) != null) { + PsiClass aClass = method.getContainingClass(); + final Set<PsiClass> probableTypes = new HashSet<PsiClass>(); + InheritanceUtil.processSupers(aClass, false, new Processor<PsiClass>() { + @Override + public boolean process(PsiClass psiClass) { + for (PsiMethod psiMethod : psiClass.findMethodsByName(method.getName(), false)) { + for (PsiParameter psiParameter : psiMethod.getParameterList().getParameters()) { + ContainerUtil.addIfNotNull(probableTypes, PsiUtil.resolveClassInClassTypeOnly(psiParameter.getType())); + } + } + return true; + } + }); + List<PsiClass> filtered = ContainerUtil.filter(candidates, new Condition<PsiClass>() { + @Override + public boolean value(PsiClass psiClass) { + return probableTypes.contains(psiClass); + } + }); + if (!filtered.isEmpty()) { + return filtered; + } + } + } + } + return candidates; + } + public enum Result { POPUP_SHOWN, CLASS_AUTO_IMPORTED, diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceInaccessibleFieldWithGetterSetterFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceInaccessibleFieldWithGetterSetterFix.java index 8e0621898dfc..12176d337f0f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceInaccessibleFieldWithGetterSetterFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceInaccessibleFieldWithGetterSetterFix.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -98,7 +99,7 @@ public class ReplaceInaccessibleFieldWithGetterSetterFix extends LocalQuickFixAn } } else if (PsiUtil.isAccessedForReading((PsiExpression)place)) { - final PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(psiField); + final PsiMethod getterPrototype = GenerateMembersUtil.generateGetterPrototype(psiField); final PsiMethod getter = containingClass.findMethodBySignature(getterPrototype, true); if (getter != null && PsiUtil.isAccessible(getter, place, accessObjectClass)) { QuickFixAction.registerQuickFixAction(error, new ReplaceInaccessibleFieldWithGetterSetterFix(place, getter, false)); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index 9c9af0f9f410..9461af0067ef 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -44,7 +44,6 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -233,7 +232,7 @@ public class StaticImportMethodFix implements IntentionAction { } public static boolean isExcluded(PsiMember method) { - String name = getMemberQualifiedName(method); + String name = PsiUtil.getMemberQualifiedName(method); if (name == null) return false; CodeInsightSettings cis = CodeInsightSettings.getInstance(); for (String excluded : cis.EXCLUDED_PACKAGES) { @@ -301,7 +300,7 @@ public class StaticImportMethodFix implements IntentionAction { return FINAL_CHOICE; } - String qname = getMemberQualifiedName(selectedValue); + String qname = PsiUtil.getMemberQualifiedName(selectedValue); if (qname == null) return FINAL_CHOICE; List<String> excludableStrings = AddImportAction.getAllExcludableStrings(qname); return new BaseListPopupStep<String>(null, excludableStrings) { @@ -371,19 +370,6 @@ public class StaticImportMethodFix implements IntentionAction { popup.showInBestPositionFor(editor); } - @Nullable - public static String getMemberQualifiedName(PsiMember member) { - if (member instanceof PsiClass) { - return ((PsiClass)member).getQualifiedName(); - } - - PsiClass containingClass = member.getContainingClass(); - if (containingClass == null) return null; - String className = containingClass.getQualifiedName(); - if (className == null) return null; - return className + "." + member.getName(); - } - @Override public boolean startInWriteAction() { return true; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java index 8483946e292e..1070533e94ca 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java @@ -312,7 +312,8 @@ public class VariableAccessFromInnerClassFix implements IntentionAction { Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems = new THashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>(); for (PsiReferenceExpression expression : references) { if (ControlFlowUtil.isVariableAssignedInLoop(expression, variable)) return false; - HighlightInfo highlightInfo = HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, variable, uninitializedVarProblems); + HighlightInfo highlightInfo = HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, variable, uninitializedVarProblems, + variable.getContainingFile()); if (highlightInfo != null) return false; highlightInfo = HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, finalVarProblems); if (highlightInfo != null) return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableParameterizedTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableParameterizedTypeFix.java index a7a666c13bf7..a8b3b2847865 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableParameterizedTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableParameterizedTypeFix.java @@ -18,10 +18,12 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.JavaSdkVersionUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; -import com.intellij.openapi.project.DumbService; import java.util.HashMap; @@ -38,8 +40,9 @@ public class VariableParameterizedTypeFix { PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(parameterList.getProject()); PsiClass[] classes = shortNamesCache.getClassesByName(shortName, GlobalSearchScope.allScope(manager.getProject())); PsiElementFactory factory = facade.getElementFactory(); + JavaSdkVersion version = JavaSdkVersionUtil.getJavaSdkVersion(parameterList); for (PsiClass aClass : classes) { - if (GenericsHighlightUtil.checkReferenceTypeArgumentList(aClass, parameterList, PsiSubstitutor.EMPTY, false) == null) { + if (GenericsHighlightUtil.checkReferenceTypeArgumentList(aClass, parameterList, PsiSubstitutor.EMPTY, false, version) == null) { PsiType[] actualTypeParameters = parameterList.getTypeArguments(); PsiTypeParameter[] classTypeParameters = aClass.getTypeParameters(); HashMap<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>(); diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index 03b8075f3b2a..ae7dfb95f2ca 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -142,7 +142,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate { } @Override - public Result charTyped(final char c, final Project project, final Editor editor, @NotNull final PsiFile file) { + public Result charTyped(final char c, final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) { if (myJavaLTTyped) { myJavaLTTyped = false; handleAfterJavaLT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE); diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java index af0a06c0b09e..f957efb1ecf4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavadocTypedHandler.java @@ -41,7 +41,7 @@ public class JavadocTypedHandler extends TypedHandlerDelegate { private static final char SLASH = '/'; @Override - public Result charTyped(char c, Project project, Editor editor, PsiFile file) { + public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (project == null || editor == null || file == null) { return Result.CONTINUE; } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java index cfb40848e403..eebf0663aaf4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java @@ -30,6 +30,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -154,7 +155,7 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { } protected String getLineBreaker(PsiElement token) { - CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(token.getProject()); + CommonCodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(token.getProject()).getCommonSettings(token.getLanguage()); return codeStyleSettings.BINARY_OPERATION_SIGN_ON_NEXT_LINE ? "\\n\"\n+ \"" : "\\n\" +\n\""; } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/wordSelection/DocTagSelectioner.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/wordSelection/DocTagSelectioner.java index c64d304249cb..d706a2d60ab0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/wordSelection/DocTagSelectioner.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/wordSelection/DocTagSelectioner.java @@ -36,7 +36,11 @@ public class DocTagSelectioner extends WordSelectioner { @Override public List<TextRange> select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { List<TextRange> result = super.select(e, editorText, cursorOffset, editor); + result.add(getDocTagRange((PsiDocTag)e, editorText, cursorOffset)); + return result; + } + public static TextRange getDocTagRange(PsiDocTag e, CharSequence documentText, int minOffset) { TextRange range = e.getTextRange(); int endOffset = range.getEndOffset(); @@ -49,7 +53,7 @@ public class DocTagSelectioner extends WordSelectioner { int childStartOffset = child.getTextRange().getStartOffset(); - if (childStartOffset <= cursorOffset) { + if (childStartOffset <= minOffset) { break; } @@ -71,10 +75,8 @@ public class DocTagSelectioner extends WordSelectioner { endOffset = Math.min(childStartOffset, endOffset); } - startOffset = CharArrayUtil.shiftBackward(editorText, startOffset - 1, "* \t") + 1; + startOffset = CharArrayUtil.shiftBackward(documentText, startOffset - 1, "* \t") + 1; - result.add(new TextRange(startOffset, endOffset)); - - return result; + return new TextRange(startOffset, endOffset); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index 538b713d550b..1b088879f59b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -19,10 +19,7 @@ import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiAnonymousClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiNewExpression; -import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; @@ -38,7 +35,8 @@ public class JavaFoldingBuilder extends JavaFoldingBuilderBase { @Override protected boolean shouldShowExplicitLambdaType(PsiAnonymousClass anonymousClass, PsiNewExpression expression) { - if (expression.getParent() instanceof PsiReferenceExpression) { + PsiElement parent = expression.getParent(); + if (parent instanceof PsiReferenceExpression || parent instanceof PsiAssignmentExpression) { return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java index a3c52e718a9b..de7261d60641 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java @@ -106,6 +106,12 @@ public class GenerateEqualsHelper implements Runnable { return id; } + private static boolean shouldAddOverrideAnnotation(PsiElement context) { + CodeStyleSettings style = CodeStyleSettingsManager.getSettings(context.getProject()); + + return style.INSERT_OVERRIDE_ANNOTATION && PsiUtil.isLanguageLevel5OrHigher(context); + } + @Override public void run() { try { @@ -133,8 +139,7 @@ public class GenerateEqualsHelper implements Runnable { else { if (!mySuperHasHashCode) { @NonNls String text = ""; - CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myProject); - if (GenerateMembersUtil.shouldAddOverrideAnnotation(myClass, false)) { + if (shouldAddOverrideAnnotation(myClass)) { text += "@Override\n"; } @@ -172,7 +177,7 @@ public class GenerateEqualsHelper implements Runnable { @NonNls StringBuffer buffer = new StringBuffer(); CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myProject); - if (GenerateMembersUtil.shouldAddOverrideAnnotation(myClass, false)) { + if (shouldAddOverrideAnnotation(myClass)) { buffer.append("@Override\n"); } buffer.append("public boolean equals(Object ").append(myParameterName).append(") {\n"); @@ -327,8 +332,7 @@ public class GenerateEqualsHelper implements Runnable { private PsiMethod createHashCode() throws IncorrectOperationException { @NonNls StringBuilder buffer = new StringBuilder(); - CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(myProject); - if (GenerateMembersUtil.shouldAddOverrideAnnotation(myClass, false)) { + if (shouldAddOverrideAnnotation(myClass)) { buffer.append("@Override\n"); } buffer.append("public int hashCode() {\n"); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java index 8b3dd21a5fd0..632dd6d7b688 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateFieldOrPropertyHandler.java @@ -21,8 +21,11 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PropertyMemberType; +import com.intellij.psi.util.PropertyUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collections; @@ -54,31 +57,38 @@ public class GenerateFieldOrPropertyHandler extends GenerateMembersHandlerBase { @Override @NotNull public List<? extends GenerationInfo> generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException { - final PsiElementFactory psiElementFactory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + PsiElementFactory psiElementFactory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); try { - final String name = myMemberType == PropertyMemberType.FIELD? myAttributeName : JavaCodeStyleManager.getInstance(aClass.getProject()).propertyNameToVariableName(myAttributeName, VariableKind.FIELD); - final PsiField psiField = psiElementFactory.createField(name, myType); - final GenerationInfo[] objects = new GenerateGetterAndSetterHandler().generateMemberPrototypes(aClass, new PsiFieldMember(psiField)); - final GenerationInfo getter = objects[0]; - final GenerationInfo setter = objects[1]; + String fieldName = getFieldName(aClass); + PsiField psiField = psiElementFactory.createField(fieldName, myType); + GenerationInfo[] infos = new GenerateGetterAndSetterHandler().generateMemberPrototypes(aClass, new PsiFieldMember(psiField)); if (myAnnotations.length > 0) { - final PsiMember targetMember; - switch (myMemberType) { - case FIELD: targetMember = psiField; - break; - case GETTER: targetMember = getter.getPsiMember(); - break; - case SETTER: targetMember = setter.getPsiMember(); - break; - default: targetMember = null; - break; + PsiMember targetMember = null; + if (myMemberType == PropertyMemberType.FIELD) { + targetMember = psiField; } - assert targetMember != null; - for (PsiAnnotation annotation : myAnnotations) { - targetMember.getModifierList().addAfter(annotation, null); + else { + for (GenerationInfo info : infos) { + PsiMember member = info.getPsiMember(); + if (!(member instanceof PsiMethod)) continue; + if (myMemberType == PropertyMemberType.GETTER && PropertyUtil.isSimplePropertyGetter((PsiMethod)member) || + myMemberType == PropertyMemberType.SETTER && PropertyUtil.isSimplePropertySetter((PsiMethod)member)) { + targetMember = member; + break; + } + } + if (targetMember == null) targetMember = findExistingMember(aClass, myMemberType); + } + PsiModifierList modifierList = targetMember != null? targetMember.getModifierList() : null; + if (modifierList != null) { + for (PsiAnnotation annotation : myAnnotations) { + PsiAnnotation existing = modifierList.findAnnotation(annotation.getQualifiedName()); + if (existing != null) existing.replace(annotation); + else modifierList.addAfter(annotation, null); + } } } - return Arrays.asList(new PsiGenerationInfo<PsiField>(psiField), getter, setter); + return ContainerUtil.concat(Collections.singletonList(new PsiGenerationInfo<PsiField>(psiField)), Arrays.asList(infos)); } catch (IncorrectOperationException e) { assert false : e; @@ -86,6 +96,33 @@ public class GenerateFieldOrPropertyHandler extends GenerateMembersHandlerBase { } } + @Nullable + public PsiMember findExistingMember(@NotNull PsiClass aClass, @NotNull PropertyMemberType memberType) { + if (memberType == PropertyMemberType.FIELD) { + return aClass.findFieldByName(getFieldName(aClass), false); + } + else if (memberType == PropertyMemberType.GETTER) { + try { + PsiElementFactory psiElementFactory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + PsiField field = psiElementFactory.createField(myAttributeName, myType); + PsiMethod[] templates = GetterSetterPrototypeProvider.generateGetterSetters(field, myMemberType == PropertyMemberType.GETTER); + for (PsiMethod template : templates) { + PsiMethod existingMethod = aClass.findMethodBySignature(template, true); + if (existingMethod != null) return existingMethod; + } + } + catch (IncorrectOperationException e) { + assert false : e; + } + } + return null; + } + + private String getFieldName(PsiClass aClass) { + return myMemberType == PropertyMemberType.FIELD? myAttributeName : JavaCodeStyleManager + .getInstance(aClass.getProject()).propertyNameToVariableName(myAttributeName, VariableKind.FIELD); + } + @Override protected ClassMember[] getAllOriginalMembers(PsiClass aClass) { throw new UnsupportedOperationException(); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java index a58dfe3dae2a..27c53252c09c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -33,6 +33,7 @@ import com.intellij.psi.impl.light.LightTypeElement; import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -260,7 +261,7 @@ public class GenerateMembersUtil { try { final PsiMethod resultMethod = createMethod(factory, sourceMethod, target); - copyDocComment(sourceMethod, resultMethod); + copyDocComment(sourceMethod, resultMethod, factory); copyModifiers(sourceMethod.getModifierList(), resultMethod.getModifierList()); final PsiSubstitutor collisionResolvedSubstitutor = substituteTypeParameters(factory, target, sourceMethod.getTypeParameterList(), resultMethod.getTypeParameterList(), substitutor, sourceMethod); @@ -305,7 +306,8 @@ public class GenerateMembersUtil { for (PsiTypeParameter typeParam : sourceTypeParameterList.getTypeParameters()) { final PsiTypeParameter substitutedTypeParam = substituteTypeParameter(factory, typeParam, substitutor, sourceMethod); - final PsiTypeParameter resolvedTypeParam = resolveTypeParametersCollision(factory, sourceTypeParameterList, target, substitutedTypeParam, substitutor); + final PsiTypeParameter resolvedTypeParam = resolveTypeParametersCollision(factory, sourceTypeParameterList, target, + substitutedTypeParam, substitutor); targetTypeParameterList.add(resolvedTypeParam); if (substitutedTypeParam != resolvedTypeParam) { substitutionMap.put(typeParam, factory.createType(resolvedTypeParam)); @@ -328,7 +330,7 @@ public class GenerateMembersUtil { return newTypeParameter; } } - return typeParam; + return factory.createTypeParameter(typeParam.getName(), typeParam.getSuperTypes()); } @NotNull @@ -383,8 +385,8 @@ public class GenerateMembersUtil { @NotNull PsiSubstitutor substitutor, PsiElement target) { PsiParameter[] parameters = sourceParameterList.getParameters(); UniqueNameGenerator generator = new UniqueNameGenerator(); - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; + + for (PsiParameter parameter : parameters) { final PsiType parameterType = parameter.getType(); final PsiType substituted = substituteType(substitutor, parameterType, (PsiMethod)parameter.getDeclarationScope()); @NonNls String paramName = parameter.getName(); @@ -394,14 +396,20 @@ public class GenerateMembersUtil { isBaseNameGenerated = false; } - if (paramName == null || isBaseNameGenerated && !isSubstituted && isBaseNameGenerated(codeStyleManager, parameterType, paramName)) { + if (paramName == null || + isBaseNameGenerated && !isSubstituted && isBaseNameGenerated(codeStyleManager, parameterType, paramName) || + !factory.isValidParameterName(paramName)) { String[] names = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, substituted).names; if (names.length > 0) { paramName = generator.generateUniqueName(names[0]); } + else { + paramName = generator.generateUniqueName("p"); + } + } + else if (!generator.value(paramName)) { + paramName = generator.generateUniqueName(paramName); } - - if (paramName == null) paramName = "p" + i; generator.addExistingName(paramName); final PsiParameter newParameter = factory.createParameter(paramName, substituted, target); copyOrReplaceModifierList(parameter, newParameter); @@ -419,12 +427,12 @@ public class GenerateMembersUtil { } } - private static void copyDocComment(PsiMethod source, PsiMethod target) { + private static void copyDocComment(PsiMethod source, PsiMethod target, JVMElementFactory factory) { final PsiElement navigationElement = source.getNavigationElement(); if (navigationElement instanceof PsiDocCommentOwner) { final PsiDocComment docComment = ((PsiDocCommentOwner)navigationElement).getDocComment(); if (docComment != null) { - target.addAfter(docComment, null); + target.addAfter(factory.createDocCommentFromText(docComment.getText()), null); } } } @@ -488,14 +496,6 @@ public class GenerateMembersUtil { } } - public static boolean shouldAddOverrideAnnotation(PsiElement context, boolean interfaceMethod) { - CodeStyleSettings style = CodeStyleSettingsManager.getSettings(context.getProject()); - if (!style.INSERT_OVERRIDE_ANNOTATION) return false; - - if (interfaceMethod) return PsiUtil.isLanguageLevel6OrHigher(context); - return PsiUtil.isLanguageLevel5OrHigher(context); - } - public static void setupGeneratedMethod(PsiMethod method) { PsiClass base = method.getContainingClass().getSuperClass(); PsiMethod overridden = base == null ? null : base.findMethodBySignature(method, true); @@ -551,4 +551,27 @@ public class GenerateMembersUtil { } } } + + @Nullable + public static PsiMethod generateGetterPrototype(@NotNull PsiField field) { + return annotateOnOverrideImplement(field.getContainingClass(), PropertyUtil.generateGetterPrototype(field)); + } + + @Nullable + public static PsiMethod generateSetterPrototype(@NotNull PsiField field) { + return annotateOnOverrideImplement(field.getContainingClass(), PropertyUtil.generateSetterPrototype(field)); + } + + @Nullable + private static PsiMethod annotateOnOverrideImplement(@Nullable PsiClass targetClass, @Nullable PsiMethod generated) { + if (generated == null || targetClass == null) return generated; + + if (CodeStyleSettingsManager.getSettings(targetClass.getProject()).INSERT_OVERRIDE_ANNOTATION) { + PsiMethod superMethod = targetClass.findMethodBySignature(generated, true); + if (superMethod != null && superMethod.getContainingClass() != targetClass) { + OverrideImplementUtil.annotateOnOverrideImplement(generated, targetClass, superMethod, true); + } + } + return generated; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index 53630f602ef1..01d71877265a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 0-2 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -119,34 +119,22 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { return !superClass.isInterface(); } - @NotNull - private static List<PsiMethod> overrideOrImplementMethod(PsiClass aClass, - PsiMethod method, - PsiSubstitutor substitutor, - boolean toCopyJavaDoc, - boolean insertOverrideIfPossible) throws IncorrectOperationException { - return overrideOrImplementMethod(aClass, method, substitutor, createDefaultDecorator(aClass, method, toCopyJavaDoc, insertOverrideIfPossible)); - } - public static List<PsiMethod> overrideOrImplementMethod(PsiClass aClass, - PsiMethod method, - PsiSubstitutor substitutor, - Consumer<PsiMethod> decorator) throws IncorrectOperationException { + PsiMethod method, + PsiSubstitutor substitutor, + boolean toCopyJavaDoc, + boolean insertOverrideIfPossible) throws IncorrectOperationException { if (!method.isValid() || !substitutor.isValid()) return Collections.emptyList(); List<PsiMethod> results = new ArrayList<PsiMethod>(); for (final MethodImplementor implementor : getImplementors()) { final PsiMethod[] prototypes = implementor.createImplementationPrototypes(aClass, method); - if (implementor.isBodyGenerated()) { - ContainerUtil.addAll(results, prototypes); - } - else { - for (PsiMethod prototype : prototypes) { - decorator.consume(prototype); - results.add(prototype); - } + for (PsiMethod prototype : prototypes) { + implementor.createDecorator(aClass, method, toCopyJavaDoc, insertOverrideIfPossible).consume(prototype); + results.add(prototype); } } + if (results.isEmpty()) { PsiMethod method1 = GenerateMembersUtil.substituteGenericMethod(method, substitutor, aClass); @@ -163,6 +151,7 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { defaultValue.getParent().deleteChildRange(defaultKeyword, defaultValue); } } + Consumer<PsiMethod> decorator = createDefaultDecorator(aClass, method, toCopyJavaDoc, insertOverrideIfPossible); decorator.consume(result); results.add(result); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java b/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java index a14108b0fdd2..0f64be3a38ce 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java @@ -83,17 +83,6 @@ public class PsiFieldMember extends PsiElementClassMember<PsiField> implements P @Nullable private static PsiMethod createMethodIfNotExists(PsiClass aClass, final PsiMethod template) { PsiMethod existing = aClass.findMethodBySignature(template, false); - if (existing == null) { - if (template != null) { - String modifier = aClass.isEnum() && aClass.hasModifierProperty(PsiModifier.PUBLIC) ? null : PsiUtil.getMaximumModifierForMember(aClass); - if (modifier != null) { - PsiUtil.setModifierProperty(template, modifier, true); - } - } - return template; - } - else { - return null; - } + return existing == null ? template : null; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java index 9d6fe8845a82..2707501ad13d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java @@ -131,11 +131,11 @@ public class HighlightSuppressedWarningsHandler extends HighlightUsagesHandlerBa Runnable inspect = new Runnable() { @Override public void run() { - pass.doInspectInBatch(managerEx, Collections.<LocalInspectionToolWrapper>singletonList(toolWrapper)); + pass.doInspectInBatch(context, managerEx, Collections.<LocalInspectionToolWrapper>singletonList(toolWrapper)); } }; if (indicator == null) { - ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(inspect, new ProgressIndicatorBase()); + ProgressManager.getInstance().executeProcessUnderProgress(inspect, new ProgressIndicatorBase()); } else { inspect.run(); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveFieldAssignmentToInitializerAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveFieldAssignmentToInitializerAction.java index 3b4127777f2e..c8a94ed44a08 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveFieldAssignmentToInitializerAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveFieldAssignmentToInitializerAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -53,8 +53,10 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - final PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file); + PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file); if (assignment == null) return false; + PsiElement parent = assignment.getParent(); + if (!(parent instanceof PsiExpressionStatement)) return false; PsiField field = getAssignedField(assignment); if (field == null || field.hasInitializer()) return false; PsiClass psiClass = field.getContainingClass(); @@ -74,11 +76,12 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction if (initializer == null) return false; final Ref<Boolean> result = new Ref<Boolean>(Boolean.TRUE); initializer.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { PsiElement resolved = expression.resolve(); if (resolved == null) return; if (PsiTreeUtil.isAncestor(ctrOrInitializer, resolved, false) && !PsiTreeUtil.isAncestor(initializer, resolved, false)) { - // resolved somewhere inside construcor but outside initializer + // resolved somewhere inside constructor but outside initializer result.set(Boolean.FALSE); } } @@ -97,16 +100,21 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction } } - private static boolean isInitializedWithSameExpression(final PsiField field, final PsiAssignmentExpression assignment, final Collection<PsiAssignmentExpression> initializingAssignments) { + private static boolean isInitializedWithSameExpression(final PsiField field, + final PsiAssignmentExpression assignment, + final Collection<PsiAssignmentExpression> initializingAssignments) { final PsiExpression expression = assignment.getRExpression(); + if (expression == null) return false; + PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) return false; + final Ref<Boolean> result = new Ref<Boolean>(Boolean.TRUE); final List<PsiAssignmentExpression> totalUsages = new ArrayList<PsiAssignmentExpression>(); - PsiClass containingClass = field.getContainingClass(); - assert containingClass != null; - containingClass.accept(new JavaRecursiveElementVisitor(){ + containingClass.accept(new JavaRecursiveElementVisitor() { private PsiCodeBlock currentInitializingBlock; //ctr or class initializer - @Override public void visitCodeBlock(PsiCodeBlock block) { + @Override + public void visitCodeBlock(PsiCodeBlock block) { PsiElement parent = block.getParent(); if (parent instanceof PsiClassInitializer || parent instanceof PsiMethod && ((PsiMethod)parent).isConstructor()) { currentInitializingBlock = block; @@ -118,7 +126,8 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction } } - @Override public void visitReferenceExpression(PsiReferenceExpression reference) { + @Override + public void visitReferenceExpression(PsiReferenceExpression reference) { if (!result.get().booleanValue()) return; super.visitReferenceExpression(reference); if (!PsiUtil.isOnAssignmentLeftHand(reference)) return; @@ -126,7 +135,7 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction if (resolved != field) return; PsiExpression rValue = ((PsiAssignmentExpression)reference.getParent()).getRExpression(); if (currentInitializingBlock != null) { - // ignore usages other than intializing + // ignore usages other than initializing if (rValue == null || !PsiEquivalenceUtil.areElementsEquivalent(rValue, expression)) { result.set(Boolean.FALSE); } @@ -160,13 +169,13 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - final PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file); + PsiAssignmentExpression assignment = getAssignmentUnderCaret(editor, file); if (assignment == null) return; PsiField field = getAssignedField(assignment); if (field == null) return; if (!FileModificationService.getInstance().prepareFileForWrite(file)) return; - ArrayList<PsiAssignmentExpression> assignments = new ArrayList<PsiAssignmentExpression>(); + List<PsiAssignmentExpression> assignments = new ArrayList<PsiAssignmentExpression>(); if (!isInitializedWithSameExpression(field, assignment, assignments)) return; PsiExpression initializer = assignment.getRExpression(); field.setInitializer(initializer); @@ -174,10 +183,10 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction for (PsiAssignmentExpression assignmentExpression : assignments) { PsiElement statement = assignmentExpression.getParent(); PsiElement parent = statement.getParent(); - if (parent instanceof PsiIfStatement - || parent instanceof PsiWhileStatement - || parent instanceof PsiForStatement - || parent instanceof PsiForeachStatement) { + if (parent instanceof PsiIfStatement || + parent instanceof PsiWhileStatement || + parent instanceof PsiForStatement || + parent instanceof PsiForeachStatement) { PsiStatement emptyStatement = JavaPsiFacade.getInstance(file.getProject()).getElementFactory().createStatementFromText(";", statement); statement.replace(emptyStatement); @@ -187,8 +196,7 @@ public class MoveFieldAssignmentToInitializerAction extends BaseIntentionAction } } - EditorColorsManager manager = EditorColorsManager.getInstance(); - TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[] {field.getInitializer()}, attributes, false,null); + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[]{field.getInitializer()}, attributes, false, null); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java index 19f3322cc9eb..550da7277f81 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java @@ -16,7 +16,7 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; +import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.openapi.editor.Editor; @@ -69,7 +69,7 @@ public class MoveInitializerToConstructorAction extends BaseMoveInitializerToMet final Iterator<PsiMethod> iterator = result.iterator(); //noinspection ForLoopThatDoesntUseLoopVariable for (PsiMethod constructor = iterator.next(); iterator.hasNext(); constructor = iterator.next()) { - final List<PsiMethod> chained = HighlightControlFlowUtil.getChainedConstructors(constructor); + final List<PsiMethod> chained = JavaHighlightUtil.getChainedConstructors(constructor); if (chained != null) { iterator.remove(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java index 168d5444ca71..0ccd769911c3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java @@ -34,7 +34,7 @@ class PackageLookupItem extends LookupItem<PsiPackage> { public void handleInsert(InsertionContext context) { super.handleInsert(context); if (getTailType() == TailType.DOT || context.getCompletionChar() == '.') { - AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null); + AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor()); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index 9e89d7ac0126..49befb363437 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -17,7 +17,7 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.completion.*; import com.intellij.diagnostic.LogMessageEx; -import com.intellij.diagnostic.errordialog.Attachment; +import com.intellij.diagnostic.AttachmentFactory; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; @@ -300,7 +300,7 @@ public class PsiTypeLookupItem extends LookupItem { "file.length=" + file.getTextLength() + "\n" + "document=" + context.getDocument() + "\n" + DebugUtil.currentStackTrace(), - new Attachment(context.getDocument()))); + AttachmentFactory.createAttachment(context.getDocument()))); return; } diff --git a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java b/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java deleted file mode 100644 index 354af57cf7d1..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2000-2009 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; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInsight.daemon.impl.RemoveSuppressWarningAction; -import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.reference.*; -import com.intellij.codeInspection.ui.InspectionToolPresentation; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.containers.BidirectionalMap; -import gnu.trove.THashMap; -import gnu.trove.THashSet; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.*; - -/** - * @author cdr - */ -public class RedundantSuppressInspection extends GlobalInspectionTool{ - private BidirectionalMap<String, QuickFix> myQuickFixes = null; - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.RedundantSuppressInspection"); - - public boolean IGNORE_ALL = false; - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getDisplayName() { - return InspectionsBundle.message("inspection.redundant.suppression.name"); - } - - @Override - @NotNull - @NonNls - public String getShortName() { - return "RedundantSuppression"; - } - - @Override - public JComponent createOptionsPanel() { - return new SingleCheckboxOptionsPanel("Ignore @SuppressWarning(\"ALL\")", this, "IGNORE_ALL"); - } - - @Override - public void writeSettings(@NotNull Element node) throws WriteExternalException { - if (IGNORE_ALL) { - super.writeSettings(node); - } - } - - @Override - public void runInspection(@NotNull final AnalysisScope scope, - @NotNull final InspectionManager manager, - @NotNull final GlobalInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor problemDescriptionsProcessor) { - globalContext.getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitClass(@NotNull RefClass refClass) { - if (!globalContext.shouldCheck(refClass, RedundantSuppressInspection.this)) return; - CommonProblemDescriptor[] descriptors = checkElement(refClass, manager, globalContext.getProject()); - if (descriptors != null) { - for (CommonProblemDescriptor descriptor : descriptors) { - if (descriptor instanceof ProblemDescriptor) { - final PsiElement psiElement = ((ProblemDescriptor)descriptor).getPsiElement(); - final PsiMember member = PsiTreeUtil.getParentOfType(psiElement, PsiMember.class); - final RefElement refElement = globalContext.getRefManager().getReference(member); - if (refElement != null) { - problemDescriptionsProcessor.addProblemElement(refElement, descriptor); - continue; - } - } - problemDescriptionsProcessor.addProblemElement(refClass, descriptor); - } - } - } - }); - } - - @Nullable - private CommonProblemDescriptor[] checkElement(@NotNull RefClass refEntity, @NotNull InspectionManager manager, @NotNull Project project) { - final PsiClass psiClass = refEntity.getElement(); - if (psiClass == null) return null; - return checkElement(psiClass, manager, project); - } - - public CommonProblemDescriptor[] checkElement(@NotNull final PsiElement psiElement, @NotNull final InspectionManager manager, @NotNull Project project) { - final Map<PsiElement, Collection<String>> suppressedScopes = new THashMap<PsiElement, Collection<String>>(); - psiElement.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitModifierList(PsiModifierList list) { - super.visitModifierList(list); - final PsiElement parent = list.getParent(); - if (parent instanceof PsiModifierListOwner && !(parent instanceof PsiClass)) { - checkElement(parent); - } - } - - @Override public void visitComment(PsiComment comment) { - checkElement(comment); - } - - @Override public void visitClass(PsiClass aClass) { - if (aClass == psiElement) { - super.visitClass(aClass); - checkElement(aClass); - } - } - - - private void checkElement(final PsiElement owner) { - String idsString = SuppressManager.getInstance().getSuppressedInspectionIdsIn(owner); - if (idsString != null && !idsString.isEmpty()) { - List<String> ids = StringUtil.split(idsString, ","); - if (IGNORE_ALL && (ids.contains(SuppressionUtil.ALL) || ids.contains(SuppressionUtil.ALL.toLowerCase()))) return; - Collection<String> suppressed = suppressedScopes.get(owner); - if (suppressed == null) { - suppressed = ids; - } - else { - for (String id : ids) { - if (!suppressed.contains(id)) { - suppressed.add(id); - } - } - } - suppressedScopes.put(owner, suppressed); - } - } - }); - - if (suppressedScopes.values().isEmpty()) return null; - // have to visit all file from scratch since inspections can be written in any perversive way including checkFile() overriding - Collection<InspectionToolWrapper> suppressedTools = new THashSet<InspectionToolWrapper>(); - InspectionToolWrapper[] toolWrappers = getInspectionTools(psiElement, manager); - for (Collection<String> ids : suppressedScopes.values()) { - for (Iterator<String> iterator = ids.iterator(); iterator.hasNext(); ) { - final String shortName = iterator.next().trim(); - for (InspectionToolWrapper toolWrapper : toolWrappers) { - if (toolWrapper instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)toolWrapper).getTool().getID().equals(shortName)) { - if (((LocalInspectionToolWrapper)toolWrapper).isUnfair()) { - iterator.remove(); - break; - } - else { - suppressedTools.add(toolWrapper); - } - } - else if (toolWrapper.getShortName().equals(shortName)) { - //ignore global unused as it won't be checked anyway - if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper) { - suppressedTools.add(toolWrapper); - } - else { - iterator.remove(); - break; - } - } - } - } - } - - final AnalysisScope scope = new AnalysisScope(psiElement.getContainingFile()); - final InspectionManagerEx inspectionManagerEx = (InspectionManagerEx)InspectionManager.getInstance(project); - final GlobalInspectionContextImpl globalContext = inspectionManagerEx.createNewGlobalContext(false); - globalContext.setCurrentScope(scope); - final RefManagerImpl refManager = (RefManagerImpl)globalContext.getRefManager(); - refManager.inspectionReadActionStarted(); - final List<ProblemDescriptor> result; - try { - result = new ArrayList<ProblemDescriptor>(); - for (InspectionToolWrapper toolWrapper : suppressedTools) { - String toolId = toolWrapper instanceof LocalInspectionToolWrapper ? ((LocalInspectionToolWrapper)toolWrapper).getTool().getID() : toolWrapper.getShortName(); - toolWrapper.initialize(globalContext); - Collection<CommonProblemDescriptor> descriptors; - final InspectionToolPresentation presentation = globalContext.getPresentation(toolWrapper); - if (toolWrapper instanceof LocalInspectionToolWrapper) { - LocalInspectionToolWrapper local = (LocalInspectionToolWrapper)toolWrapper; - if (local.isUnfair()) continue; //cant't work with passes other than LocalInspectionPass - List<ProblemDescriptor> results = local.getTool().processFile(psiElement.getContainingFile(), manager); - InspectionToolPresentation toolPresentation = globalContext.getPresentation(local); - LocalDescriptorsUtil.addProblemDescriptors(results, toolPresentation, false, globalContext, local.getTool()); - descriptors = presentation.getProblemDescriptors(); - } - else if (toolWrapper instanceof GlobalInspectionToolWrapper) { - final GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper)toolWrapper; - GlobalInspectionTool globalTool = global.getTool(); - if (globalTool.isGraphNeeded()) { - refManager.findAllDeclarations(); - } - final InspectionToolPresentation toolPresentation = globalContext.getPresentation(global); - globalContext.getRefManager().iterate(new RefVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { - CommonProblemDescriptor[] - descriptors1 = global.getTool().checkElement(refEntity, scope, manager, globalContext, toolPresentation); - if (descriptors1 != null) { - toolPresentation.addProblemElement(refEntity, false, descriptors1); - } - } - }); - descriptors = presentation.getProblemDescriptors(); - } - else { - continue; - } - for (PsiElement suppressedScope : suppressedScopes.keySet()) { - Collection<String> suppressedIds = suppressedScopes.get(suppressedScope); - if (!suppressedIds.contains(toolId)) continue; - for (CommonProblemDescriptor descriptor : descriptors) { - if (!(descriptor instanceof ProblemDescriptor)) continue; - PsiElement element = ((ProblemDescriptor)descriptor).getPsiElement(); - if (element == null) continue; - PsiElement annotation = SuppressManager.getInstance().getElementToolSuppressedIn(element, toolId); - if (annotation != null && PsiTreeUtil.isAncestor(suppressedScope, annotation, false) || annotation == null && !PsiTreeUtil.isAncestor(suppressedScope, element, false)) { - suppressedIds.remove(toolId); - break; - } - } - } - } - for (PsiElement suppressedScope : suppressedScopes.keySet()) { - Collection<String> suppressedIds = suppressedScopes.get(suppressedScope); - for (String toolId : suppressedIds) { - PsiMember psiMember; - String problemLine = null; - if (suppressedScope instanceof PsiMember) { - psiMember = (PsiMember)suppressedScope; - } - else { - psiMember = PsiTreeUtil.getParentOfType(suppressedScope, PsiDocCommentOwner.class); - final PsiStatement statement = PsiTreeUtil.getNextSiblingOfType(suppressedScope, PsiStatement.class); - problemLine = statement != null ? statement.getText() : null; - } - if (psiMember != null && psiMember.isValid()) { - String description = InspectionsBundle.message("inspection.redundant.suppression.description"); - if (myQuickFixes == null) myQuickFixes = new BidirectionalMap<String, QuickFix>(); - final String key = toolId + (problemLine != null ? ";" + problemLine : ""); - QuickFix fix = myQuickFixes.get(key); - if (fix == null) { - fix = new RemoveSuppressWarningAction(toolId, problemLine); - myQuickFixes.put(key, fix); - } - PsiElement identifier = null; - if (psiMember instanceof PsiMethod) { - identifier = ((PsiMethod)psiMember).getNameIdentifier(); - } - else if (psiMember instanceof PsiField) { - identifier = ((PsiField)psiMember).getNameIdentifier(); - } - else if (psiMember instanceof PsiClass) { - identifier = ((PsiClass)psiMember).getNameIdentifier(); - } - if (identifier == null) { - identifier = psiMember; - } - result.add( - manager.createProblemDescriptor(identifier, description, (LocalQuickFix)fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - false)); - } - } - } - } - finally { - refManager.inspectionReadActionFinished(); - globalContext.close(true); - } - return result.toArray(new ProblemDescriptor[result.size()]); - } - - protected InspectionToolWrapper[] getInspectionTools(PsiElement psiElement, @NotNull InspectionManager manager) { - ModifiableModel model = InspectionProjectProfileManager.getInstance(manager.getProject()).getInspectionProfile().getModifiableModel(); - InspectionProfileWrapper profile = new InspectionProfileWrapper((InspectionProfile)model); - profile.init(manager.getProject()); - - return profile.getInspectionTools(psiElement); - } - - - @Override - @Nullable - public QuickFix getQuickFix(final String hint) { - return myQuickFixes != null ? myQuickFixes.get(hint) : new RemoveSuppressWarningAction(hint); - } - - - @Override - @Nullable - public String getHint(@NotNull final QuickFix fix) { - if (myQuickFixes != null) { - final List<String> list = myQuickFixes.getKeysByValue(fix); - if (list != null) { - LOG.assertTrue(list.size() == 1); - return list.get(0); - } - } - return null; - } - - @Override - public boolean isEnabledByDefault() { - return false; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java index de7f6dcd3228..18ba50a4675f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/SuppressManagerImpl.java @@ -41,7 +41,7 @@ public class SuppressManagerImpl extends SuppressManager { } @NotNull - private static SuppressIntentionAction[] convertBatchToSuppressIntentionActions(@NotNull SuppressQuickFix[] actions) { + public static SuppressIntentionAction[] convertBatchToSuppressIntentionActions(@NotNull SuppressQuickFix[] actions) { return ContainerUtil.map2Array(actions, SuppressIntentionAction.class, new Function<SuppressQuickFix, SuppressIntentionAction>() { @Override public SuppressIntentionAction fun(SuppressQuickFix fix) { diff --git a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java b/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java deleted file mode 100644 index 3b322ff616ee..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2000-2009 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.canBeFinal; - -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; -import com.intellij.codeInspection.reference.*; -import com.intellij.psi.*; -import com.intellij.psi.controlFlow.*; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; - -/** - * User: anna - * Date: 27-Dec-2005 - */ -class CanBeFinalAnnotator extends RefGraphAnnotatorEx { - private final RefManager myManager; - public static int CAN_BE_FINAL_MASK; - - public CanBeFinalAnnotator(@NotNull RefManager manager) { - myManager = manager; - } - - @Override - public void initialize(RefManager refManager) { - CAN_BE_FINAL_MASK = refManager.getLastUsedMask(); - } - - @Override - public void onInitialize(RefElement refElement) { - ((RefElementImpl)refElement).setFlag(true, CAN_BE_FINAL_MASK); - if (refElement instanceof RefClass) { - final RefClass refClass = (RefClass)refElement; - final PsiClass psiClass = refClass.getElement(); - if (refClass.isEntry()) { - ((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK); - return; - } - if (refClass.isAbstract() || refClass.isAnonymous() || refClass.isInterface()) { - ((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK); - return; - } - if (!refClass.isSelfInheritor(psiClass)) { - for (PsiClass psiSuperClass : psiClass.getSupers()) { - if (myManager.belongsToScope(psiSuperClass)) { - RefClass refSuperClass = (RefClass)myManager.getReference(psiSuperClass); - if (refSuperClass != null) { - ((RefClassImpl)refSuperClass).setFlag(false, CAN_BE_FINAL_MASK); - } - } - } - } - } - else if (refElement instanceof RefMethod) { - final RefMethod refMethod = (RefMethod)refElement; - final PsiElement element = refMethod.getElement(); - if (element instanceof PsiMethod) { - PsiMethod psiMethod = (PsiMethod)element; - if (refMethod.isConstructor() || refMethod.isAbstract() || refMethod.isStatic() || - PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) || refMethod.getOwnerClass().isAnonymous() || - refMethod.getOwnerClass().isInterface()) { - ((RefMethodImpl)refMethod).setFlag(false, CAN_BE_FINAL_MASK); - } - if (PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) && refMethod.getOwner() != null && - !(refMethod.getOwnerClass().getOwner() instanceof RefElement)) { - ((RefMethodImpl)refMethod).setFlag(false, CAN_BE_FINAL_MASK); - } - for (PsiMethod psiSuperMethod : psiMethod.findSuperMethods()) { - if (myManager.belongsToScope(psiSuperMethod)) { - RefMethod refSuperMethod = (RefMethod)myManager.getReference(psiSuperMethod); - if (refSuperMethod != null) { - ((RefMethodImpl)refSuperMethod).setFlag(false, CAN_BE_FINAL_MASK); - } - } - } - } - } - } - - - @Override - public void onMarkReferenced(RefElement refWhat, - RefElement refFrom, - boolean referencedFromClassInitializer, - boolean forReading, - boolean forWriting) { - if (!(refWhat instanceof RefField)) return; - if (!(refFrom instanceof RefMethod) || - !((RefMethod)refFrom).isConstructor() || - ((PsiField)refWhat.getElement()).hasInitializer() || - ((RefMethod)refFrom).getOwnerClass() != ((RefField)refWhat).getOwnerClass() || - ((RefField)refWhat).isStatic()) { - if (!referencedFromClassInitializer && forWriting) { - ((RefFieldImpl)refWhat).setFlag(false, CAN_BE_FINAL_MASK); - } - } - } - - @Override - public void onReferencesBuild(RefElement refElement) { - if (refElement instanceof RefClass) { - final PsiClass psiClass = (PsiClass)refElement.getElement(); - if (psiClass != null) { - - if (refElement.isEntry()) { - ((RefClassImpl)refElement).setFlag(false, CAN_BE_FINAL_MASK); - } - - PsiMethod[] psiMethods = psiClass.getMethods(); - PsiField[] psiFields = psiClass.getFields(); - - HashSet<PsiVariable> allFields = new HashSet<PsiVariable>(); - ContainerUtil.addAll(allFields, psiFields); - ArrayList<PsiVariable> instanceInitializerInitializedFields = new ArrayList<PsiVariable>(); - boolean hasInitializers = false; - for (PsiClassInitializer initializer : psiClass.getInitializers()) { - PsiCodeBlock body = initializer.getBody(); - hasInitializers = true; - ControlFlow flow; - try { - flow = ControlFlowFactory.getInstance(body.getProject()) - .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); - } - catch (AnalysisCanceledException e) { - flow = ControlFlow.EMPTY; - } - Collection<PsiVariable> writtenVariables = new ArrayList<PsiVariable>(); - ControlFlowUtil.getWrittenVariables(flow, 0, flow.getSize(), false, writtenVariables); - for (PsiVariable psiVariable : writtenVariables) { - if (allFields.contains(psiVariable)) { - if (instanceInitializerInitializedFields.contains(psiVariable)) { - allFields.remove(psiVariable); - instanceInitializerInitializedFields.remove(psiVariable); - } - else { - instanceInitializerInitializedFields.add(psiVariable); - } - } - } - for (PsiVariable psiVariable : writtenVariables) { - if (!instanceInitializerInitializedFields.contains(psiVariable)) { - allFields.remove(psiVariable); - } - } - } - - for (PsiMethod psiMethod : psiMethods) { - if (psiMethod.isConstructor()) { - PsiCodeBlock body = psiMethod.getBody(); - if (body != null) { - hasInitializers = true; - ControlFlow flow; - try { - flow = ControlFlowFactory.getInstance(body.getProject()) - .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); - } - catch (AnalysisCanceledException e) { - flow = ControlFlow.EMPTY; - } - - Collection<PsiVariable> writtenVariables = ControlFlowUtil.getWrittenVariables(flow, 0, flow.getSize(), false); - for (PsiVariable psiVariable : writtenVariables) { - if (instanceInitializerInitializedFields.contains(psiVariable)) { - allFields.remove(psiVariable); - instanceInitializerInitializedFields.remove(psiVariable); - } - } - List<PsiMethod> redirectedConstructors = HighlightControlFlowUtil.getChainedConstructors(psiMethod); - if (redirectedConstructors == null || redirectedConstructors.isEmpty()) { - List<PsiVariable> ssaVariables = ControlFlowUtil.getSSAVariables(flow); - ArrayList<PsiVariable> good = new ArrayList<PsiVariable>(ssaVariables); - good.addAll(instanceInitializerInitializedFields); - allFields.retainAll(good); - } - else { - allFields.removeAll(writtenVariables); - } - } - } - } - - for (PsiField psiField : psiFields) { - if ((!hasInitializers || !allFields.contains(psiField)) && psiField.getInitializer() == null) { - final RefFieldImpl refField = (RefFieldImpl)myManager.getReference(psiField); - if (refField != null) { - refField.setFlag(false, CAN_BE_FINAL_MASK); - } - } - } - - } - } - else if (refElement instanceof RefMethod) { - final RefMethod refMethod = (RefMethod)refElement; - if (refMethod.isEntry()) { - ((RefMethodImpl)refMethod).setFlag(false, CAN_BE_FINAL_MASK); - } - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java b/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java deleted file mode 100644 index 105bee1c4449..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Dec 24, 2001 - * Time: 2:46:32 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.canBeFinal; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.reference.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; - -public class CanBeFinalInspection extends GlobalJavaInspectionTool { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.canBeFinal.CanBeFinalInspection"); - - public boolean REPORT_CLASSES = false; - public boolean REPORT_METHODS = false; - public boolean REPORT_FIELDS = true; - public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.can.be.final.display.name"); - @NonNls public static final String SHORT_NAME = "CanBeFinal"; - @NonNls private static final String QUICK_FIX_NAME = InspectionsBundle.message("inspection.can.be.final.accept.quickfix"); - - private class OptionsPanel extends JPanel { - private final JCheckBox myReportClassesCheckbox; - private final JCheckBox myReportMethodsCheckbox; - private final JCheckBox myReportFieldsCheckbox; - - private OptionsPanel() { - super(new GridBagLayout()); - - GridBagConstraints gc = new GridBagConstraints(); - gc.weighty = 0; - gc.weightx = 1; - gc.fill = GridBagConstraints.HORIZONTAL; - gc.anchor = GridBagConstraints.NORTHWEST; - - - myReportClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option")); - myReportClassesCheckbox.setSelected(REPORT_CLASSES); - myReportClassesCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_CLASSES = myReportClassesCheckbox.isSelected(); - } - }); - gc.gridy = 0; - add(myReportClassesCheckbox, gc); - - myReportMethodsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option1")); - myReportMethodsCheckbox.setSelected(REPORT_METHODS); - myReportMethodsCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_METHODS = myReportMethodsCheckbox.isSelected(); - } - }); - gc.gridy++; - add(myReportMethodsCheckbox, gc); - - myReportFieldsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option2")); - myReportFieldsCheckbox.setSelected(REPORT_FIELDS); - myReportFieldsCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - REPORT_FIELDS = myReportFieldsCheckbox.isSelected(); - } - }); - - gc.weighty = 1; - gc.gridy++; - add(myReportFieldsCheckbox, gc); - } - } - - public boolean isReportClasses() { - return REPORT_CLASSES; - } - - public boolean isReportMethods() { - return REPORT_METHODS; - } - - public boolean isReportFields() { - return REPORT_FIELDS; - } - - @Override - public JComponent createOptionsPanel() { - return new OptionsPanel(); - } - - @Override - @Nullable - public RefGraphAnnotator getAnnotator(@NotNull final RefManager refManager) { - return new CanBeFinalAnnotator(refManager); - } - - - @Override - @Nullable - public CommonProblemDescriptor[] checkElement(@NotNull final RefEntity refEntity, - @NotNull final AnalysisScope scope, - @NotNull final InspectionManager manager, - @NotNull final GlobalInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor processor) { - if (refEntity instanceof RefJavaElement) { - final RefJavaElement refElement = (RefJavaElement)refEntity; - if (refElement instanceof RefParameter) return null; - if (!refElement.isReferenced()) return null; - if (refElement.isSyntheticJSP()) return null; - if (refElement.isFinal()) return null; - if (!((RefElementImpl)refElement).checkFlag(CanBeFinalAnnotator.CAN_BE_FINAL_MASK)) return null; - - final PsiMember psiMember = (PsiMember)refElement.getElement(); - if (psiMember == null || !CanBeFinalHandler.allowToBeFinal(psiMember)) return null; - - PsiIdentifier psiIdentifier = null; - if (refElement instanceof RefClass) { - RefClass refClass = (RefClass)refElement; - if (refClass.isInterface() || refClass.isAnonymous() || refClass.isAbstract()) return null; - if (!isReportClasses()) return null; - psiIdentifier = ((PsiClass)psiMember).getNameIdentifier(); - } - else if (refElement instanceof RefMethod) { - RefMethod refMethod = (RefMethod)refElement; - if (refMethod.getOwnerClass().isFinal()) return null; - if (!isReportMethods()) return null; - psiIdentifier = ((PsiMethod)psiMember).getNameIdentifier(); - } - else if (refElement instanceof RefField) { - if (!isReportFields()) return null; - psiIdentifier = ((PsiField)psiMember).getNameIdentifier(); - } - - - if (psiIdentifier != null) { - return new ProblemDescriptor[]{manager.createProblemDescriptor(psiIdentifier, InspectionsBundle.message( - "inspection.export.results.can.be.final.description"), new AcceptSuggested(globalContext.getRefManager()), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)}; - } - } - return null; - } - - @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, - @NotNull final GlobalJavaInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor problemsProcessor) { - for (RefElement entryPoint : globalContext.getEntryPointsManager(manager).getEntryPoints()) { - problemsProcessor.ignoreElement(entryPoint); - } - - manager.iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { - if (problemsProcessor.getDescriptions(refEntity) == null) return; - refEntity.accept(new RefJavaVisitor() { - @Override public void visitMethod(@NotNull final RefMethod refMethod) { - if (!refMethod.isStatic() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) && - !(refMethod instanceof RefImplicitConstructor)) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - ((RefElementImpl)refMethod).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); - problemsProcessor.ignoreElement(refMethod); - return false; - } - }); - } - } - - @Override public void visitClass(@NotNull final RefClass refClass) { - if (!refClass.isAnonymous()) { - globalContext.enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { - @Override - public boolean process(PsiClass inheritor) { - ((RefClassImpl)refClass).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); - problemsProcessor.ignoreElement(refClass); - return false; - } - }); - } - } - - @Override public void visitField(@NotNull final RefField refField) { - globalContext.enqueueFieldUsagesProcessor(refField, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - PsiElement expression = psiReference.getElement(); - if (expression instanceof PsiReferenceExpression && PsiUtil.isAccessedForWriting((PsiExpression)expression)) { - ((RefFieldImpl)refField).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); - problemsProcessor.ignoreElement(refField); - return false; - } - return true; - } - }); - } - }); - - } - }); - - return false; - } - - - @Override - @Nullable - public QuickFix getQuickFix(final String hint) { - return new AcceptSuggested(null); - } - - @Override - @NotNull - public String getDisplayName() { - return DISPLAY_NAME; - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getShortName() { - return SHORT_NAME; - } - - private static class AcceptSuggested implements LocalQuickFix { - private final RefManager myManager; - - public AcceptSuggested(final RefManager manager) { - myManager = manager; - } - - @Override - @NotNull - public String getName() { - return QUICK_FIX_NAME; - } - - @Override - @NotNull - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - if (!FileModificationService.getInstance().preparePsiElementForWrite(descriptor.getPsiElement())) return; - final PsiElement element = descriptor.getPsiElement(); - final PsiModifierListOwner psiElement = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class); - if (psiElement != null) { - RefJavaElement refElement = (RefJavaElement)(myManager != null ? myManager.getReference(psiElement) : null); - try { - if (psiElement instanceof PsiVariable) { - ((PsiVariable)psiElement).normalizeDeclaration(); - } - final PsiModifierList modifierList = psiElement.getModifierList(); - LOG.assertTrue(modifierList != null); - modifierList.setModifierProperty(PsiModifier.FINAL, true); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - - if (refElement != null) { - RefJavaUtil.getInstance().setIsFinal(refElement, true); - } - } - } - } - -} diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index c22571a65287..8943e59c4192 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -47,6 +47,7 @@ public class DataFlowInspection extends DataFlowInspectionBase { private class OptionsPanel extends JPanel { private final JCheckBox myIgnoreAssertions; + private final JCheckBox myReportConstantReferences; private final JCheckBox mySuggestNullables; private final JCheckBox myDontReportTrueAsserts; @@ -88,6 +89,15 @@ public class DataFlowInspection extends DataFlowInspectionBase { } }); + myReportConstantReferences = new JCheckBox("Warn when reading a value guaranteed to be constant"); + myReportConstantReferences.setSelected(REPORT_CONSTANT_REFERENCE_VALUES); + myReportConstantReferences.getModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + REPORT_CONSTANT_REFERENCE_VALUES = myReportConstantReferences.isSelected(); + } + }); + gc.insets = new Insets(0, 0, 0, 0); gc.gridy = 0; add(mySuggestNullables, gc); @@ -134,6 +144,9 @@ public class DataFlowInspection extends DataFlowInspectionBase { gc.gridy++; add(myIgnoreAssertions, gc); + + gc.gridy++; + add(myReportConstantReferences, gc); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsEP.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsEP.java new file mode 100644 index 000000000000..01f982f07b45 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsEP.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 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.deadCode; + +import com.intellij.codeInspection.InspectionEP; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.codeInspection.InspectionsBundle; +import org.jetbrains.annotations.NotNull; + +public class DummyEntryPointsEP extends InspectionEP { + public DummyEntryPointsEP() { + presentation = DummyEntryPointsPresentation.class.getName(); + displayName = InspectionsBundle.message("inspection.dead.code.entry.points.display.name"); + implementationClass = ""; + shortName = ""; + } + + @NotNull + @Override + public InspectionProfileEntry instantiateTool() { + return new DummyEntryPointsTool(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java index 531c88c03f62..04fe0f2125d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.deadCode; +import com.intellij.codeInspection.GlobalJavaInspectionContext; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.reference.RefElement; @@ -28,8 +29,8 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation private static final RefEntryPointFilter myFilter = new RefEntryPointFilter(); private QuickFixAction[] myQuickFixActions; - public DummyEntryPointsPresentation(UnusedDeclarationInspection inspection, @NotNull InspectionToolWrapper toolWrapper) { - super(toolWrapper); + public DummyEntryPointsPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) { + super(toolWrapper, context); } @Override @@ -51,9 +52,9 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation } @Override - protected boolean applyFix(RefEntity[] refElements) { + protected boolean applyFix(@NotNull RefEntity[] refElements) { final EntryPointsManager entryPointsManager = - getContext().getExtension(GlobalJavaInspectionContextImpl.CONTEXT).getEntryPointsManager(getContext().getRefManager()); + getContext().getExtension(GlobalJavaInspectionContext.CONTEXT).getEntryPointsManager(getContext().getRefManager()); for (RefEntity refElement : refElements) { if (refElement instanceof RefElement) { entryPointsManager.removeEntryPoint((RefElement)refElement); diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java index 524f3338fad1..2b216dc844de 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java @@ -20,17 +20,14 @@ import com.intellij.codeInspection.GlobalInspectionContext; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ProblemDescriptionsProcessor; -import com.intellij.codeInspection.ex.InspectionPresentationProvider; -import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ex.JobDescriptor; -import com.intellij.codeInspection.ui.InspectionToolPresentation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author max */ -public class DummyEntryPointsTool extends UnusedDeclarationInspection implements InspectionPresentationProvider { +public class DummyEntryPointsTool extends UnusedDeclarationInspection { public DummyEntryPointsTool() { } @@ -64,10 +61,4 @@ public class DummyEntryPointsTool extends UnusedDeclarationInspection implements public String getShortName() { return ""; } - - @NotNull - @Override - public InspectionToolPresentation createPresentation(@NotNull InspectionToolWrapper toolWrapper) { - return new DummyEntryPointsPresentation(this, toolWrapper); - } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefEntryPointFilter.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/RefEntryPointFilter.java index 02731b765fbc..03ab97994afd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefEntryPointFilter.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/RefEntryPointFilter.java @@ -27,10 +27,11 @@ package com.intellij.codeInspection.deadCode; import com.intellij.codeInspection.reference.RefJavaElement; import com.intellij.codeInspection.reference.RefParameter; import com.intellij.codeInspection.util.RefFilter; +import org.jetbrains.annotations.NotNull; public class RefEntryPointFilter extends RefFilter { @Override - public int getElementProblemCount(RefJavaElement refElement) { + public int getElementProblemCount(@NotNull RefJavaElement refElement) { if (refElement instanceof RefParameter) return 0; return refElement.isEntry() && !refElement.isSyntheticJSP() ? 1 : 0; } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java deleted file mode 100644 index b00d7490ecc7..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Dec 2, 2001 - * Time: 12:07:30 AM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.deadCode; - -import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; -import com.intellij.codeInspection.reference.*; -import com.intellij.codeInspection.util.RefFilter; -import org.jetbrains.annotations.NotNull; - -public class RefUnreachableFilter extends RefFilter { - @NotNull - protected UnusedDeclarationInspection myTool; - @NotNull protected final GlobalInspectionContextImpl myContext; - - public RefUnreachableFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { - myTool = tool; - myContext = context; - } - - @Override - public int getElementProblemCount(RefJavaElement refElement) { - if (refElement instanceof RefParameter) return 0; - if (refElement.isSyntheticJSP()) return 0; - if (!(refElement instanceof RefMethod || refElement instanceof RefClass || refElement instanceof RefField)) return 0; - if (!myContext.isToCheckMember(refElement, myTool)) return 0; - return ((RefElementImpl)refElement).isSuspicious() ? 1 : 0; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java deleted file mode 100644 index 923e5777f6d1..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Dec 2, 2001 - * Time: 12:14:37 AM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.deadCode; - -import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; -import com.intellij.codeInspection.reference.*; -import org.jetbrains.annotations.NotNull; - -public class UnreferencedFilter extends RefUnreachableFilter { - public UnreferencedFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { - super(tool, context); - } - - @Override - public int getElementProblemCount(RefJavaElement refElement) { - if (refElement instanceof RefParameter) return 0; - if (refElement.isEntry() || !((RefElementImpl)refElement).isSuspicious() || refElement.isSyntheticJSP()) return 0; - - if (!(refElement instanceof RefMethod || refElement instanceof RefClass || refElement instanceof RefField)) return 0; - if (!myContext.isToCheckMember(refElement, myTool)) return 0; - - if (refElement instanceof RefField) { - RefField refField = (RefField) refElement; - if (refField.isUsedForReading() && !refField.isUsedForWriting()) return 1; - if (refField.isUsedForWriting() && !refField.isUsedForReading()) return 1; - } - - if (refElement instanceof RefClass && ((RefClass)refElement).isAnonymous()) return 0; - return -1; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java deleted file mode 100644 index 7799cc205f67..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Oct 12, 2001 - * Time: 9:40:45 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ - -package com.intellij.codeInspection.deadCode; - -import com.intellij.ExtensionPoints; -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInsight.daemon.ImplicitUsageProvider; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtilBase; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.reference.*; -import com.intellij.codeInspection.ui.InspectionToolPresentation; -import com.intellij.codeInspection.util.RefFilter; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPoint; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.WriteExternalException; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiClassImplUtil; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.psi.util.PsiMethodUtil; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.SeparatorFactory; -import com.intellij.util.containers.HashMap; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.*; -import java.util.List; - -public class UnusedDeclarationInspection extends GlobalInspectionTool implements InspectionPresentationProvider { - public boolean ADD_MAINS_TO_ENTRIES = true; - - public boolean ADD_APPLET_TO_ENTRIES = true; - public boolean ADD_SERVLET_TO_ENTRIES = true; - public boolean ADD_NONJAVA_TO_ENTRIES = true; - - private Set<RefElement> myProcessedSuspicious = null; - private int myPhase; - public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.dead.code.display.name"); - @NonNls public static final String SHORT_NAME = "UnusedDeclaration"; - @NonNls private static final String ALTERNATIVE_ID = "unused"; - - public final EntryPoint[] myExtensions; - private static final Logger LOG = Logger.getInstance("#" + UnusedDeclarationInspection.class.getName()); - private GlobalInspectionContextImpl myContext; - - public UnusedDeclarationInspection() { - ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); - final EntryPoint[] deadCodeAddins = new EntryPoint[point.getExtensions().length]; - EntryPoint[] extensions = point.getExtensions(); - for (int i = 0, extensionsLength = extensions.length; i < extensionsLength; i++) { - EntryPoint entryPoint = extensions[i]; - try { - deadCodeAddins[i] = entryPoint.clone(); - } - catch (CloneNotSupportedException e) { - LOG.error(e); - } - } - Arrays.sort(deadCodeAddins, new Comparator<EntryPoint>() { - @Override - public int compare(final EntryPoint o1, final EntryPoint o2) { - return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); - } - }); - myExtensions = deadCodeAddins; - } - - private GlobalInspectionContextImpl getContext() { - return myContext; - } - - private class OptionsPanel extends JPanel { - private final JCheckBox myMainsCheckbox; - private final JCheckBox myAppletToEntries; - private final JCheckBox myServletToEntries; - private final JCheckBox myNonJavaCheckbox; - - private OptionsPanel() { - super(new GridBagLayout()); - GridBagConstraints gc = new GridBagConstraints(); - gc.weightx = 1; - gc.weighty = 0; - gc.insets = new Insets(0, IdeBorderFactory.TITLED_BORDER_INDENT, 2, 0); - gc.fill = GridBagConstraints.HORIZONTAL; - gc.anchor = GridBagConstraints.NORTHWEST; - - myMainsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option")); - myMainsCheckbox.setSelected(ADD_MAINS_TO_ENTRIES); - myMainsCheckbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ADD_MAINS_TO_ENTRIES = myMainsCheckbox.isSelected(); - } - }); - - gc.gridy = 0; - add(myMainsCheckbox, gc); - - myAppletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option3")); - myAppletToEntries.setSelected(ADD_APPLET_TO_ENTRIES); - myAppletToEntries.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ADD_APPLET_TO_ENTRIES = myAppletToEntries.isSelected(); - } - }); - gc.gridy++; - add(myAppletToEntries, gc); - - myServletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option4")); - myServletToEntries.setSelected(ADD_SERVLET_TO_ENTRIES); - myServletToEntries.addActionListener(new ActionListener(){ - @Override - public void actionPerformed(ActionEvent e) { - ADD_SERVLET_TO_ENTRIES = myServletToEntries.isSelected(); - } - }); - gc.gridy++; - add(myServletToEntries, gc); - - for (final EntryPoint extension : myExtensions) { - if (extension.showUI()) { - final JCheckBox extCheckbox = new JCheckBox(extension.getDisplayName()); - extCheckbox.setSelected(extension.isSelected()); - extCheckbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - extension.setSelected(extCheckbox.isSelected()); - } - }); - gc.gridy++; - add(extCheckbox, gc); - } - } - - myNonJavaCheckbox = - new JCheckBox(InspectionsBundle.message("inspection.dead.code.option5")); - myNonJavaCheckbox.setSelected(ADD_NONJAVA_TO_ENTRIES); - myNonJavaCheckbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ADD_NONJAVA_TO_ENTRIES = myNonJavaCheckbox.isSelected(); - } - }); - - gc.gridy++; - add(myNonJavaCheckbox, gc); - - final JButton configureAnnotations = EntryPointsManagerImpl.createConfigureAnnotationsBtn(this); - gc.fill = GridBagConstraints.NONE; - gc.gridy++; - gc.insets.top = 10; - gc.weighty = 1; - - add(configureAnnotations, gc); - } - } - - @Override - public JComponent createOptionsPanel() { - final JPanel scrollPane = new JPanel(new BorderLayout()); - scrollPane.add(SeparatorFactory.createSeparator("Entry points", null), BorderLayout.NORTH); - scrollPane.add(new OptionsPanel(), BorderLayout.CENTER); - return scrollPane; - } - - private boolean isAddMainsEnabled() { - return ADD_MAINS_TO_ENTRIES; - } - - private boolean isAddAppletEnabled() { - return ADD_APPLET_TO_ENTRIES; - } - - private boolean isAddServletEnabled() { - return ADD_SERVLET_TO_ENTRIES; - } - - private boolean isAddNonJavaUsedEnabled() { - return ADD_NONJAVA_TO_ENTRIES; - } - - @Override - @NotNull - public String getDisplayName() { - return DISPLAY_NAME; - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getShortName() { - return SHORT_NAME; - } - - @Override - public void readSettings(@NotNull Element node) throws InvalidDataException { - super.readSettings(node); - for (EntryPoint extension : myExtensions) { - extension.readExternal(node); - } - } - - @Override - public void writeSettings(@NotNull Element node) throws WriteExternalException { - super.writeSettings(node); - for (EntryPoint extension : myExtensions) { - extension.writeExternal(node); - } - } - - private static boolean isExternalizableNoParameterConstructor(PsiMethod method, RefClass refClass) { - if (!method.isConstructor()) return false; - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false; - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != 0) return false; - final PsiClass aClass = method.getContainingClass(); - return aClass == null || isExternalizable(aClass, refClass); - } - - private static boolean isSerializationImplicitlyUsedField(PsiField field) { - @NonNls final String name = field.getName(); - if (!HighlightUtilBase.SERIAL_VERSION_UID_FIELD_NAME.equals(name) && !"serialPersistentFields".equals(name)) return false; - if (!field.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = field.getContainingClass(); - return aClass == null || isSerializable(aClass, null); - } - - private static boolean isWriteObjectMethod(PsiMethod method, RefClass refClass) { - @NonNls final String name = method.getName(); - if (!"writeObject".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 1) return false; - if (!parameters[0].getType().equalsToText("java.io.ObjectOutputStream")) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); - return !(aClass != null && !isSerializable(aClass, refClass)); - } - - private static boolean isReadObjectMethod(PsiMethod method, RefClass refClass) { - @NonNls final String name = method.getName(); - if (!"readObject".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 1) return false; - if (!parameters[0].getType().equalsToText("java.io.ObjectInputStream")) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); - return !(aClass != null && !isSerializable(aClass, refClass)); - } - - private static boolean isWriteReplaceMethod(PsiMethod method, RefClass refClass) { - @NonNls final String name = method.getName(); - if (!"writeReplace".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 0) return false; - if (!method.getReturnType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); - return !(aClass != null && !isSerializable(aClass, refClass)); - } - - private static boolean isReadResolveMethod(PsiMethod method, RefClass refClass) { - @NonNls final String name = method.getName(); - if (!"readResolve".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 0) return false; - if (!method.getReturnType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - final PsiClass aClass = method.getContainingClass(); - return !(aClass != null && !isSerializable(aClass, refClass)); - } - - private static boolean isSerializable(PsiClass aClass, @Nullable RefClass refClass) { - final PsiClass serializableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.io.Serializable", aClass.getResolveScope()); - return serializableClass != null && isSerializable(aClass, refClass, serializableClass); - } - - private static boolean isExternalizable(PsiClass aClass, RefClass refClass) { - final GlobalSearchScope scope = aClass.getResolveScope(); - final PsiClass externalizableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.io.Externalizable", scope); - return externalizableClass != null && isSerializable(aClass, refClass, externalizableClass); - } - - private static boolean isSerializable(PsiClass aClass, RefClass refClass, PsiClass serializableClass) { - if (aClass == null) return false; - if (aClass.isInheritor(serializableClass, true)) return true; - if (refClass != null) { - final Set<RefClass> subClasses = refClass.getSubClasses(); - for (RefClass subClass : subClasses) { - if (isSerializable(subClass.getElement(), subClass, serializableClass)) return true; - } - } - return false; - } - - @Override - public void runInspection(@NotNull final AnalysisScope scope, - @NotNull InspectionManager manager, - @NotNull final GlobalInspectionContext globalContext, - @NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) { - globalContext.getRefManager().iterate(new RefJavaVisitor() { - @Override - public void visitElement(@NotNull final RefEntity refEntity) { - if (refEntity instanceof RefJavaElement) { - final RefElementImpl refElement = (RefElementImpl)refEntity; - if (!refElement.isSuspicious()) return; - - PsiFile file = refElement.getContainingFile(); - - if (file == null) return; - final boolean isSuppressed = refElement.isSuppressed(getShortName(), ALTERNATIVE_ID); - if (!((GlobalInspectionContextImpl)globalContext).isToCheckFile(file, UnusedDeclarationInspection.this) || isSuppressed) { - if (isSuppressed || !scope.contains(file)) { - getEntryPointsManager().addEntryPoint(refElement, false); - } - return; - } - - refElement.accept(new RefJavaVisitor() { - @Override - public void visitMethod(@NotNull RefMethod method) { - if (isAddMainsEnabled() && method.isAppMain()) { - getEntryPointsManager().addEntryPoint(method, false); - } - } - - @Override - public void visitClass(@NotNull RefClass aClass) { - if (isAddAppletEnabled() && aClass.isApplet() || - isAddServletEnabled() && aClass.isServlet()) { - getEntryPointsManager().addEntryPoint(aClass, false); - } - } - }); - } - } - }); - - if (isAddNonJavaUsedEnabled()) { - checkForReachables(); - final StrictUnreferencedFilter strictUnreferencedFilter = new StrictUnreferencedFilter(this, - (GlobalInspectionContextImpl)globalContext); - ProgressManager.getInstance().runProcess(new Runnable() { - @Override - public void run() { - final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(globalContext.getRefManager().getProject()); - globalContext.getRefManager().iterate(new RefJavaVisitor() { - @Override - public void visitElement(@NotNull final RefEntity refEntity) { - if (refEntity instanceof RefClass && strictUnreferencedFilter.accepts((RefClass)refEntity)) { - findExternalClassReferences((RefClass)refEntity); - } - else if (refEntity instanceof RefMethod) { - RefMethod refMethod = (RefMethod)refEntity; - if (refMethod.isConstructor() && strictUnreferencedFilter.accepts(refMethod)) { - findExternalClassReferences(refMethod.getOwnerClass()); - } - } - } - - private void findExternalClassReferences(final RefClass refElement) { - PsiClass psiClass = refElement.getElement(); - String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName != null) { - helper.processUsagesInNonJavaFiles(qualifiedName, - new PsiNonJavaFileReferenceProcessor() { - @Override - public boolean process(PsiFile file, int startOffset, int endOffset) { - getEntryPointsManager().addEntryPoint(refElement, false); - return false; - } - }, - GlobalSearchScope.projectScope(globalContext.getProject())); - } - } - }); - } - }, null); - } - - myProcessedSuspicious = new HashSet<RefElement>(); - myPhase = 1; - } - - public boolean isEntryPoint(final RefElement owner) { - final PsiElement element = owner.getElement(); - if (RefUtil.isImplicitUsage(element)) return true; - if (element instanceof PsiModifierListOwner) { - final EntryPointsManagerImpl entryPointsManager = EntryPointsManagerImpl.getInstance(element.getProject()); - if (entryPointsManager.isEntryPoint((PsiModifierListOwner)element)) { - return true; - } - } - for (EntryPoint extension : myExtensions) { - if (extension.isEntryPoint(owner, element)) { - return true; - } - } - return false; - } - - public boolean isEntryPoint(@NotNull PsiElement element) { - final Project project = element.getProject(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - if (element instanceof PsiMethod && isAddMainsEnabled() && PsiClassImplUtil.isMainOrPremainMethod((PsiMethod)element)) { - return true; - } - if (element instanceof PsiClass) { - PsiClass aClass = (PsiClass)element; - /* - if (aClass.isAnnotationType()) { - return true; - } - - if (aClass.isEnum()) { - return true; - } - */ - final PsiClass applet = psiFacade.findClass("java.applet.Applet", GlobalSearchScope.allScope(project)); - if (isAddAppletEnabled() && applet != null && aClass.isInheritor(applet, true)) { - return true; - } - - final PsiClass servlet = psiFacade.findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project)); - if (isAddServletEnabled() && servlet != null && aClass.isInheritor(servlet, true)) { - return true; - } - if (isAddMainsEnabled() && PsiMethodUtil.hasMainMethod(aClass)) return true; - } - if (element instanceof PsiModifierListOwner) { - final EntryPointsManagerImpl entryPointsManager = EntryPointsManagerImpl.getInstance(project); - if (AnnotationUtil - .checkAnnotatedUsingPatterns((PsiModifierListOwner)element, entryPointsManager.ADDITIONAL_ANNOTATIONS) || - AnnotationUtil - .checkAnnotatedUsingPatterns((PsiModifierListOwner)element, entryPointsManager.getAdditionalAnnotations())) { - return true; - } - } - for (EntryPoint extension : myExtensions) { - if (extension.isEntryPoint(element)) { - return true; - } - } - final ImplicitUsageProvider[] implicitUsageProviders = Extensions.getExtensions(ImplicitUsageProvider.EP_NAME); - for (ImplicitUsageProvider provider : implicitUsageProviders) { - if (provider.isImplicitUsage(element)) return true; - } - return false; - } - - - private static class StrictUnreferencedFilter extends UnreferencedFilter { - private StrictUnreferencedFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { - super(tool, context); - } - - @Override - public int getElementProblemCount(RefJavaElement refElement) { - final int problemCount = super.getElementProblemCount(refElement); - if (problemCount > -1) return problemCount; - return refElement.isReferenced() ? 0 : 1; - } - } - - @Override - public boolean queryExternalUsagesRequests(@NotNull InspectionManager manager, - @NotNull GlobalInspectionContext globalContext, - @NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) { - checkForReachables(); - final RefFilter filter = myPhase == 1 ? new StrictUnreferencedFilter(this, (GlobalInspectionContextImpl)globalContext) : - new RefUnreachableFilter(this, (GlobalInspectionContextImpl)globalContext); - final boolean[] requestAdded = {false}; - - globalContext.getRefManager().iterate(new RefJavaVisitor() { - @Override - public void visitElement(@NotNull RefEntity refEntity) { - if (!(refEntity instanceof RefJavaElement)) return; - if (refEntity instanceof RefClass && ((RefClass)refEntity).isAnonymous()) return; - RefJavaElement refElement = (RefJavaElement)refEntity; - if (filter.accepts(refElement) && !myProcessedSuspicious.contains(refElement)) { - refEntity.accept(new RefJavaVisitor() { - @Override - public void visitField(@NotNull final RefField refField) { - myProcessedSuspicious.add(refField); - PsiField psiField = refField.getElement(); - if (isSerializationImplicitlyUsedField(psiField)) { - getEntryPointsManager().addEntryPoint(refField, false); - } - else { - getJavaContext().enqueueFieldUsagesProcessor(refField, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - getEntryPointsManager().addEntryPoint(refField, false); - return false; - } - }); - requestAdded[0] = true; - } - } - - @Override - public void visitMethod(@NotNull final RefMethod refMethod) { - myProcessedSuspicious.add(refMethod); - if (refMethod instanceof RefImplicitConstructor) { - visitClass(refMethod.getOwnerClass()); - } - else { - PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); - if (isSerializablePatternMethod(psiMethod, refMethod.getOwnerClass())) { - getEntryPointsManager().addEntryPoint(refMethod, false); - } - else if (!refMethod.isExternalOverride() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier())) { - for (final RefMethod derivedMethod : refMethod.getDerivedMethods()) { - myProcessedSuspicious.add(derivedMethod); - } - - enqueueMethodUsages(refMethod); - requestAdded[0] = true; - } - } - } - - @Override - public void visitClass(@NotNull final RefClass refClass) { - myProcessedSuspicious.add(refClass); - if (!refClass.isAnonymous()) { - getJavaContext().enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { - @Override - public boolean process(PsiClass inheritor) { - getEntryPointsManager().addEntryPoint(refClass, false); - return false; - } - }); - - getJavaContext().enqueueClassUsagesProcessor(refClass, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - getEntryPointsManager().addEntryPoint(refClass, false); - return false; - } - }); - requestAdded[0] = true; - } - } - }); - } - } - }); - - if (!requestAdded[0]) { - if (myPhase == 2) { - myProcessedSuspicious = null; - return false; - } - else { - myPhase = 2; - } - } - - return true; - } - - private static boolean isSerializablePatternMethod(PsiMethod psiMethod, RefClass refClass) { - return isReadObjectMethod(psiMethod, refClass) || isWriteObjectMethod(psiMethod, refClass) || isReadResolveMethod(psiMethod, refClass) || - isWriteReplaceMethod(psiMethod, refClass) || isExternalizableNoParameterConstructor(psiMethod, refClass); - } - - private void enqueueMethodUsages(final RefMethod refMethod) { - if (refMethod.getSuperMethods().isEmpty()) { - getJavaContext().enqueueMethodUsagesProcessor(refMethod, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - getEntryPointsManager().addEntryPoint(refMethod, false); - return false; - } - }); - } - else { - for (RefMethod refSuper : refMethod.getSuperMethods()) { - enqueueMethodUsages(refSuper); - } - } - } - - private GlobalJavaInspectionContext getJavaContext() { - return getContext().getExtension(GlobalJavaInspectionContext.CONTEXT); - } - - @Nullable - @Override - public JobDescriptor[] getAdditionalJobs() { - return new JobDescriptor[]{getContext().getStdJobDescriptors().BUILD_GRAPH, getContext().getStdJobDescriptors().FIND_EXTERNAL_USAGES}; - } - - - void checkForReachables() { - CodeScanner codeScanner = new CodeScanner(); - - // Cleanup previous reachability information. - getContext().getRefManager().iterate(new RefJavaVisitor() { - @Override - public void visitElement(@NotNull RefEntity refEntity) { - if (refEntity instanceof RefJavaElement) { - final RefJavaElementImpl refElement = (RefJavaElementImpl)refEntity; - if (!getContext().isToCheckMember(refElement, UnusedDeclarationInspection.this)) return; - refElement.setReachable(false); - } - } - }); - - - for (RefElement entry : getEntryPointsManager().getEntryPoints()) { - entry.accept(codeScanner); - } - - while (codeScanner.newlyInstantiatedClassesCount() != 0) { - codeScanner.cleanInstantiatedClassesCount(); - codeScanner.processDelayedMethods(); - } - } - - private EntryPointsManager getEntryPointsManager() { - return getContext().getExtension(GlobalJavaInspectionContext.CONTEXT).getEntryPointsManager(getContext().getRefManager()); - } - - private static class CodeScanner extends RefJavaVisitor { - private final HashMap<RefClass, HashSet<RefMethod>> myClassIDtoMethods; - private final HashSet<RefClass> myInstantiatedClasses; - private int myInstantiatedClassesCount; - private final HashSet<RefMethod> myProcessedMethods; - - private CodeScanner() { - myClassIDtoMethods = new HashMap<RefClass, HashSet<RefMethod>>(); - myInstantiatedClasses = new HashSet<RefClass>(); - myProcessedMethods = new HashSet<RefMethod>(); - myInstantiatedClassesCount = 0; - } - - @Override public void visitMethod(@NotNull RefMethod method) { - if (!myProcessedMethods.contains(method)) { - // Process class's static intitializers - if (method.isStatic() || method.isConstructor()) { - if (method.isConstructor()) { - addInstantiatedClass(method.getOwnerClass()); - } - else { - ((RefClassImpl)method.getOwnerClass()).setReachable(true); - } - myProcessedMethods.add(method); - makeContentReachable((RefJavaElementImpl)method); - makeClassInitializersReachable(method.getOwnerClass()); - } - else { - if (isClassInstantiated(method.getOwnerClass())) { - myProcessedMethods.add(method); - makeContentReachable((RefJavaElementImpl)method); - } - else { - addDelayedMethod(method); - } - - for (RefMethod refSub : method.getDerivedMethods()) { - visitMethod(refSub); - } - } - } - } - - @Override public void visitClass(@NotNull RefClass refClass) { - boolean alreadyActive = refClass.isReachable(); - ((RefClassImpl)refClass).setReachable(true); - - if (!alreadyActive) { - // Process class's static intitializers. - makeClassInitializersReachable(refClass); - } - - addInstantiatedClass(refClass); - } - - @Override public void visitField(@NotNull RefField field) { - // Process class's static intitializers. - if (!field.isReachable()) { - makeContentReachable((RefJavaElementImpl)field); - makeClassInitializersReachable(field.getOwnerClass()); - } - } - - private void addInstantiatedClass(RefClass refClass) { - if (myInstantiatedClasses.add(refClass)) { - ((RefClassImpl)refClass).setReachable(true); - myInstantiatedClassesCount++; - - final List<RefMethod> refMethods = refClass.getLibraryMethods(); - for (RefMethod refMethod : refMethods) { - refMethod.accept(this); - } - for (RefClass baseClass : refClass.getBaseClasses()) { - addInstantiatedClass(baseClass); - } - } - } - - private void makeContentReachable(RefJavaElementImpl refElement) { - refElement.setReachable(true); - for (RefElement refCallee : refElement.getOutReferences()) { - refCallee.accept(this); - } - } - - private void makeClassInitializersReachable(RefClass refClass) { - for (RefElement refCallee : refClass.getOutReferences()) { - refCallee.accept(this); - } - } - - private void addDelayedMethod(RefMethod refMethod) { - HashSet<RefMethod> methods = myClassIDtoMethods.get(refMethod.getOwnerClass()); - if (methods == null) { - methods = new HashSet<RefMethod>(); - myClassIDtoMethods.put(refMethod.getOwnerClass(), methods); - } - methods.add(refMethod); - } - - private boolean isClassInstantiated(RefClass refClass) { - return myInstantiatedClasses.contains(refClass); - } - - private int newlyInstantiatedClassesCount() { - return myInstantiatedClassesCount; - } - - private void cleanInstantiatedClassesCount() { - myInstantiatedClassesCount = 0; - } - - private void processDelayedMethods() { - RefClass[] instClasses = myInstantiatedClasses.toArray(new RefClass[myInstantiatedClasses.size()]); - for (RefClass refClass : instClasses) { - if (isClassInstantiated(refClass)) { - HashSet<RefMethod> methods = myClassIDtoMethods.get(refClass); - if (methods != null) { - RefMethod[] arMethods = methods.toArray(new RefMethod[methods.size()]); - for (RefMethod arMethod : arMethods) { - arMethod.accept(this); - } - } - } - } - } - } - - - @NotNull - @Override - public InspectionToolPresentation createPresentation(@NotNull InspectionToolWrapper toolWrapper) { - return new UnusedDeclarationPresentation(toolWrapper); - } - - @Override - public void initialize(@NotNull GlobalInspectionContext context) { - super.initialize(context); - myContext = (GlobalInspectionContextImpl)context; - } - - @Override - public void cleanup() { - super.cleanup(); - myContext = null; - } - - @Override - public boolean isGraphNeeded() { - return true; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 29f0578073ff..0db0532cac90 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -65,9 +65,10 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta @NonNls private static final String COMMENT = "comment"; @NonNls private static final String [] HINTS = {COMMENT, DELETE}; - public UnusedDeclarationPresentation(@NotNull InspectionToolWrapper toolWrapper) { - super(toolWrapper); + public UnusedDeclarationPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) { + super(toolWrapper, context); myQuickFixActions = createQuickFixes(toolWrapper); + ((EntryPointsManagerBase)getEntryPointsManager()).setAddNonJavaEntries(getTool().ADD_NONJAVA_TO_ENTRIES); } public RefFilter getFilter() { @@ -82,7 +83,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - public int getElementProblemCount(final RefJavaElement refElement) { + public int getElementProblemCount(@NotNull final RefJavaElement refElement) { final int problemCount = super.getElementProblemCount(refElement); if (problemCount > - 1) return problemCount; if (!((RefElementImpl)refElement).hasSuspiciousCallers() || ((RefJavaElementImpl)refElement).isSuspiciousRecursive()) return 1; @@ -91,7 +92,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @NotNull - UnusedDeclarationInspection getTool() { + private UnusedDeclarationInspection getTool() { return (UnusedDeclarationInspection)getToolWrapper().getTool(); } @@ -162,7 +163,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - protected boolean applyFix(final RefEntity[] refElements) { + protected boolean applyFix(@NotNull final RefEntity[] refElements) { if (!super.applyFix(refElements)) return false; final ArrayList<PsiElement> psiElements = new ArrayList<PsiElement>(); for (RefEntity refElement : refElements) { @@ -176,6 +177,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta @Override public void run() { final Project project = getContext().getProject(); + if (isDisposed() || project.isDisposed()) return; SafeDeleteHandler.invoke(project, PsiUtilCore.toPsiElementArray(psiElements), false, new Runnable() { @Override public void run() { @@ -199,7 +201,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - protected boolean applyFix(RefEntity[] refElements) { + protected boolean applyFix(@NotNull RefEntity[] refElements) { final EntryPointsManager entryPointsManager = getEntryPointsManager(); for (RefEntity refElement : refElements) { if (refElement instanceof RefElement) { @@ -218,9 +220,9 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - protected boolean applyFix(RefEntity[] refElements) { + protected boolean applyFix(@NotNull RefEntity[] refElements) { if (!super.applyFix(refElements)) return false; - ArrayList<RefElement> deletedRefs = new ArrayList<RefElement>(1); + List<RefElement> deletedRefs = new ArrayList<RefElement>(1); for (RefEntity refElement : refElements) { PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; if (psiElement == null) continue; @@ -331,12 +333,6 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - public void initialize(@NotNull GlobalInspectionContextImpl context) { - super.initialize(context); - ((EntryPointsManagerImpl)getEntryPointsManager()).setAddNonJavaEntries(getTool().ADD_NONJAVA_TO_ENTRIES); - } - - @Override public void updateContent() { getTool().checkForReachables(); myPackageContents = new HashMap<String, Set<RefEntity>>(); @@ -360,7 +356,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta @Override public boolean hasReportedProblems() { final GlobalInspectionContextImpl context = getContext(); - if (context != null && context.getUIOptions().SHOW_ONLY_DIFF){ + if (!isDisposed() && context.getUIOptions().SHOW_ONLY_DIFF){ return containsOnlyDiff(myPackageContents) || myOldPackageContents != null && containsOnlyDiff(myOldPackageContents); } @@ -438,7 +434,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta @Override public FileStatus getElementStatus(final RefEntity element) { final GlobalInspectionContextImpl context = getContext(); - if (context != null && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ + if (!isDisposed() && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ if (myOldPackageContents != null){ final boolean old = RefUtil.contains(element, collectRefElements(myOldPackageContents)); final boolean current = RefUtil.contains(element, collectRefElements(myPackageContents)); diff --git a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java index a2a95d734ec2..a35c30d9c09e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java @@ -15,7 +15,7 @@ */ package com.intellij.codeInspection.emptyMethod; -import com.intellij.ExtensionPoints; +import com.intellij.ToolExtensionPoints; import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.GroupNames; @@ -51,7 +51,7 @@ import java.util.List; /** * @author max */ -public class EmptyMethodInspection extends GlobalJavaInspectionTool { +public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool { private static final String DISPLAY_NAME = InspectionsBundle.message("inspection.empty.method.display.name"); @NonNls private static final String SHORT_NAME = "EmptyMethod"; @@ -166,7 +166,7 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { if (AnnotationUtil.isAnnotated(owner, EXCLUDE_ANNOS)) { return false; } - for (final Object extension : Extensions.getExtensions(ExtensionPoints.EMPTY_METHOD_TOOL)) { + for (final Object extension : Extensions.getExtensions(ToolExtensionPoints.EMPTY_METHOD_TOOL)) { if (((Condition<RefMethod>) extension).value(refMethod)) { return false; } @@ -358,7 +358,7 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { } @Override - public void applyFix(final @NotNull Project project, @NotNull ProblemDescriptor descriptor) { + public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { applyFix(project, new ProblemDescriptor[]{descriptor}, new ArrayList<PsiElement>(), null); } diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index caacfbfd622e..d8851e0f074d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -24,339 +24,31 @@ */ package com.intellij.codeInspection.ex; -import com.intellij.ExtensionPoints; -import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; -import com.intellij.openapi.extensions.ExtensionPoint; -import com.intellij.openapi.extensions.ExtensionPointListener; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.extensions.PluginDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.*; -import com.intellij.profile.codeInspection.InspectionProfileManager; -import com.intellij.psi.*; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.*; +import java.util.ArrayList; +import java.util.List; @State( name = "EntryPointsManager", storages = {@Storage( file = StoragePathMacros.PROJECT_FILE)} ) -public class EntryPointsManagerImpl implements PersistentStateComponent<Element>, EntryPointsManager { - @NonNls private static final String[] STANDARD_ANNOS = { - "javax.ws.rs.*", - }; - - // null means uninitialized - private volatile List<String> ADDITIONAL_ANNOS; - - public Collection<String> getAdditionalAnnotations() { - List<String> annos = ADDITIONAL_ANNOS; - if (annos == null) { - annos = new ArrayList<String>(); - Collections.addAll(annos, STANDARD_ANNOS); - final EntryPoint[] extensions = Extensions.getExtensions(ExtensionPoints.DEAD_CODE_TOOL, null); - for (EntryPoint extension : extensions) { - final String[] ignoredAnnotations = extension.getIgnoreAnnotations(); - if (ignoredAnnotations != null) { - ContainerUtil.addAll(annos, ignoredAnnotations); - } - } - ADDITIONAL_ANNOS = annos = Collections.unmodifiableList(annos); - } - return annos; - } - public JDOMExternalizableStringList ADDITIONAL_ANNOTATIONS = new JDOMExternalizableStringList(); - private final Map<String, SmartRefElementPointer> myPersistentEntryPoints; - private final Set<RefElement> myTemporaryEntryPoints; - private static final String VERSION = "2.0"; - @NonNls private static final String VERSION_ATTR = "version"; - @NonNls private static final String ENTRY_POINT_ATTR = "entry_point"; - private boolean myAddNonJavaEntries = true; - private boolean myResolved = false; - private final Project myProject; - private long myLastModificationCount = -1; - +public class EntryPointsManagerImpl extends EntryPointsManagerBase implements PersistentStateComponent<Element> { public EntryPointsManagerImpl(Project project) { - myProject = project; - myTemporaryEntryPoints = new HashSet<RefElement>(); - myPersistentEntryPoints = - new LinkedHashMap<String, SmartRefElementPointer>(); // To keep the order between readExternal to writeExternal - Disposer.register(project, this); - final ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); - point.addExtensionPointListener(new ExtensionPointListener<EntryPoint>() { - @Override - public void extensionAdded(@NotNull EntryPoint extension, @Nullable PluginDescriptor pluginDescriptor) { - extensionRemoved(extension, pluginDescriptor); - } - - @Override - public void extensionRemoved(@NotNull EntryPoint extension, @Nullable PluginDescriptor pluginDescriptor) { - if (ADDITIONAL_ANNOS != null) { - ADDITIONAL_ANNOS = null; - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (ApplicationManager.getApplication().isDisposed()) return; - InspectionProfileManager.getInstance().fireProfileChanged(null); - } - }); - } - } - }, this); - } - - public static EntryPointsManagerImpl getInstance(Project project) { - return ServiceManager.getService(project, EntryPointsManagerImpl.class); - } - - @Override - @SuppressWarnings({"HardCodedStringLiteral"}) - public void loadState(Element element) { - Element entryPointsElement = element.getChild("entry_points"); - if (entryPointsElement != null) { - final String version = entryPointsElement.getAttributeValue(VERSION_ATTR); - if (!Comparing.strEqual(version, VERSION)) { - convert(entryPointsElement, myPersistentEntryPoints); - } - else { - List content = entryPointsElement.getChildren(); - for (final Object aContent : content) { - Element entryElement = (Element)aContent; - if (ENTRY_POINT_ATTR.equals(entryElement.getName())) { - SmartRefElementPointerImpl entryPoint = new SmartRefElementPointerImpl(entryElement); - myPersistentEntryPoints.put(entryPoint.getFQName(), entryPoint); - } - } - } - } - try { - ADDITIONAL_ANNOTATIONS.readExternal(element); - } - catch (InvalidDataException ignored) { - } - } - - @Override - @SuppressWarnings({"HardCodedStringLiteral"}) - public Element getState() { - Element element = new Element("state"); - writeExternal(element, myPersistentEntryPoints, ADDITIONAL_ANNOTATIONS); - return element; - } - - @SuppressWarnings({"HardCodedStringLiteral"}) - public static void writeExternal(final Element element, - final Map<String, SmartRefElementPointer> persistentEntryPoints, - final JDOMExternalizableStringList additional_annotations) { - Element entryPointsElement = new Element("entry_points"); - entryPointsElement.setAttribute(VERSION_ATTR, VERSION); - for (SmartRefElementPointer entryPoint : persistentEntryPoints.values()) { - assert entryPoint.isPersistent(); - entryPoint.writeExternal(entryPointsElement); - } - - element.addContent(entryPointsElement); - if (!additional_annotations.isEmpty()) { - try { - additional_annotations.writeExternal(element); - } - catch (WriteExternalException ignored) { - } - } - } - - @Override - public void resolveEntryPoints(final RefManager manager) { - if (!myResolved) { - myResolved = true; - cleanup(); - validateEntryPoints(); - - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - for (SmartRefElementPointer entryPoint : myPersistentEntryPoints.values()) { - if (entryPoint.resolve(manager)) { - RefEntity refElement = entryPoint.getRefElement(); - ((RefElementImpl)refElement).setEntry(true); - ((RefElementImpl)refElement).setPermanentEntry(entryPoint.isPersistent()); - } - } - } - }); - } - } - - private void purgeTemporaryEntryPoints() { - for (RefElement entryPoint : myTemporaryEntryPoints) { - ((RefElementImpl)entryPoint).setEntry(false); - } - - myTemporaryEntryPoints.clear(); - } - - @Override - public void addEntryPoint(RefElement newEntryPoint, boolean isPersistent) { - if (!newEntryPoint.isValid()) return; - if (newEntryPoint instanceof RefClass) { - RefClass refClass = (RefClass)newEntryPoint; - - if (refClass.isAnonymous()) { - // Anonymous class cannot be an entry point. - return; - } - - List<RefMethod> refConstructors = refClass.getConstructors(); - if (refConstructors.size() == 1) { - addEntryPoint(refConstructors.get(0), isPersistent); - return; - } - else if (refConstructors.size() > 1) { - // Many constructors here. Need to ask user which ones are used - for (int i = 0; i < refConstructors.size(); i++) { - addEntryPoint(refConstructors.get(i), isPersistent); - } - - return; - } - } - - if (!isPersistent) { - myTemporaryEntryPoints.add(newEntryPoint); - ((RefElementImpl)newEntryPoint).setEntry(true); - } - else { - if (myPersistentEntryPoints.get(newEntryPoint.getExternalName()) == null) { - final SmartRefElementPointerImpl entry = new SmartRefElementPointerImpl(newEntryPoint, true); - myPersistentEntryPoints.put(entry.getFQName(), entry); - ((RefElementImpl)newEntryPoint).setEntry(true); - ((RefElementImpl)newEntryPoint).setPermanentEntry(true); - if (entry.isPersistent()) { //do save entry points - final EntryPointsManagerImpl entryPointsManager = getInstance(newEntryPoint.getElement().getProject()); - if (this != entryPointsManager) { - entryPointsManager.addEntryPoint(newEntryPoint, true); - } - } - } - } - } - - @Override - public void removeEntryPoint(RefElement anEntryPoint) { - if (anEntryPoint instanceof RefClass) { - RefClass refClass = (RefClass)anEntryPoint; - if (!refClass.isInterface()) { - anEntryPoint = refClass.getDefaultConstructor(); - } - } - - if (anEntryPoint == null) return; - - myTemporaryEntryPoints.remove(anEntryPoint); - - Set<Map.Entry<String, SmartRefElementPointer>> set = myPersistentEntryPoints.entrySet(); - String key = null; - for (Map.Entry<String, SmartRefElementPointer> entry : set) { - SmartRefElementPointer value = entry.getValue(); - if (value.getRefElement() == anEntryPoint) { - key = entry.getKey(); - break; - } - } - - if (key != null) { - myPersistentEntryPoints.remove(key); - ((RefElementImpl)anEntryPoint).setEntry(false); - } - - if (anEntryPoint.isPermanentEntry() && anEntryPoint.isValid()) { - final Project project = anEntryPoint.getElement().getProject(); - final EntryPointsManagerImpl entryPointsManager = getInstance(project); - if (this != entryPointsManager) { - entryPointsManager.removeEntryPoint(anEntryPoint); - } - } - } - - @Override - public RefElement[] getEntryPoints() { - validateEntryPoints(); - List<RefElement> entries = new ArrayList<RefElement>(); - Collection<SmartRefElementPointer> collection = myPersistentEntryPoints.values(); - for (SmartRefElementPointer refElementPointer : collection) { - final RefEntity elt = refElementPointer.getRefElement(); - if (elt instanceof RefElement) { - entries.add((RefElement)elt); - } - } - entries.addAll(myTemporaryEntryPoints); - - return entries.toArray(new RefElement[entries.size()]); - } - - @Override - public void dispose() { - cleanup(); - } - - private void validateEntryPoints() { - long count = PsiManager.getInstance(myProject).getModificationTracker().getModificationCount(); - if (count != myLastModificationCount) { - myLastModificationCount = count; - Collection<SmartRefElementPointer> collection = myPersistentEntryPoints.values(); - SmartRefElementPointer[] entries = collection.toArray(new SmartRefElementPointer[collection.size()]); - for (SmartRefElementPointer entry : entries) { - RefElement refElement = (RefElement)entry.getRefElement(); - if (refElement != null && !refElement.isValid()) { - myPersistentEntryPoints.remove(entry.getFQName()); - } - } - - final Iterator<RefElement> it = myTemporaryEntryPoints.iterator(); - while (it.hasNext()) { - RefElement refElement = it.next(); - if (!refElement.isValid()) { - it.remove(); - } - } - } - } - - @Override - public void cleanup() { - purgeTemporaryEntryPoints(); - Collection<SmartRefElementPointer> entries = myPersistentEntryPoints.values(); - for (SmartRefElementPointer entry : entries) { - entry.freeReference(); - } - } - - @Override - public boolean isAddNonJavaEntries() { - return myAddNonJavaEntries; + super(project); } @Override public void configureAnnotations() { - final ArrayList<String> list = new ArrayList<String>(ADDITIONAL_ANNOTATIONS); + final List<String> list = new ArrayList<String>(ADDITIONAL_ANNOTATIONS); final JPanel listPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(list, "Do not check if annotated by", true); new DialogWrapper(myProject) { { @@ -379,77 +71,15 @@ public class EntryPointsManagerImpl implements PersistentStateComponent<Element> }.show(); } - public static JButton createConfigureAnnotationsBtn(final JComponent parent) { + @Override + public JButton createConfigureAnnotationsBtn() { final JButton configureAnnotations = new JButton("Configure annotations..."); configureAnnotations.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parent)); - if (project == null) project = ProjectManager.getInstance().getDefaultProject(); - EntryPointsManagerImpl.getInstance(project).configureAnnotations(); + configureAnnotations(); } }); return configureAnnotations; } - - public void addAllPersistentEntries(EntryPointsManagerImpl manager) { - myPersistentEntryPoints.putAll(manager.myPersistentEntryPoints); - } - - public static void convert(Element element, final Map<String, SmartRefElementPointer> persistentEntryPoints) { - List content = element.getChildren(); - for (final Object aContent : content) { - Element entryElement = (Element)aContent; - if (ENTRY_POINT_ATTR.equals(entryElement.getName())) { - String fqName = entryElement.getAttributeValue(SmartRefElementPointerImpl.FQNAME_ATTR); - final String type = entryElement.getAttributeValue(SmartRefElementPointerImpl.TYPE_ATTR); - if (Comparing.strEqual(type, RefJavaManager.METHOD)) { - - int spaceIdx = fqName.indexOf(' '); - int lastDotIdx = fqName.lastIndexOf('.'); - - int parenIndex = fqName.indexOf('('); - - while (lastDotIdx > parenIndex) lastDotIdx = fqName.lastIndexOf('.', lastDotIdx - 1); - - boolean notype = false; - if (spaceIdx < 0 || spaceIdx + 1 > lastDotIdx || spaceIdx > parenIndex) { - notype = true; - } - - final String className = fqName.substring(notype ? 0 : spaceIdx + 1, lastDotIdx); - final String methodSignature = - notype ? fqName.substring(lastDotIdx + 1) : fqName.substring(0, spaceIdx) + ' ' + fqName.substring(lastDotIdx + 1); - - fqName = className + " " + methodSignature; - } - else if (Comparing.strEqual(type, RefJavaManager.FIELD)) { - final int lastDotIdx = fqName.lastIndexOf('.'); - if (lastDotIdx > 0 && lastDotIdx < fqName.length() - 2) { - String className = fqName.substring(0, lastDotIdx); - String fieldName = fqName.substring(lastDotIdx + 1); - fqName = className + " " + fieldName; - } - else { - continue; - } - } - SmartRefElementPointerImpl entryPoint = new SmartRefElementPointerImpl(type, fqName); - persistentEntryPoints.put(entryPoint.getFQName(), entryPoint); - } - } - } - - public void setAddNonJavaEntries(final boolean addNonJavaEntries) { - myAddNonJavaEntries = addNonJavaEntries; - } - - public boolean isEntryPoint(@NotNull PsiModifierListOwner element) { - if (!ADDITIONAL_ANNOTATIONS.isEmpty() && ADDITIONAL_ANNOTATIONS.contains(Deprecated.class.getName()) && - element instanceof PsiDocCommentOwner && ((PsiDocCommentOwner)element).isDeprecated()) { - return true; - } - return AnnotationUtil.isAnnotated(element, ADDITIONAL_ANNOTATIONS) || - AnnotationUtil.isAnnotated(element, getAdditionalAnnotations()); - } } diff --git a/java/java-impl/src/com/intellij/codeInspection/inconsistentLanguageLevel/InconsistentLanguageLevelInspection.java b/java/java-impl/src/com/intellij/codeInspection/inconsistentLanguageLevel/InconsistentLanguageLevelInspection.java index 4c0e2227e038..ecd1dcad59cd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/inconsistentLanguageLevel/InconsistentLanguageLevelInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/inconsistentLanguageLevel/InconsistentLanguageLevelInspection.java @@ -27,7 +27,7 @@ import com.intellij.codeInspection.reference.RefManager; import com.intellij.codeInspection.reference.RefModule; import com.intellij.codeInspection.unnecessaryModuleDependency.UnnecessaryModuleDependencyInspection; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.*; @@ -44,6 +44,11 @@ import java.util.Set; public class InconsistentLanguageLevelInspection extends GlobalInspectionTool { @Override + public boolean isGraphNeeded() { + return false; + } + + @Override public void runInspection(@NotNull AnalysisScope scope, @NotNull InspectionManager manager, @NotNull GlobalInspectionContext globalContext, @@ -52,7 +57,7 @@ public class InconsistentLanguageLevelInspection extends GlobalInspectionTool { scope.accept(new PsiElementVisitor(){ @Override public void visitElement(PsiElement element) { - final Module module = ModuleUtil.findModuleForPsiElement(element); + final Module module = ModuleUtilCore.findModuleForPsiElement(element); if (module != null) { modules.add(module); } diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java index 2a82958eb202..4f9fa882be6e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java @@ -51,6 +51,10 @@ public class MagicCompletionContributor extends CompletionContributor { PsiElement pos = parameters.getPosition(); MagicConstantInspection.AllowedValues allowedValues = null; + if (JavaCompletionData.AFTER_DOT.accepts(pos)) { + return; + } + if (IN_METHOD_CALL_ARGUMENT.accepts(pos)) { PsiCall call = PsiTreeUtil.getParentOfType(pos, PsiCall.class); if (!(call instanceof PsiExpression)) return; diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java index f185806be3c6..7193cc96ffed 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java @@ -55,6 +55,8 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class MagicConstantInspection extends BaseJavaLocalInspectionTool { + public static final Key<Boolean> NO_ANNOTATIONS_FOUND = Key.create("REPORTED_NO_ANNOTATIONS_FOUND"); + @Nls @NotNull @Override @@ -152,8 +154,19 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool { }; } + @Override + public void cleanup(Project project) { + super.cleanup(project); + project.putUserData(NO_ANNOTATIONS_FOUND, null); + } + private static void checkAnnotationsJarAttached(@NotNull PsiFile file, @NotNull ProblemsHolder holder) { final Project project = file.getProject(); + if (!holder.isOnTheFly()) { + final Boolean found = project.getUserData(NO_ANNOTATIONS_FOUND); + if (found != null) return; + } + PsiClass event = JavaPsiFacade.getInstance(project).findClass("java.awt.event.InputEvent", GlobalSearchScope.allScope(project)); if (event == null) return; // no jdk to attach PsiMethod[] methods = event.findMethodsByName("getModifiers", false); @@ -172,6 +185,11 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool { } } if (jdk == null) return; // no jdk to attach + + if (!holder.isOnTheFly()) { + project.putUserData(NO_ANNOTATIONS_FOUND, Boolean.TRUE); + } + final Sdk finalJdk = jdk; String path = finalJdk.getHomePath(); diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java deleted file mode 100644 index 8c9cda6eb582..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Oct 21, 2001 - * Time: 4:29:19 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.reference; - -import com.intellij.codeInsight.TestFrameworks; -import com.intellij.lang.injection.InjectedLanguageManager; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.ClassUtil; -import com.intellij.psi.util.PsiFormatUtil; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -public class RefClassImpl extends RefJavaElementImpl implements RefClass { - private static final Set<RefElement> EMPTY_SET = Collections.emptySet(); - private static final Set<RefClass> EMPTY_CLASS_SET = Collections.emptySet(); - private static final List<RefMethod> EMPTY_METHOD_LIST = new ArrayList<RefMethod>(0); - private static final int IS_ANONYMOUS_MASK = 0x10000; - private static final int IS_INTERFACE_MASK = 0x20000; - private static final int IS_UTILITY_MASK = 0x40000; - private static final int IS_ABSTRACT_MASK = 0x80000; - - private static final int IS_APPLET_MASK = 0x200000; - private static final int IS_SERVLET_MASK = 0x400000; - private static final int IS_TESTCASE_MASK = 0x800000; - private static final int IS_LOCAL_MASK = 0x1000000; - - private Set<RefClass> myBases; // singleton (to conserve the memory) or THashSet - private Set<RefClass> mySubClasses; // singleton (to conserve the memory) or THashSet - private List<RefMethod> myConstructors; - private RefMethodImpl myDefaultConstructor; - private List<RefMethod> myOverridingMethods; - private Set<RefElement> myInTypeReferences; - private Set<RefElement> myInstanceReferences; - private List<RefJavaElement> myClassExporters; - - RefClassImpl(PsiClass psiClass, RefManager manager) { - super(psiClass, manager); - } - - @Override - protected void initialize() { - myDefaultConstructor = null; - - final PsiClass psiClass = getElement(); - - LOG.assertTrue(psiClass != null); - - PsiElement psiParent = psiClass.getParent(); - if (psiParent instanceof PsiFile) { - if (isSyntheticJSP()) { - final RefFileImpl refFile = (RefFileImpl)getRefManager().getReference(JspPsiUtil.getJspFile(psiClass)); - LOG.assertTrue(refFile != null); - refFile.add(this); - } else if (psiParent instanceof PsiJavaFile) { - PsiJavaFile psiFile = (PsiJavaFile) psiParent; - String packageName = psiFile.getPackageName(); - if (!"".equals(packageName)) { - ((RefPackageImpl)getRefJavaManager().getPackage(packageName)).add(this); - } else { - ((RefPackageImpl)getRefJavaManager().getDefaultPackage()).add(this); - } - } - final Module module = ModuleUtil.findModuleForPsiElement(psiClass); - LOG.assertTrue(module != null); - final RefModuleImpl refModule = ((RefModuleImpl)getRefManager().getRefModule(module)); - LOG.assertTrue(refModule != null); - refModule.add(this); - } else { - while (!(psiParent instanceof PsiClass || psiParent instanceof PsiMethod || psiParent instanceof PsiField)) { - psiParent = psiParent.getParent(); - } - RefElement refParent = getRefManager().getReference(psiParent); - LOG.assertTrue (refParent != null); - ((RefElementImpl)refParent).add(this); - - } - - setAbstract(psiClass.hasModifierProperty(PsiModifier.ABSTRACT)); - - setAnonymous(psiClass instanceof PsiAnonymousClass); - setIsLocal(!(isAnonymous() || psiParent instanceof PsiClass || psiParent instanceof PsiFile)); - setInterface(psiClass.isInterface()); - - initializeSuperReferences(psiClass); - - PsiMethod[] psiMethods = psiClass.getMethods(); - PsiField[] psiFields = psiClass.getFields(); - - setUtilityClass(psiMethods.length > 0 || psiFields.length > 0); - - for (PsiField psiField : psiFields) { - getRefManager().getReference(psiField); - } - - if (!isApplet()) { - final PsiClass servlet = getRefJavaManager().getServlet(); - setServlet(servlet != null && psiClass.isInheritor(servlet, true)); - } - if (!isApplet() && !isServlet()) { - final boolean isTestClass = TestFrameworks.getInstance().isTestClass(psiClass); - setTestCase(isTestClass); - if (isTestClass) { - for (RefClass refBase : getBaseClasses()) { - ((RefClassImpl)refBase).setTestCase(true); - } - } - } - - for (PsiMethod psiMethod : psiMethods) { - RefMethod refMethod = (RefMethod)getRefManager().getReference(psiMethod); - - if (refMethod != null) { - if (psiMethod.isConstructor()) { - if (psiMethod.getParameterList().getParametersCount() > 0 || !psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) { - setUtilityClass(false); - } - - addConstructor(refMethod); - if (psiMethod.getParameterList().getParametersCount() == 0) { - setDefaultConstructor((RefMethodImpl)refMethod); - } - } - else { - if (!psiMethod.hasModifierProperty(PsiModifier.STATIC)) { - setUtilityClass(false); - } - } - } - } - - if (getConstructors().isEmpty() && !isInterface() && !isAnonymous()) { - RefImplicitConstructorImpl refImplicitConstructor = new RefImplicitConstructorImpl(this); - setDefaultConstructor(refImplicitConstructor); - addConstructor(refImplicitConstructor); - } - - if (isInterface()) { - for (int i = 0; i < psiFields.length && isUtilityClass(); i++) { - PsiField psiField = psiFields[i]; - if (!psiField.hasModifierProperty(PsiModifier.STATIC)) { - setUtilityClass(false); - } - } - } - - - final PsiClass applet = getRefJavaManager().getApplet(); - setApplet(applet != null && psiClass.isInheritor(applet, true)); - PsiManager psiManager = getRefManager().getPsiManager(); - psiManager.dropResolveCaches(); - PsiFile file = psiClass.getContainingFile(); - if (file != null) { - InjectedLanguageManager.getInstance(file.getProject()).dropFileCaches(file); - } - } - - private void initializeSuperReferences(PsiClass psiClass) { - if (!isSelfInheritor(psiClass)) { - for (PsiClass psiSuperClass : psiClass.getSupers()) { - if (getRefManager().belongsToScope(psiSuperClass)) { - RefClassImpl refClass = (RefClassImpl)getRefManager().getReference(psiSuperClass); - if (refClass != null) { - addBaseClass(refClass); - refClass.addSubClass(this); - } - } - } - } - } - - @Override - public boolean isSelfInheritor(PsiClass psiClass) { - return isSelfInheritor(psiClass, new ArrayList<PsiClass>()); - } - - @Override - public PsiClass getElement() { - return (PsiClass)super.getElement(); - } - - private static boolean isSelfInheritor(PsiClass psiClass, ArrayList<PsiClass> visited) { - if (visited.contains(psiClass)) return true; - - visited.add(psiClass); - for (PsiClass aSuper : psiClass.getSupers()) { - if (isSelfInheritor(aSuper, visited)) return true; - } - visited.remove(psiClass); - - return false; - } - - private void setDefaultConstructor(RefMethodImpl defaultConstructor) { - if (defaultConstructor != null) { - for (RefClass superClass : getBaseClasses()) { - RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor(); - - if (superDefaultConstructor != null) { - superDefaultConstructor.addInReference(defaultConstructor); - defaultConstructor.addOutReference(superDefaultConstructor); - } - } - } - - myDefaultConstructor = defaultConstructor; - } - - @Override - public void buildReferences() { - PsiClass psiClass = getElement(); - - if (psiClass != null) { - for (PsiClassInitializer classInitializer : psiClass.getInitializers()) { - RefJavaUtil.getInstance().addReferences(psiClass, this, classInitializer.getBody()); - } - - RefJavaUtil.getInstance().addReferences(psiClass, this, psiClass.getModifierList()); - - PsiField[] psiFields = psiClass.getFields(); - for (PsiField psiField : psiFields) { - getRefManager().getReference(psiField); - final PsiExpression initializer = psiField.getInitializer(); - if (initializer != null) { - RefJavaUtil.getInstance().addReferences(psiClass, this, initializer); - } - } - - PsiMethod[] psiMethods = psiClass.getMethods(); - for (PsiMethod psiMethod : psiMethods) { - getRefManager().getReference(psiMethod); - } - getRefManager().fireBuildReferences(this); - } - } - - @Override - public void accept(@NotNull final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor)visitor).visitClass(RefClassImpl.this); - } - }); - } else { - super.accept(visitor); - } - } - - @Override - @NotNull - public Set<RefClass> getBaseClasses() { - if (myBases == null) return EMPTY_CLASS_SET; - return myBases; - } - - private void addBaseClass(RefClass refClass){ - if (myBases == null) { - myBases = Collections.singleton(refClass); - return; - } - if (myBases.size() == 1) { - // convert from singleton - myBases = new THashSet<RefClass>(myBases); - } - myBases.add(refClass); - } - - @Override - @NotNull - public Set<RefClass> getSubClasses() { - if (mySubClasses == null) return EMPTY_CLASS_SET; - return mySubClasses; - } - - private void addSubClass(@NotNull RefClass refClass){ - if (mySubClasses == null) { - mySubClasses = Collections.singleton(refClass); - return; - } - if (mySubClasses.size() == 1) { - // convert from singleton - mySubClasses = new THashSet<RefClass>(mySubClasses); - } - mySubClasses.add(refClass); - } - private void removeSubClass(RefClass refClass){ - if (mySubClasses == null) return; - if (mySubClasses.size() == 1) { - mySubClasses = null; - } - else { - mySubClasses.remove(refClass); - } - } - - @Override - @NotNull - public List<RefMethod> getConstructors() { - if (myConstructors == null) return EMPTY_METHOD_LIST; - return myConstructors; - } - - @Override - @NotNull - public Set<RefElement> getInTypeReferences() { - if (myInTypeReferences == null) return EMPTY_SET; - return myInTypeReferences; - } - - public void addTypeReference(RefJavaElement from) { - if (from != null) { - if (myInTypeReferences == null){ - myInTypeReferences = new THashSet<RefElement>(1); - } - myInTypeReferences.add(from); - ((RefJavaElementImpl)from).addOutTypeRefernce(this); - getRefManager().fireNodeMarkedReferenced(this, from, false, false, false); - } - } - - @Override - @NotNull - public Set<RefElement> getInstanceReferences() { - if (myInstanceReferences == null) return EMPTY_SET; - return myInstanceReferences; - } - - public void addInstanceReference(RefElement from) { - if (myInstanceReferences == null){ - myInstanceReferences = new THashSet<RefElement>(1); - } - myInstanceReferences.add(from); - } - - @Override - public RefMethod getDefaultConstructor() { - return myDefaultConstructor; - } - - private void addConstructor(RefMethod refConstructor) { - if (myConstructors == null){ - myConstructors = new ArrayList<RefMethod>(1); - } - myConstructors.add(refConstructor); - } - - public void addLibraryOverrideMethod(RefMethod refMethod) { - if (myOverridingMethods == null){ - myOverridingMethods = new ArrayList<RefMethod>(2); - } - myOverridingMethods.add(refMethod); - } - - @Override - @NotNull - public List<RefMethod> getLibraryMethods() { - if (myOverridingMethods == null) return EMPTY_METHOD_LIST; - return myOverridingMethods; - } - - @Override - public boolean isAnonymous() { - return checkFlag(IS_ANONYMOUS_MASK); - } - - @Override - public boolean isInterface() { - return checkFlag(IS_INTERFACE_MASK); - } - - @Override - public boolean isSuspicious() { - return !(isUtilityClass() && getOutReferences().isEmpty()) && super.isSuspicious(); - } - - @Override - public boolean isUtilityClass() { - return checkFlag(IS_UTILITY_MASK); - } - - @Override - public String getExternalName() { - final String[] result = new String[1]; - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() {//todo synthetic JSP - final PsiClass psiClass = getElement(); - LOG.assertTrue(psiClass != null); - result[0] = PsiFormatUtil.getExternalName(psiClass); - } - }); - return result[0]; - } - - - @Nullable - public static RefClass classFromExternalName(RefManager manager, String externalName) { - return (RefClass) manager.getReference(ClassUtil.findPsiClass(PsiManager.getInstance(manager.getProject()), externalName)); - } - - @Override - public void referenceRemoved() { - super.referenceRemoved(); - - for (RefClass subClass : getSubClasses()) { - ((RefClassImpl)subClass).removeBase(this); - } - - for (RefClass superClass : getBaseClasses()) { - ((RefClassImpl)superClass).removeSubClass(this); - } - } - - private void removeBase(RefClass superClass) { - final Set<RefClass> baseClasses = getBaseClasses(); - if (baseClasses.contains(superClass)) { - if (baseClasses.size() == 1) { - myBases = null; - return; - } - baseClasses.remove(superClass); - } - } - - protected void methodRemoved(RefMethod method) { - getConstructors().remove(method); - getLibraryMethods().remove(method); - - if (getDefaultConstructor() == method) { - setDefaultConstructor(null); - } - } - - @Override - public boolean isAbstract() { - return checkFlag(IS_ABSTRACT_MASK); - } - - @Override - public boolean isApplet() { - return checkFlag(IS_APPLET_MASK); - } - - @Override - public boolean isServlet() { - return checkFlag(IS_SERVLET_MASK); - } - - @Override - public boolean isTestCase() { - return checkFlag(IS_TESTCASE_MASK); - } - - @Override - public boolean isLocalClass() { - return checkFlag(IS_LOCAL_MASK); - } - - - @Override - public boolean isReferenced() { - if (super.isReferenced()) return true; - - if (isInterface() || isAbstract()) { - if (!getSubClasses().isEmpty()) return true; - } - - return false; - } - - @Override - public boolean hasSuspiciousCallers() { - if (super.hasSuspiciousCallers()) return true; - - if (isInterface() || isAbstract()) { - if (!getSubClasses().isEmpty()) return true; - } - - return false; - } - - public void addClassExporter(RefJavaElement exporter) { - if (myClassExporters == null) myClassExporters = new ArrayList<RefJavaElement>(1); - if (myClassExporters.contains(exporter)) return; - myClassExporters.add(exporter); - } - - public List<RefJavaElement> getClassExporters() { - return myClassExporters; - } - - private void setAnonymous(boolean anonymous) { - setFlag(anonymous, IS_ANONYMOUS_MASK); - } - - private void setInterface(boolean anInterface) { - setFlag(anInterface, IS_INTERFACE_MASK); - } - - private void setUtilityClass(boolean utilityClass) { - setFlag(utilityClass, IS_UTILITY_MASK); - } - - private void setAbstract(boolean anAbstract) { - setFlag(anAbstract, IS_ABSTRACT_MASK); - } - - private void setApplet(boolean applet) { - setFlag(applet, IS_APPLET_MASK); - } - - private void setServlet(boolean servlet) { - setFlag(servlet, IS_SERVLET_MASK); - } - - private void setTestCase(boolean testCase) { - setFlag(testCase, IS_TESTCASE_MASK); - } - - private void setIsLocal(boolean isLocal) { - setFlag(isLocal, IS_LOCAL_MASK); - } - - @Override - @NotNull - public RefElement getContainingEntry() { - RefElement defaultConstructor = getDefaultConstructor(); - if (defaultConstructor != null) return defaultConstructor; - return super.getContainingEntry(); - } -} - diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java deleted file mode 100644 index 35262e3e725c..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2000-2009 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.reference; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Computable; -import com.intellij.psi.*; -import com.intellij.psi.util.ClassUtil; -import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author max - * Date: Oct 21, 2001 - */ -public class RefFieldImpl extends RefJavaElementImpl implements RefField { - private static final int USED_FOR_READING_MASK = 0x10000; - private static final int USED_FOR_WRITING_MASK = 0x20000; - private static final int ASSIGNED_ONLY_IN_INITIALIZER = 0x40000; - - RefFieldImpl(@NotNull RefClass ownerClass, PsiField field, RefManager manager) { - super(field, manager); - - ((RefClassImpl)ownerClass).add(this); - - if (ownerClass.isInterface()) { - setIsStatic(true); - setIsFinal(true); - } - } - - @Override - public PsiField getElement() { - return (PsiField)super.getElement(); - } - - @Override - protected void markReferenced(RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) { - addInReference(refFrom); - - boolean referencedFromClassInitializer = false; - - if (forWriting && expressionFrom != null) { - PsiClassInitializer initializer = PsiTreeUtil.getParentOfType(expressionFrom, PsiClassInitializer.class); - if (initializer != null) { - if (initializer.getParent() instanceof PsiClass && psiFrom == initializer.getParent() && !expressionFrom.isQualified()) { - referencedFromClassInitializer = true; - } - } - } - - if (forWriting) { - setUsedForWriting(true); - } - - if (forReading) { - setUsedForReading(true); - } - getRefManager().fireNodeMarkedReferenced(this, refFrom, referencedFromClassInitializer, forReading, forWriting); - } - - @Override - public boolean isUsedForReading() { - return checkFlag(USED_FOR_READING_MASK); - } - - private void setUsedForReading(boolean usedForReading) { - setFlag(usedForReading, USED_FOR_READING_MASK); - } - - @Override - public boolean isUsedForWriting() { - return checkFlag(USED_FOR_WRITING_MASK); - } - - private void setUsedForWriting(boolean usedForWriting) { - setFlag(false, ASSIGNED_ONLY_IN_INITIALIZER); - setFlag(usedForWriting, USED_FOR_WRITING_MASK); - } - - @Override - public boolean isOnlyAssignedInInitializer() { - return checkFlag(ASSIGNED_ONLY_IN_INITIALIZER); - } - - @Override - public void accept(@NotNull final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor)visitor).visitField(RefFieldImpl.this); - } - }); - } else { - super.accept(visitor); - } - } - - @Override - public void buildReferences() { - PsiField psiField = getElement(); - if (psiField != null) { - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - refUtil.addReferences(psiField, this, psiField.getInitializer()); - refUtil.addReferences(psiField, this, psiField.getModifierList()); - if (psiField instanceof PsiEnumConstant) { - refUtil.addReferences(psiField, this, psiField); - } - - if (psiField.getInitializer() != null || psiField instanceof PsiEnumConstant) { - if (!checkFlag(USED_FOR_WRITING_MASK)) { - setFlag(true, ASSIGNED_ONLY_IN_INITIALIZER); - setFlag(true, USED_FOR_WRITING_MASK); - } - } - PsiType psiType = psiField.getType(); - RefClass ownerClass = refUtil.getOwnerClass(getRefManager(), psiField); - - if (ownerClass != null) { - psiType = psiType.getDeepComponentType(); - if (psiType instanceof PsiClassType) { - PsiClass psiClass = PsiUtil.resolveClassInType(psiType); - if (psiClass != null && getRefManager().belongsToScope(psiClass)) { - RefClassImpl refClass = (RefClassImpl)getRefManager().getReference(psiClass); - if (refClass != null) { - refClass.addTypeReference(ownerClass); - refClass.addClassExporter(this); - } - } - } - - } - getRefManager().fireBuildReferences(this); - } - } - - @Override - public RefClass getOwnerClass() { - return (RefClass) getOwner(); - } - - @Override - public String getExternalName() { - return ApplicationManager.getApplication().runReadAction(new Computable<String>() { - @Override - public String compute() { - PsiField psiField = getElement(); - return psiField != null ? PsiFormatUtil.getExternalName(psiField) : null; - } - }); - } - - @Nullable - public static RefField fieldFromExternalName(RefManager manager, String externalName) { - return (RefField)manager.getReference(findPsiField(PsiManager.getInstance(manager.getProject()), externalName)); - } - - @Nullable - public static PsiField findPsiField(PsiManager manager, String externalName) { - int classNameDelimeter = externalName.lastIndexOf(' '); - if (classNameDelimeter > 0 && classNameDelimeter < externalName.length() - 1) { - final String className = externalName.substring(0, classNameDelimeter); - final String fieldName = externalName.substring(classNameDelimeter + 1); - final PsiClass psiClass = ClassUtil.findPsiClass(manager, className); - if (psiClass != null) { - return psiClass.findFieldByName(fieldName, false); - } - } - return null; - } - - @Override - public boolean isSuspicious() { - if (isEntry()) return false; - if (super.isSuspicious()) return true; - return isUsedForReading() != isUsedForWriting(); - } - - @Override - protected void initialize() { - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java deleted file mode 100644 index 7dd92822237d..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Nov 28, 2001 - * Time: 4:17:17 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.reference; - -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Computable; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiModifierListOwner; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImplicitConstructor { - - RefImplicitConstructorImpl(RefClass ownerClass) { - super(InspectionsBundle.message("inspection.reference.implicit.constructor.name", ownerClass.getName()), ownerClass); - } - - @Override - public void buildReferences() { - getRefManager().fireBuildReferences(this); - } - - @Override - public boolean isSuspicious() { - return ((RefClassImpl)getOwnerClass()).isSuspicious(); - } - - @NotNull - @Override - public String getName() { - return InspectionsBundle.message("inspection.reference.implicit.constructor.name", getOwnerClass().getName()); - } - - @Override - public String getExternalName() { - return getOwnerClass().getExternalName(); - } - - @Override - public boolean isValid() { - return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { - @Override - public Boolean compute() { - return getOwnerClass().isValid(); - } - }).booleanValue(); - } - - @Override - public String getAccessModifier() { - return getOwnerClass().getAccessModifier(); - } - - @Override - public void setAccessModifier(String am) { - RefJavaUtil.getInstance().setAccessModifier(getOwnerClass(), am); - } - - @Override - public PsiModifierListOwner getElement() { - return getOwnerClass().getElement(); - } - - @Override - @Nullable - public PsiFile getContainingFile() { - return ((RefClassImpl)getOwnerClass()).getContainingFile(); - } - - @Override - public RefClass getOwnerClass() { - return myOwnerClass; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java deleted file mode 100644 index c0cd71eda18a..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * User: anna - * Date: 20-Dec-2007 - */ -package com.intellij.codeInspection.reference; - -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.openapi.util.Iconable; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.jsp.jspJava.JspClass; -import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; -import com.intellij.util.IconUtil; -import com.intellij.util.containers.Stack; -import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; - -public abstract class RefJavaElementImpl extends RefElementImpl implements RefJavaElement { - private Set<RefClass> myOutTypeReferences; - private static final int ACCESS_MODIFIER_MASK = 0x03; - private static final int ACCESS_PRIVATE = 0x00; - private static final int ACCESS_PROTECTED = 0x01; - private static final int ACCESS_PACKAGE = 0x02; - private static final int ACCESS_PUBLIC = 0x03; - private static final int IS_STATIC_MASK = 0x04; - private static final int IS_FINAL_MASK = 0x08; - private static final int IS_USES_DEPRECATION_MASK = 0x200; - private static final int IS_SYNTHETIC_JSP_ELEMENT = 0x400; - - protected RefJavaElementImpl(String name, @NotNull RefJavaElement owner) { - super(name, owner); - String am = owner.getAccessModifier(); - doSetAccessModifier(am); - - final boolean synthOwner = owner.isSyntheticJSP(); - if (synthOwner) { - setSyntheticJSP(true); - } - } - - protected RefJavaElementImpl(PsiFile file, RefManager manager) { - super(file, manager); - } - - protected RefJavaElementImpl(PsiModifierListOwner elem, RefManager manager) { - super(getName(elem), elem, manager); - - setAccessModifier(RefJavaUtil.getInstance().getAccessModifier(elem)); - final boolean isSynth = elem instanceof JspHolderMethod || elem instanceof JspClass; - if (isSynth) { - setSyntheticJSP(true); - } - - setIsStatic(elem.hasModifierProperty(PsiModifier.STATIC)); - setIsFinal(elem.hasModifierProperty(PsiModifier.FINAL)); - } - - @Override - @NotNull - public Collection<RefClass> getOutTypeReferences() { - if (myOutTypeReferences == null){ - return Collections.emptySet(); - } - return myOutTypeReferences; - } - - public void addOutTypeRefernce(RefClass refClass){ - if (myOutTypeReferences == null){ - myOutTypeReferences = new THashSet<RefClass>(); - } - myOutTypeReferences.add(refClass); - } - - public static String getName(PsiElement element) { - if (element instanceof PsiAnonymousClass) { - PsiAnonymousClass psiAnonymousClass = (PsiAnonymousClass)element; - PsiClass psiBaseClass = psiAnonymousClass.getBaseClassType().resolve(); - return InspectionsBundle.message("inspection.reference.anonymous.name", psiBaseClass == null ? "" : psiBaseClass.getQualifiedName()); - } - - if (element instanceof JspClass) { - final JspClass jspClass = (JspClass)element; - final PsiFile jspxFile = jspClass.getContainingFile(); - return "<" + jspxFile.getName() + ">"; - } - - if (element instanceof JspHolderMethod) { - return InspectionsBundle.message("inspection.reference.jsp.holder.method.anonymous.name"); - } - - String name = null; - if (element instanceof PsiNamedElement) { - name = ((PsiNamedElement)element).getName(); - } - - return name == null ? InspectionsBundle.message("inspection.reference.anonymous") : name; - } - - @Override - public boolean isFinal() { - return checkFlag(IS_FINAL_MASK); - } - - @Override - public boolean isStatic() { - return checkFlag(IS_STATIC_MASK); - } - - public void setIsStatic(boolean isStatic) { - setFlag(isStatic, IS_STATIC_MASK); - } - - @Override - public boolean isUsesDeprecatedApi() { - return checkFlag(IS_USES_DEPRECATION_MASK); - } - - public void setUsesDeprecatedApi(boolean usesDeprecatedApi) { - setFlag(usesDeprecatedApi, IS_USES_DEPRECATION_MASK); - } - - public void setIsFinal(boolean isFinal) { - setFlag(isFinal, IS_FINAL_MASK); - } - - public void setReachable(boolean reachable) { - setFlag(reachable, IS_REACHABLE_MASK); - } - - @Override - public boolean isSyntheticJSP() { - return checkFlag(IS_SYNTHETIC_JSP_ELEMENT); - } - - public void setSyntheticJSP(boolean b) { - setFlag(b, IS_SYNTHETIC_JSP_ELEMENT); - } - - @Override - @Nullable - public String getAccessModifier() { - long access_id = myFlags & ACCESS_MODIFIER_MASK; - if (access_id == ACCESS_PRIVATE) return PsiModifier.PRIVATE; - if (access_id == ACCESS_PUBLIC) return PsiModifier.PUBLIC; - if (access_id == ACCESS_PACKAGE) return PsiModifier.PACKAGE_LOCAL; - return PsiModifier.PROTECTED; - } - - public void setAccessModifier(String am) { - doSetAccessModifier(am); - } - - private void doSetAccessModifier(String am) { - final int access_id; - - if (PsiModifier.PRIVATE.equals(am)) { - access_id = ACCESS_PRIVATE; - } - else if (PsiModifier.PUBLIC.equals(am)) { - access_id = ACCESS_PUBLIC; - } - else if (PsiModifier.PACKAGE_LOCAL.equals(am)) { - access_id = ACCESS_PACKAGE; - } - else { - access_id = ACCESS_PROTECTED; - } - - myFlags = myFlags & ~0x3 | access_id; - } - - public boolean isSuspiciousRecursive() { - return isCalledOnlyFrom(this, new Stack<RefJavaElement>()); - } - - private boolean isCalledOnlyFrom(RefJavaElement refElement, Stack<RefJavaElement> callStack) { - if (callStack.contains(this)) return refElement == this; - if (getInReferences().isEmpty()) return false; - - if (refElement instanceof RefMethod) { - RefMethod refMethod = (RefMethod) refElement; - for (RefMethod refSuper : refMethod.getSuperMethods()) { - if (!refSuper.getInReferences().isEmpty()) return false; - } - if (refMethod.isConstructor()){ - boolean unreachable = true; - for (RefElement refOut : refMethod.getOutReferences()){ - unreachable &= !refOut.isReachable(); - } - if (unreachable) return true; - } - } - - callStack.push(this); - for (RefElement refCaller : getInReferences()) { - if (!((RefElementImpl)refCaller).isSuspicious() || !((RefJavaElementImpl)refCaller).isCalledOnlyFrom(refElement, callStack)) { - callStack.pop(); - return false; - } - } - - callStack.pop(); - return true; - } - - public void addReference(RefElement refWhat, PsiElement psiWhat, PsiElement psiFrom, boolean forWriting, boolean forReading, PsiReferenceExpression expression) { - if (refWhat != null) { - if (refWhat instanceof RefParameter) { - if (forWriting) { - ((RefParameter)refWhat).parameterReferenced(true); - } - if (forReading) { - ((RefParameter)refWhat).parameterReferenced(false); - } - } - addOutReference(refWhat); - ((RefJavaElementImpl)refWhat).markReferenced(this, psiFrom, psiWhat, forWriting, forReading, expression); - } else { - if (psiWhat instanceof PsiMethod) { - final PsiClass containingClass = ((PsiMethod)psiWhat).getContainingClass(); - if (containingClass != null && containingClass.isEnum() && "values".equals(((PsiMethod)psiWhat).getName())) { - for (PsiField enumConstant : containingClass.getFields()) { - if (enumConstant instanceof PsiEnumConstant) { - final RefJavaElementImpl enumConstantReference = (RefJavaElementImpl)getRefManager().getReference(enumConstant); - if (enumConstantReference != null) { - addOutReference(enumConstantReference); - enumConstantReference.markReferenced(this, psiFrom, enumConstant, false, true, expression); - } - } - } - } - } - } - } - - protected void markReferenced(final RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, final boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) { - addInReference(refFrom); - getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting); - } - - protected RefJavaManager getRefJavaManager() { - return getRefManager().getExtension(RefJavaManager.MANAGER); - } - - @Override - public void referenceRemoved() { - super.referenceRemoved(); - if (isEntry()) { - getRefJavaManager().getEntryPointsManager().removeEntryPoint(this); - } - } - - @Override - public Icon getIcon(final boolean expanded) { - if (isSyntheticJSP()) { - final PsiElement element = getElement(); - if (element != null && element.isValid()) { - return IconUtil.getIcon(element.getContainingFile().getVirtualFile(), - Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS, element.getProject()); - } - } - return super.getIcon(expanded); - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java deleted file mode 100644 index 9bfd6f01c07d..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * User: anna - * Date: 20-Dec-2007 - */ -package com.intellij.codeInspection.reference; - -import com.intellij.psi.PsiJavaFile; - -public class RefJavaFileImpl extends RefFileImpl { - RefJavaFileImpl(PsiJavaFile elem, RefManager manager) { - super(elem, manager); - ((RefPackageImpl)getRefManager().getExtension(RefJavaManager.MANAGER).getPackage(elem.getPackageName())).add(this); - } -}
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index 8ebd6ab6a87b..f53e1fb6e824 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -122,11 +122,6 @@ public class RefJavaManagerImpl extends RefJavaManager { return file != null ? DEAD_CODE_TOOL.get(file, myRefManager).get() : null; } - public boolean isEntryPoint(PsiElement element) { - UnusedDeclarationInspection tool = getDeadCodeTool(element); - return tool != null && tool.isEntryPoint(element); - } - @Override public RefPackage getDefaultPackage() { if (myDefaultPackage == null) { @@ -349,7 +344,7 @@ public class RefJavaManagerImpl extends RefJavaManager { private static void appendPackageElement(final Element element, final String packageName) { final Element packageElement = new Element("package"); - packageElement.addContent(packageName.length() > 0 ? packageName : InspectionsBundle.message("inspection.export.results.default")); + packageElement.addContent(packageName.isEmpty() ? InspectionsBundle.message("inspection.export.results.default") : packageName); element.addContent(packageElement); } @@ -358,7 +353,7 @@ public class RefJavaManagerImpl extends RefJavaManager { if (myEntryPointsManager == null) { final Project project = myRefManager.getProject(); myEntryPointsManager = new EntryPointsManagerImpl(project); - ((EntryPointsManagerImpl)myEntryPointsManager).addAllPersistentEntries(EntryPointsManagerImpl.getInstance(project)); + ((EntryPointsManagerBase)myEntryPointsManager).addAllPersistentEntries(EntryPointsManagerBase.getInstance(project)); } return myEntryPointsManager; } diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java deleted file mode 100644 index 71fa80a2077f..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * User: anna - * Date: 21-Dec-2007 - */ -package com.intellij.codeInspection.reference; - -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.VisibilityUtil; -import org.jetbrains.annotations.Nullable; - -public class RefJavaUtilImpl extends RefJavaUtil{ - - @Override - public void addReferences(final PsiModifierListOwner psiFrom, final RefJavaElement ref, @Nullable PsiElement findIn) { - final RefJavaElementImpl refFrom = (RefJavaElementImpl)ref; - if (findIn != null) { - findIn.accept( - new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - } - - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { - visitElement(expression); - - PsiElement psiResolved = expression.resolve(); - - if (psiResolved instanceof PsiModifierListOwner) { - if (isDeprecated(psiResolved)) refFrom.setUsesDeprecatedApi(true); - } - - RefElement refResolved = refFrom.getRefManager().getReference(psiResolved); - refFrom.addReference( - refResolved, psiResolved, psiFrom, PsiUtil.isAccessedForWriting(expression), - PsiUtil.isAccessedForReading(expression), expression - ); - - if (refResolved instanceof RefMethod) { - updateRefMethod(psiResolved, refResolved, expression, psiFrom, refFrom); - } - } - - - @Override public void visitEnumConstant(PsiEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); - processNewLikeConstruct(enumConstant.resolveConstructor(), enumConstant.getArgumentList()); - } - - @Override public void visitNewExpression(PsiNewExpression newExpr) { - super.visitNewExpression(newExpr); - PsiMethod psiConstructor = newExpr.resolveConstructor(); - final PsiExpressionList argumentList = newExpr.getArgumentList(); - - RefMethod refConstructor = processNewLikeConstruct(psiConstructor, argumentList); - - if (refConstructor == null) { // No explicit constructor referenced. Should use default one. - PsiType newType = newExpr.getType(); - if (newType instanceof PsiClassType) { - processClassReference(PsiUtil.resolveClassInType(newType), refFrom, psiFrom, true); - } - } - } - - @Nullable - private RefMethod processNewLikeConstruct(final PsiMethod psiConstructor, final PsiExpressionList argumentList) { - if (psiConstructor != null) { - if (isDeprecated(psiConstructor)) refFrom.setUsesDeprecatedApi(true); - } - - RefMethodImpl refConstructor = (RefMethodImpl)refFrom.getRefManager().getReference( - psiConstructor - ); - refFrom.addReference(refConstructor, psiConstructor, psiFrom, false, true, null); - - if (argumentList != null) { - PsiExpression[] psiParams = argumentList.getExpressions(); - for (PsiExpression param : psiParams) { - param.accept(this); - } - - if (refConstructor != null) { - refConstructor.updateParameterValues(psiParams); - } - } - return refConstructor; - } - - @Override public void visitAnonymousClass(PsiAnonymousClass psiClass) { - super.visitAnonymousClass(psiClass); - RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(psiClass); - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); - } - - @Override public void visitReturnStatement(PsiReturnStatement statement) { - super.visitReturnStatement(statement); - - if (refFrom instanceof RefMethodImpl) { - RefMethodImpl refMethod = (RefMethodImpl)refFrom; - refMethod.updateReturnValueTemplate(statement.getReturnValue()); - } - } - - @Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - super.visitClassObjectAccessExpression(expression); - final PsiTypeElement operand = expression.getOperand(); - final PsiType type = operand.getType(); - if (type instanceof PsiClassType) { - processClassReference(((PsiClassType)type).resolve(), refFrom, psiFrom, false); - } - } - - private void processClassReference(final PsiClass psiClass, - final RefJavaElementImpl refFrom, - final PsiModifierListOwner psiFrom, - boolean defaultConstructorOnly) { - if (psiClass != null) { - RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(psiClass); - - if (refClass != null) { - boolean hasConstructorsMarked = false; - - if (defaultConstructorOnly) { - RefMethodImpl refDefaultConstructor = (RefMethodImpl)refClass.getDefaultConstructor(); - if (refDefaultConstructor != null && !(refDefaultConstructor instanceof RefImplicitConstructor)) { - refDefaultConstructor.addInReference(refFrom); - refFrom.addOutReference(refDefaultConstructor); - hasConstructorsMarked = true; - } - } - else { - for (RefMethod cons : refClass.getConstructors()) { - if (cons instanceof RefImplicitConstructor) continue; - ((RefMethodImpl)cons).addInReference(refFrom); - refFrom.addOutReference(cons); - hasConstructorsMarked = true; - } - } - - if (!hasConstructorsMarked) { - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); - } - } - } - } - } - ); - } - } - - private void updateRefMethod(PsiElement psiResolved, - RefElement refResolved, - PsiElement refExpression, - final PsiElement psiFrom, - final RefElement refFrom) { - PsiMethod psiMethod = (PsiMethod)psiResolved; - RefMethodImpl refMethod = (RefMethodImpl)refResolved; - - PsiMethodCallExpression call = PsiTreeUtil.getParentOfType( - refExpression, - PsiMethodCallExpression.class - ); - if (call != null) { - PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && returnType != PsiType.VOID) { - if (!(call.getParent() instanceof PsiExpressionStatement)) { - refMethod.setReturnValueUsed(true); - } - - addTypeReference(psiFrom, returnType, refFrom.getRefManager()); - } - - PsiExpressionList argumentList = call.getArgumentList(); - if (argumentList.getExpressions().length > 0) { - refMethod.updateParameterValues(argumentList.getExpressions()); - } - - final PsiExpression psiExpression = call.getMethodExpression().getQualifierExpression(); - if (psiExpression != null) { - final PsiType usedType = psiExpression.getType(); - if (usedType != null) { - final String fqName = psiMethod.getContainingClass().getQualifiedName(); - if (fqName != null) { - final PsiClassType methodOwnerType = JavaPsiFacade.getInstance(call.getProject()).getElementFactory() - .createTypeByFQClassName(fqName, GlobalSearchScope.allScope(psiMethod.getProject())); - if (!usedType.equals(methodOwnerType)) { - refMethod.setCalledOnSubClass(true); - } - } - } - } - } - } - - - - - @Override - public RefClass getTopLevelClass(RefElement refElement) { - RefEntity refParent = refElement.getOwner(); - - while (refParent != null && refParent instanceof RefElement && !(refParent instanceof RefFile)) { - refElement = (RefElementImpl)refParent; - refParent = refParent.getOwner(); - } - - return (RefClass)refElement; - } - - @Override - public boolean isInheritor(RefClass subClass, RefClass superClass) { - if (subClass == superClass) return true; - - for (RefClass baseClass : subClass.getBaseClasses()) { - if (isInheritor(baseClass, superClass)) return true; - } - - return false; - } - - @Override - @Nullable - public String getPackageName(RefEntity refEntity) { - if (refEntity instanceof RefProject) { - return null; - } - RefPackage refPackage = getPackage(refEntity); - - return refPackage == null ? InspectionsBundle.message("inspection.reference.default.package") : refPackage.getQualifiedName(); - } - - @Override - public String getAccessModifier(PsiModifierListOwner psiElement) { - if (psiElement instanceof PsiParameter) return PsiModifier.PACKAGE_LOCAL; - - PsiModifierList list = psiElement.getModifierList(); - String result = PsiModifier.PACKAGE_LOCAL; - - if (list != null) { - if (list.hasModifierProperty(PsiModifier.PRIVATE)) { - result = PsiModifier.PRIVATE; - } - else if (list.hasModifierProperty(PsiModifier.PROTECTED)) { - result = PsiModifier.PROTECTED; - } - else if (list.hasModifierProperty(PsiModifier.PUBLIC)) { - result = PsiModifier.PUBLIC; - } - else if (psiElement.getParent() instanceof PsiClass) { - PsiClass ownerClass = (PsiClass)psiElement.getParent(); - if (ownerClass.isInterface()) { - result = PsiModifier.PUBLIC; - } - } - } - - return result; - } - - @Override - @Nullable public RefClass getOwnerClass(RefManager refManager, PsiElement psiElement) { - while (psiElement != null && !(psiElement instanceof PsiClass)) { - psiElement = psiElement.getParent(); - } - - return psiElement != null ? (RefClass)refManager.getReference(psiElement) : null; - } - - @Override - @Nullable public RefClass getOwnerClass(RefElement refElement) { - RefEntity parent = refElement.getOwner(); - - while (!(parent instanceof RefClass) && parent instanceof RefElement) { - parent = parent.getOwner(); - } - - if (parent instanceof RefClass) return (RefClass)parent; - - return null; - } - - - - @Override - public boolean isMethodOnlyCallsSuper(PsiMethod method) { - boolean hasStatements = false; - PsiCodeBlock body = method.getBody(); - if (body != null) { - PsiStatement[] statements = body.getStatements(); - for (PsiStatement statement : statements) { - boolean isCallToSameSuper = false; - if (statement instanceof PsiExpressionStatement) { - isCallToSameSuper = isCallToSuperMethod(((PsiExpressionStatement)statement).getExpression(), method); - } - else if (statement instanceof PsiReturnStatement) { - PsiExpression expression = ((PsiReturnStatement)statement).getReturnValue(); - isCallToSameSuper = expression == null || isCallToSuperMethod(expression, method); - } - - hasStatements = true; - if (isCallToSameSuper) continue; - - return false; - } - } - - if (hasStatements) { - final PsiMethod[] superMethods = method.findSuperMethods(); - for (PsiMethod superMethod : superMethods) { - if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(superMethod.getModifierList()), - VisibilityUtil.getVisibilityModifier(method.getModifierList())) > 0) return false; - } - } - return hasStatements; - } - - @Override - public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) { - if (expression instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression; - if (methodCall.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) { - PsiMethod superMethod = (PsiMethod)methodCall.getMethodExpression().resolve(); - if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method, superMethod)) return false; - PsiExpression[] args = methodCall.getArgumentList().getExpressions(); - PsiParameter[] parms = method.getParameterList().getParameters(); - - for (int i = 0; i < args.length; i++) { - PsiExpression arg = args[i]; - if (!(arg instanceof PsiReferenceExpression)) return false; - if (!parms[i].equals(((PsiReferenceExpression)arg).resolve())) return false; - } - - return true; - } - } - - return false; - } - - @Override - public int compareAccess(String a1, String a2) { - int i1 = getAccessNumber(a1); - int i2 = getAccessNumber(a2); - - if (i1 == i2) return 0; - if (i1 < i2) return -1; - return 1; - } - - @SuppressWarnings("StringEquality") - private static int getAccessNumber(String a) { - if (a == PsiModifier.PRIVATE) { - return 0; - } - else if (a == PsiModifier.PACKAGE_LOCAL) { - return 1; - } - else if (a == PsiModifier.PROTECTED) { - return 2; - } - else if (a == PsiModifier.PUBLIC) return 3; - - return -1; - } - - @Override - public void setAccessModifier(RefJavaElement refElement, String newAccess) { - ((RefJavaElementImpl)refElement).setAccessModifier(newAccess); - } - - @Override - public void setIsStatic(RefJavaElement refElement, boolean isStatic) { - ((RefJavaElementImpl)refElement).setIsStatic(isStatic); - } - - @Override - public void setIsFinal(RefJavaElement refElement, boolean isFinal) { - ((RefJavaElementImpl)refElement).setIsFinal(isFinal); - } - - @Override - public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager) { - RefClass ownerClass = getOwnerClass(refManager, psiElement); - - if (ownerClass != null) { - psiType = psiType.getDeepComponentType(); - - if (psiType instanceof PsiClassType) { - PsiClass psiClass = PsiUtil.resolveClassInType(psiType); - if (psiClass != null && refManager.belongsToScope(psiClass)) { - RefClassImpl refClass = (RefClassImpl)refManager.getReference(psiClass); - if (refClass != null) { - refClass.addTypeReference(ownerClass); - } - } - } - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java deleted file mode 100644 index bca7bd179d03..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java +++ /dev/null @@ -1,687 +0,0 @@ -/* - * Copyright 2000-2009 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.reference; - -import com.intellij.codeInsight.ExceptionUtil; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.*; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SmartList; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -/** - * @author max - * Date: Oct 21, 2001 - */ -public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { - private static final List<RefMethod> EMPTY_METHOD_LIST = Collections.emptyList(); - private static final RefParameter[] EMPTY_PARAMS_ARRAY = new RefParameter[0]; - - private static final int IS_APPMAIN_MASK = 0x10000; - private static final int IS_LIBRARY_OVERRIDE_MASK = 0x20000; - private static final int IS_CONSTRUCTOR_MASK = 0x40000; - private static final int IS_ABSTRACT_MASK = 0x80000; - private static final int IS_BODY_EMPTY_MASK = 0x100000; - private static final int IS_ONLY_CALLS_SUPER_MASK = 0x200000; - private static final int IS_RETURN_VALUE_USED_MASK = 0x400000; - - private static final int IS_TEST_METHOD_MASK = 0x4000000; - private static final int IS_CALLED_ON_SUBCLASS = 0x8000000; - - private static final String RETURN_VALUE_UNDEFINED = "#"; - - private List<RefMethod> mySuperMethods; - private List<RefMethod> myDerivedMethods; - private List<String> myUnThrownExceptions; - - private RefParameter[] myParameters; - private String myReturnValueTemplate; - protected final RefClass myOwnerClass; - - RefMethodImpl(@NotNull RefClass ownerClass, PsiMethod method, RefManager manager) { - super(method, manager); - - ((RefClassImpl)ownerClass).add(this); - - myOwnerClass = ownerClass; - } - - // To be used only from RefImplicitConstructor. - protected RefMethodImpl(String name, @NotNull RefClass ownerClass) { - super(name, ownerClass); - myOwnerClass = ownerClass; - ((RefClassImpl)ownerClass).add(this); - - addOutReference(getOwnerClass()); - ((RefClassImpl)getOwnerClass()).addInReference(this); - - setConstructor(true); - } - - @Override - protected void initialize() { - final PsiMethod method = (PsiMethod)getElement(); - LOG.assertTrue(method != null); - setConstructor(method.isConstructor()); - setFlag(method.getReturnType() == null || PsiType.VOID.equals(method.getReturnType()), IS_RETURN_VALUE_USED_MASK); - - if (!isReturnValueUsed()) { - myReturnValueTemplate = RETURN_VALUE_UNDEFINED; - } - - if (isConstructor()) { - addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null); - } - - if (getOwnerClass().isInterface()) { - setAbstract(false); - } else { - setAbstract(method.hasModifierProperty(PsiModifier.ABSTRACT)); - } - - - setAppMain(isAppMain(method, this)); - setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE)); - - initializeSuperMethods(method); - if (isExternalOverride()) { - ((RefClassImpl)getOwnerClass()).addLibraryOverrideMethod(this); - } - - @NonNls final String name = method.getName(); - if (getOwnerClass().isTestCase() && name.startsWith("test")) { - setTestMethod(true); - } - - PsiParameter[] paramList = method.getParameterList().getParameters(); - if (paramList.length > 0){ - myParameters = new RefParameterImpl[paramList.length]; - for (int i = 0; i < paramList.length; i++) { - PsiParameter parameter = paramList[i]; - myParameters[i] = getRefJavaManager().getParameterReference(parameter, i); - } - } - - if (method.hasModifierProperty(PsiModifier.NATIVE)) { - updateReturnValueTemplate(null); - updateThrowsList(null); - } - collectUncaughtExceptions(method); - } - - private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) { - if (!refMethod.isStatic()) return false; - if (!PsiType.VOID.equals(psiMethod.getReturnType())) return false; - - PsiMethod appMainPattern = ((RefMethodImpl)refMethod).getRefJavaManager().getAppMainPattern(); - if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appMainPattern)) return true; - - PsiMethod appPremainPattern = ((RefMethodImpl)refMethod).getRefJavaManager().getAppPremainPattern(); - return MethodSignatureUtil.areSignaturesEqual(psiMethod, appPremainPattern); - } - - private void checkForSuperCall(PsiMethod method) { - if (isConstructor()) { - PsiCodeBlock body = method.getBody(); - if (body == null) return; - PsiStatement[] statements = body.getStatements(); - boolean isBaseExplicitlyCalled = false; - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression firstExpression = ((PsiExpressionStatement) first).getExpression(); - if (firstExpression instanceof PsiMethodCallExpression) { - PsiExpression qualifierExpression = ((PsiMethodCallExpression)firstExpression).getMethodExpression().getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression) { - @NonNls String text = qualifierExpression.getText(); - if ("super".equals(text) || text.equals("this")) { - isBaseExplicitlyCalled = true; - } - } - } - } - } - - if (!isBaseExplicitlyCalled) { - for (RefClass superClass : getOwnerClass().getBaseClasses()) { - RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor(); - - if (superDefaultConstructor != null) { - superDefaultConstructor.addInReference(this); - addOutReference(superDefaultConstructor); - } - } - } - } - } - - @Override - @NotNull - public Collection<RefMethod> getSuperMethods() { - if (mySuperMethods == null) return EMPTY_METHOD_LIST; - if (mySuperMethods.size() > 10) { - LOG.info("method: " + getName() + " owner:" + getOwnerClass().getQualifiedName()); - } - return mySuperMethods; - } - - @Override - @NotNull - public Collection<RefMethod> getDerivedMethods() { - if (myDerivedMethods == null) return EMPTY_METHOD_LIST; - return myDerivedMethods; - } - - @Override - public boolean isBodyEmpty() { - return checkFlag(IS_BODY_EMPTY_MASK); - } - - @Override - public boolean isOnlyCallsSuper() { - return checkFlag(IS_ONLY_CALLS_SUPER_MASK); - } - - @Override - public boolean hasBody() { - return !isAbstract() && !getOwnerClass().isInterface() || !isBodyEmpty(); - } - - private void initializeSuperMethods(PsiMethod method) { - for (PsiMethod psiSuperMethod : method.findSuperMethods()) { - if (getRefManager().belongsToScope(psiSuperMethod)) { - RefMethodImpl refSuperMethod = (RefMethodImpl)getRefManager().getReference(psiSuperMethod); - if (refSuperMethod != null) { - addSuperMethod(refSuperMethod); - refSuperMethod.markExtended(this); - } - } - else { - setLibraryOverride(true); - } - } - } - - public void addSuperMethod(RefMethodImpl refSuperMethod) { - if (!getSuperMethods().contains(refSuperMethod) && !refSuperMethod.getSuperMethods().contains(this)) { - if (mySuperMethods == null){ - mySuperMethods = new ArrayList<RefMethod>(1); - } - mySuperMethods.add(refSuperMethod); - } - } - - public void markExtended(RefMethodImpl method) { - if (!getDerivedMethods().contains(method) && !method.getDerivedMethods().contains(this)) { - if (myDerivedMethods == null) { - myDerivedMethods = new ArrayList<RefMethod>(1); - } - myDerivedMethods.add(method); - } - } - - @Override - @NotNull - public RefParameter[] getParameters() { - if (myParameters == null) return EMPTY_PARAMS_ARRAY; - return myParameters; - } - - @Override - public void buildReferences() { - // Work on code block to find what we're referencing... - PsiMethod method = (PsiMethod) getElement(); - if (method == null) return; - PsiCodeBlock body = method.getBody(); - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - refUtil.addReferences(method, this, body); - refUtil.addReferences(method, this, method.getModifierList()); - checkForSuperCall(method); - setOnlyCallsSuper(refUtil.isMethodOnlyCallsSuper(method)); - - setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && (body == null || body.getStatements().length == 0)); - - PsiType retType = method.getReturnType(); - if (retType != null) { - PsiType psiType = retType; - RefClass ownerClass = refUtil.getOwnerClass(getRefManager(), method); - - if (ownerClass != null) { - psiType = psiType.getDeepComponentType(); - - if (psiType instanceof PsiClassType) { - PsiClass psiClass = PsiUtil.resolveClassInType(psiType); - if (psiClass != null && getRefManager().belongsToScope(psiClass)) { - RefClassImpl refClass = (RefClassImpl) getRefManager().getReference(psiClass); - if (refClass != null) { - refClass.addTypeReference(ownerClass); - refClass.addClassExporter(this); - } - } - } - } - } - - for (RefParameter parameter : getParameters()) { - refUtil.setIsFinal(parameter, parameter.getElement().hasModifierProperty(PsiModifier.FINAL)); - } - - getRefManager().fireBuildReferences(this); - } - - private void collectUncaughtExceptions(@NotNull PsiMethod method) { - if (isExternalOverride()) return; - @NonNls final String name = method.getName(); - if (getOwnerClass().isTestCase() && name.startsWith("test")) return; - - if (getSuperMethods().isEmpty()) { - PsiClassType[] throwsList = method.getThrowsList().getReferencedTypes(); - if (throwsList.length > 0) { - myUnThrownExceptions = throwsList.length == 1 ? new SmartList<String>() : new ArrayList<String>(throwsList.length); - for (final PsiClassType type : throwsList) { - PsiClass aClass = type.resolve(); - String fqn = aClass == null ? null : aClass.getQualifiedName(); - if (fqn != null) { - myUnThrownExceptions.add(fqn); - } - } - } - } - - final PsiCodeBlock body = method.getBody(); - if (body == null) return; - - final Collection<PsiClassType> exceptionTypes = ExceptionUtil.collectUnhandledExceptions(body, method, false); - for (final PsiClassType exceptionType : exceptionTypes) { - updateThrowsList(exceptionType); - } - } - - public void removeUnThrownExceptions(PsiClass unThrownException) { - if (myUnThrownExceptions != null) { - myUnThrownExceptions.remove(unThrownException.getQualifiedName()); - } - } - - @Override - public void accept(@NotNull final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor)visitor).visitMethod(RefMethodImpl.this); - } - }); - } else { - super.accept(visitor); - } - } - - @Override - public boolean isExternalOverride() { - return isLibraryOverride(new HashSet<RefMethod>()); - } - - private boolean isLibraryOverride(Collection<RefMethod> processed) { - if (processed.contains(this)) return false; - processed.add(this); - - if (checkFlag(IS_LIBRARY_OVERRIDE_MASK)) return true; - for (RefMethod superMethod : getSuperMethods()) { - if (((RefMethodImpl)superMethod).isLibraryOverride(processed)) { - setFlag(true, IS_LIBRARY_OVERRIDE_MASK); - return true; - } - } - - return false; - } - - @Override - public boolean isAppMain() { - return checkFlag(IS_APPMAIN_MASK); - } - - @Override - public boolean isAbstract() { - return checkFlag(IS_ABSTRACT_MASK); - } - - @Override - public boolean hasSuperMethods() { - return !getSuperMethods().isEmpty() || isExternalOverride(); - } - - @Override - public boolean isReferenced() { - // Directly called from somewhere.. - for (RefElement refCaller : getInReferences()) { - if (!getDerivedMethods().contains(refCaller)) return true; - } - - // Library override probably called from library code. - return isExternalOverride(); - } - - @Override - public boolean hasSuspiciousCallers() { - // Directly called from somewhere.. - for (RefElement refCaller : getInReferences()) { - if (((RefElementImpl)refCaller).isSuspicious() && !getDerivedMethods().contains(refCaller)) return true; - } - - // Library override probably called from library code. - if (isExternalOverride()) return true; - - // Class isn't instantiated. Most probably we have problem with class, not method. - if (!isStatic() && !isConstructor()) { - if (((RefClassImpl)getOwnerClass()).isSuspicious()) return true; - - // Is an override. Probably called via reference to base class. - for (RefMethod refSuper : getSuperMethods()) { - if (((RefMethodImpl)refSuper).isSuspicious()) return true; - } - } - - return false; - } - - @Override - public boolean isConstructor() { - return checkFlag(IS_CONSTRUCTOR_MASK); - } - - @Override - public RefClass getOwnerClass() { - return (RefClass) getOwner(); - } - - @NotNull - @Override - public String getName() { - if (isValid()) { - final String[] result = new String[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - PsiMethod psiMethod = (PsiMethod) getElement(); - if (psiMethod instanceof JspHolderMethod) { - result[0] = psiMethod.getName(); - } - else { - result[0] = PsiFormatUtil.formatMethod(psiMethod, - PsiSubstitutor.EMPTY, - PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, - PsiFormatUtilBase.SHOW_TYPE - ); - } - } - }; - - ApplicationManager.getApplication().runReadAction(runnable); - - return result[0]; - } else { - return super.getName(); - } - } - - @Override - public String getExternalName() { - final String[] result = new String[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - final PsiMethod psiMethod = (PsiMethod)getElement(); - LOG.assertTrue(psiMethod != null); - result[0] = PsiFormatUtil.getExternalName(psiMethod); - } - }; - - ApplicationManager.getApplication().runReadAction(runnable); - - return result[0]; - } - - @Nullable - public static RefMethod methodFromExternalName(RefManager manager, String externalName) { - return (RefMethod) manager.getReference(findPsiMethod(PsiManager.getInstance(manager.getProject()), externalName)); - } - - @Nullable - public static PsiMethod findPsiMethod(PsiManager manager, String externalName) { - final int spaceIdx = externalName.indexOf(' '); - final String className = externalName.substring(0, spaceIdx); - final PsiClass psiClass = ClassUtil.findPsiClass(manager, className); - if (psiClass == null) return null; - try { - PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); - String methodSignature = externalName.substring(spaceIdx + 1); - PsiMethod patternMethod = factory.createMethodFromText(methodSignature, psiClass); - return psiClass.findMethodBySignature(patternMethod, false); - } catch (IncorrectOperationException e) { - // Do nothing. Returning null is acceptable in this case. - return null; - } - } - - @Override - public void referenceRemoved() { - if (getOwnerClass() != null) { - ((RefClassImpl)getOwnerClass()).methodRemoved(this); - } - - super.referenceRemoved(); - - for (RefMethod superMethod : getSuperMethods()) { - superMethod.getDerivedMethods().remove(this); - } - - for (RefMethod subMethod : getDerivedMethods()) { - subMethod.getSuperMethods().remove(this); - } - - ArrayList<RefElement> deletedRefs = new ArrayList<RefElement>(); - for (RefParameter parameter : getParameters()) { - getRefManager().removeRefElement(parameter, deletedRefs); - } - } - - @Override - public boolean isSuspicious() { - if (isConstructor() && PsiModifier.PRIVATE.equals(getAccessModifier()) && getParameters().length == 0 && getOwnerClass().getConstructors().size() == 1) return false; - return super.isSuspicious(); - } - - public void setReturnValueUsed(boolean value) { - if (checkFlag(IS_RETURN_VALUE_USED_MASK) == value) return; - setFlag(value, IS_RETURN_VALUE_USED_MASK); - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl)refSuper).setReturnValueUsed(value); - } - } - - @Override - public boolean isReturnValueUsed() { - return checkFlag(IS_RETURN_VALUE_USED_MASK); - } - - public void updateReturnValueTemplate(PsiExpression expression) { - if (myReturnValueTemplate == null) return; - - if (!getSuperMethods().isEmpty()) { - for (final RefMethod refMethod : getSuperMethods()) { - RefMethodImpl refSuper = (RefMethodImpl)refMethod; - refSuper.updateReturnValueTemplate(expression); - } - }else { - String newTemplate = null; - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - if (expression instanceof PsiLiteralExpression) { - PsiLiteralExpression psiLiteralExpression = (PsiLiteralExpression) expression; - newTemplate = psiLiteralExpression.getText(); - } else if (expression instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression; - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiField) { - PsiField psiField = (PsiField) resolved; - if (psiField.hasModifierProperty(PsiModifier.STATIC) && - psiField.hasModifierProperty(PsiModifier.FINAL) && - refUtil.compareAccess(refUtil.getAccessModifier(psiField), getAccessModifier()) >= 0) { - newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME | - PsiFormatUtilBase.SHOW_CONTAINING_CLASS | - PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); - } - } - } else if (refUtil.isCallToSuperMethod(expression, (PsiMethod) getElement())) return; - - //noinspection StringEquality - if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) { - myReturnValueTemplate = newTemplate; - } else if (!Comparing.equal(myReturnValueTemplate, newTemplate)) { - myReturnValueTemplate = null; - } - } - } - - public void updateParameterValues(PsiExpression[] args) { - if (isExternalOverride()) return; - - if (!getSuperMethods().isEmpty()) { - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl)refSuper).updateParameterValues(args); - } - } else { - final RefParameter[] params = getParameters(); - if (params.length <= args.length && params.length > 0) { - for (int i = 0; i < args.length; i++) { - RefParameter refParameter; - if (params.length <= i){ - refParameter = params[params.length - 1]; - } else { - refParameter = params[i]; - } - ((RefParameterImpl)refParameter).updateTemplateValue(args[i]); - } - } - } - } - - @Override - public String getReturnValueIfSame() { - //noinspection StringEquality - if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) return null; - return myReturnValueTemplate; - } - - public void updateThrowsList(PsiClassType exceptionType) { - if (!getSuperMethods().isEmpty()) { - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl)refSuper).updateThrowsList(exceptionType); - } - } - else if (myUnThrownExceptions != null) { - if (exceptionType == null) { - myUnThrownExceptions = null; - return; - } - PsiClass exceptionClass = exceptionType.resolve(); - JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); - for (int i = myUnThrownExceptions.size() - 1; i >= 0; i--) { - String exceptionFqn = myUnThrownExceptions.get(i); - PsiClass classType = facade.findClass(exceptionFqn, GlobalSearchScope.allScope(getRefManager().getProject())); - if (InheritanceUtil.isInheritorOrSelf(exceptionClass, classType, true) || - InheritanceUtil.isInheritorOrSelf(classType, exceptionClass, true)) { - myUnThrownExceptions.remove(i); - } - } - - if (myUnThrownExceptions.isEmpty()) myUnThrownExceptions = null; - } - } - - @Override - @Nullable - public PsiClass[] getUnThrownExceptions() { - if (myUnThrownExceptions == null) return null; - JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); - List<PsiClass> result = new ArrayList<PsiClass>(myUnThrownExceptions.size()); - for (String exception : myUnThrownExceptions) { - PsiClass element = facade.findClass(exception, GlobalSearchScope.allScope(myManager.getProject())); - if (element != null) result.add(element); - } - return result.toArray(new PsiClass[result.size()]); - } - - - public void setLibraryOverride(boolean libraryOverride) { - setFlag(libraryOverride, IS_LIBRARY_OVERRIDE_MASK); - } - - private void setAppMain(boolean appMain) { - setFlag(appMain, IS_APPMAIN_MASK); - } - - private void setAbstract(boolean anAbstract) { - setFlag(anAbstract, IS_ABSTRACT_MASK); - } - - public void setBodyEmpty(boolean bodyEmpty) { - setFlag(bodyEmpty, IS_BODY_EMPTY_MASK); - } - - private void setOnlyCallsSuper(boolean onlyCallsSuper) { - setFlag(onlyCallsSuper, IS_ONLY_CALLS_SUPER_MASK); - } - - - - private void setConstructor(boolean constructor) { - setFlag(constructor, IS_CONSTRUCTOR_MASK); - } - - @Override - public boolean isTestMethod() { - return checkFlag(IS_TEST_METHOD_MASK); - } - - private void setTestMethod(boolean testMethod){ - setFlag(testMethod, IS_TEST_METHOD_MASK); - } - - @Override - public PsiModifierListOwner getElement() { - return (PsiModifierListOwner)super.getElement(); - } - - @Override - public boolean isCalledOnSubClass() { - return checkFlag(IS_CALLED_ON_SUBCLASS); - } - - public void setCalledOnSubClass(boolean isCalledOnSubClass){ - setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS); - } - -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java deleted file mode 100644 index 32649b924a25..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefPackageImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Nov 15, 2001 - * Time: 5:17:38 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.reference; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.util.PlatformIcons; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - - -public class RefPackageImpl extends RefEntityImpl implements RefPackage { - private final String myQualifiedName; - - public RefPackageImpl(@NotNull String name, @NotNull RefManager refManager) { - super(getPackageSuffix(name), refManager); - myQualifiedName = name; - } - - @NotNull - @Override - public String getQualifiedName() { - return myQualifiedName; - } - - private static String getPackageSuffix(@NotNull String fullName) { - int dotIndex = fullName.lastIndexOf('.'); - return (dotIndex >= 0) ? fullName.substring(dotIndex + 1) : fullName; - } - - - @Override - public void accept(@NotNull final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor)visitor).visitPackage(RefPackageImpl.this); - } - }); - } else { - super.accept(visitor); - } - } - - @Override - public String getExternalName() { - return getQualifiedName(); - } - - public static RefEntity packageFromFQName(final RefManager manager, final String name) { - return manager.getExtension(RefJavaManager.MANAGER).getPackage(name); - } - - @Override - public boolean isValid() { - return true; - } - - @Override - public Icon getIcon(final boolean expanded) { - return PlatformIcons.PACKAGE_ICON; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java deleted file mode 100644 index f33145fa070e..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Oct 21, 2001 - * Time: 4:35:07 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.reference; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class RefParameterImpl extends RefJavaElementImpl implements RefParameter { - private static final int USED_FOR_READING_MASK = 0x10000; - private static final int USED_FOR_WRITING_MASK = 0x20000; - private static final String VALUE_UNDEFINED = "#"; - - private final short myIndex; - private String myActualValueTemplate; - - RefParameterImpl(PsiParameter parameter, int index, RefManager manager) { - super(parameter, manager); - - myIndex = (short)index; - myActualValueTemplate = VALUE_UNDEFINED; - final RefElementImpl owner = (RefElementImpl)manager.getReference(PsiTreeUtil.getParentOfType(parameter, PsiMethod.class)); - if (owner != null) { - owner.add(this); - } - } - - @Override - public void parameterReferenced(boolean forWriting) { - if (forWriting) { - setUsedForWriting(); - } else { - setUsedForReading(); - } - } - - @Override - public boolean isUsedForReading() { - return checkFlag(USED_FOR_READING_MASK); - } - - private void setUsedForReading() { - setFlag(true, USED_FOR_READING_MASK); - } - - @Override - public PsiParameter getElement() { - return (PsiParameter)super.getElement(); - } - - @Override - public boolean isUsedForWriting() { - return checkFlag(USED_FOR_WRITING_MASK); - } - - private void setUsedForWriting() { - setFlag(true, USED_FOR_WRITING_MASK); - } - - @Override - public void accept(@NotNull final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor)visitor).visitParameter(RefParameterImpl.this); - } - }); - } else { - super.accept(visitor); - } - } - - @Override - public int getIndex() { - return myIndex; - } - - public void updateTemplateValue(PsiExpression expression) { - if (myActualValueTemplate == null) return; - - String newTemplate = null; - if (expression instanceof PsiLiteralExpression) { - PsiLiteralExpression psiLiteralExpression = (PsiLiteralExpression) expression; - newTemplate = psiLiteralExpression.getText(); - } else if (expression instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression; - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiField) { - PsiField psiField = (PsiField) resolved; - if (psiField.hasModifierProperty(PsiModifier.STATIC) && - psiField.hasModifierProperty(PsiModifier.FINAL) && - psiField.getContainingClass().getQualifiedName() != null) { - newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_CONTAINING_CLASS | PsiFormatUtil.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); - } - } - } - - if (myActualValueTemplate == VALUE_UNDEFINED) { - myActualValueTemplate = newTemplate; - } else if (!Comparing.equal(myActualValueTemplate, newTemplate)) { - myActualValueTemplate = null; - } - } - - @Override - public String getActualValueIfSame() { - if (myActualValueTemplate == VALUE_UNDEFINED) return null; - return myActualValueTemplate; - } - - @Override - protected void initialize() { - } - - @Override - public String getExternalName() { - final String[] result = new String[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - PsiParameter parameter = getElement(); - LOG.assertTrue(parameter != null); - result[0] = PsiFormatUtil.getExternalName(parameter); - } - }; - - ApplicationManager.getApplication().runReadAction(runnable); - - return result[0]; - } - - @Nullable - public static RefElement parameterFromExternalName(final RefManager manager, final String fqName) { - final int idx = fqName.lastIndexOf(' '); - if (idx > 0) { - final String paramName = fqName.substring(idx + 1); - final String method = fqName.substring(0, idx); - final RefMethod refMethod = RefMethodImpl.methodFromExternalName(manager, method); - if (refMethod != null) { - final PsiMethod element = (PsiMethod)refMethod.getElement(); - final PsiParameterList list = element.getParameterList(); - final PsiParameter[] parameters = list.getParameters(); - int paramIdx = 0; - for (PsiParameter parameter : parameters) { - final String name = parameter.getName(); - if (name != null && name.equals(paramName)) { - return manager.getExtension(RefJavaManager.MANAGER).getParameterReference(parameter, paramIdx); - } - paramIdx++; - } - } - } - return null; - } - - @Nullable - public static PsiParameter findPsiParameter(String fqName, final PsiManager manager) { - final int idx = fqName.lastIndexOf(' '); - if (idx > 0) { - final String paramName = fqName.substring(idx + 1); - final String method = fqName.substring(0, idx); - final PsiMethod psiMethod = RefMethodImpl.findPsiMethod(manager, method); - if (psiMethod != null) { - final PsiParameterList list = psiMethod.getParameterList(); - final PsiParameter[] parameters = list.getParameters(); - for (PsiParameter parameter : parameters) { - final String name = parameter.getName(); - if (name != null && name.equals(paramName)) { - return parameter; - } - } - } - } - return null; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java index 0f756686403c..12e26f8bd673 100644 --- a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java @@ -41,7 +41,7 @@ import java.util.List; /** * @author max */ -public class SameParameterValueInspection extends GlobalJavaInspectionTool { +public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool { private static final Logger LOG = Logger.getInstance("#" + SameParameterValueInspection.class.getName()); @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java deleted file mode 100644 index 7d4c3536b139..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2000-2009 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.sameReturnValue; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.reference.*; -import com.intellij.psi.PsiMethod; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author max - */ -public class SameReturnValueInspection extends GlobalJavaInspectionTool { - @Override - @Nullable - public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, @NotNull AnalysisScope scope, @NotNull InspectionManager manager, @NotNull GlobalInspectionContext globalContext, - @NotNull ProblemDescriptionsProcessor processor) { - if (refEntity instanceof RefMethod) { - final RefMethod refMethod = (RefMethod)refEntity; - - if (refMethod.isConstructor()) return null; - if (refMethod.hasSuperMethods()) return null; - - String returnValue = refMethod.getReturnValueIfSame(); - if (returnValue != null) { - final String message; - if (refMethod.getDerivedMethods().isEmpty()) { - message = InspectionsBundle.message("inspection.same.return.value.problem.descriptor", "<code>" + returnValue + "</code>"); - } else if (refMethod.hasBody()) { - message = InspectionsBundle.message("inspection.same.return.value.problem.descriptor1", "<code>" + returnValue + "</code>"); - } else { - message = InspectionsBundle.message("inspection.same.return.value.problem.descriptor2", "<code>" + returnValue + "</code>"); - } - - return new ProblemDescriptor[] {manager.createProblemDescriptor(refMethod.getElement().getNavigationElement(), message, false, null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING)}; - } - } - - return null; - } - - - @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor processor) { - manager.iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { - if (refEntity instanceof RefElement && processor.getDescriptions(refEntity) != null) { - refEntity.accept(new RefJavaVisitor() { - @Override public void visitMethod(@NotNull final RefMethod refMethod) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - processor.ignoreElement(refMethod); - return false; - } - }); - } - }); - } - } - }); - - return false; - } - - @Override - @NotNull - public String getDisplayName() { - return InspectionsBundle.message("inspection.same.return.value.display.name"); - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getShortName() { - return "SameReturnValue"; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java b/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java index 7363d43c104b..b02ce22527bf 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java +++ b/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java @@ -15,7 +15,7 @@ */ package com.intellij.codeInspection.ui; -import com.intellij.codeInspection.deadCode.DummyEntryPointsTool; +import com.intellij.codeInspection.deadCode.DummyEntryPointsEP; import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; import com.intellij.codeInspection.ex.InspectionToolWrapper; @@ -33,7 +33,7 @@ public class EntryPointsNode extends InspectionNode { } private static InspectionToolWrapper createDummyWrapper(@NotNull GlobalInspectionContextImpl context) { - InspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new DummyEntryPointsTool()); + InspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new DummyEntryPointsEP()); toolWrapper.initialize(context); return toolWrapper; } diff --git a/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java index 24cc9d181fd2..b740fcf9e7f6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java @@ -24,14 +24,12 @@ import com.intellij.codeInsight.daemon.impl.quickfix.VariableArrayTypeFix; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.codeInsight.quickfix.ChangeVariableTypeQuickFixProvider; -import com.intellij.codeInspection.BaseJavaLocalInspectionTool; -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.codeInspection.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.*; import org.intellij.lang.annotations.Pattern; @@ -168,8 +166,13 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool @NotNull @Override - public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { - return new UncheckedWarningsVisitor(isOnTheFly){ + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, + boolean isOnTheFly, + @NotNull LocalInspectionToolSession session) { + LanguageLevel languageLevel = PsiUtil.getLanguageLevel(session.getFile()); + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) return super.buildVisitor(holder, isOnTheFly, session); + + return new UncheckedWarningsVisitor(isOnTheFly, languageLevel){ @Override protected void registerProblem(@NotNull String message, @NotNull PsiElement psiElement, @NotNull LocalQuickFix[] quickFixes) { holder.registerProblem(psiElement, message, quickFixes); @@ -179,10 +182,12 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool private abstract class UncheckedWarningsVisitor extends JavaElementVisitor { private final boolean myOnTheFly; + @NotNull private final LanguageLevel myLanguageLevel; private final LocalQuickFix[] myGenerifyFixes; - public UncheckedWarningsVisitor(boolean onTheFly) { + public UncheckedWarningsVisitor(boolean onTheFly, @NotNull LanguageLevel level) { myOnTheFly = onTheFly; + myLanguageLevel = level; myGenerifyFixes = onTheFly ? new LocalQuickFix[]{new GenerifyFileFix()} : LocalQuickFix.EMPTY_ARRAY; } @@ -192,9 +197,8 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool @Override public void visitReferenceExpression(PsiReferenceExpression expression) { if (IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION) return; - if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; final JavaResolveResult result = expression.advancedResolve(false); - if (JavaGenericsUtil.isUncheckedWarning(expression, result)) { + if (JavaGenericsUtil.isUncheckedWarning(expression, result, myLanguageLevel)) { registerProblem("Unchecked generics array creation for varargs parameter", expression, LocalQuickFix.EMPTY_ARRAY); } } @@ -203,9 +207,8 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitNewExpression(PsiNewExpression expression) { super.visitNewExpression(expression); if (IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION) return; - if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); - if (JavaGenericsUtil.isUncheckedWarning(classReference, expression.resolveMethodGenerics())) { + if (classReference != null && JavaGenericsUtil.isUncheckedWarning(classReference, expression.resolveMethodGenerics(), myLanguageLevel)) { registerProblem("Unchecked generics array creation for varargs parameter", classReference, LocalQuickFix.EMPTY_ARRAY); } } @@ -214,7 +217,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitTypeCastExpression(PsiTypeCastExpression expression) { super.visitTypeCastExpression(expression); if (IGNORE_UNCHECKED_CAST) return; - if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; final PsiTypeElement typeElement = expression.getCastType(); if (typeElement == null) return; final PsiType castType = typeElement.getType(); @@ -234,7 +236,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool @Override public void visitCallExpression(PsiCallExpression callExpression) { super.visitCallExpression(callExpression); - if (!PsiUtil.isLanguageLevel5OrHigher(callExpression)) return; final JavaResolveResult result = callExpression.resolveMethodGenerics(); final String description = getUncheckedCallDescription(result); if (description != null) { @@ -273,7 +274,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitVariable(PsiVariable variable) { super.visitVariable(variable); if (IGNORE_UNCHECKED_ASSIGNMENT) return; - if (!PsiUtil.isLanguageLevel5OrHigher(variable)) return; PsiExpression initializer = variable.getInitializer(); if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return; final PsiType initializerType = initializer.getType(); @@ -285,13 +285,11 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitForeachStatement(PsiForeachStatement statement) { super.visitForeachStatement(statement); if (IGNORE_UNCHECKED_ASSIGNMENT) return; - if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; final PsiParameter parameter = statement.getIterationParameter(); final PsiType parameterType = parameter.getType(); final PsiExpression iteratedValue = statement.getIteratedValue(); if (iteratedValue == null) return; final PsiType itemType = JavaGenericsUtil.getCollectionItemType(iteratedValue); - if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; checkRawToGenericsAssignment(parameter, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType) : LocalQuickFix.EMPTY_ARRAY); } @@ -299,7 +297,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitAssignmentExpression(PsiAssignmentExpression expression) { super.visitAssignmentExpression(expression); if (IGNORE_UNCHECKED_ASSIGNMENT) return; - if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; if (!"=".equals(expression.getOperationSign().getText())) return; PsiExpression lExpr = expression.getLExpression(); PsiExpression rExpr = expression.getRExpression(); @@ -321,7 +318,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitArrayInitializerExpression(PsiArrayInitializerExpression arrayInitializer) { super.visitArrayInitializerExpression(arrayInitializer); if (IGNORE_UNCHECKED_ASSIGNMENT) return; - if (!PsiUtil.isLanguageLevel5OrHigher(arrayInitializer)) return; final PsiType type = arrayInitializer.getType(); if (!(type instanceof PsiArrayType)) return; final PsiType componentType = ((PsiArrayType)type).getComponentType(); @@ -372,7 +368,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitMethod(PsiMethod method) { super.visitMethod(method); if (IGNORE_UNCHECKED_OVERRIDING) return; - if (!PsiUtil.isLanguageLevel5OrHigher(method)) return; if (!method.isConstructor()) { List<HierarchicalMethodSignature> superMethodSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); if (!superMethodSignatures.isEmpty() && !method.hasModifierProperty(PsiModifier.STATIC)) { @@ -403,7 +398,6 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public void visitReturnStatement(PsiReturnStatement statement) { super.visitReturnStatement(statement); if (IGNORE_UNCHECKED_ASSIGNMENT) return; - if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); if (method != null) { final PsiType returnType = method.getReturnType(); diff --git a/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java b/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java deleted file mode 100644 index 0ee3c679beb5..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.intellij.codeInspection.unnecessaryModuleDependency; - -import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefGraphAnnotator; -import com.intellij.codeInspection.reference.RefManager; -import com.intellij.codeInspection.reference.RefModule; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiElement; - -import java.util.HashSet; -import java.util.Set; - -/** - * User: anna - * Date: 09-Jan-2006 - */ -public class UnnecessaryModuleDependencyAnnotator extends RefGraphAnnotator { - public static final Key<Set<Module>> DEPENDENCIES = Key.create("inspection.dependencies"); - - private final RefManager myManager; - - public UnnecessaryModuleDependencyAnnotator(final RefManager manager) { - myManager = manager; - } - - - - @Override - public void onMarkReferenced(RefElement refWhat, RefElement refFrom, boolean referencedFromClassInitializer) { - final PsiElement onElement = refWhat.getElement(); - final PsiElement fromElement = refFrom.getElement(); - if (onElement != null && fromElement!= null){ - final Module onModule = ModuleUtil.findModuleForPsiElement(onElement); - final Module fromModule = ModuleUtil.findModuleForPsiElement(fromElement); - if (onModule != null && fromModule != null && onModule != fromModule){ - final RefModule refModule = myManager.getRefModule(fromModule); - if (refModule != null) { - Set<Module> modules = refModule.getUserData(DEPENDENCIES); - if (modules == null){ - modules = new HashSet<Module>(); - refModule.putUserData(DEPENDENCIES, modules); - } - modules.add(onModule); - } - } - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java b/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java deleted file mode 100644 index 87e99c553b36..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.intellij.codeInspection.unnecessaryModuleDependency; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.reference.RefGraphAnnotator; -import com.intellij.codeInspection.reference.RefManager; -import com.intellij.codeInspection.reference.RefModule; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ModifiableRootModel; -import com.intellij.openapi.roots.ModuleOrderEntry; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.OrderEntry; -import com.intellij.openapi.util.Comparing; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * User: anna - * Date: 09-Jan-2006 - */ -public class UnnecessaryModuleDependencyInspection extends GlobalInspectionTool { - - @Override - public RefGraphAnnotator getAnnotator(@NotNull final RefManager refManager) { - return new UnnecessaryModuleDependencyAnnotator(refManager); - } - - @Override - public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, @NotNull AnalysisScope scope, @NotNull InspectionManager manager, @NotNull final GlobalInspectionContext globalContext) { - if (refEntity instanceof RefModule){ - final RefModule refModule = (RefModule)refEntity; - final Module module = refModule.getModule(); - final Module[] declaredDependencies = ModuleRootManager.getInstance(module).getDependencies(); - List<CommonProblemDescriptor> descriptors = new ArrayList<CommonProblemDescriptor>(); - final Set<Module> modules = refModule.getUserData(UnnecessaryModuleDependencyAnnotator.DEPENDENCIES); - for (final Module dependency : declaredDependencies) { - if (modules == null || !modules.contains(dependency)) { - final CommonProblemDescriptor problemDescriptor; - if (scope.containsModule(dependency)) { //external references are rejected -> annotator doesn't provide any information on them -> false positives - problemDescriptor = manager.createProblemDescriptor( - InspectionsBundle.message("unnecessary.module.dependency.problem.descriptor", module.getName(), dependency.getName()), - new RemoveModuleDependencyFix(module, dependency)); - } else { - String message = InspectionsBundle - .message("suspected.module.dependency.problem.descriptor", module.getName(), dependency.getName(), scope.getDisplayName(), - dependency.getName()); - problemDescriptor = manager.createProblemDescriptor(message); - } - descriptors.add(problemDescriptor); - } - } - return descriptors.isEmpty() ? null : descriptors.toArray(new CommonProblemDescriptor[descriptors.size()]); - } - return null; - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getDisplayName() { - return InspectionsBundle.message("unnecessary.module.dependency.display.name"); - } - - @Override - @NotNull - @NonNls - public String getShortName() { - return "UnnecessaryModuleDependencyInspection"; - } - - public static class RemoveModuleDependencyFix implements QuickFix { - private final Module myModule; - private final Module myDependency; - - public RemoveModuleDependencyFix(Module module, Module dependency) { - myModule = module; - myDependency = dependency; - } - - @Override - @NotNull - public String getName() { - return "Remove dependency"; - } - - @Override - @NotNull - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull CommonProblemDescriptor descriptor) { - final ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel(); - for (OrderEntry entry : model.getOrderEntries()) { - if (entry instanceof ModuleOrderEntry) { - final Module mDependency = ((ModuleOrderEntry)entry).getModule(); - if (Comparing.equal(mDependency, myDependency)) { - model.removeOrderEntry(entry); - break; - } - } - } - model.commit(); - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrows.java b/java/java-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrows.java deleted file mode 100644 index 8810af9e6bea..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrows.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright 2000-2009 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.unneededThrows; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.ExceptionUtil; -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.reference.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.searches.AllOverridingMethodsSearch; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; -import com.intellij.util.Query; -import com.intellij.util.containers.BidirectionalMap; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author max - */ -public class RedundantThrows extends GlobalJavaInspectionTool { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.unneededThrows.RedundantThrows"); - private static final String DISPLAY_NAME = InspectionsBundle.message("inspection.redundant.throws.display.name"); - private final BidirectionalMap<String, QuickFix> myQuickFixes = new BidirectionalMap<String, QuickFix>(); - @NonNls private static final String SHORT_NAME = "RedundantThrows"; - - @Override - @Nullable - public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, - @NotNull AnalysisScope scope, - @NotNull InspectionManager manager, - @NotNull GlobalInspectionContext globalContext, - @NotNull ProblemDescriptionsProcessor processor) { - if (refEntity instanceof RefMethod) { - final RefMethod refMethod = (RefMethod)refEntity; - if (refMethod.isSyntheticJSP()) return null; - - if (refMethod.hasSuperMethods()) return null; - - if (refMethod.isEntry()) return null; - - PsiClass[] unThrown = refMethod.getUnThrownExceptions(); - if (unThrown == null) return null; - - PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); - PsiClassType[] throwsList = psiMethod.getThrowsList().getReferencedTypes(); - PsiJavaCodeReferenceElement[] throwsRefs = psiMethod.getThrowsList().getReferenceElements(); - List<ProblemDescriptor> problems = null; - - final PsiManager psiManager = psiMethod.getManager(); - for (int i = 0; i < throwsList.length; i++) { - final PsiClassType throwsType = throwsList[i]; - final String throwsClassName = throwsType.getClassName(); - final PsiJavaCodeReferenceElement throwsRef = throwsRefs[i]; - if (ExceptionUtil.isUncheckedException(throwsType)) continue; - if (declaredInRemotableMethod(psiMethod, throwsType)) continue; - - for (PsiClass s : unThrown) { - final PsiClass throwsResolvedType = throwsType.resolve(); - if (psiManager.areElementsEquivalent(s, throwsResolvedType)) { - if (problems == null) problems = new ArrayList<ProblemDescriptor>(1); - - if (refMethod.isAbstract() || refMethod.getOwnerClass().isInterface()) { - problems.add(manager.createProblemDescriptor(throwsRef, InspectionsBundle.message( - "inspection.redundant.throws.problem.descriptor", "<code>#ref</code>"), getFix(processor, throwsClassName), ProblemHighlightType.LIKE_UNUSED_SYMBOL, - false)); - } - else if (!refMethod.getDerivedMethods().isEmpty()) { - problems.add(manager.createProblemDescriptor(throwsRef, InspectionsBundle.message( - "inspection.redundant.throws.problem.descriptor1", "<code>#ref</code>"), getFix(processor, throwsClassName), ProblemHighlightType.LIKE_UNUSED_SYMBOL, - false)); - } - else { - problems.add(manager.createProblemDescriptor(throwsRef, InspectionsBundle.message( - "inspection.redundant.throws.problem.descriptor2", "<code>#ref</code>"), getFix(processor, throwsClassName), ProblemHighlightType.LIKE_UNUSED_SYMBOL, - false)); - } - } - } - } - - if (problems != null) { - return problems.toArray(new CommonProblemDescriptor[problems.size()]); - } - } - - return null; - } - - private static boolean declaredInRemotableMethod(final PsiMethod psiMethod, final PsiClassType throwsType) { - if (!throwsType.equalsToText("java.rmi.RemoteException")) return false; - PsiClass aClass = psiMethod.getContainingClass(); - if (aClass == null) return false; - PsiClass remote = - JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.rmi.Remote", GlobalSearchScope.allScope(aClass.getProject())); - return remote != null && aClass.isInheritor(remote, true); - } - - - @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor processor) { - manager.iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { - if (processor.getDescriptions(refEntity) != null) { - refEntity.accept(new RefJavaVisitor() { - @Override public void visitMethod(@NotNull final RefMethod refMethod) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - processor.ignoreElement(refMethod); - return true; - } - }); - } - }); - } - } - }); - - return false; - } - - @Override - @NotNull - public String getDisplayName() { - return DISPLAY_NAME; - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getShortName() { - return SHORT_NAME; - } - - private LocalQuickFix getFix(final ProblemDescriptionsProcessor processor, final String hint) { - QuickFix fix = myQuickFixes.get(hint); - if (fix == null) { - fix = new MyQuickFix(processor, hint); - if (hint != null) { - myQuickFixes.put(hint, fix); - } - } - return (LocalQuickFix)fix; - } - - - @Override - @Nullable - public QuickFix getQuickFix(String hint) { - return getFix(null, hint); - } - - @Override - @Nullable - public String getHint(@NotNull final QuickFix fix) { - final List<String> hints = myQuickFixes.getKeysByValue(fix); - LOG.assertTrue(hints != null && hints.size() == 1); - return hints.get(0); - } - - private static class MyQuickFix implements LocalQuickFix { - private final ProblemDescriptionsProcessor myProcessor; - private final String myHint; - - public MyQuickFix(final ProblemDescriptionsProcessor processor, final String hint) { - myProcessor = processor; - myHint = hint; - } - - @Override - @NotNull - public String getName() { - return InspectionsBundle.message("inspection.redundant.throws.remove.quickfix"); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - if (myProcessor != null) { - RefElement refElement = (RefElement)myProcessor.getElement(descriptor); - if (refElement instanceof RefMethod && refElement.isValid()) { - RefMethod refMethod = (RefMethod)refElement; - final CommonProblemDescriptor[] problems = myProcessor.getDescriptions(refMethod); - if (problems != null) { - removeExcessiveThrows(refMethod, null, problems); - } - } - } - else { - final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethod.class); - if (psiMethod != null) { - removeExcessiveThrows(null, psiMethod, new CommonProblemDescriptor[]{descriptor}); - } - } - } - - @Override - @NotNull - public String getFamilyName() { - return getName(); - } - - private void removeExcessiveThrows(@Nullable RefMethod refMethod, @Nullable final PsiModifierListOwner element, final CommonProblemDescriptor[] problems) { - try { - @Nullable final PsiMethod psiMethod; - if (element == null) { - LOG.assertTrue(refMethod != null); - psiMethod = (PsiMethod)refMethod.getElement(); - } - else { - psiMethod = (PsiMethod)element; - } - if (psiMethod == null) return; //invalid refMethod - final Project project = psiMethod.getProject(); - final PsiManager psiManager = PsiManager.getInstance(project); - final List<PsiJavaCodeReferenceElement> refsToDelete = new ArrayList<PsiJavaCodeReferenceElement>(); - for (CommonProblemDescriptor problem : problems) { - final PsiElement psiElement = ((ProblemDescriptor)problem).getPsiElement(); - if (psiElement instanceof PsiJavaCodeReferenceElement) { - final PsiJavaCodeReferenceElement classRef = (PsiJavaCodeReferenceElement)psiElement; - final PsiType psiType = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createType(classRef); - removeException(refMethod, psiType, refsToDelete, psiMethod); - } else { - final PsiReferenceList throwsList = psiMethod.getThrowsList(); - final PsiClassType[] classTypes = throwsList.getReferencedTypes(); - for (PsiClassType classType : classTypes) { - final String text = classType.getClassName(); - if (Comparing.strEqual(myHint, text)) { - removeException(refMethod, classType, refsToDelete, psiMethod); - break; - } - } - } - } - - //check read-only status for derived methods - if (!FileModificationService.getInstance().preparePsiElementsForWrite(refsToDelete)) return; - - for (final PsiJavaCodeReferenceElement aRefsToDelete : refsToDelete) { - aRefsToDelete.delete(); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - - private static void removeException(final RefMethod refMethod, - final PsiType exceptionType, - final List<PsiJavaCodeReferenceElement> refsToDelete, - final PsiMethod psiMethod) { - PsiManager psiManager = psiMethod.getManager(); - - PsiJavaCodeReferenceElement[] refs = psiMethod.getThrowsList().getReferenceElements(); - for (PsiJavaCodeReferenceElement ref : refs) { - PsiType refType = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createType(ref); - if (exceptionType.isAssignableFrom(refType)) { - refsToDelete.add(ref); - } - } - - if (refMethod != null) { - for (RefMethod refDerived : refMethod.getDerivedMethods()) { - removeException(refDerived, exceptionType, refsToDelete, (PsiMethod)refDerived.getElement()); - } - } else { - final Query<Pair<PsiMethod,PsiMethod>> query = AllOverridingMethodsSearch.search(psiMethod.getContainingClass()); - query.forEach(new Processor<Pair<PsiMethod, PsiMethod>>(){ - @Override - public boolean process(final Pair<PsiMethod, PsiMethod> pair) { - if (pair.first == psiMethod) { - removeException(null, exceptionType, refsToDelete, pair.second); - } - return true; - } - }); - } - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportLocalInspection.java index 807cf4bc8308..a8feaf9c148e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedImport/UnusedImportLocalInspection.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.PairedUnfairLocalInspectionTool; +import com.siyeh.ig.imports.UnusedImportInspection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -55,8 +56,9 @@ public class UnusedImportLocalInspection extends BaseJavaLocalInspectionTool imp return true; } + @NotNull @Override public String getInspectionForBatchShortName() { - return "UnusedImport"; + return new UnusedImportInspection().getShortName(); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java deleted file mode 100644 index a8a6be97c268..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * User: anna - * Date: 18-Apr-2007 - */ -package com.intellij.codeInspection.unusedLibraries; - -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; -import com.intellij.codeInspection.ex.JobDescriptor; -import com.intellij.codeInspection.reference.RefManager; -import com.intellij.codeInspection.reference.RefModule; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.impl.ProgressManagerImpl; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.roots.libraries.LibraryUtil; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packageDependencies.BackwardDependenciesBuilder; -import com.intellij.psi.PsiCompiledElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiRecursiveElementVisitor; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.GlobalSearchScopes; -import com.intellij.psi.search.scope.packageSet.NamedScope; -import com.intellij.psi.search.scope.packageSet.PackageSetFactory; -import com.intellij.psi.search.scope.packageSet.ParsingException; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -public class UnusedLibrariesInspection extends GlobalInspectionTool { - private static final Logger LOG = Logger.getInstance("#" + UnusedLibrariesInspection.class.getName()); - private final JobDescriptor BACKWARD_ANALYSIS = new JobDescriptor(InspectionsBundle.message("unused.library.backward.analysis.job.description")); - - @Override - public void runInspection(@NotNull AnalysisScope scope, - @NotNull InspectionManager manager, - @NotNull final GlobalInspectionContext globalContext, - @NotNull ProblemDescriptionsProcessor problemProcessor) { - ((GlobalInspectionContextImpl)globalContext).appendJobDescriptor(BACKWARD_ANALYSIS); - final Project project = manager.getProject(); - final ArrayList<VirtualFile> libraryRoots = new ArrayList<VirtualFile>(); - if (scope.getScopeType() == AnalysisScope.PROJECT) { - ContainerUtil.addAll(libraryRoots, LibraryUtil.getLibraryRoots(project, false, false)); - } - else { - final Set<Module> modules = new HashSet<Module>(); - scope.accept(new PsiRecursiveElementVisitor() { - @Override - public void visitFile(PsiFile file) { - if (!(file instanceof PsiCompiledElement)) { - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile != null) { - final Module module = ModuleUtil.findModuleForFile(virtualFile, project); - if (module != null) { - modules.add(module); - } - } - } - } - }); - ContainerUtil.addAll(libraryRoots, LibraryUtil.getLibraryRoots(modules.toArray(new Module[modules.size()]), false, false)); - } - if (libraryRoots.isEmpty()) { - return; - } - - GlobalSearchScope searchScope; - try { - @NonNls final String libsName = "libs"; - NamedScope libScope = new NamedScope(libsName, PackageSetFactory.getInstance().compile("lib:*..*")); - searchScope = GlobalSearchScopes.filterScope(project, libScope); - } - catch (ParsingException e) { - //can't be - LOG.error(e); - return; - } - final AnalysisScope analysisScope = new AnalysisScope(searchScope, project); - analysisScope.setSearchInLibraries(true); - final BackwardDependenciesBuilder builder = new BackwardDependenciesBuilder(project, analysisScope); - - final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); - - BACKWARD_ANALYSIS.setTotalAmount(builder.getTotalFileCount()); - ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(new Runnable(){ - @Override - public void run() { - builder.analyze(); - } - }, new ProgressIndicatorBase() { - @Override - public void setFraction(final double fraction) { - super.setFraction(fraction); - int nextAmount = (int)(fraction * BACKWARD_ANALYSIS.getTotalAmount()); - if (nextAmount > BACKWARD_ANALYSIS.getDoneAmount() && nextAmount < BACKWARD_ANALYSIS.getTotalAmount()) { - BACKWARD_ANALYSIS.setDoneAmount(nextAmount); - globalContext.incrementJobDoneAmount(BACKWARD_ANALYSIS, getText2()); - } - } - - @Override - public boolean isCanceled() { - return progressIndicator != null && progressIndicator.isCanceled() || super.isCanceled(); - } - }); - BACKWARD_ANALYSIS.setDoneAmount(BACKWARD_ANALYSIS.getTotalAmount()); - final Map<PsiFile, Set<PsiFile>> dependencies = builder.getDependencies(); - for (PsiFile file : dependencies.keySet()) { - final VirtualFile virtualFile = file.getVirtualFile(); - LOG.assertTrue(virtualFile != null); - for (Iterator<VirtualFile> i = libraryRoots.iterator(); i.hasNext();) { - if (VfsUtil.isAncestor(i.next(), virtualFile, false)) { - i.remove(); - } - } - } - if (libraryRoots.isEmpty()) { - return; - } - ProjectFileIndex projectIndex = ProjectRootManager.getInstance(project).getFileIndex(); - Map<OrderEntry, Set<VirtualFile>> unusedLibs = new HashMap<OrderEntry, Set<VirtualFile>>(); - for (VirtualFile libraryRoot : libraryRoots) { - final List<OrderEntry> orderEntries = projectIndex.getOrderEntriesForFile(libraryRoot); - for (OrderEntry orderEntry : orderEntries) { - Set<VirtualFile> files = unusedLibs.get(orderEntry); - if (files == null) { - files = new HashSet<VirtualFile>(); - unusedLibs.put(orderEntry, files); - } - files.add(libraryRoot); - } - } - final RefManager refManager = globalContext.getRefManager(); - for (OrderEntry orderEntry : unusedLibs.keySet()) { - if (!(orderEntry instanceof LibraryOrderEntry)) continue; - final RefModule refModule = refManager.getRefModule(orderEntry.getOwnerModule()); - final Set<VirtualFile> files = unusedLibs.get(orderEntry); - final VirtualFile[] roots = ((LibraryOrderEntry)orderEntry).getRootFiles(OrderRootType.CLASSES); - if (files.size() < roots.length) { - final String unusedLibraryRoots = StringUtil.join(files, new Function<VirtualFile, String>() { - @Override - public String fun(final VirtualFile file) { - return file.getPresentableName(); - } - }, ","); - String message = - InspectionsBundle.message("unused.library.roots.problem.descriptor", unusedLibraryRoots, orderEntry.getPresentableName()); - problemProcessor.addProblemElement(refModule, - manager.createProblemDescriptor(message, new RemoveUnusedLibrary(refModule, orderEntry, files))); - } - else { - String message = InspectionsBundle.message("unused.library.problem.descriptor", orderEntry.getPresentableName()); - problemProcessor.addProblemElement(refModule, - manager.createProblemDescriptor(message, new RemoveUnusedLibrary(refModule, orderEntry, null))); - } - } - } - - @Override - public boolean isEnabledByDefault() { - return false; - } - - @Override - @Nls - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getDisplayName() { - return InspectionsBundle.message("unused.library.display.name"); - } - - @Override - @NonNls - @NotNull - public String getShortName() { - return "UnusedLibrary"; - } - - private static class RemoveUnusedLibrary implements QuickFix { - private final RefModule myRefModule; - private final OrderEntry myOrderEntry; - private final Set<VirtualFile> myFiles; - - public RemoveUnusedLibrary(final RefModule refModule, final OrderEntry orderEntry, final Set<VirtualFile> files) { - myRefModule = refModule; - myOrderEntry = orderEntry; - myFiles = files; - } - - @Override - @NotNull - public String getName() { - return myFiles == null ? InspectionsBundle.message("detach.library.quickfix.name") : InspectionsBundle.message("detach.library.roots.quickfix.name"); - } - - @Override - @NotNull - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull final Project project, @NotNull final CommonProblemDescriptor descriptor) { - final Module module = myRefModule.getModule(); - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel(); - for (OrderEntry entry : model.getOrderEntries()) { - if (entry instanceof LibraryOrderEntry && Comparing.strEqual(entry.getPresentableName(), myOrderEntry.getPresentableName())) { - if (myFiles == null) { - model.removeOrderEntry(entry); - } - else { - final Library library = ((LibraryOrderEntry)entry).getLibrary(); - if (library != null) { - final Library.ModifiableModel modifiableModel = library.getModifiableModel(); - for (VirtualFile file : myFiles) { - modifiableModel.removeRoot(file.getUrl(), OrderRootType.CLASSES); - } - modifiableModel.commit(); - } - } - } - } - model.commit(); - } - }); - } - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index 5d576bbbd27e..9750838e9c0c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -28,9 +28,10 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.EntryPointsManagerImpl; +import com.intellij.codeInspection.ex.EntryPointsManager; import com.intellij.codeInspection.reference.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.search.PsiReferenceProcessor; @@ -52,8 +53,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class UnusedParametersInspection extends GlobalJavaInspectionTool { - +public class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { @NonNls public static final String SHORT_NAME = "UnusedParameters"; @Override @@ -83,7 +83,7 @@ public class UnusedParametersInspection extends GlobalJavaInspectionTool { if (refMethod.isEntry()) return null; final PsiModifierListOwner element = refMethod.getElement(); - if (element != null && EntryPointsManagerImpl.getInstance(manager.getProject()).isEntryPoint(element)) return null; + if (element != null && EntryPointsManager.getInstance(manager.getProject()).isEntryPoint(element)) return null; final List<ProblemDescriptor> result = new ArrayList<ProblemDescriptor>(); for (RefParameter refParameter : unusedParameters) { @@ -235,7 +235,8 @@ public class UnusedParametersInspection extends GlobalJavaInspectionTool { @Override public JComponent createOptionsPanel() { final JPanel panel = new JPanel(new GridBagLayout()); - panel.add(EntryPointsManagerImpl.createConfigureAnnotationsBtn(panel), + Project project = ProjectUtil.guessCurrentProject(panel); + panel.add(EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); return panel; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index 2bfbdf833c93..1ca2c0e8bdbd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -41,7 +41,7 @@ import java.util.List; /** * @author max */ -public class UnusedReturnValue extends GlobalJavaInspectionTool{ +public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{ private MakeVoidQuickFix myQuickFix; public boolean IGNORE_BUILDER_PATTERN = false; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java index f88e7517f7c9..1f7434ee85d8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java @@ -22,10 +22,12 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; -import com.intellij.codeInspection.ex.EntryPointsManagerImpl; +import com.intellij.codeInspection.ex.EntryPointsManager; +import com.intellij.codeInspection.ex.EntryPointsManagerBase; import com.intellij.codeInspection.ex.PairedUnfairLocalInspectionTool; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.psi.PsiModifierListOwner; import org.intellij.lang.annotations.Pattern; import org.jetbrains.annotations.Nls; @@ -92,6 +94,7 @@ public class UnusedSymbolLocalInspection extends BaseJavaLocalInspectionTool imp return true; } + @NotNull @Override public String getInspectionForBatchShortName() { return UnusedDeclarationInspection.SHORT_NAME; @@ -136,7 +139,8 @@ public class UnusedSymbolLocalInspection extends BaseJavaLocalInspectionTool imp myCheckClassesCheckBox.addActionListener(listener); myCheckParametersCheckBox.addActionListener(listener); myReportUnusedParametersInPublics.addActionListener(listener); - myAnnos.add(EntryPointsManagerImpl.createConfigureAnnotationsBtn(myPanel), + Project project = ProjectUtil.guessCurrentProject(myPanel); + myAnnos.add(EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0)); } @@ -153,7 +157,7 @@ public class UnusedSymbolLocalInspection extends BaseJavaLocalInspectionTool imp } public static IntentionAction createQuickFix(@NonNls String qualifiedName, @Nls String element, Project project) { - final EntryPointsManagerImpl entryPointsManager = EntryPointsManagerImpl.getInstance(project); + final EntryPointsManagerBase entryPointsManager = EntryPointsManagerBase.getInstance(project); return SpecialAnnotationsUtil.createAddToSpecialAnnotationsListIntentionAction( QuickFixBundle.message("fix.unused.symbol.injection.text", element, qualifiedName), QuickFixBundle.message("fix.unused.symbol.injection.family"), @@ -161,6 +165,6 @@ public class UnusedSymbolLocalInspection extends BaseJavaLocalInspectionTool imp } public static boolean isInjected(final PsiModifierListOwner modifierListOwner) { - return EntryPointsManagerImpl.getInstance(modifierListOwner.getProject()).isEntryPoint(modifierListOwner); + return EntryPointsManagerBase.getInstance(modifierListOwner.getProject()).isEntryPoint(modifierListOwner); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/util/RefFilter.java b/java/java-impl/src/com/intellij/codeInspection/util/RefFilter.java deleted file mode 100644 index 4e9f11a531f3..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/util/RefFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Dec 1, 2001 - * Time: 11:42:56 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.util; - -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.reference.RefJavaElement; -import com.intellij.codeInspection.reference.RefParameter; - -public abstract class RefFilter { - // Default accepts implementation accepts element if one under unaccepted one. Thus it will accept all and only upper level classes. - public int getElementProblemCount(RefJavaElement refElement) { - if (refElement instanceof RefParameter) return 0; - RefEntity refOwner = refElement.getOwner(); - if (refOwner == null || !(refOwner instanceof RefJavaElement)) return 1; - - return 1 - getElementProblemCount((RefJavaElement)refOwner); - } - - public final boolean accepts(RefJavaElement refElement) { - return getElementProblemCount(refElement) > 0; - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java deleted file mode 100644 index ab0a63ebdff5..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2000-2009 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.visibility; - -import com.intellij.codeInspection.ProblemDescriptionsProcessor; -import com.intellij.codeInspection.reference.RefManager; -import org.jetbrains.annotations.NotNull; - -public interface VisibilityExtension { - void fillIgnoreList(@NotNull RefManager refManager, @NotNull ProblemDescriptionsProcessor processor); -}
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java deleted file mode 100644 index 88ff09b295a6..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Dec 21, 2001 - * Time: 8:46:41 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.visibility; - -import com.intellij.ExtensionPoints; -import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInsight.highlighting.HighlightUsagesHandler; -import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.EntryPointsManager; -import com.intellij.codeInspection.reference.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPoint; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.util.List; - -public class VisibilityInspection extends GlobalJavaInspectionTool { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.visibility.VisibilityInspection"); - public boolean SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = true; - public boolean SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = true; - public boolean SUGGEST_PRIVATE_FOR_INNERS = false; - private static final String DISPLAY_NAME = InspectionsBundle.message("inspection.visibility.display.name"); - @NonNls private static final String SHORT_NAME = "WeakerAccess"; - private static final String CAN_BE_PRIVATE = InspectionsBundle.message("inspection.visibility.compose.suggestion", "private"); - private static final String CAN_BE_PACKAGE_LOCAL = InspectionsBundle.message("inspection.visibility.compose.suggestion", "package local"); - private static final String CAN_BE_PROTECTED = InspectionsBundle.message("inspection.visibility.compose.suggestion", "protected"); - - private class OptionsPanel extends JPanel { - private final JCheckBox myPackageLocalForMembersCheckbox; - private final JCheckBox myPrivateForInnersCheckbox; - private final JCheckBox myPackageLocalForTopClassesCheckbox; - - private OptionsPanel() { - super(new GridBagLayout()); - - GridBagConstraints gc = new GridBagConstraints(); - gc.fill = GridBagConstraints.HORIZONTAL; - gc.weightx = 1; - gc.weighty = 0; - gc.anchor = GridBagConstraints.NORTHWEST; - - myPackageLocalForMembersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option")); - myPackageLocalForMembersCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS); - myPackageLocalForMembersCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = myPackageLocalForMembersCheckbox.isSelected(); - } - }); - - gc.gridy = 0; - add(myPackageLocalForMembersCheckbox, gc); - - myPackageLocalForTopClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option1")); - myPackageLocalForTopClassesCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES); - myPackageLocalForTopClassesCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = myPackageLocalForTopClassesCheckbox.isSelected(); - } - }); - - gc.gridy = 1; - add(myPackageLocalForTopClassesCheckbox, gc); - - - myPrivateForInnersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option2")); - myPrivateForInnersCheckbox.setSelected(SUGGEST_PRIVATE_FOR_INNERS); - myPrivateForInnersCheckbox.getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - SUGGEST_PRIVATE_FOR_INNERS = myPrivateForInnersCheckbox.isSelected(); - } - }); - - gc.gridy = 2; - gc.weighty = 1; - add(myPrivateForInnersCheckbox, gc); - } - } - - @Override - public JComponent createOptionsPanel() { - return new OptionsPanel(); - } - - @Override - @NotNull - public String getDisplayName() { - return DISPLAY_NAME; - } - - @Override - @NotNull - public String getGroupDisplayName() { - return GroupNames.DECLARATION_REDUNDANCY; - } - - @Override - @NotNull - public String getShortName() { - return SHORT_NAME; - } - - @Override - @Nullable - public CommonProblemDescriptor[] checkElement(@NotNull final RefEntity refEntity, - @NotNull final AnalysisScope scope, - @NotNull final InspectionManager manager, - @NotNull final GlobalInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor processor) { - if (refEntity instanceof RefJavaElement) { - final RefJavaElement refElement = (RefJavaElement)refEntity; - - if (refElement instanceof RefParameter) return null; - if (refElement.isSyntheticJSP()) return null; - - //ignore entry points. - if (refElement.isEntry()) return null; - - //ignore implicit constructors. User should not be able to see them. - if (refElement instanceof RefImplicitConstructor) return null; - - if (refElement instanceof RefField && ((RefField)refElement).getElement() instanceof PsiEnumConstant) return null; - - //ignore library override methods. - if (refElement instanceof RefMethod) { - RefMethod refMethod = (RefMethod) refElement; - if (refMethod.isExternalOverride()) return null; - if (refMethod.isEntry()) return null; - } - - //ignore anonymous classes. They do not have access modifiers. - if (refElement instanceof RefClass) { - RefClass refClass = (RefClass) refElement; - if (refClass.isAnonymous() || refClass.isEntry() || refClass.isTestCase() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass()) return null; - if (isTopLevelClass(refClass) && !SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES) return null; - } - - //ignore unreferenced code. They could be a potential entry points. - if (refElement.getInReferences().isEmpty()) return null; - - //ignore interface members. They always have public access modifier. - if (refElement.getOwner() instanceof RefClass) { - RefClass refClass = (RefClass) refElement.getOwner(); - if (refClass.isInterface()) return null; - } - String access = getPossibleAccess(refElement); - if (access != refElement.getAccessModifier() && access != null) { - final PsiElement element = refElement.getElement(); - final PsiElement nameIdentifier = element != null ? HighlightUsagesHandler.getNameIdentifier(element) : null; - if (nameIdentifier != null) { - return new ProblemDescriptor[]{manager.createProblemDescriptor(nameIdentifier, - access.equals(PsiModifier.PRIVATE) - ? CAN_BE_PRIVATE - : access.equals(PsiModifier.PACKAGE_LOCAL) - ? CAN_BE_PACKAGE_LOCAL - : CAN_BE_PROTECTED, - new AcceptSuggestedAccess(globalContext.getRefManager(), access), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)}; - } - } - } - return null; - } - - @Nullable - @PsiModifier.ModifierConstant - public String getPossibleAccess(@Nullable RefJavaElement refElement) { - if (refElement == null) return null; - String curAccess = refElement.getAccessModifier(); - String weakestAccess = PsiModifier.PRIVATE; - - if (isTopLevelClass(refElement) || isCalledOnSubClasses(refElement)) { - weakestAccess = PsiModifier.PACKAGE_LOCAL; - } - - if (isAbstractMethod(refElement)) { - weakestAccess = PsiModifier.PROTECTED; - } - - if (curAccess == weakestAccess) return curAccess; - - while (true) { - String weakerAccess = getWeakerAccess(curAccess, refElement); - if (weakerAccess == null || RefJavaUtil.getInstance().compareAccess(weakerAccess, weakestAccess) < 0) break; - if (isAccessible(refElement, weakerAccess)) { - curAccess = weakerAccess; - } - else { - break; - } - } - - return curAccess; - } - - private static boolean isCalledOnSubClasses(RefElement refElement) { - return refElement instanceof RefMethod && ((RefMethod)refElement).isCalledOnSubClass(); - } - - private static boolean isAbstractMethod(RefElement refElement) { - return refElement instanceof RefMethod && ((RefMethod) refElement).isAbstract(); - } - - private static boolean isTopLevelClass(RefElement refElement) { - return refElement instanceof RefClass && RefJavaUtil.getInstance().getTopLevelClass(refElement) == refElement; - } - - @Nullable - @PsiModifier.ModifierConstant - private String getWeakerAccess(@PsiModifier.ModifierConstant String curAccess, RefElement refElement) { - if (curAccess == PsiModifier.PUBLIC) { - return isTopLevelClass(refElement) ? PsiModifier.PACKAGE_LOCAL : PsiModifier.PROTECTED; - } - if (curAccess == PsiModifier.PROTECTED) { - return SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS ? PsiModifier.PACKAGE_LOCAL : PsiModifier.PRIVATE; - } - if (curAccess == PsiModifier.PACKAGE_LOCAL) { - return PsiModifier.PRIVATE; - } - - return null; - } - - private boolean isAccessible(RefJavaElement to, @PsiModifier.ModifierConstant String accessModifier) { - - for (RefElement refElement : to.getInReferences()) { - if (!isAccessibleFrom(refElement, to, accessModifier)) return false; - } - - if (to instanceof RefMethod) { - RefMethod refMethod = (RefMethod) to; - - if (refMethod.isAbstract() && (refMethod.getDerivedMethods().isEmpty() || refMethod.getAccessModifier() == PsiModifier.PRIVATE)) return false; - - for (RefMethod refOverride : refMethod.getDerivedMethods()) { - if (!isAccessibleFrom(refOverride, to, accessModifier)) return false; - } - - for (RefMethod refSuper : refMethod.getSuperMethods()) { - if (RefJavaUtil.getInstance().compareAccess(refSuper.getAccessModifier(), accessModifier) > 0) return false; - } - } - - if (to instanceof RefClass) { - RefClass refClass = (RefClass) to; - for (RefClass subClass : refClass.getSubClasses()) { - if (!isAccessibleFrom(subClass, to, accessModifier)) return false; - } - - List children = refClass.getChildren(); - if (children != null) { - for (Object refElement : children) { - if (!isAccessible((RefJavaElement)refElement, accessModifier)) return false; - } - } - - for (final RefElement refElement : refClass.getInTypeReferences()) { - if (!isAccessibleFrom(refElement, refClass, accessModifier)) return false; - } - - List<RefJavaElement> classExporters = ((RefClassImpl)refClass).getClassExporters(); - if (classExporters != null) { - for (RefJavaElement refExporter : classExporters) { - if (getAccessLevel(accessModifier) < getAccessLevel(refExporter.getAccessModifier())) return false; - } - } - } - - return true; - } - - private static int getAccessLevel(@PsiModifier.ModifierConstant String access) { - if (access == PsiModifier.PRIVATE) return 1; - if (access == PsiModifier.PACKAGE_LOCAL) return 2; - if (access == PsiModifier.PROTECTED) return 3; - return 4; - } - - private boolean isAccessibleFrom(RefElement from, RefJavaElement to, String accessModifier) { - if (accessModifier == PsiModifier.PUBLIC) return true; - - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - if (accessModifier == PsiModifier.PACKAGE_LOCAL) { - return RefJavaUtil.getPackage(from) == RefJavaUtil.getPackage(to); - } - - RefClass fromTopLevel = refUtil.getTopLevelClass(from); - RefClass toTopLevel = refUtil.getTopLevelClass(to); - RefClass fromOwner = refUtil.getOwnerClass(from); - RefClass toOwner = refUtil.getOwnerClass(to); - - if (accessModifier == PsiModifier.PROTECTED) { - if (SUGGEST_PRIVATE_FOR_INNERS) { - return refUtil.isInheritor(fromTopLevel, toOwner) - || fromOwner != null && refUtil.isInheritor(fromOwner, toTopLevel) - || toOwner != null && refUtil.getOwnerClass(toOwner) == from; - } - - return refUtil.isInheritor(fromTopLevel, toOwner); - } - - if (accessModifier == PsiModifier.PRIVATE) { - if (SUGGEST_PRIVATE_FOR_INNERS) { - if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false; - if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false; - if (isInAnnotations(to, fromTopLevel)) return false; - return fromTopLevel == toOwner || fromOwner == toTopLevel || toOwner != null && refUtil.getOwnerClass(toOwner) == from; - } - - if (fromOwner != null && fromOwner.isStatic() && !to.isStatic() && refUtil.isInheritor(fromOwner, toOwner)) return false; - - if (fromTopLevel == toOwner) { - if (from instanceof RefClass && to instanceof RefClass) { - final PsiClass fromClass = ((RefClass)from).getElement(); - LOG.assertTrue(fromClass != null); - if (isInExtendsList(to, fromClass.getExtendsList())) return false; - if (isInExtendsList(to, fromClass.getImplementsList())) return false; - } - - return true; - } - } - - return false; - } - - private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) { - final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList(); - if (modifierList == null) return false; - final PsiElement toElement = to.getElement(); - - final boolean [] resolved = new boolean[] {false}; - modifierList.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - if (resolved[0]) return; - super.visitReferenceExpression(expression); - if (expression.resolve() == toElement) { - resolved[0] = true; - } - } - }); - return resolved[0]; - } - - private static boolean isInExtendsList(final RefJavaElement to, final PsiReferenceList extendsList) { - if (extendsList != null) { - final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements(); - for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { - final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); - if (parameterList != null) { - for (PsiType type : parameterList.getTypeArguments()) { - if (extendsList.getManager().areElementsEquivalent(PsiUtil.resolveClassInType(type), to.getElement())) { - return true; - } - } - } - } - } - return false; - } - - - @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, - @NotNull final GlobalJavaInspectionContext globalContext, - @NotNull final ProblemDescriptionsProcessor processor) { - final EntryPointsManager entryPointsManager = globalContext.getEntryPointsManager(manager); - for (RefElement entryPoint : entryPointsManager.getEntryPoints()) { - ignoreElement(processor, entryPoint); - } - - ExtensionPoint<VisibilityExtension> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.VISIBLITY_TOOL); - for (VisibilityExtension addin : point.getExtensions()) { - addin.fillIgnoreList(manager, processor); - } - manager.iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull final RefEntity refEntity) { - if (!(refEntity instanceof RefElement)) return; - if (processor.getDescriptions(refEntity) == null) return; - refEntity.accept(new RefJavaVisitor() { - @Override public void visitField(@NotNull final RefField refField) { - if (refField.getAccessModifier() != PsiModifier.PRIVATE) { - globalContext.enqueueFieldUsagesProcessor(refField, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - ignoreElement(processor, refField); - return false; - } - }); - } - } - - @Override public void visitMethod(@NotNull final RefMethod refMethod) { - if (!refMethod.isExternalOverride() && refMethod.getAccessModifier() != PsiModifier.PRIVATE && - !(refMethod instanceof RefImplicitConstructor)) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - ignoreElement(processor, refMethod); - return false; - } - }); - - globalContext.enqueueMethodUsagesProcessor(refMethod, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - ignoreElement(processor, refMethod); - return false; - } - }); - - if (entryPointsManager.isAddNonJavaEntries()) { - final RefClass ownerClass = refMethod.getOwnerClass(); - if (refMethod.isConstructor() && ownerClass.getDefaultConstructor() != null) { - String qualifiedName = ownerClass.getElement().getQualifiedName(); - if (qualifiedName != null) { - final Project project = manager.getProject(); - PsiSearchHelper.SERVICE.getInstance(project) - .processUsagesInNonJavaFiles(qualifiedName, new PsiNonJavaFileReferenceProcessor() { - @Override - public boolean process(PsiFile file, int startOffset, int endOffset) { - entryPointsManager.addEntryPoint(refMethod, false); - ignoreElement(processor, refMethod); - return false; - } - }, GlobalSearchScope.projectScope(project)); - } - } - } - } - } - - @Override public void visitClass(@NotNull final RefClass refClass) { - if (!refClass.isAnonymous()) { - globalContext.enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { - @Override - public boolean process(PsiClass inheritor) { - ignoreElement(processor, refClass); - return false; - } - }); - - globalContext.enqueueClassUsagesProcessor(refClass, new GlobalJavaInspectionContext.UsagesProcessor() { - @Override - public boolean process(PsiReference psiReference) { - ignoreElement(processor, refClass); - return false; - } - }); - } - } - }); - - } - }); - return false; - } - - private static void ignoreElement(@NotNull ProblemDescriptionsProcessor processor, @NotNull RefEntity refElement){ - processor.ignoreElement(refElement); - - if (refElement instanceof RefClass) { - RefClass refClass = (RefClass) refElement; - RefMethod defaultConstructor = refClass.getDefaultConstructor(); - if (defaultConstructor != null) { - processor.ignoreElement(defaultConstructor); - return; - } - } - - RefEntity owner = refElement.getOwner(); - if (owner instanceof RefElement) { - processor.ignoreElement(owner); - } - } - - @Override - public void compose(@NotNull final StringBuffer buf, @NotNull final RefEntity refEntity, @NotNull final HTMLComposer composer) { - composer.appendElementInReferences(buf, (RefElement)refEntity); - } - - @Override - @Nullable - public QuickFix getQuickFix(final String hint) { - return new AcceptSuggestedAccess(null, hint); - } - - @Override - @Nullable - public String getHint(@NotNull final QuickFix fix) { - return ((AcceptSuggestedAccess)fix).getHint(); - } - - private static class AcceptSuggestedAccess implements LocalQuickFix{ - private final RefManager myManager; - @PsiModifier.ModifierConstant private final String myHint; - - private AcceptSuggestedAccess(final RefManager manager, @PsiModifier.ModifierConstant String hint) { - myManager = manager; - myHint = hint; - } - - @Override - @NotNull - public String getName() { - return InspectionsBundle.message("inspection.visibility.accept.quickfix"); - } - - @Override - @NotNull - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - if (!FileModificationService.getInstance().preparePsiElementForWrite(descriptor.getPsiElement())) return; - final PsiModifierListOwner element = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiModifierListOwner.class); - if (element != null) { - RefElement refElement = null; - if (myManager != null) { - refElement = myManager.getReference(element); - } - try { - if (element instanceof PsiVariable) { - ((PsiVariable)element).normalizeDeclaration(); - } - - PsiModifierList list = element.getModifierList(); - - LOG.assertTrue(list != null); - - if (element instanceof PsiMethod) { - PsiMethod psiMethod = (PsiMethod)element; - PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass != null && containingClass.getParent() instanceof PsiFile && - myHint == PsiModifier.PRIVATE && - list.hasModifierProperty(PsiModifier.FINAL)) { - list.setModifierProperty(PsiModifier.FINAL, false); - } - } - - list.setModifierProperty(myHint, true); - if (refElement instanceof RefJavaElement) { - RefJavaUtil.getInstance().setAccessModifier((RefJavaElement)refElement, myHint); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - - public String getHint() { - return myHint; - } - } -} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/ArrayListKeyDescriptor.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/ArrayListKeyDescriptor.java new file mode 100644 index 000000000000..0f2d3de6e0a0 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/ArrayListKeyDescriptor.java @@ -0,0 +1,50 @@ +package com.intellij.compilerOutputIndex.api.descriptor; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class ArrayListKeyDescriptor<E> implements KeyDescriptor<List<E>> { + + private final DataExternalizer<E> myDataExternalizer; + + public ArrayListKeyDescriptor(final DataExternalizer<E> dataExternalizer) { + myDataExternalizer = dataExternalizer; + } + + @Override + public void save(final DataOutput out, final List<E> list) throws IOException { + out.writeInt(list.size()); + for (final E element : list) { + myDataExternalizer.save(out, element); + } + } + + @Override + public ArrayList<E> read(final DataInput in) throws IOException { + final int size = in.readInt(); + final ArrayList<E> list = new ArrayList<E>(size); + for (int i = 0; i < size; i++) { + list.add(myDataExternalizer.read(in)); + } + return list; + } + + @Override + public int getHashCode(final List<E> value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(final List<E> val1, final List<E> val2) { + return val1.equals(val2); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashMapKeyDescriptor.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashMapKeyDescriptor.java new file mode 100644 index 000000000000..1f012dd68a44 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashMapKeyDescriptor.java @@ -0,0 +1,54 @@ +package com.intellij.compilerOutputIndex.api.descriptor; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Dmitry Batkovich + */ +public class HashMapKeyDescriptor<K, V> implements KeyDescriptor<Map<K, V>> { + + private final DataExternalizer<K> myKeyDataExternalizer; + private final DataExternalizer<V> myValueDataExternalizer; + + public HashMapKeyDescriptor(final DataExternalizer<K> keyDataExternalizer, final DataExternalizer<V> valueDataExternalizer) { + myKeyDataExternalizer = keyDataExternalizer; + myValueDataExternalizer = valueDataExternalizer; + } + + @Override + public void save(final DataOutput out, final Map<K, V> map) throws IOException { + final int size = map.size(); + out.writeInt(size); + for (final Map.Entry<K, V> e : map.entrySet()) { + myKeyDataExternalizer.save(out, e.getKey()); + myValueDataExternalizer.save(out, e.getValue()); + } + } + + @Override + public Map<K, V> read(final DataInput in) throws IOException { + final int size = in.readInt(); + final HashMap<K, V> map = new HashMap<K, V>(size); + for (int i = 0; i < size; i++) { + map.put(myKeyDataExternalizer.read(in), myValueDataExternalizer.read(in)); + } + return map; + } + + @Override + public int getHashCode(final Map<K, V> map) { + return map.hashCode(); + } + + @Override + public boolean isEqual(final Map<K, V> val1, final Map<K, V> val2) { + return val1.equals(val2); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashSetKeyDescriptor.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashSetKeyDescriptor.java new file mode 100644 index 000000000000..1201ccf98446 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/descriptor/HashSetKeyDescriptor.java @@ -0,0 +1,54 @@ +package com.intellij.compilerOutputIndex.api.descriptor; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class HashSetKeyDescriptor<K> implements KeyDescriptor<Set<K>> { + + private final DataExternalizer<K> keyDataExternalizer; + + public HashSetKeyDescriptor(final DataExternalizer<K> keyDataExternalizer) { + this.keyDataExternalizer = keyDataExternalizer; + } + + @Override + public void save(final DataOutput out, final Set<K> set) throws IOException { + out.writeInt(set.size()); + for (final K k : set) { + keyDataExternalizer.save(out, k); + } + } + + @Override + public HashSet<K> read(final DataInput in) throws IOException { + final int size = in.readInt(); + final HashSet<K> set = new HashSet<K>(size); + for (int i = 0; i < size; i++) { + set.add(keyDataExternalizer.read(in)); + } + return set; + } + + public static <K> HashSetKeyDescriptor<K> of(final DataExternalizer<K> keyDataExternalizer) { + return new HashSetKeyDescriptor<K>(keyDataExternalizer); + } + + @Override + public int getHashCode(final Set<K> value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(final Set<K> val1, final Set<K> val2) { + return val1.equals(val2); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/AsmUtil.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/AsmUtil.java new file mode 100644 index 000000000000..45f761e3203f --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/AsmUtil.java @@ -0,0 +1,129 @@ +package com.intellij.compilerOutputIndex.api.fs; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.asm4.Type; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public final class AsmUtil implements Opcodes { + + private AsmUtil() {} + + public static boolean isStaticMethodDeclaration(final int access) { + return (access & Opcodes.ACC_STATIC) != 0; + } + + public static boolean isStaticMethodInvocation(final int opcode) { + return opcode == Opcodes.INVOKESTATIC; + } + + public static String getQualifiedClassName(final String name) { + return asJavaInnerClassQName(Type.getObjectType(name).getClassName()); + } + + public static String getReturnType(final String desc) { + return asJavaInnerClassQName(Type.getReturnType(desc).getClassName()); + } + + public static String[] getQualifiedClassNames(final String[] classNames, final String... yetAnotherClassNames) { + final List<String> qualifiedClassNames = new ArrayList<String>(classNames.length + yetAnotherClassNames.length); + for (final String className : classNames) { + qualifiedClassNames.add(getQualifiedClassName(className)); + } + for (final String className : yetAnotherClassNames) { + if (className != null) { + qualifiedClassNames.add(getQualifiedClassName(className)); + } + } + return ArrayUtil.toStringArray(qualifiedClassNames); + } + + public static String[] getParamsTypes(final String desc) { + final Type[] types = Type.getArgumentTypes(desc); + final String[] typesAsString = new String[types.length]; + for (int i = 0; i < types.length; i++) { + typesAsString[i] = types[i].getClassName(); + } + return typesAsString; + } + + @Nullable + public static String getSignature(final PsiMethod psiMethod) { + final PsiParameter[] parameters = psiMethod.getParameterList().getParameters(); + final StringBuilder sb = new StringBuilder(); + sb.append("("); + for (final PsiParameter p : parameters) { + final String desc = getDescriptor(p); + if (desc == null) { + return null; + } + sb.append(desc); + } + sb.append(")"); + final String desc = getDescriptor(psiMethod.getReturnType()); + if (desc == null) { + return null; + } + sb.append(desc); + return sb.toString(); + } + + @Nullable + private static String getDescriptor(final PsiParameter parameter) { + return getDescriptor(parameter.getType()); + } + + @Nullable + private static String getDescriptor(@Nullable final PsiType type) { + if (type == null) { + return null; + } + if (type instanceof PsiPrimitiveType) { + final PsiPrimitiveType primitiveType = (PsiPrimitiveType) type; + if (PsiType.INT.equals(primitiveType)) { + return "I"; + } else if (primitiveType.equals(PsiType.VOID)) { + return "V"; + } else if (primitiveType.equals(PsiType.BOOLEAN)) { + return "Z"; + } else if (primitiveType.equals(PsiType.BYTE)) { + return "B"; + } else if (primitiveType.equals(PsiType.CHAR)) { + return "C"; + } else if (primitiveType.equals(PsiType.SHORT)) { + return "S"; + } else if (primitiveType.equals(PsiType.DOUBLE)) { + return "D"; + } else if (primitiveType.equals(PsiType.FLOAT)) { + return "F"; + } else /* if (primitiveType.equals(PsiType.LONG)) */ { + return "J"; + } + } else if (type instanceof PsiArrayType) { + return "[" + getDescriptor(((PsiArrayType) type).getComponentType()); + } else { + final PsiClassType classType = (PsiClassType) type; + final PsiClass aClass = classType.resolve(); + if (aClass == null) { + return null; + } + final String qName = aClass.getQualifiedName(); + if (qName == null) { + return null; + } + return "L" + StringUtil.replace(qName, ".", "/") + ";"; + } + } + + private static String asJavaInnerClassQName(final String byteCodeClassQName) { + return StringUtil.replaceChar(byteCodeClassQName, '$', '.'); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/CompilerOutputFilesUtil.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/CompilerOutputFilesUtil.java new file mode 100644 index 000000000000..ef4137079f95 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/CompilerOutputFilesUtil.java @@ -0,0 +1,64 @@ +package com.intellij.compilerOutputIndex.api.fs; + +import com.intellij.openapi.compiler.CompilerPaths; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public final class CompilerOutputFilesUtil { + + private CompilerOutputFilesUtil() {} + + public final static String CLASS_FILES_SUFFIX = ".class"; + + public static void iterateProjectClassFiles(@NotNull final Project project, @NotNull final Consumer<File> fileConsumer) { + for (final Module module : ModuleManager.getInstance(project).getModules()) { + iterateModuleClassFiles(module, fileConsumer); + } + } + + public static void iterateModuleClassFiles(@NotNull final Module module, @NotNull final Consumer<File> fileConsumer) { + final VirtualFile moduleOutputDirectory = CompilerPaths.getModuleOutputDirectory(module, false); + if (moduleOutputDirectory == null) { + return; + } + final String canonicalPath = moduleOutputDirectory.getCanonicalPath(); + if (canonicalPath == null) { + return; + } + final File root = new File(canonicalPath); + iterateClassFilesOverRoot(root, fileConsumer); + } + + public static void iterateClassFilesOverRoot(@NotNull final File file, final Consumer<File> fileConsumer) { + iterateClassFilesOverRoot(file, fileConsumer, new HashSet<File>()); + } + + private static void iterateClassFilesOverRoot(@NotNull final File file, final Consumer<File> fileConsumer, final Set<File> visited) { + if (file.isDirectory()) { + final File[] files = file.listFiles(); + if (files != null) { + for (final File childFile : files) { + if (visited.add(childFile)) { + iterateClassFilesOverRoot(childFile.getAbsoluteFile(), fileConsumer, visited); + } + } + } + } + else { + if (file.getName().endsWith(CLASS_FILES_SUFFIX)) { + fileConsumer.consume(file); + } + } + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/FileVisitorService.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/FileVisitorService.java new file mode 100644 index 000000000000..9a7f00be3dc3 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/fs/FileVisitorService.java @@ -0,0 +1,53 @@ +package com.intellij.compilerOutputIndex.api.fs; + +import com.intellij.openapi.project.Project; +import com.intellij.util.Consumer; + +import java.io.File; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public interface FileVisitorService { + + interface Visitor { + void visit(File file); + } + + void visit(final Consumer<File> visitor); + + class ProjectClassFiles implements FileVisitorService { + private final Project myProject; + + public ProjectClassFiles(final Project project) { + myProject = project; + } + + @Override + public void visit(final Consumer<File> visitor) { + CompilerOutputFilesUtil.iterateProjectClassFiles(myProject, visitor); + } + } + + class DirectoryClassFiles implements FileVisitorService { + private final File myDir; + + public DirectoryClassFiles(final File dir) { + if (!dir.isDirectory()) { + throw new IllegalArgumentException(); + } + myDir = dir; + } + + @Override + public void visit(final Consumer<File> visitor) { + //noinspection ConstantConditions + for (final File file : myDir.listFiles()) { + if (file.getName().endsWith(CompilerOutputFilesUtil.CLASS_FILES_SUFFIX)) { + visitor.consume(file); + } + } + } + } +} + diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java new file mode 100644 index 000000000000..a37368b03d86 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java @@ -0,0 +1,141 @@ +package com.intellij.compilerOutputIndex.api.indexer; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.indexing.*; +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; +import com.intellij.util.io.PersistentHashMap; +import org.jetbrains.asm4.ClassReader; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; + +import static com.intellij.util.indexing.IndexInfrastructure.*; + +/** + * @author Dmitry Batkovich + */ +public abstract class CompilerOutputBaseIndex<K, V> { + public final static ExtensionPointName<CompilerOutputBaseIndex> EXTENSION_POINT_NAME = + ExtensionPointName.create("com.intellij.java.compilerOutputIndex"); + + private final static Logger LOG = Logger.getInstance(CompilerOutputBaseIndex.class); + private final KeyDescriptor<K> myKeyDescriptor; + private final DataExternalizer<V> myValueExternalizer; + + protected volatile MapReduceIndex<K, V, ClassReader> myIndex; + + private volatile Project myProject; + + public CompilerOutputBaseIndex(final KeyDescriptor<K> keyDescriptor, final DataExternalizer<V> valueExternalizer) { + myKeyDescriptor = keyDescriptor; + myValueExternalizer = valueExternalizer; + } + + public final boolean init(final Project project) { + myProject = project; + final MapReduceIndex<K, V, ClassReader> index; + final Ref<Boolean> rewriteIndex = new Ref<Boolean>(false); + try { + final ID<K, V> indexId = getIndexId(); + if (!IndexInfrastructure.getIndexRootDir(indexId).exists()) { + rewriteIndex.set(true); + } + final File storageFile = IndexInfrastructure.getStorageFile(indexId); + final MapIndexStorage<K, V> indexStorage = new MapIndexStorage<K, V>(storageFile, myKeyDescriptor, myValueExternalizer, 1024); + index = new MapReduceIndex<K, V, ClassReader>(indexId, getIndexer(), indexStorage); + index.setInputIdToDataKeysIndex(new Factory<PersistentHashMap<Integer, Collection<K>>>() { + @Override + public PersistentHashMap<Integer, Collection<K>> create() { + Exception failCause = null; + for (int attempts = 0; attempts < 2; attempts++) { + try { + return FileBasedIndexImpl.createIdToDataKeysIndex(indexId, myKeyDescriptor, new MemoryIndexStorage<K, V>(indexStorage)); + } + catch (IOException e) { + failCause = e; + FileUtil.delete(IndexInfrastructure.getInputIndexStorageFile(getIndexId())); + rewriteIndex.set(true); + } + } + throw new RuntimeException("couldn't create index", failCause); + } + }); + final File versionFile = getVersionFile(indexId); + if (versionFile.exists()) { + if (versionDiffers(versionFile, getVersion())) { + rewriteVersion(versionFile, getVersion()); + rewriteIndex.set(true); + try { + LOG.info("clearing index for updating index version"); + index.clear(); + } + catch (StorageException e) { + LOG.error("couldn't clear index for reinitializing"); + throw new RuntimeException(e); + } + } + } + else if (versionFile.createNewFile()) { + rewriteVersion(versionFile, getVersion()); + rewriteIndex.set(true); + } + else { + LOG.error(String.format("problems while access to index version file to index %s ", indexId)); + } + } + catch (IOException e) { + LOG.error("couldn't initialize index"); + throw new RuntimeException(e); + } + myIndex = index; + return rewriteIndex.get(); + } + + protected abstract ID<K, V> getIndexId(); + + protected abstract int getVersion(); + + protected abstract DataIndexer<K, V, ClassReader> getIndexer(); + + public final void projectClosed() { + if (myIndex != null) { + try { + myIndex.flush(); + } + catch (StorageException ignored) { + } + myIndex.dispose(); + } + } + + public void update(final int id, final ClassReader classReader) { + Boolean result = myIndex.update(id, classReader).compute(); + if (result == Boolean.FALSE) throw new RuntimeException(); + } + + public void clear() { + try { + myIndex.clear(); + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + protected final ID<K, V> generateIndexId(final String indexName) { + return CompilerOutputIndexUtil.generateIndexId(indexName, myProject); + } + + protected final ID<K, V> generateIndexId(final Class aClass) { + final String className = StringUtil.getShortName(aClass); + return generateIndexId(StringUtil.trimEnd(className, "Index")); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexUtil.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexUtil.java new file mode 100644 index 000000000000..c096cc81a364 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexUtil.java @@ -0,0 +1,21 @@ +package com.intellij.compilerOutputIndex.api.indexer; + +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.openapi.project.Project; +import com.intellij.util.indexing.ID; + +/** + * @author Dmitry Batkovich + */ +public final class CompilerOutputIndexUtil { + private CompilerOutputIndexUtil() {} + + public static <K, V> ID<K, V> generateIndexId(final String indexName, final Project project) { + return ID.create(String.format("compilerOutputIndex.%s.%d", indexName, Math.abs(project.getBasePath().hashCode()))); + } + + public static boolean isSetterOrConstructorMethodName(final String methodName) { + return MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(methodName) || methodName.startsWith("set"); + + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java new file mode 100644 index 000000000000..83da82862c22 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java @@ -0,0 +1,360 @@ +package com.intellij.compilerOutputIndex.api.indexer; + +import com.intellij.compilerOutputIndex.api.fs.CompilerOutputFilesUtil; +import com.intellij.compilerOutputIndex.api.fs.FileVisitorService; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.registry.RegistryValue; +import com.intellij.openapi.util.registry.RegistryValueListener; +import com.intellij.util.Consumer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.IndexInfrastructure; +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.util.io.PersistentEnumeratorDelegate; +import com.intellij.util.io.PersistentHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; +import org.jetbrains.asm4.ClassReader; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Dmitry Batkovich + */ +public class CompilerOutputIndexer extends AbstractProjectComponent { + private final static Logger LOG = Logger.getInstance(CompilerOutputIndexer.class); + + public final static String REGISTRY_KEY = "completion.enable.relevant.method.chain.suggestions"; + public final static String TITLE = "Compiler output indexer in progress..."; + + private volatile CompilerOutputBaseIndex[] myIndexes; + private volatile Map<String, CompilerOutputBaseIndex> myIndexTypeQNameToIndex; + private volatile PersistentHashMap<String, Long> myFileTimestampsIndex; + private volatile PersistentEnumeratorDelegate<String> myFileEnumerator; + private volatile boolean myInitialized = false; + + private final Lock myLock = new ReentrantLock(); + private final AtomicBoolean myInProgress = new AtomicBoolean(false); + private AtomicBoolean myEnabled = new AtomicBoolean(false); + + public static CompilerOutputIndexer getInstance(final Project project) { + return project.getComponent(CompilerOutputIndexer.class); + } + + protected CompilerOutputIndexer(final Project project) { + super(project); + } + + public boolean isEnabled() { + return myEnabled.get(); + } + + private ID<String, Long> getFileTimestampsIndexId() { + return CompilerOutputIndexUtil.generateIndexId("ProjectCompilerOutputClassFilesTimestamps", myProject); + } + + @Override + public final void projectOpened() { + Registry.get(REGISTRY_KEY).addListener(new RegistryValueListener.Adapter() { + @Override + public void afterValueChanged(final RegistryValue value) { + myEnabled.set(value.asBoolean()); + if (myEnabled.get()) { + doEnable(); + } + } + }, myProject); + + myEnabled = new AtomicBoolean(Registry.is(REGISTRY_KEY) || ApplicationManager.getApplication().isUnitTestMode()); + if (myEnabled.get()) { + doEnable(); + } + } + + private void doEnable() { + if (!myInitialized) { + myIndexes = Extensions.getExtensions(CompilerOutputBaseIndex.EXTENSION_POINT_NAME, myProject); + myIndexTypeQNameToIndex = new HashMap<String, CompilerOutputBaseIndex>(); + boolean needReindex = false; + for (final CompilerOutputBaseIndex index : myIndexes) { + if (index.init(myProject)) { + needReindex = true; + } + myIndexTypeQNameToIndex.put(index.getClass().getCanonicalName(), index); + } + initTimestampIndex(needReindex); + try { + myFileEnumerator = new PersistentEnumeratorDelegate<String>( + IndexInfrastructure.getStorageFile(CompilerOutputIndexUtil.generateIndexId("compilerOutputIndexFileId.enum", myProject)), + new EnumeratorStringDescriptor(), 2048); + } + catch (IOException e) { + throw new RuntimeException(e); + } + CompilerManager.getInstance(myProject).addAfterTask(new CompileTask() { + @Override + public boolean execute(final CompileContext context) { + if (myEnabled.get() && myInProgress.compareAndSet(false, true)) { + myLock.lock(); + try { + context.getProgressIndicator().setText("Compiler output indexing in progress"); + final Consumer<File> fileConsumer = new Consumer<File>() { + @Override + public void consume(final File file) { + try { + doIndexing(file, context.getProgressIndicator()); + } + catch (ProcessCanceledException e0) { + throw e0; + } + catch (RuntimeException e) { + LOG.error(e); + } + } + }; + for (final Module module : context.getCompileScope().getAffectedModules()) { + CompilerOutputFilesUtil.iterateModuleClassFiles(module, fileConsumer); + } + } + finally { + myLock.unlock(); + myInProgress.set(false); + } + } + return true; + } + }); + if (needReindex) { + reindexAllProjectInBackground(); + } + myInitialized = true; + } + } + + private void initTimestampIndex(final boolean needReindex) { + if (needReindex) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId())); + } + for (int attempts = 0; attempts < 2; attempts++) { + try { + myFileTimestampsIndex = new PersistentHashMap<String, Long>(IndexInfrastructure.getStorageFile(getFileTimestampsIndexId()), + new EnumeratorStringDescriptor(), new DataExternalizer<Long>() { + @Override + public void save(final DataOutput out, final Long value) throws IOException { + out.writeLong(value); + } + + @Override + public Long read(final DataInput in) throws IOException { + return in.readLong(); + } + }); + } + catch (IOException e) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId())); + } + if (myFileTimestampsIndex != null) { + return; + } + } + throw new RuntimeException("Timestamps index not initialized"); + } + + + public void reindex(final FileVisitorService visitorService, @NotNull final ProgressIndicator indicator) { + myLock.lock(); + try { + indicator.setText(TITLE); + visitorService.visit(new Consumer<File>() { + @Override + public void consume(final File file) { + try { + doIndexing(file, indicator); + } + catch (ProcessCanceledException e0) { + throw e0; + } + catch (RuntimeException e) { + LOG.error(e); + } + } + }); + } + finally { + myLock.unlock(); + } + } + + public void reindexAllProjectInBackground() { + if (myInProgress.compareAndSet(false, true)) { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, TITLE) { + + @Override + public void onCancel() { + myIndexTypeQNameToIndex.clear(); + myInProgress.set(false); + } + + @Override + public void onSuccess() { + myInProgress.set(false); + } + + @Override + public void run(@NotNull final ProgressIndicator indicator) { + reindexAllProject(indicator); + } + }); + } + } + + public void reindexAllProject(@NotNull final ProgressIndicator indicator) { + reindex(new FileVisitorService.ProjectClassFiles(myProject), indicator); + } + + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + private void doIndexing(@NotNull final File file, @NotNull final ProgressIndicator indicator) { + final String filePath; + try { + filePath = file.getCanonicalPath(); + } + catch (IOException e) { + LOG.error(e); + return; + } + final Long timestamp = getTimestamp(filePath); + ProgressManager.checkCanceled(); + final long currentTimeStamp = file.lastModified(); + if (timestamp == null || timestamp != currentTimeStamp) { + putTimestamp(filePath, currentTimeStamp); + final ClassReader reader; + InputStream is = null; + try { + is = new FileInputStream(file); + reader = new ClassReader(is); + } + catch (IOException e) { + removeTimestamp(filePath); + return; + } + finally { + if (is != null) { + try { + is.close(); + } + catch (IOException ignored) { + } + } + } + try { + indicator.setText2(filePath); + final int id = myFileEnumerator.enumerate(filePath); + for (final CompilerOutputBaseIndex index : myIndexes) { + index.update(id, reader); + } + } + catch (RuntimeException e) { + LOG.error(String.format("can't index file: %s", file.getAbsolutePath()), e); + } + catch (IOException e) { + LOG.error(String.format("can't index file: %s", file.getAbsolutePath()), e); + } + } + } + + public void clear() { + try { + myFileTimestampsIndex.close(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + initTimestampIndex(true); + for (final CompilerOutputBaseIndex index : myIndexes) { + index.clear(); + } + } + + private void removeTimestamp(final String fileId) { + try { + myFileTimestampsIndex.remove(fileId); + } + catch (IOException e) { + LOG.error(e); + } + } + + @Nullable + private Long getTimestamp(final String fileName) { + try { + return myFileTimestampsIndex.get(fileName); + } + catch (IOException e) { + LOG.error(e); + return 0L; + } + } + + private void putTimestamp(final String fileName, final long timestamp) { + try { + myFileTimestampsIndex.put(fileName, timestamp); + } + catch (IOException e) { + LOG.error(e); + } + } + + + @Override + public void projectClosed() { + if (myInitialized) { + for (final CompilerOutputBaseIndex index : myIndexes) { + index.projectClosed(); + } + try { + myFileTimestampsIndex.close(); + myFileEnumerator.close(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @TestOnly + public void removeIndexes() { + for (final CompilerOutputBaseIndex index : myIndexes) { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(index.getIndexId())); + } + FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId())); + } + + @SuppressWarnings("unchecked") + public <T extends CompilerOutputBaseIndex> T getIndex(final Class<T> tClass) { + final CompilerOutputBaseIndex index = myIndexTypeQNameToIndex.get(tClass.getCanonicalName()); + if (index == null) { + throw new RuntimeException(String.format("index class with name %s not found", tClass.getName())); + } + return (T)index; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/ClassFileData.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/ClassFileData.java new file mode 100644 index 000000000000..f0a7c27d0be6 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/ClassFileData.java @@ -0,0 +1,116 @@ +package com.intellij.compilerOutputIndex.impl; + +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.MethodVisitor; +import org.jetbrains.asm4.Opcodes; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class ClassFileData { + private final List<MethodData> myMethodDatas; + + public ClassFileData(final ClassReader classReader) { + this(classReader, true); + } + + public ClassFileData(final ClassReader classReader, final boolean checkForPrimitiveReturn) { + myMethodDatas = new ArrayList<MethodData>(); + classReader.accept(new ClassVisitor(Opcodes.ASM4) { + @Override + public MethodVisitor visitMethod(final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) { + final MethodDataAccumulator methodDataAccumulator = new MethodDataAccumulator(checkForPrimitiveReturn); + myMethodDatas.add(methodDataAccumulator.getMethodData()); + return methodDataAccumulator; + } + }, Opcodes.ASM4); + } + + public List<MethodData> getMethodDatas() { + return myMethodDatas; + } + + public static class MethodData { + private final List<MethodInsnSignature> myMethodInsnSignatures = new ArrayList<MethodInsnSignature>(); + + private void addSign(final MethodInsnSignature signature) { + myMethodInsnSignatures.add(signature); + } + + public List<MethodInsnSignature> getMethodInsnSignatures() { + return myMethodInsnSignatures; + } + } + + private static class MethodDataAccumulator extends MethodVisitor { + private final MethodData myMethodData = new MethodData(); + private final boolean myCheckForPrimitiveReturn; + + public MethodDataAccumulator(final boolean checkForPrimitiveReturn) { + super(Opcodes.ASM4); + myCheckForPrimitiveReturn = checkForPrimitiveReturn; + } + + private MethodData getMethodData() { + return myMethodData; + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(name)) { + return; + } + final String ownerClassName = AsmUtil.getQualifiedClassName(owner); + if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(ownerClassName)) { + return; + } + if (myCheckForPrimitiveReturn) { + final String returnType = AsmUtil.getReturnType(desc); + if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(returnType)) { + return; + } + } + myMethodData.addSign(new MethodInsnSignature(opcode, owner, name, desc)); + } + } + + public static class MethodInsnSignature { + private final int myOpcode; + private final String myOwner; + private final String myName; + private final String myDesc; + + private MethodInsnSignature(final int opcode, final String owner, final String name, final String desc) { + myOpcode = opcode; + myOwner = owner; + myName = name; + myDesc = desc; + } + + public int getOpcode() { + return myOpcode; + } + + public String getOwner() { + return myOwner; + } + + public String getName() { + return myName; + } + + public String getDesc() { + return myDesc; + } + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/CompilerOutputBaseGramsIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/CompilerOutputBaseGramsIndex.java new file mode 100644 index 000000000000..b1afc8395951 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/CompilerOutputBaseGramsIndex.java @@ -0,0 +1,47 @@ +package com.intellij.compilerOutputIndex.impl; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.KeyDescriptor; + +import java.util.TreeSet; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public abstract class CompilerOutputBaseGramsIndex<K> extends CompilerOutputBaseIndex<K, Multiset<MethodIncompleteSignature>> { + + protected CompilerOutputBaseGramsIndex(final KeyDescriptor<K> keyDescriptor) { + super(keyDescriptor, new GuavaHashMultiSetExternalizer<MethodIncompleteSignature>(MethodIncompleteSignature.createKeyDescriptor())); + } + + public TreeSet<UsageIndexValue> getValues(final K key) { + try { + final ValueContainer<Multiset<MethodIncompleteSignature>> valueContainer = myIndex.getData(key); + final Multiset<MethodIncompleteSignature> rawValues = HashMultiset.create(); + valueContainer.forEach(new ValueContainer.ContainerAction<Multiset<MethodIncompleteSignature>>() { + @Override + public boolean perform(final int id, final Multiset<MethodIncompleteSignature> values) { + for (final Multiset.Entry<MethodIncompleteSignature> entry : values.entrySet()) { + rawValues.add(entry.getElement(), entry.getCount()); + } + return true; + } + }); + return rawValuesToValues(rawValues); + } catch (StorageException e) { + throw new RuntimeException(); + } + } + + private static TreeSet<UsageIndexValue> rawValuesToValues(final Multiset<MethodIncompleteSignature> rawValues) { + final TreeSet<UsageIndexValue> values = new TreeSet<UsageIndexValue>(); + for (final Multiset.Entry<MethodIncompleteSignature> entry : rawValues.entrySet()) { + values.add(new UsageIndexValue(entry.getElement(), entry.getCount())); + } + return values; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/GuavaHashMultiSetExternalizer.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/GuavaHashMultiSetExternalizer.java new file mode 100644 index 000000000000..fe36071af30a --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/GuavaHashMultiSetExternalizer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2013 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.compilerOutputIndex.impl; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.util.io.DataExternalizer; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class GuavaHashMultiSetExternalizer<K> implements DataExternalizer<Multiset<K>> { + private final DataExternalizer<K> myKeyDataExternalizer; + + public GuavaHashMultiSetExternalizer(final DataExternalizer<K> keyDataExternalizer) { + myKeyDataExternalizer = keyDataExternalizer; + } + + @Override + public void save(final DataOutput out, final Multiset<K> multiset) throws IOException { + final Set<Multiset.Entry<K>> entries = multiset.entrySet(); + out.writeInt(entries.size()); + for (final Multiset.Entry<K> entry : entries) { + myKeyDataExternalizer.save(out, entry.getElement()); + out.writeInt(entry.getCount()); + } + } + + @Override + public Multiset<K> read(final DataInput in) throws IOException { + final int size = in.readInt(); + final Multiset<K> multiset = HashMultiset.create(size); + for (int i = 0; i < size; i++) { + multiset.add(myKeyDataExternalizer.read(in), in.readInt()); + } + return multiset; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignature.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignature.java new file mode 100644 index 000000000000..ad85322f3f6a --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignature.java @@ -0,0 +1,183 @@ +package com.intellij.compilerOutputIndex.impl; + +import com.intellij.openapi.util.Condition; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodIncompleteSignature { + + public static final String CONSTRUCTOR_METHOD_NAME = "<init>"; + + @NotNull + private final String myOwner; + @NotNull + private final String myReturnType; + @NotNull + private final String myName; + private final boolean myStatic; + + public MethodIncompleteSignature(@NotNull final String owner, + @NotNull final String returnType, + @NotNull final String name, + final boolean aStatic) { + myOwner = owner; + myReturnType = returnType; + myName = name; + myStatic = aStatic; + } + + public static MethodIncompleteSignature constructor(@NotNull final String className) { + return new MethodIncompleteSignature(className, className, CONSTRUCTOR_METHOD_NAME, true); + } + + @NotNull + public String getOwner() { + return myOwner; + } + + @NotNull + public String getReturnType() { + return myReturnType; + } + + @NotNull + public String getName() { + return myName; + } + + public boolean isStatic() { + return myStatic; + } + + @NotNull + public PsiMethod[] resolveNotDeprecated(final JavaPsiFacade javaPsiFacade, final GlobalSearchScope scope) { + return notDeprecated(resolve(javaPsiFacade, scope)); + } + + @NotNull + public PsiMethod[] resolve(final JavaPsiFacade javaPsiFacade, final GlobalSearchScope scope) { + if (CONSTRUCTOR_METHOD_NAME.equals(getName())) { + return PsiMethod.EMPTY_ARRAY; + } + final PsiClass aClass = javaPsiFacade.findClass(getOwner(), scope); + if (aClass == null) { + return PsiMethod.EMPTY_ARRAY; + } + final PsiMethod[] methods = aClass.findMethodsByName(getName(), true); + final List<PsiMethod> filtered = new ArrayList<PsiMethod>(methods.length); + for (final PsiMethod method : methods) { + if (method.hasModifierProperty(PsiModifier.STATIC) == isStatic()) { + final PsiType returnType = method.getReturnType(); + if (returnType != null && returnType.equalsToText(getReturnType())) { + filtered.add(method); + } + } + } + return filtered.toArray(new PsiMethod[filtered.size()]); + } + + public static KeyDescriptor<MethodIncompleteSignature> createKeyDescriptor() { + final EnumeratorStringDescriptor stringDescriptor = new EnumeratorStringDescriptor(); + return new KeyDescriptor<MethodIncompleteSignature>() { + @Override + public void save(final DataOutput out, final MethodIncompleteSignature value) throws IOException { + stringDescriptor.save(out, value.getOwner()); + stringDescriptor.save(out, value.getReturnType()); + stringDescriptor.save(out, value.getName()); + out.writeBoolean(value.isStatic()); + } + + @Override + public MethodIncompleteSignature read(final DataInput in) throws IOException { + return new MethodIncompleteSignature(stringDescriptor.read(in), stringDescriptor.read(in), stringDescriptor.read(in), + in.readBoolean()); + } + + @Override + public int getHashCode(final MethodIncompleteSignature value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(final MethodIncompleteSignature val1, final MethodIncompleteSignature val2) { + return val1.equals(val2); + } + }; + } + + @NotNull + private static PsiMethod[] notDeprecated(@NotNull final PsiMethod[] methods) { + final List<PsiMethod> filtered = ContainerUtil.filter(methods, NOT_DEPRECATED_CONDITION); + return filtered.toArray(new PsiMethod[filtered.size()]); + } + + private final static Condition<PsiMethod> NOT_DEPRECATED_CONDITION = new Condition<PsiMethod>() { + @Override + public boolean value(final PsiMethod method) { + return !method.isDeprecated(); + } + }; + + public final static Comparator<MethodIncompleteSignature> COMPARATOR = new Comparator<MethodIncompleteSignature>() { + @Override + public int compare(final MethodIncompleteSignature o1, final MethodIncompleteSignature o2) { + int sub = o1.getOwner().compareTo(o2.getOwner()); + if (sub != 0) { + return sub; + } + sub = o1.getName().compareTo(o2.getName()); + if (sub != 0) { + return sub; + } + sub = o1.getReturnType().compareTo(o2.getReturnType()); + if (sub != 0) { + return sub; + } + if (o1.isStatic() && !o2.isStatic()) { + return 1; + } + if (o2.isStatic() && !o1.isStatic()) { + return -1; + } + return 0; + } + }; + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final MethodIncompleteSignature that = (MethodIncompleteSignature)o; + + if (myStatic != that.myStatic) return false; + if (!myName.equals(that.myName)) return false; + if (!myOwner.equals(that.myOwner)) return false; + if (!myReturnType.equals(that.myReturnType)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myOwner.hashCode(); + result = 31 * result + myReturnType.hashCode(); + result = 31 * result + myName.hashCode(); + result = 31 * result + (myStatic ? 1 : 0); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignatureChain.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignatureChain.java new file mode 100644 index 000000000000..a11e731f3d34 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodIncompleteSignatureChain.java @@ -0,0 +1,44 @@ +package com.intellij.compilerOutputIndex.impl; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodIncompleteSignatureChain { + private final List<MethodIncompleteSignature> myMethodIncompleteSignatures; + + public MethodIncompleteSignatureChain(final List<MethodIncompleteSignature> methodIncompleteSignatures) { + myMethodIncompleteSignatures = methodIncompleteSignatures; + } + + public List<MethodIncompleteSignature> list() { + return myMethodIncompleteSignatures; + } + + public boolean isEmpty() { + return myMethodIncompleteSignatures.isEmpty(); + } + + @Nullable + public MethodIncompleteSignature getFirstInvocation() { + final int size = myMethodIncompleteSignatures.size(); + return size == 0 ? null : myMethodIncompleteSignatures.get(0); + } + + @Nullable + public MethodIncompleteSignature getLastInvocation() { + final int size = myMethodIncompleteSignatures.size(); + return size == 0 ? null : myMethodIncompleteSignatures.get(size -1); + } + + public int size() { + return myMethodIncompleteSignatures.size(); + } + + public MethodIncompleteSignature get(final int index) { + return myMethodIncompleteSignatures.get(index); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodsUsageIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodsUsageIndex.java new file mode 100644 index 000000000000..e07c0380ad9e --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/MethodsUsageIndex.java @@ -0,0 +1,91 @@ +package com.intellij.compilerOutputIndex.impl; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.openapi.project.Project; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.Opcodes; + +import java.util.HashMap; +import java.util.Map; + + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodsUsageIndex extends CompilerOutputBaseGramsIndex<String> { + + public static MethodsUsageIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(MethodsUsageIndex.class); + } + + public MethodsUsageIndex() { + super(new EnumeratorStringDescriptor()); + } + + @Override + protected DataIndexer<String, Multiset<MethodIncompleteSignature>, ClassReader> getIndexer() { + return new DataIndexer<String, Multiset<MethodIncompleteSignature>, ClassReader>() { + @NotNull + @Override + public Map<String, Multiset<MethodIncompleteSignature>> map(final ClassReader inputData) { + final Map<String, Multiset<MethodIncompleteSignature>> map = new HashMap<String, Multiset<MethodIncompleteSignature>>(); + for (final ClassFileData.MethodData data : new ClassFileData(inputData).getMethodDatas()) { + for (final ClassFileData.MethodInsnSignature ms : data.getMethodInsnSignatures()) { + final String ownerClassName = AsmUtil.getQualifiedClassName(ms.getOwner()); + final String returnType = AsmUtil.getReturnType(ms.getDesc()); + if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(ms.getName())) { + addToIndex(map, ownerClassName, MethodIncompleteSignature.constructor(ownerClassName)); + } + else { + final boolean isStatic = ms.getOpcode() == Opcodes.INVOKESTATIC; + if (!ownerClassName.equals(returnType) || isStatic) { + addToIndex(map, returnType, new MethodIncompleteSignature(ownerClassName, returnType, ms.getName(), isStatic)); + } + } + } + } + return map; + } + + + }; + } + + public void clear() { + try { + myIndex.clear(); + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + protected ID<String, Multiset<MethodIncompleteSignature>> getIndexId() { + return generateIndexId(MethodsUsageIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + private static void addToIndex(final Map<String, Multiset<MethodIncompleteSignature>> map, + final String key, + final MethodIncompleteSignature mi) { + Multiset<MethodIncompleteSignature> occurrences = map.get(key); + if (occurrences == null) { + occurrences = HashMultiset.create(); + map.put(key, occurrences); + } + occurrences.add(mi); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/UsageIndexValue.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/UsageIndexValue.java new file mode 100644 index 000000000000..f99a0dea18c6 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/UsageIndexValue.java @@ -0,0 +1,69 @@ +package com.intellij.compilerOutputIndex.impl; + +import com.intellij.util.io.DataExternalizer; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Dmitry Batkovich + */ +public class UsageIndexValue implements Comparable<UsageIndexValue> { + private final int myOccurrences; + private final MethodIncompleteSignature myMethodIncompleteSignature; + + public UsageIndexValue(final MethodIncompleteSignature signature, final int occurrences) { + myOccurrences = occurrences; + myMethodIncompleteSignature = signature; + } + + public int getOccurrences() { + return myOccurrences; + } + + public MethodIncompleteSignature getMethodIncompleteSignature() { + return myMethodIncompleteSignature; + } + + public static DataExternalizer<UsageIndexValue> createDataExternalizer() { + final DataExternalizer<MethodIncompleteSignature> methodInvocationDataExternalizer = MethodIncompleteSignature.createKeyDescriptor(); + return new DataExternalizer<UsageIndexValue>() { + @Override + public void save(final DataOutput out, final UsageIndexValue value) throws IOException { + methodInvocationDataExternalizer.save(out, value.myMethodIncompleteSignature); + out.writeInt(value.myOccurrences); + } + + @Override + public UsageIndexValue read(final DataInput in) throws IOException { + return new UsageIndexValue(methodInvocationDataExternalizer.read(in), in.readInt()); + } + }; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final UsageIndexValue that = (UsageIndexValue)o; + + return myOccurrences == that.myOccurrences && myMethodIncompleteSignature.equals(that.myMethodIncompleteSignature); + } + + @Override + public int hashCode() { + int result = myOccurrences; + result = 31 * result + myMethodIncompleteSignature.hashCode(); + return result; + } + + @Override + public int compareTo(@NotNull final UsageIndexValue that) { + final int sub = -myOccurrences + that.myOccurrences; + if (sub != 0) return sub; + return MethodIncompleteSignature.COMPARATOR.compare(myMethodIncompleteSignature, that.myMethodIncompleteSignature); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/Bigram.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/Bigram.java new file mode 100644 index 000000000000..f5f4ff87a095 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/Bigram.java @@ -0,0 +1,22 @@ +package com.intellij.compilerOutputIndex.impl.bigram; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class Bigram<E> extends Pair<E, E> { + public Bigram(@NotNull final E first, @NotNull final E second) { + super(first, second); + } + + public Bigram<E> swap() { + return new Bigram<E>(second, first); + } + + @Override + public String toString() { + return String.format("%s - %s", first, second); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/BigramMethodsUsageIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/BigramMethodsUsageIndex.java new file mode 100644 index 000000000000..1f4d7e2cf6e6 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/BigramMethodsUsageIndex.java @@ -0,0 +1,86 @@ +package com.intellij.compilerOutputIndex.impl.bigram; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.compilerOutputIndex.impl.ClassFileData; +import com.intellij.compilerOutputIndex.impl.CompilerOutputBaseGramsIndex; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignatureChain; +import com.intellij.openapi.project.Project; +import com.intellij.util.SmartList; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.Opcodes; + +import java.util.*; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class BigramMethodsUsageIndex extends CompilerOutputBaseGramsIndex<MethodIncompleteSignature> { + public static BigramMethodsUsageIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(BigramMethodsUsageIndex.class); + } + + public BigramMethodsUsageIndex() { + super(MethodIncompleteSignature.createKeyDescriptor()); + } + + @Override + protected ID<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> getIndexId() { + return generateIndexId(BigramMethodsUsageIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + @Override + protected DataIndexer<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>, ClassReader> getIndexer() { + // + // not fair way, but works fast + // + return new DataIndexer<MethodIncompleteSignature,Multiset<MethodIncompleteSignature>,ClassReader>() { + @NotNull + @Override + public Map<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> map(final ClassReader inputData) { + final Map<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>> map = + new HashMap<MethodIncompleteSignature, Multiset<MethodIncompleteSignature>>(); + for (final ClassFileData.MethodData data : new ClassFileData(inputData).getMethodDatas()) { + final SimpleBigramsExtractor extractor = new SimpleBigramsExtractor(new SimpleBigramsExtractor.BigramMethodIncompleteSignatureProcessor() { + @Override + public void process(final Bigram<MethodIncompleteSignature> bigram) { + final MethodIncompleteSignature secondGram = bigram.getSecond(); + Multiset<MethodIncompleteSignature> occurrences = map.get(secondGram); + if (occurrences == null) { + occurrences = HashMultiset.create(); + map.put(secondGram, occurrences); + } + occurrences.add(bigram.getFirst()); + } + }); + for (final ClassFileData.MethodInsnSignature ms : data.getMethodInsnSignatures()) { + final List<MethodIncompleteSignature> methodInvocations = new SmartList<MethodIncompleteSignature>(); + final String ownerClassName = AsmUtil.getQualifiedClassName(ms.getOwner()); + final String returnType = AsmUtil.getReturnType(ms.getDesc()); + + if (ms.getName().equals(MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME)) { + methodInvocations.add(MethodIncompleteSignature.constructor(ownerClassName)); + } + else { + methodInvocations.add(new MethodIncompleteSignature(ownerClassName, returnType, ms.getName(), ms.getOpcode() == Opcodes.INVOKESTATIC)); + } + extractor.addChain(new MethodIncompleteSignatureChain(methodInvocations)); + } + } + return map; + } + }; + } + +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/SimpleBigramsExtractor.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/SimpleBigramsExtractor.java new file mode 100644 index 000000000000..d231a07e0f18 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/bigram/SimpleBigramsExtractor.java @@ -0,0 +1,55 @@ +package com.intellij.compilerOutputIndex.impl.bigram; + +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignatureChain; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** +* @author Dmitry Batkovich +*/ +class SimpleBigramsExtractor { + private final Map<String, MethodIncompleteSignature> myHolder = new HashMap<String, MethodIncompleteSignature>(); + private final BigramMethodIncompleteSignatureProcessor myProcessor; + + public SimpleBigramsExtractor(final BigramMethodIncompleteSignatureProcessor processor) { + myProcessor = processor; + } + + public void addChain(final MethodIncompleteSignatureChain chain) { + if (chain.isEmpty()) { + return; + } + final MethodIncompleteSignature firstInvocation = chain.getFirstInvocation(); + assert firstInvocation != null; + final MethodIncompleteSignature head = firstInvocation.isStatic() ? null : myHolder.get(firstInvocation.getOwner()); + for (final Bigram<MethodIncompleteSignature> bigram : toBigrams(head, chain)) { + myProcessor.process(bigram); + } + final MethodIncompleteSignature lastInvocation = chain.getLastInvocation(); + assert lastInvocation != null; + myHolder.put(lastInvocation.getReturnType(), lastInvocation); + } + + private static Collection<Bigram<MethodIncompleteSignature>> toBigrams(final @Nullable MethodIncompleteSignature head, + final @NotNull MethodIncompleteSignatureChain chain) { + MethodIncompleteSignature currentLast = null; + if (head != null) { + currentLast = head; + } + final List<Bigram<MethodIncompleteSignature>> bigrams = new ArrayList<Bigram<MethodIncompleteSignature>>(chain.size()); + for (final MethodIncompleteSignature current : chain.list()) { + if (currentLast != null) { + bigrams.add(new Bigram<MethodIncompleteSignature>(currentLast, current)); + } + currentLast = current; + } + return bigrams; + } + + public interface BigramMethodIncompleteSignatureProcessor { + void process(Bigram<MethodIncompleteSignature> bigram); + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/CallingLocation.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/CallingLocation.java new file mode 100644 index 000000000000..b2a154121737 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/CallingLocation.java @@ -0,0 +1,71 @@ +package com.intellij.compilerOutputIndex.impl.callingLocation; + +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class CallingLocation { + @NotNull + private final MethodIncompleteSignature myMethodIncompleteSignature; + @NotNull + private final VariableType myVariableType; + + public CallingLocation(@NotNull final MethodIncompleteSignature methodIncompleteSignature, @NotNull final VariableType variableType) { + myMethodIncompleteSignature = methodIncompleteSignature; + myVariableType = variableType; + } + + @NotNull + public MethodIncompleteSignature getMethodIncompleteSignature() { + return myMethodIncompleteSignature; + } + + @NotNull + public VariableType getVariableType() { + return myVariableType; + } + + public static DataExternalizer<CallingLocation> createDataExternalizer() { + final KeyDescriptor<MethodIncompleteSignature> methodIncompleteSignatureKeyDescriptor = MethodIncompleteSignature.createKeyDescriptor(); + return new DataExternalizer<CallingLocation>() { + @Override + public void save(final DataOutput out, final CallingLocation value) throws IOException { + methodIncompleteSignatureKeyDescriptor.save(out, value.getMethodIncompleteSignature()); + VariableType.KEY_DESCRIPTOR.save(out, value.getVariableType()); + } + + @Override + public CallingLocation read(final DataInput in) throws IOException { + return new CallingLocation(methodIncompleteSignatureKeyDescriptor.read(in), VariableType.KEY_DESCRIPTOR.read(in)); + } + }; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CallingLocation that = (CallingLocation)o; + + if (!myMethodIncompleteSignature.equals(that.myMethodIncompleteSignature)) return false; + if (myVariableType != that.myVariableType) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myMethodIncompleteSignature.hashCode(); + result = 31 * result + myVariableType.hashCode(); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationExtractor.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationExtractor.java new file mode 100644 index 000000000000..f5cdadb6d170 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationExtractor.java @@ -0,0 +1,157 @@ +package com.intellij.compilerOutputIndex.impl.callingLocation; + +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.*; +import org.jetbrains.asm4.commons.AnalyzerAdapter; +import org.jetbrains.asm4.commons.JSRInlinerAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public class MethodCallingLocationExtractor { + private MethodCallingLocationExtractor() { + } + + public static Map<MethodNameAndQualifier, List<CallingLocation>> extract(final ClassReader classReader) { + final MyClassVisitor classVisitor = new MyClassVisitor(); + classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES); + return classVisitor.getExtractedMethodsCallings(); + } + + private static class MyClassVisitor extends ClassVisitor { + public MyClassVisitor() { + super(Opcodes.ASM4); + } + + private final Map<MethodNameAndQualifier, List<CallingLocation>> myExtractedMethodsCallings = + new HashMap<MethodNameAndQualifier, List<CallingLocation>>(); + + private String myClassName; + private String myRawClassName; + + private Map<MethodNameAndQualifier, List<CallingLocation>> getExtractedMethodsCallings() { + return myExtractedMethodsCallings; + } + + @Override + public void visit(final int version, + final int access, + final String className, + final String signature, + final String superName, + final String[] interfaces) { + myRawClassName = className; + myClassName = AsmUtil.getQualifiedClassName(className); + } + + @Nullable + @Override + public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) { + return null; + } + + @Nullable + @Override + public MethodVisitor visitMethod(final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) { + + if (name.charAt(0) == '<') { + return null; + } + final boolean isStaticMethod = AsmUtil.isStaticMethodDeclaration(access); + if (isStaticMethod) { + return null; + } + @SuppressWarnings("UnnecessaryLocalVariable") final String methodName = name; + final String[] methodParams = AsmUtil.getParamsTypes(desc); + final MethodIncompleteSignature currentMethodSignature = + new MethodIncompleteSignature(myClassName, AsmUtil.getReturnType(desc), methodName, isStaticMethod); + return new JSRInlinerAdapter(new AnalyzerAdapter(Opcodes.ASM4, myRawClassName, access, name, desc, null) { + private final Map<Integer, Variable> myFieldsAndParamsPositionInStack = new HashMap<Integer, Variable>(); + + @Override + public void visitInsn(final int opcode) { + super.visitInsn(opcode); + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { + boolean onThis = false; + if (stack != null && opcode == Opcodes.GETFIELD && !ChainCompletionStringUtil.isPrimitiveOrArray(AsmUtil.getReturnType(desc))) { + final Object objectRef = stack.get(stack.size() - 1); + if (objectRef instanceof String && objectRef.equals(myRawClassName)) { + onThis = true; + } + } + super.visitFieldInsn(opcode, owner, name, desc); + if (onThis) { + final int index = stack.size() - 1; + final Object marker = stack.get(index); + myFieldsAndParamsPositionInStack.put(index, new Variable(marker, VariableType.FIELD)); + } + } + + @Override + public void visitVarInsn(final int opcode, final int varIndex) { + super.visitVarInsn(opcode, varIndex); + if (stack != null && opcode == Opcodes.ALOAD && + varIndex > 0 && + varIndex <= methodParams.length && + !ChainCompletionStringUtil.isPrimitiveOrArray(methodParams[varIndex - 1])) { + final int stackPos = stack.size() - 1; + myFieldsAndParamsPositionInStack.put(stackPos, new Variable(stack.get(stackPos), VariableType.METHOD_PARAMETER)); + } + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (stack != null && opcode != Opcodes.INVOKESTATIC && !methodName.startsWith("<")) { + final int index = stack.size() - 1 - AsmUtil.getParamsTypes(desc).length; + final Object stackValue = stack.get(index); + final Variable variable = myFieldsAndParamsPositionInStack.get(index); + if (variable != null && variable.getMarker() == stackValue /*equality by reference is not mistake*/) { + final CallingLocation callingLocation = new CallingLocation(currentMethodSignature, variable.getVariableType()); + final MethodNameAndQualifier invokedMethod = new MethodNameAndQualifier(name, AsmUtil.getQualifiedClassName(owner)); + List<CallingLocation> callingLocations = myExtractedMethodsCallings.get(invokedMethod); + if (callingLocations == null) { + callingLocations = new ArrayList<CallingLocation>(); + myExtractedMethodsCallings.put(invokedMethod, callingLocations); + } + callingLocations.add(callingLocation); + } + } + super.visitMethodInsn(opcode, owner, name, desc); + } + }, access, name, desc, signature, exceptions); + } + } + + private static class Variable { + private final Object myMarker; + private final VariableType myVariableType; + + private Variable(final Object marker, final VariableType variableType) { + myMarker = marker; + myVariableType = variableType; + } + + private Object getMarker() { + return myMarker; + } + + private VariableType getVariableType() { + return myVariableType; + } + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationIndex.java new file mode 100644 index 000000000000..c55273ab5254 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodCallingLocationIndex.java @@ -0,0 +1,94 @@ +package com.intellij.compilerOutputIndex.impl.callingLocation; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.api.descriptor.ArrayListKeyDescriptor; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature; +import com.intellij.openapi.project.Project; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.asm4.ClassReader; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Dmitry Batkovich + */ +public class MethodCallingLocationIndex extends CompilerOutputBaseIndex<MethodNameAndQualifier, List<CallingLocation>> { + + public static MethodCallingLocationIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(MethodCallingLocationIndex.class); + } + + public MethodCallingLocationIndex() { + super(MethodNameAndQualifier.createKeyDescriptor(), + new ArrayListKeyDescriptor<CallingLocation>(CallingLocation.createDataExternalizer())); + } + + @Override + protected ID<MethodNameAndQualifier, List<CallingLocation>> getIndexId() { + return generateIndexId(MethodCallingLocationIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + public List<CallingLocation> getAllLocations(final MethodNameAndQualifier methodNameAndQualifier) { + try { + final List<CallingLocation> result = new ArrayList<CallingLocation>(); + myIndex.getData(methodNameAndQualifier).forEach(new ValueContainer.ContainerAction<List<CallingLocation>>() { + @Override + public boolean perform(final int id, final List<CallingLocation> values) { + result.addAll(values); + return true; + } + }); + return result; + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + public Multiset<MethodIncompleteSignature> getLocationsAsParam(final MethodNameAndQualifier methodNameAndQualifier) { + final Multiset<MethodIncompleteSignature> result = HashMultiset.create(); + try { + myIndex.getData(methodNameAndQualifier).forEach(new ValueContainer.ContainerAction<List<CallingLocation>>() { + @Override + public boolean perform(final int id, final List<CallingLocation> values) { + for (final CallingLocation value : values) { + if (value.getVariableType().equals(VariableType.METHOD_PARAMETER)) { + result.add(value.getMethodIncompleteSignature()); + } + } + return true; + } + }); + } + catch (StorageException e) { + throw new RuntimeException(e); + } + return result; + } + + + @Override + protected DataIndexer<MethodNameAndQualifier, List<CallingLocation>, ClassReader> getIndexer() { + return new DataIndexer<MethodNameAndQualifier, List<CallingLocation>, ClassReader>() { + @NotNull + @Override + public Map<MethodNameAndQualifier, List<CallingLocation>> map(final ClassReader inputData) { + return MethodCallingLocationExtractor.extract(inputData); + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodNameAndQualifier.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodNameAndQualifier.java new file mode 100644 index 000000000000..e69d4f322f9b --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/MethodNameAndQualifier.java @@ -0,0 +1,81 @@ +package com.intellij.compilerOutputIndex.impl.callingLocation; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Dmitry Batkovich + */ +public class MethodNameAndQualifier { + @NotNull + private final String myMethodName; + @NotNull + private final String myQualifierName; + + public MethodNameAndQualifier(@NotNull final String methodName, @NotNull final String qualifierName) { + myMethodName = methodName; + myQualifierName = qualifierName; + } + + @NotNull + public String getMethodName() { + return myMethodName; + } + + @NotNull + public String getQualifierName() { + return myQualifierName; + } + + public static KeyDescriptor<MethodNameAndQualifier> createKeyDescriptor() { + final DataExternalizer<String> stringDataExternalizer = new EnumeratorStringDescriptor(); + return new KeyDescriptor<MethodNameAndQualifier>() { + @Override + public void save(final DataOutput out, final MethodNameAndQualifier value) throws IOException { + stringDataExternalizer.save(out, value.myMethodName); + stringDataExternalizer.save(out, value.myQualifierName); + } + + @Override + public MethodNameAndQualifier read(final DataInput in) throws IOException { + return new MethodNameAndQualifier(stringDataExternalizer.read(in), stringDataExternalizer.read(in)); + } + + @Override + public int getHashCode(final MethodNameAndQualifier value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(final MethodNameAndQualifier val1, final MethodNameAndQualifier val2) { + return val1.equals(val2); + } + }; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final MethodNameAndQualifier that = (MethodNameAndQualifier)o; + + if (!myMethodName.equals(that.myMethodName)) return false; + if (!myQualifierName.equals(that.myQualifierName)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myMethodName.hashCode(); + result = 31 * result + myQualifierName.hashCode(); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/VariableType.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/VariableType.java new file mode 100644 index 000000000000..6cf1ff232881 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/callingLocation/VariableType.java @@ -0,0 +1,15 @@ +package com.intellij.compilerOutputIndex.impl.callingLocation; + +import com.intellij.util.io.EnumDataDescriptor; +import com.intellij.util.io.KeyDescriptor; + +/** + * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com> + */ +public enum VariableType { + FIELD, + METHOD_PARAMETER, + OTHER; + + public static final KeyDescriptor<VariableType> KEY_DESCRIPTOR = new EnumDataDescriptor<VariableType>(VariableType.class); +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickInheritanceIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickInheritanceIndex.java new file mode 100644 index 000000000000..9a136f5f5084 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickInheritanceIndex.java @@ -0,0 +1,96 @@ +package com.intellij.compilerOutputIndex.impl.quickInheritance; + +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.CommonClassNames; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.compilerOutputIndex.api.descriptor.HashSetKeyDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.asm4.Type; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class QuickInheritanceIndex extends CompilerOutputBaseIndex<String, Set<String>> { + + public static QuickInheritanceIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(QuickInheritanceIndex.class); + } + + public QuickInheritanceIndex() { + super(new EnumeratorStringDescriptor(), new HashSetKeyDescriptor<String>(new EnumeratorStringDescriptor())); + } + + @Override + protected ID<String, Set<String>> getIndexId() { + return generateIndexId(QuickInheritanceIndex.class); + } + + protected Set<String> getSupers(final String classQName) { + try { + final ValueContainer<Set<String>> valueContainer = myIndex.getData(classQName); + final Ref<Set<String>> setRef = Ref.create(); + valueContainer.forEach(new ValueContainer.ContainerAction<Set<String>>() { + @Override + public boolean perform(final int id, final Set<String> value) { + setRef.set(value); + return false; + } + }); + final Set<String> supers = setRef.get(); + if (supers == null) { + return Collections.emptySet(); + } + return supers; + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + protected int getVersion() { + return 0; + } + + @Override + protected DataIndexer<String, Set<String>, ClassReader> getIndexer() { + return new DataIndexer<String, Set<String>, ClassReader>() { + @NotNull + @Override + public Map<String, Set<String>> map(final ClassReader inputData) { + final Map<String, Set<String>> map = new HashMap<String, Set<String>>(); + inputData.accept(new ClassVisitor(Opcodes.ASM4) { + @Override + public void visit(final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + final String className = Type.getObjectType(name).getClassName(); + if (className != null) { + final HashSet<String> value = ContainerUtil.newHashSet(AsmUtil.getQualifiedClassNames(interfaces, superName)); + value.remove(CommonClassNames.JAVA_LANG_OBJECT); + map.put(className, value); + } + } + }, Opcodes.ASM4); + return map; + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickMethodsIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickMethodsIndex.java new file mode 100644 index 000000000000..d857706f58d8 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickMethodsIndex.java @@ -0,0 +1,103 @@ +package com.intellij.compilerOutputIndex.impl.quickInheritance; + +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import com.intellij.compilerOutputIndex.api.descriptor.HashSetKeyDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.MethodVisitor; +import org.jetbrains.asm4.Opcodes; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class QuickMethodsIndex extends CompilerOutputBaseIndex<String, Set<String>> { + + public static QuickMethodsIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(QuickMethodsIndex.class); + } + + public QuickMethodsIndex() { + super(new EnumeratorStringDescriptor(), new HashSetKeyDescriptor<String>(new EnumeratorStringDescriptor())); + } + + @Override + protected ID<String, Set<String>> getIndexId() { + return generateIndexId(QuickMethodsIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + protected Set<String> getMethodsNames(final String classQName) { + final Ref<Set<String>> methodsRef = Ref.create(); + try { + myIndex.getData(classQName).forEach(new ValueContainer.ContainerAction<Set<String>>() { + @Override + public boolean perform(final int id, final Set<String> value) { + methodsRef.set(value); + return true; + } + }); + final Set<String> methods = methodsRef.get(); + return methods == null ? Collections.<String>emptySet() : methods; + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + protected DataIndexer<String, Set<String>, ClassReader> getIndexer() { + return new DataIndexer<String, Set<String>, ClassReader>() { + @NotNull + @Override + public Map<String, Set<String>> map(final ClassReader inputData) { + final Map<String, Set<String>> map = new HashMap<String, Set<String>>(); + inputData.accept(new ClassVisitor(Opcodes.ASM4) { + + private String myClassName; + private final HashSet<String> myMethodNames = new HashSet<String>(); + + @Override + public void visit(final int i, final int i2, final String name, final String s2, final String s3, final String[] strings) { + myClassName = AsmUtil.getQualifiedClassName(name); + } + + @Override + public void visitEnd() { + map.put(myClassName, myMethodNames); + } + + @Nullable + @Override + public MethodVisitor visitMethod(final int access, + final String name, + final String desc, + final String sign, + final String[] exceptions) { + if ((access & Opcodes.ACC_STATIC) == 0) { + myMethodNames.add(name); + } + return null; + } + }, Opcodes.ASM4); + return map; + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickOverrideUtil.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickOverrideUtil.java new file mode 100644 index 000000000000..78583aa9446f --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/quickInheritance/QuickOverrideUtil.java @@ -0,0 +1,23 @@ +package com.intellij.compilerOutputIndex.impl.quickInheritance; + +/** + * @author Dmitry Batkovich + */ +public final class QuickOverrideUtil { + + private QuickOverrideUtil() {} + + public static boolean isMethodOverriden(final String classQName, final String methodName, + final QuickInheritanceIndex quickInheritanceIndex, + final QuickMethodsIndex quickMethodsIndex) { + for (final String aSuper : quickInheritanceIndex.getSupers(classQName)) { + if (quickMethodsIndex.getMethodsNames(aSuper).contains(methodName)) { + return true; + } + if (isMethodOverriden(aSuper, methodName, quickInheritanceIndex, quickMethodsIndex)) { + return true; + } + } + return false; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignature.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignature.java new file mode 100644 index 000000000000..a1ef8129a19a --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignature.java @@ -0,0 +1,71 @@ +package com.intellij.compilerOutputIndex.impl.singleton; + +import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * @author Dmitry Batkovich + */ +public class MethodShortSignature { + @NotNull + private final String myName; + @NotNull + private final String mySignature; //in raw asm type + + public MethodShortSignature(final @NotNull String name, final @NotNull String signature) { + myName = name; + mySignature = signature; + } + + @NotNull + public String getName() { + return myName; + } + + @NotNull + public String getSignature() { + return mySignature; + } + + public static DataExternalizer<MethodShortSignature> createDataExternalizer() { + final EnumeratorStringDescriptor stringDescriptor = new EnumeratorStringDescriptor(); + return new DataExternalizer<MethodShortSignature>() { + + @Override + public void save(final DataOutput out, final MethodShortSignature value) throws IOException { + stringDescriptor.save(out, value.getName()); + stringDescriptor.save(out, value.getSignature()); + } + + @Override + public MethodShortSignature read(final DataInput in) throws IOException { + return new MethodShortSignature(stringDescriptor.read(in), stringDescriptor.read(in)); + } + }; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final MethodShortSignature that = (MethodShortSignature) o; + + if (!myName.equals(that.myName)) return false; + if (!mySignature.equals(that.mySignature)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myName.hashCode(); + result = 31 * result + mySignature.hashCode(); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignatureWithWeight.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignatureWithWeight.java new file mode 100644 index 000000000000..a6381ec99c79 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/MethodShortSignatureWithWeight.java @@ -0,0 +1,53 @@ +package com.intellij.compilerOutputIndex.impl.singleton; + +import org.jetbrains.annotations.NotNull; + +import java.util.Comparator; + +/** + * @author Dmitry Batkovich + */ +public class MethodShortSignatureWithWeight { + private final MethodShortSignature myMethodShortSignature; + private final int myWeight; + + public MethodShortSignatureWithWeight(final MethodShortSignature methodShortSignature, final int weight) { + myMethodShortSignature = methodShortSignature; + myWeight = weight; + } + + public MethodShortSignature getMethodShortSignature() { + return myMethodShortSignature; + } + + public int getWeight() { + return myWeight; + } + + public static Comparator<MethodShortSignatureWithWeight> COMPARATOR = new Comparator<MethodShortSignatureWithWeight>() { + @Override + public int compare(final MethodShortSignatureWithWeight o1, final MethodShortSignatureWithWeight o2) { + return o1.getWeight() - o2.getWeight(); + } + } ; + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final MethodShortSignatureWithWeight that = (MethodShortSignatureWithWeight) o; + + if (myWeight != that.myWeight) return false; + if (!myMethodShortSignature.equals(that.myMethodShortSignature)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myMethodShortSignature.hashCode(); + result = 31 * result + myWeight; + return result; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/ParamsInMethodOccurrencesIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/ParamsInMethodOccurrencesIndex.java new file mode 100644 index 000000000000..dff423bd32d1 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/ParamsInMethodOccurrencesIndex.java @@ -0,0 +1,116 @@ +package com.intellij.compilerOutputIndex.impl.singleton; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.compilerOutputIndex.impl.GuavaHashMultiSetExternalizer; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.*; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class ParamsInMethodOccurrencesIndex extends CompilerOutputBaseIndex<String, Multiset<MethodShortSignature>> { + + public static ParamsInMethodOccurrencesIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(ParamsInMethodOccurrencesIndex.class); + } + + public ParamsInMethodOccurrencesIndex() { + super(new EnumeratorStringDescriptor(), new GuavaHashMultiSetExternalizer<MethodShortSignature>(MethodShortSignature.createDataExternalizer())); + } + + @Override + protected ID<String, Multiset<MethodShortSignature>> getIndexId() { + return generateIndexId(ParamsInMethodOccurrencesIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + public Pair<List<MethodShortSignatureWithWeight>, Integer> getParameterOccurrences(final String parameterTypeName) { + try { + final Multiset<MethodShortSignature> resultAsMultiset = HashMultiset.create(); + final ValueContainer<Multiset<MethodShortSignature>> valueContainer = myIndex.getData(parameterTypeName); + valueContainer.forEach(new ValueContainer.ContainerAction<Multiset<MethodShortSignature>>() { + @Override + public boolean perform(final int id, final Multiset<MethodShortSignature> localMap) { + for (final Multiset.Entry<MethodShortSignature> e : localMap.entrySet()) { + resultAsMultiset.add(e.getElement(), e.getCount()); + } + return true; + } + }); + + final List<MethodShortSignatureWithWeight> result = new ArrayList<MethodShortSignatureWithWeight>(resultAsMultiset.elementSet().size()); + int sumWeight = 0; + for (final Multiset.Entry<MethodShortSignature> e : resultAsMultiset.entrySet()) { + sumWeight += e.getCount(); + result.add(new MethodShortSignatureWithWeight(e.getElement(), e.getCount())); + } + Collections.sort(result, MethodShortSignatureWithWeight.COMPARATOR); + + return Pair.create(result, sumWeight); + } catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + protected DataIndexer<String, Multiset<MethodShortSignature>, ClassReader> getIndexer() { + return new DataIndexer<String, Multiset<MethodShortSignature>, ClassReader>() { + @NotNull + @Override + public Map<String, Multiset<MethodShortSignature>> map(final ClassReader inputData) { + final Map<String, Multiset<MethodShortSignature>> result = new HashMap<String, Multiset<MethodShortSignature>>(); + inputData.accept(new ClassVisitor(Opcodes.ASM4) { + @Nullable + @Override + public MethodVisitor visitMethod(final int i, final String name, final String desc, final String signature, final String[] exception) { + if (CompilerOutputIndexUtil.isSetterOrConstructorMethodName(name)) { + return null; + } + final String[] parameters = AsmUtil.getParamsTypes(desc); + final MethodShortSignature thisMethodShortSignature = new MethodShortSignature(name, desc); + for (final String parameter : parameters) { + Multiset<MethodShortSignature> methods = result.get(parameter); + if (methods == null) { + methods = HashMultiset.create(); + result.put(parameter, methods); + } + methods.add(thisMethodShortSignature); + } + return new MethodVisitor(Opcodes.ASM4) { + @Override + public void visitLocalVariable(final String s, final String desc, final String signature, final Label label, final Label label2, final int i) { + final String varType = AsmUtil.getQualifiedClassName(desc); + Multiset<MethodShortSignature> methods = result.get(varType); + if (methods == null) { + methods = HashMultiset.create(); + result.put(varType, methods); + } + methods.add(thisMethodShortSignature); + } + }; + } + }, Opcodes.ASM4); + return result; + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/TwinVariablesIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/TwinVariablesIndex.java new file mode 100644 index 000000000000..8a04b72dca62 --- /dev/null +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/impl/singleton/TwinVariablesIndex.java @@ -0,0 +1,137 @@ +package com.intellij.compilerOutputIndex.impl.singleton; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.intellij.codeInsight.completion.methodChains.ChainCompletionStringUtil; +import com.intellij.compilerOutputIndex.api.descriptor.ArrayListKeyDescriptor; +import com.intellij.compilerOutputIndex.api.fs.AsmUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexUtil; +import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer; +import com.intellij.openapi.project.Project; +import com.intellij.util.indexing.DataIndexer; +import com.intellij.util.indexing.ID; +import com.intellij.util.indexing.StorageException; +import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.EnumeratorIntegerDescriptor; +import com.intellij.util.io.EnumeratorStringDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.*; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class TwinVariablesIndex extends CompilerOutputBaseIndex<String, List<Integer>> { + public static TwinVariablesIndex getInstance(final Project project) { + return CompilerOutputIndexer.getInstance(project).getIndex(TwinVariablesIndex.class); + } + + public TwinVariablesIndex() { + super(new EnumeratorStringDescriptor(), new ArrayListKeyDescriptor<Integer>(EnumeratorIntegerDescriptor.INSTANCE)); + } + + @Override + protected ID<String, List<Integer>> getIndexId() { + return generateIndexId(TwinVariablesIndex.class); + } + + @Override + protected int getVersion() { + return 0; + } + + @NotNull + public List<Integer> getTwinInfo(final String typeQName) { + try { + final ValueContainer<List<Integer>> valueContainer = myIndex.getData(typeQName); + final List<Integer> result = new ArrayList<Integer>(valueContainer.size()); + valueContainer.forEach(new ValueContainer.ContainerAction<List<Integer>>() { + @Override + public boolean perform(final int id, final List<Integer> value) { + result.addAll(value); + return true; + } + }); + return result; + } + catch (StorageException e) { + throw new RuntimeException(e); + } + } + + @Override + protected DataIndexer<String, List<Integer>, ClassReader> getIndexer() { + return new DataIndexer<String, List<Integer>, ClassReader>() { + @NotNull + @Override + public Map<String, List<Integer>> map(final ClassReader inputData) { + final Map<String, List<Integer>> map = new HashMap<String, List<Integer>>(); + inputData.accept(new ClassVisitor(Opcodes.ASM4) { + + @Nullable + @Override + public MethodVisitor visitMethod(final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) { + if (CompilerOutputIndexUtil.isSetterOrConstructorMethodName(name)) { + return null; + } + final Multiset<String> myTypesOccurrences = HashMultiset.create(); + final String[] paramsTypes = AsmUtil.getParamsTypes(desc); + Collections.addAll(myTypesOccurrences, paramsTypes); + return new MethodVisitor(Opcodes.ASM4) { + private final Set<String> myLocalVarNames = new HashSet<String>(); + + @SuppressWarnings("unchecked") + @Override + public void visitEnd() { + for (final Multiset.Entry<String> e: myTypesOccurrences.entrySet()) { + final String key = e.getElement(); + if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(key)) { + List<Integer> values = map.get(key); + if (values == null) { + values = new ArrayList<Integer>(); + map.put(key, values); + } + values.add(e.getCount()); + } + } + } + + private final Set<String> myUsedReadFieldsIndex = new HashSet<String>(); + + @Override + public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { + final String fieldTypeQName = AsmUtil.getReturnType(desc); + if ((opcode == Opcodes.GETSTATIC || opcode == Opcodes.GETFIELD)) { + if (myUsedReadFieldsIndex.add(owner + name)) { + myTypesOccurrences.add(fieldTypeQName); + } + } + } + + @Override + public void visitLocalVariable(final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) { + if (index > paramsTypes.length && myLocalVarNames.add(name)) { + final String type = AsmUtil.getReturnType(desc); + myTypesOccurrences.add(type); + } + } + }; + } + }, Opcodes.ASM4); + return map; + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/externalSystem/JavaProjectData.java b/java/java-impl/src/com/intellij/externalSystem/JavaProjectData.java index 9deea918441a..fb632cdd7123 100644 --- a/java/java-impl/src/com/intellij/externalSystem/JavaProjectData.java +++ b/java/java-impl/src/com/intellij/externalSystem/JavaProjectData.java @@ -43,7 +43,7 @@ public class JavaProjectData extends AbstractExternalEntityData { private static final LanguageLevel DEFAULT_LANGUAGE_LEVEL = LanguageLevel.JDK_1_6; private static final JavaSdkVersion DEFAULT_JDK_VERSION = JavaSdkVersion.JDK_1_6; - private static final Pattern JDK_VERSION_PATTERN = Pattern.compile(".*1\\.(\\d+).*"); + private static final Pattern JDK_VERSION_PATTERN = Pattern.compile(".*1.(\\d+).*"); @NotNull private JavaSdkVersion myJdkVersion = DEFAULT_JDK_VERSION; @NotNull private LanguageLevel myLanguageLevel = DEFAULT_LANGUAGE_LEVEL; @@ -128,6 +128,13 @@ public class JavaProjectData extends AbstractExternalEntityData { public void setLanguageLevel(@Nullable String languageLevel) { LanguageLevel level = LanguageLevel.parse(languageLevel); + if (level == null) { + Matcher matcher = JDK_VERSION_PATTERN.matcher(languageLevel); + if (matcher.matches()) { + String versionAsString = matcher.group(1); + level = LanguageLevel.parse("1." + versionAsString); + } + } if (level != null) { myLanguageLevel = level; } diff --git a/java/java-impl/src/com/intellij/ide/actions/JavaCreateTemplateInPackageAction.java b/java/java-impl/src/com/intellij/ide/actions/JavaCreateTemplateInPackageAction.java index a6c302b3174b..e80c05e0acf1 100644 --- a/java/java-impl/src/com/intellij/ide/actions/JavaCreateTemplateInPackageAction.java +++ b/java/java-impl/src/com/intellij/ide/actions/JavaCreateTemplateInPackageAction.java @@ -15,12 +15,14 @@ */ package com.intellij.ide.actions; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import javax.swing.*; -public abstract class JavaCreateTemplateInPackageAction<T extends PsiElement> extends CreateTemplateInPackageAction<T> { +public abstract class JavaCreateTemplateInPackageAction<T extends PsiElement> extends CreateTemplateInPackageAction<T> implements + DumbAware { protected JavaCreateTemplateInPackageAction(String text, String description, Icon icon, boolean inSourceOnly) { super(text, description, icon, inSourceOnly); diff --git a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java index de3446ecb4bb..13ac82b52dcb 100644 --- a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java +++ b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java @@ -72,6 +72,9 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { if (containingClass == null) return null; String classFqn = containingClass.getQualifiedName(); if (classFqn == null) return member.getName(); // refer to member of anonymous class by simple name + if (member instanceof PsiMethod && containingClass.findMethodsByName(member.getName(), false).length > 1) { + return classFqn + "#" + member.getName() + getParameterString((PsiMethod)member); + } return classFqn + "#" + member.getName(); } return null; @@ -89,17 +92,18 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { final int endIndex = fqn.indexOf('#'); if (endIndex != -1) { String className = fqn.substring(0, endIndex); - if (className != null) { - aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); - if (aClass != null) { - String memberName = fqn.substring(endIndex + 1); - PsiField field = aClass.findFieldByName(memberName, false); - if (field != null) { - return field; - } - PsiMethod[] methods = aClass.findMethodsByName(memberName, false); - if (methods.length != 0) { - return methods[0]; + int paramIndex = fqn.indexOf('(', endIndex); + aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); + if (aClass != null) { + String memberName = fqn.substring(endIndex + 1, paramIndex < 0 ? fqn.length() : paramIndex); + PsiField field = aClass.findFieldByName(memberName, false); + if (field != null) { + return field; + } + String paramString = paramIndex < 0 ? "" : fqn.substring(paramIndex); + for (PsiMethod overload : aClass.findMethodsByName(memberName, false)) { + if (StringUtil.isEmpty(paramString) || paramString.equals(getParameterString(overload))) { + return overload; } } } @@ -161,14 +165,7 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { if (toInsert.length() != 0) toInsert += "#"; toInsert += member.getName(); if (member instanceof PsiMethod) { - toInsert += "("; - PsiParameter[] parameters = ((PsiMethod)member).getParameterList().getParameters(); - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - if (i != 0) toInsert += ", "; - toInsert += parameter.getType().getCanonicalText(); - } - toInsert += ")"; + toInsert += getParameterString((PsiMethod)member); } } else if (elementAtCaret == null || @@ -256,6 +253,18 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { editor.getCaretModel().moveToOffset(caretOffset); } + private static String getParameterString(PsiMethod method) { + String toInsert = "("; + PsiParameter[] parameters = method.getParameterList().getParameters(); + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + if (i != 0) toInsert += ", "; + toInsert += parameter.getType().getCanonicalText(); + } + toInsert += ")"; + return toInsert; + } + private static boolean isReferencedTo(PsiReferenceExpression referenceExpression, PsiMember targetElement) { PsiElement resolved = referenceExpression.advancedResolve(true).getElement(); if (!(resolved instanceof PsiMember)) return false; diff --git a/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java b/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java index a025a1e7cdc6..3f81ae349c8a 100644 --- a/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java +++ b/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java @@ -119,7 +119,7 @@ public class ClassesScopeTreeStructureExpander implements ScopeTreeStructureExpa public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { final TreePath path = event.getPath(); if (path == null) return; - final DefaultMutableTreeNode node = (PackageDependenciesNode)path.getLastPathComponent(); + final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); if (node instanceof DirectoryNode) { Set<FileNode> fileNodes = null; for (int i = node.getChildCount() - 1; i >= 0; i--) { diff --git a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java new file mode 100644 index 000000000000..8fdf05c0a620 --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java @@ -0,0 +1,301 @@ +package com.intellij.jarFinder; + +import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Iconable; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.ui.components.JBList; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NotNullFunction; +import com.intellij.util.PlatformIcons; +import com.intellij.util.download.DownloadableFileDescription; +import com.intellij.util.download.DownloadableFileService; +import org.apache.xerces.parsers.DOMParser; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.swing.*; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author Konstantin Bulenkov + */ +public abstract class FindJarFix<T extends PsiElement> implements IntentionAction, Iconable { + private static final String CLASS_ROOT_URL = "http://findjar.com/class/"; + private static final String CLASS_PAGE_EXT = ".html"; + private static final String SERVICE_URL = "http://findjar.com"; + private static final String LINK_TAG_NAME = "a"; + private static final String LINK_ATTR_NAME = "href"; + + protected final T myRef; + protected final Module myModule; + protected JComponent myEditorComponent; + + public FindJarFix(T ref) { + myRef = ref; + myModule = ModuleUtil.findModuleForPsiElement(ref); + } + + @NotNull + @Override + public String getText() { + return "Find jar on web"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Family name"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return myRef.isValid() + && JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, file.getResolveScope()) != null + && myModule != null + && isFqnsOk(project, getPossibleFqns(myRef)); + } + + private static boolean isFqnsOk(Project project, List<String> fqns) { + if (fqns.isEmpty()) return false; + final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + for (String fqn : fqns) { + if (facade.findClass(fqn, scope) != null) return false; + } + return true; + } + + @Override + public void invoke(@NotNull Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + final List<String> fqns = getPossibleFqns(myRef); + myEditorComponent = editor.getComponent(); + if (fqns.size() > 1) { + final JBList listOfFqns = new JBList(fqns); + JBPopupFactory.getInstance() + .createListPopupBuilder(listOfFqns) + .setTitle("Select Qualified Name") + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + final Object value = listOfFqns.getSelectedValue(); + if (value instanceof String) { + findJarsForFqn(((String)value), editor); + } + } + }).createPopup().showInBestPositionFor(editor); + } + else if (fqns.size() == 1) { + findJarsForFqn(fqns.get(0), editor); + } + } + + private void findJarsForFqn(final String fqn, final Editor editor) { + final Map<String, String> libs = new HashMap<String, String>(); + + final Runnable runnable = new Runnable() { + public void run() { + try { + final DOMParser parser = new DOMParser(); + parser.parse(CLASS_ROOT_URL + fqn.replace('.', '/') + CLASS_PAGE_EXT); + final Document doc = parser.getDocument(); + if (doc != null) { + final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME); + for (int i = 0; i < links.getLength(); i++) { + final Node link = links.item(i); + final String libName = link.getTextContent(); + final NamedNodeMap attributes = link.getAttributes(); + if (attributes != null) { + final Node href = attributes.getNamedItem(LINK_ATTR_NAME); + if (href != null) { + final String pathToJar = href.getTextContent(); + if (pathToJar != null && (pathToJar.startsWith("/jar/") || pathToJar.startsWith("/class/../"))) { + libs.put(libName, SERVICE_URL + pathToJar); + } + } + } + } + } + } + catch (IOException ignore) {// + } + catch (SAXException e) {// + } + } + }; + + final Task.Modal task = new Task.Modal(editor.getProject(), "Looking for libraries", true) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + indicator.setIndeterminate(true); + runnable.run(); + } + + @Override + public void onSuccess() { + super.onSuccess(); + if (libs.isEmpty()) { + HintManager.getInstance().showInformationHint(editor, "No libraries found for '" + fqn + "'"); + } else { + final ArrayList<String> variants = new ArrayList<String>(libs.keySet()); + Collections.sort(variants, new Comparator<String>() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + final JBList libNames = new JBList(variants); + libNames.installCellRenderer(new NotNullFunction<Object, JComponent>() { + @NotNull + @Override + public JComponent fun(Object o) { + return new JLabel(o.toString(), PlatformIcons.JAR_ICON, SwingConstants.LEFT); + } + }); + if (libs.size() == 1) { + final String jarName = libs.keySet().iterator().next(); + final String url = libs.get(jarName); + initiateDownload(url, jarName); + } else { + JBPopupFactory.getInstance() + .createListPopupBuilder(libNames) + .setTitle("Select a jar file") + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + final Object value = libNames.getSelectedValue(); + if (value instanceof String) { + final String jarName = (String)value; + final String url = libs.get(jarName); + if (url != null) { + initiateDownload(url, jarName); + } + } + } + }) + .createPopup().showInBestPositionFor(editor); + } + } + } + }; + + ProgressManager.getInstance().run(task); + } + + private void initiateDownload(String url, String jarName) { + DOMParser parser = new DOMParser(); + try { + parser.parse(url); + final Document doc = parser.getDocument(); + if (doc != null) { + final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME); + if (links != null) { + for (int i = 0; i < links.getLength(); i++) { + final Node item = links.item(i); + if (item != null) { + final NamedNodeMap attributes = item.getAttributes(); + if (attributes != null) { + final Node link = attributes.getNamedItem(LINK_ATTR_NAME); + if (link != null) { + final String jarUrl = link.getTextContent(); + if (jarUrl != null && jarUrl.endsWith(jarName)) { + downloadJar(jarUrl, jarName); + } + } + } + } + } + } + } + } + catch (SAXException e) {// + } + catch (IOException e) {// + } + } + + private void downloadJar(String jarUrl, String jarName) { + final Project project = myModule.getProject(); + final String dirPath = PropertiesComponent.getInstance(project).getValue("findjar.last.used.dir"); + VirtualFile toSelect = dirPath == null ? null : LocalFileSystem.getInstance().findFileByIoFile(new File(dirPath)); + final VirtualFile file = FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFolderDescriptor(), project, toSelect); + if (file != null) { + PropertiesComponent.getInstance(project).setValue("findjar.last.used.dir", file.getPath()); + final DownloadableFileService downloader = DownloadableFileService.getInstance(); + final DownloadableFileDescription description = downloader.createFileDescription(jarUrl, jarName); + final VirtualFile[] jars = downloader.createDownloader(Arrays.asList(description), project, myEditorComponent, jarName) + .toDirectory(file.getPath()).download(); + if (jars != null && jars.length == 1) { + AccessToken token = WriteAction.start(); + try { + OrderEntryFix.addJarToRoots(jars[0].getPresentableUrl(), myModule, myRef); + } + finally { + token.finish(); + } + } + } + } + + protected abstract Collection<String> getFqns(@NotNull T ref); + + protected List<String> getPossibleFqns(T ref) { + Collection<String> fqns = getFqns(ref); + + List<String> res = new ArrayList<String>(fqns.size()); + + for (String fqn : fqns) { + if (fqn.startsWith("java.") || fqn.startsWith("javax.swing.")) { + continue; + } + final int index = fqn.lastIndexOf('.'); + if (index == -1) { + continue; + } + final String className = fqn.substring(index + 1); + if (className.length() == 0 || Character.isLowerCase(className.charAt(0))) { + continue; + } + + res.add(fqn); + } + + return res; + } + + @Override + public boolean startInWriteAction() { + return false; + } + + @Override + public Icon getIcon(int flags) { + return PlatformIcons.WEB_ICON; + } +} diff --git a/java/java-impl/src/com/intellij/jarFinder/FindJarQuickFixProvider.java b/java/java-impl/src/com/intellij/jarFinder/FindJarQuickFixProvider.java new file mode 100644 index 000000000000..9cf66d3991fe --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/FindJarQuickFixProvider.java @@ -0,0 +1,22 @@ +package com.intellij.jarFinder; + +import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; +import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author Konstantin Bulenkov + */ +public class FindJarQuickFixProvider extends UnresolvedReferenceQuickFixProvider<PsiJavaCodeReferenceElement> { + @Override + public void registerFixes(PsiJavaCodeReferenceElement ref, QuickFixActionRegistrar registrar) { + registrar.register(new JavaFindJarFix(ref)); + } + + @NotNull + @Override + public Class<PsiJavaCodeReferenceElement> getReferenceClass() { + return PsiJavaCodeReferenceElement.class; + } +} diff --git a/java/java-impl/src/com/intellij/jarFinder/JavaFindJarFix.java b/java/java-impl/src/com/intellij/jarFinder/JavaFindJarFix.java new file mode 100644 index 000000000000..98e5a6709a5c --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/JavaFindJarFix.java @@ -0,0 +1,78 @@ +package com.intellij.jarFinder; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.PsiImportStaticStatementImpl; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Sergey Evdokimov + */ +public class JavaFindJarFix extends FindJarFix<PsiQualifiedReferenceElement> { + public JavaFindJarFix(PsiQualifiedReferenceElement ref) { + super(ref); + } + + @Override + protected Collection<String> getFqns(@NotNull PsiQualifiedReferenceElement ref) { + final PsiImportStatementBase importStatement = PsiTreeUtil.getParentOfType(ref.getElement(), PsiImportStatementBase.class); + + //from static imports + if (importStatement != null) { + if (importStatement instanceof PsiImportStatement) { + final String importFQN = ((PsiImportStatement)importStatement).getQualifiedName(); + if (importFQN != null && !importFQN.endsWith("*")) { + return Collections.singleton(importFQN); + } + } + else if (importStatement instanceof PsiImportStaticStatementImpl) { + final PsiJavaCodeReferenceElement classRef = ((PsiImportStaticStatementImpl)importStatement).getClassReference(); + if (classRef != null) { + final String importFQN = classRef.getQualifiedName(); + if (importFQN != null) { + return Collections.singleton(importFQN); + } + } + } + return Collections.emptyList(); + } + + final PsiElement qualifier = ref.getQualifier(); + if (qualifier instanceof PsiQualifiedReference) { + //PsiQualifiedReference r = (PsiQualifiedReference)qualifier; + //TODO[kb] get fqn from expressions like org.unresolvedPackage.MyClass.staticMethodCall(...); + return Collections.emptyList(); + } + final String className = ref.getReferenceName(); + PsiFile file = ref.getContainingFile().getOriginalFile(); + if (className != null && file instanceof PsiJavaFile) { + final PsiImportList importList = ((PsiJavaFile)file).getImportList(); + if (importList != null) { + final PsiImportStatementBase statement = importList.findSingleImportStatement(className); + if (statement instanceof PsiImportStatement) { + final String importFQN = ((PsiImportStatement)statement).getQualifiedName(); + if (importFQN != null) { + return Collections.singleton(importFQN); + } + } + else { + List<String> res = new ArrayList<String>(); + // iterate through * + for (PsiImportStatementBase imp : importList.getAllImportStatements()) { + if (imp.isOnDemand() && imp instanceof PsiImportStatement) { + res.add(((PsiImportStatement)imp).getQualifiedName() + "." + className); + } + } + + return res; + } + } + } + return Collections.emptyList(); + } +} diff --git a/java/java-impl/src/com/intellij/jarFinder/MavenCentralSourceSearcher.java b/java/java-impl/src/com/intellij/jarFinder/MavenCentralSourceSearcher.java new file mode 100644 index 000000000000..deaed59885ec --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/MavenCentralSourceSearcher.java @@ -0,0 +1,70 @@ +package com.intellij.jarFinder; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.xpath.XPath; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.List; + +/** + * @author Sergey Evdokimov + */ +public class MavenCentralSourceSearcher extends SourceSearcher { + + private static final Logger LOG = Logger.getInstance(MavenCentralSourceSearcher.class); + + @Nullable + @Override + protected String findSourceJar(@NotNull ProgressIndicator indicator, + @NotNull String artifactId, + @NotNull String version) throws SourceSearchException { + try { + indicator.setIndeterminate(true); + indicator.setText("Connecting to http://search.maven.org"); + + indicator.checkCanceled(); + + String url = "http://search.maven.org/solrsearch/select?rows=3&wt=xml&q=a:%22" + artifactId + "%22%20AND%20v:%22" + version + "%22%20AND%20l:%22sources%22"; + Document document = readDocumentCancelable(indicator, url); + + indicator.checkCanceled(); + + List<Element> artifactList = (List<Element>)XPath.newInstance("/response/result/doc/str[@name='g']").selectNodes(document); + if (artifactList.isEmpty()) { + return null; + } + + Element element; + + if (artifactList.size() == 1) { + element = artifactList.get(0); + } + else { + // TODO handle + return null; + } + + String groupId = element.getValue(); + + String downloadUrl = "http://search.maven.org/remotecontent?filepath=" + groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + '-' + version + "-sources.jar"; + + return downloadUrl; + } + catch (JDOMException e) { + LOG.warn(e); + throw new SourceSearchException("Failed to parse response from server. See log for more details."); + } + catch (IOException e) { + indicator.checkCanceled(); // Cause of IOException may be canceling of operation. + + LOG.warn(e); + throw new SourceSearchException("Connection problem. See log for more details."); + } + } +} diff --git a/java/java-impl/src/com/intellij/jarFinder/SonatypeSourceSearcher.java b/java/java-impl/src/com/intellij/jarFinder/SonatypeSourceSearcher.java new file mode 100644 index 000000000000..2a942cca8946 --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/SonatypeSourceSearcher.java @@ -0,0 +1,87 @@ +package com.intellij.jarFinder; + +import com.intellij.notification.NotificationType; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.Pair; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.xpath.XPath; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.List; + +/** + * @author Sergey Evdokimov + */ +public class SonatypeSourceSearcher extends SourceSearcher { + + private static final Logger LOG = Logger.getInstance(SonatypeSourceSearcher.class); + + @Nullable + @Override + public String findSourceJar(@NotNull final ProgressIndicator indicator, @NotNull String artifactId, @NotNull String version) + throws SourceSearchException { + try { + indicator.setIndeterminate(true); + indicator.setText("Connecting to https://oss.sonatype.org"); + + indicator.checkCanceled(); + + String url = "https://oss.sonatype.org/service/local/lucene/search?collapseresults=true&c=sources&a=" + artifactId + "&v=" + version; + Document document = readDocumentCancelable(indicator, url); + + indicator.checkCanceled(); + + List<Element> artifactList = (List<Element>)XPath.newInstance("/searchNGResponse/data/artifact").selectNodes(document); + if (artifactList.isEmpty()) { + return null; + } + + Element element; + + if (artifactList.size() == 1) { + element = artifactList.get(0); + } + else { + // TODO handle + return null; + } + + List<Element> artifactHintList = + (List<Element>)XPath.newInstance("artifactHits/artifactHit/artifactLinks/artifactLink/classifier[text()='sources']/../../..") + .selectNodes(element); + if (artifactHintList.isEmpty()) { + return null; + } + + String groupId = element.getChildTextTrim("groupId"); + String repositoryId = artifactHintList.get(0).getChildTextTrim("repositoryId"); + + String downloadUrl = "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=" + + repositoryId + + "&g=" + + groupId + + "&a=" + + artifactId + + "&v=" + + version + + "&e=jar&c=sources"; + + return downloadUrl; + } + catch (JDOMException e) { + LOG.warn(e); + throw new SourceSearchException("Failed to parse response from server. See log for more details."); + } + catch (IOException e) { + indicator.checkCanceled(); // Cause of IOException may be canceling of operation. + + LOG.warn(e); + throw new SourceSearchException("Connection problem. See log for more details."); + } + } +} diff --git a/java/java-impl/src/com/intellij/jarFinder/SourceSearcher.java b/java/java-impl/src/com/intellij/jarFinder/SourceSearcher.java new file mode 100644 index 000000000000..b1d635af8525 --- /dev/null +++ b/java/java-impl/src/com/intellij/jarFinder/SourceSearcher.java @@ -0,0 +1,77 @@ +package com.intellij.jarFinder; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.util.net.HttpConfigurable; +import org.jdom.Document; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; + +/** + * @author Sergey Evdokimov + */ +public abstract class SourceSearcher { + + /** + * @param indicator + * @param artifactId + * @param version + * @return groupId of found artifact and url. + */ + @Nullable + protected abstract String findSourceJar(@NotNull final ProgressIndicator indicator, @NotNull String artifactId, @NotNull String version) throws SourceSearchException; + + protected static Document readDocumentCancelable(final ProgressIndicator indicator, String url) throws JDOMException, IOException { + final HttpURLConnection urlConnection = HttpConfigurable.getInstance().openHttpConnection(url); + + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + //noinspection InfiniteLoopStatement + while (true) { + if (indicator.isCanceled()) { + urlConnection.disconnect(); + } + + //noinspection BusyWait + Thread.sleep(100); + } + } + catch (InterruptedException ignored) { + + } + } + }); + + t.start(); + + try { + urlConnection.setRequestProperty("accept", "application/xml"); + + InputStream inputStream = urlConnection.getInputStream(); + try { + return new SAXBuilder().build(inputStream); + } + finally { + inputStream.close(); + } + } + finally { + t.interrupt(); + } + } +} + +class SourceSearchException extends Exception { + + SourceSearchException(String message) { + super(message); + } + +}
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java index 5b7c3ef01ad2..08ecb6a716a4 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java @@ -21,8 +21,6 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.filters.RegexpFilter; -import com.intellij.execution.filters.TextConsoleBuilder; -import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; @@ -138,10 +136,8 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl super(null); myGenerationOptions = generationOptions; myProject = project; - TextConsoleBuilder builder = TextConsoleBuilderFactory.getInstance().createBuilder(project); - builder.addFilter(new RegexpFilter(project, "$FILE_PATH$:$LINE$:[^\\^]+\\^")); - builder.addFilter(new RegexpFilter(project, "$FILE_PATH$:$LINE$: warning - .+$")); - setConsoleBuilder(builder); + addConsoleFilters(new RegexpFilter(project, "$FILE_PATH$:$LINE$:[^\\^]+\\^"), + new RegexpFilter(project, "$FILE_PATH$:$LINE$: warning - .+$")); } protected GeneralCommandLine createCommandLine() throws ExecutionException { diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java index ecebc06f9555..e34cafbbb10c 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java @@ -18,6 +18,7 @@ package com.intellij.javadoc; import com.intellij.CommonBundle; import com.intellij.analysis.AnalysisScope; import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; import com.intellij.execution.RunnerRegistry; import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.runners.ExecutionEnvironment; @@ -83,7 +84,8 @@ public final class JavadocGenerationManager implements PersistentStateComponent< try { final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(DefaultRunExecutor.EXECUTOR_ID, myConfiguration); assert runner != null; - runner.execute(DefaultRunExecutor.getRunExecutorInstance(), new ExecutionEnvironment(myConfiguration, myProject, null, null, null)); + Executor executor = DefaultRunExecutor.getRunExecutorInstance(); + runner.execute(new ExecutionEnvironment(myConfiguration ,executor, myProject, null)); } catch (ExecutionException e) { ExecutionErrorDialog.show(e, CommonBundle.getErrorTitle(), myProject); diff --git a/java/java-impl/src/com/intellij/lang/java/JavaLiteralEscaper.java b/java/java-impl/src/com/intellij/lang/java/JavaLiteralEscaper.java deleted file mode 100644 index 4d3712d6ae08..000000000000 --- a/java/java-impl/src/com/intellij/lang/java/JavaLiteralEscaper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2009 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.lang.java; - -import com.intellij.lang.LiteralEscaper; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiJavaToken; -import com.intellij.psi.JavaTokenType; -import com.intellij.openapi.util.text.StringUtil; - -/** - * @author yole - */ -public class JavaLiteralEscaper implements LiteralEscaper { - @Override - public String getEscapedText(final PsiElement context, final String originalText) { - if (context instanceof PsiJavaToken && ((PsiJavaToken)context).getTokenType() == JavaTokenType.STRING_LITERAL) { - return StringUtil.escapeStringCharacters(originalText); - } - return originalText; - } - - @Override - public String escapeText(String originalText) { - return StringUtil.escapeStringCharacters(originalText); - } - - @Override - public String unescapeText(String originalText) { - return StringUtil.unescapeStringCharacters(originalText); - } -} diff --git a/java/java-impl/src/com/intellij/openapi/module/JavaModuleType.java b/java/java-impl/src/com/intellij/openapi/module/JavaModuleType.java index e8e66664f4d9..a86e3a6b7e7c 100644 --- a/java/java-impl/src/com/intellij/openapi/module/JavaModuleType.java +++ b/java/java-impl/src/com/intellij/openapi/module/JavaModuleType.java @@ -28,6 +28,7 @@ import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaPsiFacade; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -41,7 +42,7 @@ public class JavaModuleType extends ModuleType<JavaModuleBuilder> { public static final String MODULE_NAME = ProjectBundle.message("module.type.java.name"); public static final String JAVA_GROUP = "Java"; - private static final String JAVA_MODULE = "JAVA_MODULE"; + private static final String JAVA_MODULE = ModuleTypeId.JAVA_MODULE; public JavaModuleType() { this(JAVA_MODULE); @@ -51,16 +52,19 @@ public class JavaModuleType extends ModuleType<JavaModuleBuilder> { super(id); } + @NotNull @Override public JavaModuleBuilder createModuleBuilder() { return new JavaModuleBuilder(); } + @NotNull @Override public String getName() { return MODULE_NAME; } + @NotNull @Override public String getDescription() { return ProjectBundle.message("module.type.java.description"); @@ -76,9 +80,10 @@ public class JavaModuleType extends ModuleType<JavaModuleBuilder> { return getJavaModuleNodeIconClosed(); } + @NotNull @Override - public ModuleWizardStep[] createWizardSteps(final WizardContext wizardContext, final JavaModuleBuilder moduleBuilder, - final ModulesProvider modulesProvider) { + public ModuleWizardStep[] createWizardSteps(@NotNull final WizardContext wizardContext, @NotNull final JavaModuleBuilder moduleBuilder, + @NotNull final ModulesProvider modulesProvider) { final ProjectWizardStepFactory wizardFactory = ProjectWizardStepFactory.getInstance(); ArrayList<ModuleWizardStep> steps = new ArrayList<ModuleWizardStep>(); final ModuleWizardStep supportForFrameworksStep = wizardFactory.createSupportForFrameworksStep(wizardContext, moduleBuilder, modulesProvider); @@ -91,7 +96,7 @@ public class JavaModuleType extends ModuleType<JavaModuleBuilder> { @Nullable @Override - public ModuleWizardStep modifySettingsStep(SettingsStep settingsStep, final ModuleBuilder moduleBuilder) { + public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep, @NotNull final ModuleBuilder moduleBuilder) { return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, moduleBuilder, new Condition<SdkTypeId>() { @Override public boolean value(SdkTypeId sdkType) { @@ -118,13 +123,13 @@ public class JavaModuleType extends ModuleType<JavaModuleBuilder> { } @Override - public boolean isValidSdk(final Module module, final Sdk projectSdk) { + public boolean isValidSdk(@NotNull final Module module, final Sdk projectSdk) { return isValidJavaSdk(module); } - public static boolean isValidJavaSdk(final Module module) { + public static boolean isValidJavaSdk(@NotNull Module module) { if (ModuleRootManager.getInstance(module).getSourceRoots().length == 0) return true; - return JavaPsiFacade.getInstance(module.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, + return JavaPsiFacade.getInstance(module.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, module.getModuleWithLibrariesScope()) != null; } } diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java index 016e9f737156..76e9875e42c0 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java @@ -15,36 +15,16 @@ */ package com.intellij.openapi.projectRoots; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; +import org.jetbrains.annotations.NotNull; /** * @author anna * @since 3/28/12 */ public class JavaVersionServiceImpl extends JavaVersionService { - private JavaSdkVersion myTestVersion = JavaSdkVersion.JDK_1_7; - - @TestOnly - public void setTestVersion(@Nullable JavaSdkVersion testVersion, Disposable parentDisposable) { - myTestVersion = testVersion; - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - myTestVersion = JavaSdkVersion.JDK_1_7; - } - }); - } - @Override - public boolean isAtLeast(PsiElement element, JavaSdkVersion version) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - return myTestVersion != null && myTestVersion.isAtLeast(version); - } + public boolean isAtLeast(@NotNull PsiElement element, @NotNull JavaSdkVersion version) { return JavaSdkVersionUtil.isAtLeast(element, version); } } diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java index 248f5a7978d5..ad59dda1c471 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java @@ -314,7 +314,7 @@ public class JavaSdkImpl extends JavaSdk { @Override @SuppressWarnings({"HardCodedStringLiteral"}) - public void setupSdkPaths(Sdk sdk) { + public void setupSdkPaths(@NotNull Sdk sdk) { final File jdkHome = new File(sdk.getHomePath()); List<VirtualFile> classes = findClasses(jdkHome, false); VirtualFile sources = findSources(jdkHome); @@ -427,10 +427,6 @@ public class JavaSdkImpl extends JavaSdk { @Override public JavaSdkVersion getVersion(@NotNull Sdk sdk) { - return getVersion1(sdk); - } - - private static JavaSdkVersion getVersion1(Sdk sdk) { String version = sdk.getVersionString(); if (version == null) return null; return JdkVersionUtil.getVersion(version); diff --git a/java/java-impl/src/com/intellij/openapi/roots/impl/JavaLanguageLevelPusher.java b/java/java-impl/src/com/intellij/openapi/roots/impl/JavaLanguageLevelPusher.java index 8a12fac0e341..b177f9a9aa12 100644 --- a/java/java-impl/src/com/intellij/openapi/roots/impl/JavaLanguageLevelPusher.java +++ b/java/java-impl/src/com/intellij/openapi/roots/impl/JavaLanguageLevelPusher.java @@ -27,6 +27,7 @@ import com.intellij.util.indexing.FileBasedIndex; import com.intellij.util.io.DataInputOutputUtil; import com.intellij.util.messages.MessageBus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -42,7 +43,7 @@ public class JavaLanguageLevelPusher implements FilePropertyPusher<LanguageLevel } @Override - public void initExtra(Project project, MessageBus bus, Engine languageLevelUpdater) { + public void initExtra(@NotNull Project project, @NotNull MessageBus bus, @NotNull Engine languageLevelUpdater) { // nothing } @@ -64,24 +65,24 @@ public class JavaLanguageLevelPusher implements FilePropertyPusher<LanguageLevel } @Override - public LanguageLevel getImmediateValue(Project project, VirtualFile file) { + public LanguageLevel getImmediateValue(@NotNull Project project, @Nullable VirtualFile file) { return null; } @Override - public LanguageLevel getImmediateValue(Module module) { + public LanguageLevel getImmediateValue(@NotNull Module module) { return LanguageLevelUtil.getEffectiveLanguageLevel(module); } @Override - public boolean acceptsFile(VirtualFile file) { + public boolean acceptsFile(@NotNull VirtualFile file) { return false; } private static final FileAttribute PERSISTENCE = new FileAttribute("language_level_persistence", 2, true); @Override - public void persistAttribute(VirtualFile fileOrDir, @NotNull LanguageLevel level) throws IOException { + public void persistAttribute(@NotNull VirtualFile fileOrDir, @NotNull LanguageLevel level) throws IOException { final DataInputStream iStream = PERSISTENCE.readAttribute(fileOrDir); if (iStream != null) { try { @@ -105,6 +106,6 @@ public class JavaLanguageLevelPusher implements FilePropertyPusher<LanguageLevel } @Override - public void afterRootsChanged(Project project) { + public void afterRootsChanged(@NotNull Project project) { } } diff --git a/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java b/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java index 17d937611b17..af890621d62f 100644 --- a/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java +++ b/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java @@ -178,7 +178,8 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder { @Override public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, - @NotNull Processor<PsiDirectory> consumer) { + @NotNull Processor<PsiDirectory> consumer, + boolean includeLibrarySources) { final List<VirtualFile> classRoots = getClassRoots(); if (classRoots.isEmpty()) { return true; diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/DocCommentBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/DocCommentBlock.java index d5b7e90b2fe6..b65393f3a4b3 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/DocCommentBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/DocCommentBlock.java @@ -18,9 +18,9 @@ package com.intellij.psi.formatter.java; import com.intellij.formatting.*; import com.intellij.formatting.alignment.AlignmentStrategy; import com.intellij.lang.ASTNode; +import com.intellij.psi.JavaDocTokenType; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; -import com.intellij.psi.impl.source.tree.ElementType; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -37,7 +37,7 @@ public class DocCommentBlock extends AbstractJavaBlock{ ASTNode child = myNode.getFirstChildNode(); while (child != null) { - if (child.getElementType() == ElementType.DOC_COMMENT_START) { + if (child.getElementType() == JavaDocTokenType.DOC_COMMENT_START) { result.add(createJavaBlock(child, mySettings, Indent.getNoneIndent(), null, AlignmentStrategy.getNullStrategy())); } else if (!FormatterUtil.containsWhiteSpacesOnly(child) && child.getText().trim().length() > 0){ result.add(createJavaBlock(child, mySettings, Indent.getSpaceIndent(1), null, AlignmentStrategy.getNullStrategy())); diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java index 1594b3b3674e..0309800ad813 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java @@ -39,6 +39,7 @@ class AnchorElementInfo extends SelfElementInfo { AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFile containingFile) { super(containingFile.getProject(), ProperTextRange.create(anchor.getTextRange()), anchor.getClass(), containingFile, containingFile.getLanguage()); + assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor; } // will restore by stub index until file tree get loaded AnchorElementInfo(@NotNull PsiElement anchor, @@ -50,18 +51,19 @@ class AnchorElementInfo extends SelfElementInfo { myStubElementType = stubElementType; IElementType contentElementType = ((PsiFileImpl)containingFile).getContentElementType(); assert contentElementType instanceof IStubFileElementType : contentElementType; + assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor; } @Override @Nullable public PsiElement restoreElement() { if (stubId != -1) { - PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject); + PsiFile file = restoreFile(); if (!(file instanceof PsiFileWithStubSupport)) return null; return PsiAnchor.restoreFromStubIndex((PsiFileWithStubSupport)file, stubId, myStubElementType, false); } if (!mySyncMarkerIsValid) return null; - PsiFile file = SelfElementInfo.restoreFileFromVirtual(getVirtualFile(), myProject); + PsiFile file = restoreFile(); if (file == null) return null; PsiElement anchor = file.findElementAt(getSyncStartOffset()); if (anchor == null) return null; diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java index 57f919f9e63e..a3ed29f87ddd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl.smartPointers; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiFileWithStubSupport; import com.intellij.psi.stubs.IStubElementType; @@ -27,8 +26,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class AnchorElementInfoFactory implements SmartPointerElementInfoFactory { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.AnchorElementInfoFactory"); - @Override @Nullable public SmartPointerElementInfo createElementInfo(@NotNull PsiElement element) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java index 5c80f43240d7..841b8b530e16 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java @@ -16,9 +16,11 @@ package com.intellij.psi.impl.source.codeStyle; import com.intellij.lang.ASTNode; -import com.intellij.lang.StdLanguages; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; @@ -31,57 +33,65 @@ public class FormatCommentsProcessor implements PreFormatProcessor { @NotNull @Override public TextRange process(@NotNull final ASTNode element, @NotNull final TextRange range) { - final Project project = SourceTreeToPsiMap.treeElementToPsi(element).getProject(); + PsiElement e = SourceTreeToPsiMap.treeElementToPsi(element); + assert e != null; + final Project project = e.getProject(); if (!CodeStyleSettingsManager.getSettings(project).ENABLE_JAVADOC_FORMATTING || - element.getPsi().getContainingFile().getLanguage() != StdLanguages.JAVA) { + element.getPsi().getContainingFile().getLanguage() != JavaLanguage.INSTANCE) + { return range; } - return formatCommentsInner(project, element, range); } - private static TextRange formatCommentsInner(Project project, ASTNode element, final TextRange range) { - TextRange result = range; - - - // check for RepositoryTreeElement is optimization - if (shouldProcess(element)) { - final TextRange elementRange = element.getTextRange(); + /** + * Formats PsiDocComments of current ASTNode element and all his children PsiDocComments + */ + @NotNull + private static TextRange formatCommentsInner(@NotNull Project project, @NotNull ASTNode element, @NotNull final TextRange markedRange) { + TextRange resultTextRange = markedRange; + final PsiElement elementPsi = element.getPsi(); + boolean shouldFormat = markedRange.contains(element.getTextRange()); - if (range.contains(elementRange)) { - new CommentFormatter(project).process(element); - final TextRange newRange = element.getTextRange(); - result = new TextRange(range.getStartOffset(), range.getEndOffset() + newRange.getLength() - elementRange.getLength()); + if (shouldFormat) { + final ASTNode rangeAnchor; + // There are two possible cases: + // 1. Given element correspond to comment's owner (e.g. field or method); + // 2. Given element corresponds to comment itself; + // However, doc comment formatter replaces old comment with the new one, hence, old element becomes invalid. That's why we need + // to calculate text length delta not for the given comment element (it's invalid because removed from the AST tree) but for + // its parent. + if (elementPsi instanceof PsiDocComment) { + rangeAnchor = element.getTreeParent(); } - - // optimization, does not seek PsiDocComment inside fields / methods or out of range - if (element.getPsi() instanceof PsiField || - element.getPsi() instanceof PsiMethod || - element instanceof PsiDocComment || - range.getEndOffset() < elementRange.getStartOffset() - ) { - return result; + else { + rangeAnchor = element; } + TextRange before = rangeAnchor.getTextRange(); + new CommentFormatter(project).processComment(element); + int deltaRange = rangeAnchor.getTextRange().getLength() - before.getLength(); + resultTextRange = new TextRange(markedRange.getStartOffset(), markedRange.getEndOffset() + deltaRange); + } + + + // If element is Psi{Method, Field, DocComment} and was formatted there is no reason to continue - we formatted all possible javadocs. + // If element is out of range its children are also out of range. So in both cases formatting is finished. It's just for optimization. + if ((shouldFormat && (elementPsi instanceof PsiMethod || elementPsi instanceof PsiField || elementPsi instanceof PsiDocComment)) + || markedRange.getEndOffset() < element.getStartOffset()) + { + return resultTextRange; } ASTNode current = element.getFirstChildNode(); while (current != null) { - // we expand the chameleons here for effectiveness - current.getFirstChildNode(); - result = formatCommentsInner(project, current, result); + // When element is PsiClass its PsiDocComment is formatted up to this moment, so we didn't need to format it again. + if (!(shouldFormat && current.getPsi() instanceof PsiDocComment && elementPsi instanceof PsiClass)) { + resultTextRange = formatCommentsInner(project, current, resultTextRange); + } current = current.getTreeNext(); } - return result; - } - private static boolean shouldProcess(final ASTNode element) { - if (element instanceof PsiDocComment) { - return true; - } - else { - return true;//element.getElementType() instanceof JavaStubElementType && - //(element.getPsi()) instanceof PsiDocCommentOwner; - } + return resultTextRange; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index 8beff5d7b21e..0fe403b84ff8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -748,8 +748,11 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { String suffix = getSuffixByVariableKind(variableKind); boolean doDecapitalize = false; - if (name.startsWith(prefix) && name.length() > prefix.length()) { - name = name.substring(prefix.length()); + int pLength = prefix.length(); + if (pLength > 0 && name.startsWith(prefix) && name.length() > pLength && + // check it's not just a long camel word that happens to begin with the specified prefix + (!Character.isJavaIdentifierPart(prefix.charAt(pLength - 1)) || Character.isUpperCase(name.charAt(pLength)))) { + name = name.substring(pLength); doDecapitalize = true; } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java index 9f900c0f6573..624c5370c4ad 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/CommentFormatter.java @@ -15,16 +15,21 @@ */ package com.intellij.psi.impl.source.codeStyle.javadoc; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.lang.ASTNode; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.LineTokenizer; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -38,7 +43,7 @@ public class CommentFormatter { private final JDParser myParser; private final Project myProject; - public CommentFormatter(Project project) { + public CommentFormatter(@NotNull Project project) { mySettings = CodeStyleSettingsManager.getSettings(project); myParser = new JDParser(mySettings); myProject = project; @@ -52,14 +57,14 @@ public class CommentFormatter { return myParser; } - public void process(ASTNode element) { + public void processComment(@Nullable ASTNode element) { if (!getSettings().ENABLE_JAVADOC_FORMATTING) return; PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element); processElementComment(psiElement); } - private void processElementComment(PsiElement psiElement) { + private void processElementComment(@Nullable PsiElement psiElement) { if (psiElement instanceof PsiClass) { String newCommentText = formatClassComment((PsiClass)psiElement); replaceDocComment(newCommentText, (PsiDocCommentOwner)psiElement); @@ -77,7 +82,7 @@ public class CommentFormatter { } } - private void replaceDocComment(String newCommentText, final PsiDocCommentOwner psiDocCommentOwner) { + private void replaceDocComment(@Nullable String newCommentText, @NotNull final PsiDocCommentOwner psiDocCommentOwner) { final PsiDocComment oldComment = psiDocCommentOwner.getDocComment(); if (newCommentText != null) newCommentText = stripSpaces(newCommentText); if (newCommentText == null || oldComment == null || newCommentText.equals(oldComment.getText())) { @@ -99,7 +104,7 @@ public class CommentFormatter { private static String stripSpaces(String text) { String[] lines = LineTokenizer.tokenize(text.toCharArray(), false); - StringBuffer buf = new StringBuffer(text.length()); + StringBuilder buf = new StringBuilder(text.length()); for (int i = 0; i < lines.length; i++) { if (i > 0) buf.append('\n'); buf.append(rTrim(lines[i])); @@ -117,7 +122,7 @@ public class CommentFormatter { } @Nullable - private String formatClassComment(PsiClass psiClass) { + private String formatClassComment(@NotNull PsiClass psiClass) { final String info = getOrigCommentInfo(psiClass); if (info == null) return null; @@ -126,7 +131,7 @@ public class CommentFormatter { } @Nullable - private String formatMethodComment(PsiMethod psiMethod) { + private String formatMethodComment(@NotNull PsiMethod psiMethod) { final String info = getOrigCommentInfo(psiMethod); if (info == null) return null; @@ -135,7 +140,7 @@ public class CommentFormatter { } @Nullable - private String formatFieldComment(PsiField psiField) { + private String formatFieldComment(@NotNull PsiField psiField) { final String info = getOrigCommentInfo(psiField); if (info == null) return null; @@ -149,8 +154,9 @@ public class CommentFormatter { * @param element the specified element * @return text chunk */ + @Nullable private static String getOrigCommentInfo(PsiDocCommentOwner element) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); PsiElement e = element.getFirstChild(); if (!(e instanceof PsiComment)) { // no comments for this element @@ -188,39 +194,38 @@ public class CommentFormatter { } /** - * For the specified element returns its indentation - * - * @param element the specified element - * @return indentation as string + * Computes indentation of PsiClass, PsiMethod and PsiField elements after formatting + * @param element PsiClass or PsiMethod or PsiField + * @return indentation size */ - private static String getIndent(PsiElement element) { - PsiElement e = element.getFirstChild(); - PsiWhiteSpace lastWS = null; - for (; ; e = e.getNextSibling()) { - if (e instanceof PsiWhiteSpace) { - lastWS = (PsiWhiteSpace)e; - } - else if (e instanceof PsiComment) { - lastWS = null; - } - else { + private int getIndentSpecial(@NotNull PsiElement element) { + assert(element instanceof PsiClass || + element instanceof PsiField || + element instanceof PsiMethod); + + int indentSize = mySettings.getIndentSize(JavaFileType.INSTANCE); + boolean doNotIndentTopLevelClassMembers = mySettings.getCommonSettings(JavaLanguage.INSTANCE).DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS; + + int indent = 0; + PsiClass top = PsiUtil.getTopLevelClass(element); + while (top != null && !element.isEquivalentTo(top)) { + if (doNotIndentTopLevelClassMembers && element.getParent().isEquivalentTo(top)) { break; } + element = element.getParent(); + indent += indentSize; } - e = lastWS == null ? element.getPrevSibling() : lastWS; - if (!(e instanceof PsiWhiteSpace)) return ""; - PsiWhiteSpace ws = (PsiWhiteSpace)e; - String t = ws.getText(); - int l = t.length(); - int i = l; - while (--i >= 0) { - char ch = t.charAt(i); - if (ch == '\n' || ch == '\r') break; - } - if (i < 0) return t; - i++; - if (i == l) return ""; - return t.substring(i); + return indent; + } + + /** + * Used while formatting javadocs. We need precise element indentation after formatting to wrap comments correctly. + * Used only for PsiClass, PsiMethod and PsiFields. + * @return indent which would be used for the given element when it's formatted according to the current code style settings + */ + @NotNull + private String getIndent(@NotNull PsiElement element) { + return StringUtil.repeatSymbol(' ', getIndentSpecial(element)); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java index 28dc6a359942..740b77cb2228 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java @@ -36,6 +36,7 @@ public class JDComment { private List<String> mySeeAlsoList; private String mySince; private String myDeprecated; + private boolean myMultiLineComment; public JDComment(@NotNull CommentFormatter formatter) { myFormatter = formatter; @@ -49,6 +50,10 @@ public class JDComment { return l == null || l.size() == 0; } + public void setMultiLine(boolean value) { + myMultiLineComment = value; + } + @Nullable public String generate(@NotNull String indent) { final String prefix; @@ -118,12 +123,14 @@ public class JDComment { sb.delete(nlen, sb.length()); } - if( !myFormatter.getSettings().JD_DO_NOT_WRAP_ONE_LINE_COMMENTS || - sb.indexOf("\n") != sb.length()-1 ) { + if (myMultiLineComment && myFormatter.getSettings().JD_DO_NOT_WRAP_ONE_LINE_COMMENTS + || !myFormatter.getSettings().JD_DO_NOT_WRAP_ONE_LINE_COMMENTS + || sb.indexOf("\n") != sb.length() - 1) // If comment has become multiline after formatting - it must be shown as multiline. + // Last symbol is always '\n', so we need to check if there is one more LF symbol before it. + { sb.insert(0, "/**\n"); sb.append(indent); - } - else { + } else { sb.replace(0, prefix.length(), "/** "); sb.deleteCharAt(sb.length()-1); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java index 859e848d3304..f4ba00070611 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java @@ -47,14 +47,24 @@ public class JDParser { private static final char lineSeparator = '\n'; @NotNull - public JDComment parse(@Nullable String text, @NotNull JDComment c) { - if (text == null) return c; + public JDComment parse(@Nullable String text, @NotNull JDComment comment) { + if (text == null) return comment; List<Boolean> markers = new ArrayList<Boolean>(); List<String> l = toArray(text, "\n", markers); - if (l == null) return c; + + //if it is - we are dealing with multiline comment: + // /** + // * comment + // */ + //which shouldn't be wrapped into one line comment like /** comment */ + if (text.indexOf('\n') >= 0) { + comment.setMultiLine(true); + } + + if (l == null) return comment; int size = l.size(); - if (size == 0) return c; + if (size == 0) return comment; // preprocess strings - removes first '*' for (int i = 0; i < size; i++) { @@ -85,17 +95,17 @@ public class JDParser { if (i == size || line.length() > 0) { if (i == size || line.charAt(0) == '@') { if (tag == null) { - c.setDescription(sb.toString()); + comment.setDescription(sb.toString()); } else { int j = 0; String myline = sb.toString(); for (; j < tagParsers.length; j++) { TagParser parser = tagParsers[j]; - if (parser.parse(tag, myline, c)) break; + if (parser.parse(tag, myline, comment)) break; } if (j == tagParsers.length) { - c.addUnknownTag("@" + tag + " " + myline); + comment.addUnknownTag("@" + tag + " " + myline); } } @@ -127,7 +137,7 @@ public class JDParser { } } - return c; + return comment; } /** diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/GenericReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/GenericReference.java index 83e623b64cfe..ca65db6af59f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/GenericReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/GenericReference.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.reference.impl; +import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider; import com.intellij.psi.*; import com.intellij.psi.PsiReferenceProvider; import com.intellij.psi.impl.source.resolve.reference.impl.providers.GenericReferenceProvider; @@ -29,7 +30,7 @@ import org.jetbrains.annotations.Nullable; * Time: 17:33:24 * To change this template use Options | File Templates. */ -public abstract class GenericReference extends CachingReference { +public abstract class GenericReference extends CachingReference implements EmptyResolveMessageProvider { public static final GenericReference[] EMPTY_ARRAY = new GenericReference[0]; @Nullable diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java index d14698237643..604b90e896d6 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java @@ -23,10 +23,8 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; -import com.intellij.util.containers.*; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.*; @@ -166,7 +164,7 @@ public class FilePathReferenceProvider extends PsiReferenceProvider { final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory); if (aPackage != null && aPackage.getName() != null) { // package prefix - result.add(PackagePrefixFileSystemItem.create(directory)); + result.add(PackagePrefixFileSystemItemImpl.create(directory)); } else { result.add(directory); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java index 4a379e02abb2..5e4f2790d25e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.resolve.reference.impl.providers; import com.intellij.codeInsight.completion.JavaLookupElementBuilder; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; -import com.intellij.codeInsight.daemon.QuickFixProvider; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix; import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; @@ -68,7 +67,7 @@ import java.util.Map; /** * @author peter */ -public class JavaClassReference extends GenericReference implements PsiJavaReference, QuickFixProvider, LocalQuickFixProvider { +public class JavaClassReference extends GenericReference implements PsiJavaReference, LocalQuickFixProvider { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference"); protected final int myIndex; private TextRange myRange; @@ -94,7 +93,7 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer } @Override - public void processVariants(final PsiScopeProcessor processor) { + public void processVariants(@NotNull final PsiScopeProcessor processor) { if (processor instanceof JavaCompletionProcessor) { final Map<CustomizableReferenceProvider.CustomizationKey, Object> options = getOptions(); if (options != null && @@ -472,11 +471,6 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer return new JavaResolveResult[]{javaResolveResult}; } - @Override - public void registerQuickfix(HighlightInfo info, PsiReference reference) { - registerFixes(info); - } - @Nullable private List<? extends LocalQuickFix> registerFixes(final HighlightInfo info) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PackagePrefixFileSystemItem.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PackagePrefixFileSystemItemImpl.java index 022f69acc9b7..7b85d17470ed 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PackagePrefixFileSystemItem.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PackagePrefixFileSystemItemImpl.java @@ -36,20 +36,20 @@ import java.util.ArrayList; /** * @author Gregory.Shrago */ -class PackagePrefixFileSystemItem extends PsiElementBase implements PsiFileSystemItem { +class PackagePrefixFileSystemItemImpl extends PsiElementBase implements PsiFileSystemItem, PackagePrefixFileSystemItem { private final PsiDirectory myDirectory; private final int myIndex; private final PsiPackage[] myPackages; - public static PackagePrefixFileSystemItem create(final PsiDirectory directory) { + public static PackagePrefixFileSystemItemImpl create(final PsiDirectory directory) { final ArrayList<PsiPackage> packages = new ArrayList<PsiPackage>(); for (PsiPackage cur = JavaDirectoryService.getInstance().getPackage(directory); cur != null; cur = cur.getParentPackage()) { packages.add(0, cur); } - return new PackagePrefixFileSystemItem(directory, 0, packages.toArray(new PsiPackage[packages.size()])); + return new PackagePrefixFileSystemItemImpl(directory, 0, packages.toArray(new PsiPackage[packages.size()])); } - private PackagePrefixFileSystemItem(final PsiDirectory directory, int index, final PsiPackage[] packages) { + private PackagePrefixFileSystemItemImpl(final PsiDirectory directory, int index, final PsiPackage[] packages) { myDirectory = directory; myIndex = index; myPackages = packages; @@ -78,7 +78,7 @@ class PackagePrefixFileSystemItem extends PsiElementBase implements PsiFileSyste @Override public PsiFileSystemItem getParent() { - return myIndex > 0 ? new PackagePrefixFileSystemItem(myDirectory, myIndex - 1, myPackages) : myDirectory.getParent(); + return myIndex > 0 ? new PackagePrefixFileSystemItemImpl(myDirectory, myIndex - 1, myPackages) : myDirectory.getParent(); } @Override @@ -207,7 +207,7 @@ class PackagePrefixFileSystemItem extends PsiElementBase implements PsiFileSyste return myDirectory.processChildren(processor); } else { - return processor.execute(new PackagePrefixFileSystemItem(myDirectory, myIndex+1, myPackages)); + return processor.execute(new PackagePrefixFileSystemItemImpl(myDirectory, myIndex+1, myPackages)); } } @@ -225,7 +225,7 @@ class PackagePrefixFileSystemItem extends PsiElementBase implements PsiFileSyste @Override @NotNull public PsiElement[] getChildren() { - return myIndex == myPackages.length -1? myDirectory.getChildren() : new PsiElement[] {new PackagePrefixFileSystemItem(myDirectory, myIndex + 1, myPackages)}; + return myIndex == myPackages.length -1? myDirectory.getChildren() : new PsiElement[] {new PackagePrefixFileSystemItemImpl(myDirectory, myIndex + 1, myPackages)}; } @Override @@ -248,4 +248,9 @@ class PackagePrefixFileSystemItem extends PsiElementBase implements PsiFileSyste public Icon getIcon(final int flags) { return myDirectory.getIcon(flags); } + + @Override + public PsiDirectory getDirectory() { + return myDirectory; + } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java index 537b3216df4d..8e287ac310a7 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PsiPackageReference.java @@ -40,7 +40,7 @@ public class PsiPackageReference extends PsiPolyVariantReferenceBase<PsiElement> private Set<PsiPackage> getContext() { if (myIndex == 0) return myReferenceSet.getInitialContext(); Set<PsiPackage> psiPackages = new HashSet<PsiPackage>(); - for (ResolveResult resolveResult : myReferenceSet.getReference(myIndex - 1).multiResolve(false)) { + for (ResolveResult resolveResult : myReferenceSet.getReference(myIndex - 1).doMultiResolve()) { PsiElement psiElement = resolveResult.getElement(); if (psiElement instanceof PsiPackage) { psiPackages.add((PsiPackage)psiElement); @@ -69,6 +69,11 @@ public class PsiPackageReference extends PsiPolyVariantReferenceBase<PsiElement> @Override @NotNull public ResolveResult[] multiResolve(final boolean incompleteCode) { + return doMultiResolve(); + } + + @NotNull + protected ResolveResult[] doMultiResolve() { final Collection<PsiPackage> packages = new HashSet<PsiPackage>(); for (PsiPackage parentPackage : getContext()) { packages.addAll(myReferenceSet.resolvePackageName(parentPackage, getValue())); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java index 5b4dd7af48b7..7d70ee9f2cb3 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java @@ -72,7 +72,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { return myModificationCounter; } - private static Pair<PsiElement,PsiElement[]> computeAnchorAndOperandsImpl(PsiElement context) { + private static Pair<PsiElement,PsiElement[]> computeAnchorAndOperandsImpl(@NotNull PsiElement context) { PsiElement element = context; PsiElement parent = context.getParent(); while (parent instanceof PsiPolyadicExpression && ((PsiPolyadicExpression)parent).getOperationTokenType() == JavaTokenType.PLUS @@ -102,8 +102,12 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { return Pair.create(anchor, operands); } - private static MultiHostRegistrarImpl doCompute(PsiElement context, Project project, PsiElement anchor, PsiElement[] operands) { - MultiHostRegistrarImpl registrar = new MultiHostRegistrarImpl(project, context.getContainingFile(), anchor); + + private static MultiHostRegistrarImpl doCompute(@NotNull PsiFile containingFile, + @NotNull Project project, + @NotNull PsiElement anchor, + @NotNull PsiElement[] operands) { + MultiHostRegistrarImpl registrar = new MultiHostRegistrarImpl(project, containingFile, anchor); JavaConcatenationInjectorManager concatenationInjectorManager = getInstance(project); for (ConcatenationAwareInjector concatenationInjector : concatenationInjectorManager.myConcatenationInjectors) { concatenationInjector.getLanguagesToInject(registrar, operands); @@ -119,7 +123,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { private static final Key<ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>> INJECTED_PSI_IN_CONCATENATION = Key.create("INJECTED_PSI_IN_CONCATENATION"); private static final Key<Integer> NO_CONCAT_INJECTION_TIMESTAMP = Key.create("NO_CONCAT_INJECTION_TIMESTAMP"); - public static abstract class BaseConcatenation2InjectorAdapter implements MultiHostInjector { + public abstract static class BaseConcatenation2InjectorAdapter implements MultiHostInjector { private final JavaConcatenationInjectorManager myManager; public BaseConcatenation2InjectorAdapter(Project project) { @@ -130,7 +134,8 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) { if (myManager.myConcatenationInjectors.isEmpty()) return; - Project project = context.getProject(); + final PsiFile containingFile = ((MultiHostRegistrarImpl)registrar).getHostPsiFile(); + Project project = containingFile.getProject(); long modificationCount = PsiManager.getInstance(project).getModificationTracker().getModificationCount(); Pair<PsiElement, PsiElement[]> pair = computeAnchorAndOperands(context); PsiElement anchor = pair.first; @@ -146,7 +151,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { data = anchor.getUserData(INJECTED_PSI_IN_CONCATENATION); if (data == null) { - result = doCompute(context, project, anchor, operands); + result = doCompute(containingFile, project, anchor, operands); } else { result = data.getValue(context); @@ -164,10 +169,11 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { new ParameterizedCachedValueProvider<MultiHostRegistrarImpl, PsiElement>() { @Override public CachedValueProvider.Result<MultiHostRegistrarImpl> compute(PsiElement context) { - Project project = context.getProject(); + PsiFile containingFile1 = context.getContainingFile(); + Project project1 = containingFile1.getProject(); Pair<PsiElement, PsiElement[]> pair = computeAnchorAndOperands(context); - MultiHostRegistrarImpl registrar = doCompute(context, project, pair.first, pair.second); - return registrar == null ? null : CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, getInstance(project)); + MultiHostRegistrarImpl registrar = doCompute(containingFile1, project1, pair.first, pair.second); + return registrar == null ? null : CachedValueProvider.Result.create(registrar, PsiModificationTracker.MODIFICATION_COUNT, getInstance(project1)); } }, false); ((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>)data).setValue(cachedResult); @@ -187,7 +193,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { } } - protected abstract Pair<PsiElement, PsiElement[]> computeAnchorAndOperands(PsiElement context); + protected abstract Pair<PsiElement, PsiElement[]> computeAnchorAndOperands(@NotNull PsiElement context); } public static class Concatenation2InjectorAdapter extends BaseConcatenation2InjectorAdapter implements MultiHostInjector { @@ -197,7 +203,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { } @Override - public Pair<PsiElement, PsiElement[]> computeAnchorAndOperands(PsiElement context) { + public Pair<PsiElement, PsiElement[]> computeAnchorAndOperands(@NotNull PsiElement context) { return computeAnchorAndOperandsImpl(context); } diff --git a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java index 3db0c30e8fb4..2a17536550d1 100644 --- a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java +++ b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java @@ -21,8 +21,8 @@ import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.scope.PsiConflictResolver; import com.intellij.psi.scope.PsiScopeProcessor; -import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver; +import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; import com.intellij.psi.scope.processor.MethodCandidatesProcessor; import com.intellij.psi.scope.processor.MethodResolverProcessor; import com.intellij.psi.util.MethodSignature; @@ -33,7 +33,9 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Set; /** @@ -45,11 +47,12 @@ public class JavaMethodResolveHelper { private final MethodCandidatesProcessor myProcessor; @Nullable private final PsiType[] myArgumentTypes; - public JavaMethodResolveHelper(final PsiElement argumentList, @Nullable final PsiType[] argumentTypes) { + public JavaMethodResolveHelper(@NotNull final PsiElement argumentList, PsiFile containingFile, @Nullable final PsiType[] argumentTypes) { myArgumentTypes = argumentTypes; final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(argumentList); - final PsiConflictResolver resolver = argumentTypes == null ? DuplicateConflictResolver.INSTANCE : new JavaMethodsConflictResolver(argumentList, argumentTypes); - myProcessor = new MethodResolverProcessor(argumentList, new PsiConflictResolver[]{resolver}) { + final PsiConflictResolver resolver = argumentTypes == null ? DuplicateConflictResolver.INSTANCE : new JavaMethodsConflictResolver(argumentList, argumentTypes, + languageLevel); + myProcessor = new MethodResolverProcessor(argumentList, containingFile, new PsiConflictResolver[]{resolver}) { @Override protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor, final boolean staticProblem, @@ -72,7 +75,8 @@ public class JavaMethodResolveHelper { PsiElement currentFileContext, boolean accessProblem, PsiElement argumentList, - PsiType[] argumentTypes, LanguageLevel languageLevel) { + PsiType[] argumentTypes, + @NotNull LanguageLevel languageLevel) { return new MethodCandidateInfo(method, substitutor, accessProblem, staticProblem, argumentList, currentFileContext, argumentTypes, PsiType.EMPTY_ARRAY, languageLevel); } @@ -85,12 +89,16 @@ public class JavaMethodResolveHelper { @NotNull public ErrorType getResolveError() { - final CandidateInfo[] candidates = myProcessor.getCandidates(); - if (candidates.length != 1) return ErrorType.RESOLVE; + final List<CandidateInfo> candidates = getCandidates(); + if (candidates.size() != 1) return ErrorType.RESOLVE; - if (!candidates[0].isStaticsScopeCorrect()) return ErrorType.STATIC; + if (!candidates.get(0).isStaticsScopeCorrect()) return ErrorType.STATIC; + + return getResolveError((MethodCandidateInfo)candidates.get(0)); + } - return getResolveError((MethodCandidateInfo)candidates[0]); + protected List<CandidateInfo> getCandidates() { + return Arrays.asList(myProcessor.getCandidates()); } protected ErrorType getResolveError(MethodCandidateInfo info) { @@ -125,7 +133,7 @@ public class JavaMethodResolveHelper { } public Collection<JavaMethodCandidateInfo> getMethods() { - return ContainerUtil.mapNotNull(myProcessor.getResult(), new Function<JavaResolveResult, JavaMethodCandidateInfo>() { + return ContainerUtil.mapNotNull(getCandidates(), new Function<JavaResolveResult, JavaMethodCandidateInfo>() { @Override public JavaMethodCandidateInfo fun(final JavaResolveResult javaResolveResult) { return new JavaMethodCandidateInfo((PsiMethod)javaResolveResult.getElement(), javaResolveResult.getSubstitutor()); diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java index b5d0e0966205..8b721b62a009 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java @@ -258,10 +258,11 @@ class JavaChangeInfoImpl implements JavaChangeInfo { } protected void setupPropagationEnabled(final PsiParameter[] parameters, final ParameterInfoImpl[] newParms) { - if (parameters.length != newParms.length) { + if (parameters.length >= newParms.length) { isPropagationEnabled = false; } else { + isPropagationEnabled = !propagateParametersMethods.isEmpty(); for (int i = 0; i < parameters.length; i++) { final ParameterInfoImpl newParm = newParms[i]; if (newParm.oldParameterIndex != i) { diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java index d46fa203f7e0..bfbe8b2413e0 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -192,7 +192,7 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet myPropExceptionsButton.setShortcut(CustomShortcutSet.fromString("alt X")); final JPanel panel = ToolbarDecorator.createDecorator(table).addExtraAction(myPropExceptionsButton).createPanel(); - panel.setBorder(IdeBorderFactory.createEmptyBorder(0)); + panel.setBorder(IdeBorderFactory.createEmptyBorder()); myExceptionsModel.addTableModelListener(mySignatureUpdater); diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index cc4d0cd7443d..e8bb45ce350d 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -380,7 +380,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr else { newArg = factory.createExpressionFromText(info.getName(), list); } - JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg)); + if (newArg != null) JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg)); } } else { diff --git a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java index 9943d48fc8d6..e8d41e0efa8c 100644 --- a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.encapsulateFields; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.icons.AllIcons; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.help.HelpManager; @@ -509,8 +510,8 @@ public String getAccessorsVisibility() { private PsiMethod generateMethodPrototype(PsiField field, String methodName, boolean isGetter) { PsiMethod prototype = isGetter - ? PropertyUtil.generateGetterPrototype(field) - : PropertyUtil.generateSetterPrototype(field); + ? GenerateMembersUtil.generateGetterPrototype(field) + : GenerateMembersUtil.generateSetterPrototype(field); try { PsiElementFactory factory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); PsiIdentifier identifier = factory.createIdentifier(methodName); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index 284433f7c4f0..90131299c98d 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -21,6 +21,7 @@ package com.intellij.refactoring.extractMethodObject; import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -255,7 +256,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { field = PropertyUtil.findPropertyField(myProject, myInnerClass, name, false); } LOG.assertTrue(field != null, "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList().getParameters()) + "; output field: " + outputField ); - myInnerClass.add(PropertyUtil.generateGetterPrototype(field)); + myInnerClass.add(GenerateMembersUtil.generateGetterPrototype(field)); } PsiParameter[] params = getMethod().getParameterList().getParameters(); diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java index d096db58b1cf..3969ae580919 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.extractclass; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.ide.util.PackageUtil; import com.intellij.openapi.application.ApplicationManager; @@ -311,11 +312,11 @@ public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor { if (myGenerateAccessors) { final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4SourceClass(); for (PsiField field : visitor.getFieldsNeedingGetter()) { - sourceClass.add(PropertyUtil.generateGetterPrototype(field)); + sourceClass.add(GenerateMembersUtil.generateGetterPrototype(field)); } for (PsiField field : visitor.getFieldsNeedingSetter()) { - sourceClass.add(PropertyUtil.generateSetterPrototype(field)); + sourceClass.add(GenerateMembersUtil.generateSetterPrototype(field)); } } super.performRefactoring(usageInfos); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java index 0ef27c9b930d..a94f41155c54 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java @@ -15,11 +15,11 @@ */ package com.intellij.refactoring.introduceParameter; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.IntroduceParameterRefactoring; import com.intellij.refactoring.util.RefactoringUtil; @@ -217,7 +217,7 @@ public class OldReferenceResolver { } PsiElement newExpr = expr; - PsiMethod getterPrototype = PropertyUtil.generateGetterPrototype(psiField); + PsiMethod getterPrototype = GenerateMembersUtil.generateGetterPrototype(psiField); PsiMethod getter = psiField.getContainingClass().findMethodBySignature(getterPrototype, true); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java index 59ec81a7ec48..e862915d8db8 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/AppendAccessorsUsageInfo.java @@ -20,12 +20,12 @@ */ package com.intellij.refactoring.introduceparameterobject.usageInfo; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiParameter; -import com.intellij.psi.util.PropertyUtil; import com.intellij.refactoring.RefactorJBundle; import com.intellij.refactoring.introduceparameterobject.IntroduceParameterObjectProcessor; import com.intellij.refactoring.util.FixableUsageInfo; @@ -70,8 +70,8 @@ public class AppendAccessorsUsageInfo extends FixableUsageInfo{ final PsiField field = parameterChunk.getField(); if (field != null) { element.add(isGetter - ? PropertyUtil.generateGetterPrototype(field) - : PropertyUtil.generateSetterPrototype(field)); + ? GenerateMembersUtil.generateGetterPrototype(field) + : GenerateMembersUtil.generateSetterPrototype(field)); } } diff --git a/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java b/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java index ab14d4f8f2c9..091e6f7fc0d3 100644 --- a/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/removemiddleman/RemoveMiddlemanProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.removemiddleman; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; @@ -99,7 +100,7 @@ public class RemoveMiddlemanProcessor extends FixableUsagesRefactoringProcessor } else { access = getterName + "()"; if (getter == null) { - getter = PropertyUtil.generateGetterPrototype(field); + getter = GenerateMembersUtil.generateGetterPrototype(field); } } usages.add(new InlineDelegatingCall(call, paramPermutation, access, delegatedMethod.getName())); diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticTestRenamerFactory.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticTestRenamerFactory.java index 6c296231d6dc..5045c2b99ac4 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticTestRenamerFactory.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticTestRenamerFactory.java @@ -15,16 +15,20 @@ */ package com.intellij.refactoring.rename.naming; -import com.intellij.openapi.project.Project; -import com.intellij.psi.JavaPsiFacade; +import com.intellij.codeInsight.TestFrameworks; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.usageView.UsageInfo; +import com.intellij.util.containers.HashSet; import java.util.Collection; +import java.util.regex.Pattern; /** * @author yole @@ -59,18 +63,33 @@ public class AutomaticTestRenamerFactory implements AutomaticRenamerFactory { private static class TestsRenamer extends AutomaticRenamer { public TestsRenamer(PsiClass aClass, String newClassName) { - appendTestClass(aClass, "Test"); - appendTestClass(aClass, "TestCase"); + final Module module = ModuleUtilCore.findModuleForPsiElement(aClass); + if (module != null) { + final GlobalSearchScope moduleScope = GlobalSearchScope.moduleWithDependentsScope(module); - suggestAllNames(aClass.getName(), newClassName); + appendTestClass(aClass, "Test", moduleScope); + appendTestClass(aClass, "TestCase", moduleScope); + + suggestAllNames(aClass.getName(), newClassName); + } } - private void appendTestClass(PsiClass aClass, String testSuffix) { - final Project project = aClass.getProject(); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); - final PsiClass psiClassTest = facade.findClass(aClass.getQualifiedName() + testSuffix, GlobalSearchScope.projectScope(project)); - if (psiClassTest != null) { - myElements.add(psiClassTest); + private void appendTestClass(PsiClass aClass, String testSuffix, final GlobalSearchScope moduleScope) { + PsiShortNamesCache cache = PsiShortNamesCache.getInstance(aClass.getProject()); + + String klassName = aClass.getName(); + Pattern pattern = Pattern.compile(".*" + klassName + ".*" + testSuffix); + + HashSet<String> names = new HashSet<String>(); + cache.getAllClassNames(names); + for (String eachName : names) { + if (pattern.matcher(eachName).matches()) { + for (PsiClass eachClass : cache.getClassesByName(eachName, moduleScope)) { + if (TestFrameworks.getInstance().isTestClass(eachClass)) { + myElements.add(eachClass); + } + } + } } } diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index ac7a6d9ece69..46b604e8d0a7 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -457,13 +457,6 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { removeDeletedMethods(OverridingMethodsSearch.search(psiMethod, true).toArray(PsiMethod.EMPTY_ARRAY), allElementsToDelete); - for (PsiReference reference : references) { - final PsiElement element = reference.getElement(); - if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) { - usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiMethod, PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null)); - } - } - final HashMap<PsiMethod, Collection<PsiReference>> methodToReferences = new HashMap<PsiMethod, Collection<PsiReference>>(); for (PsiMethod overridingMethod : overridingMethods) { final Collection<PsiReference> overridingReferences = ReferencesSearch.search(overridingMethod).findAll(); @@ -472,6 +465,12 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { final Set<PsiMethod> validOverriding = validateOverridingMethods(psiMethod, references, Arrays.asList(overridingMethods), methodToReferences, usages, allElementsToDelete); + for (PsiReference reference : references) { + final PsiElement element = reference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { + usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiMethod, PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class) != null)); + } + } return new Condition<PsiElement>() { public boolean value(PsiElement usage) { if(usage instanceof PsiFile) return false; @@ -594,12 +593,12 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { } for (PsiMethod method : overridingMethods) { - if (!validOverriding.contains(method) && !multipleInterfaceImplementations.contains(method)) { - final boolean methodCanBePrivate = - canBePrivate(method, methodToReferences.get(method), validOverriding, allElementsToDelete); - if (methodCanBePrivate) { - usages.add(new SafeDeletePrivatizeMethod(method, originalMethod)); - } + if (!validOverriding.contains(method) && + !multipleInterfaceImplementations.contains(method) && + canBePrivate(method, methodToReferences.get(method), validOverriding, allElementsToDelete)) { + usages.add(new SafeDeletePrivatizeMethod(method, originalMethod)); + } else { + usages.add(new SafeDeleteOverrideAnnotation(method, originalMethod)); } } return validOverriding; diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeleteOverrideAnnotation.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeleteOverrideAnnotation.java new file mode 100644 index 000000000000..9a3159564ae6 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeleteOverrideAnnotation.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2013 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.refactoring.safeDelete.usageInfo; + +import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.psi.PsiAnnotation; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.util.IncorrectOperationException; + +/** + * User: anna + * Date: 7/22/13 + */ +public class SafeDeleteOverrideAnnotation extends SafeDeleteUsageInfo implements SafeDeleteCustomUsageInfo { + public SafeDeleteOverrideAnnotation(PsiElement element, PsiElement referencedElement) { + super(element, referencedElement); + } + + public PsiMethod getMethod() { + return (PsiMethod)getElement(); + } + + public void performRefactoring() throws IncorrectOperationException { + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(getMethod(), true, Override.class.getName()); + if (annotation != null) { + annotation.delete(); + } + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeletePrivatizeMethod.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeletePrivatizeMethod.java index 0e0e70fc8837..70a6b44ce033 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeletePrivatizeMethod.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/usageInfo/SafeDeletePrivatizeMethod.java @@ -15,8 +15,6 @@ */ package com.intellij.refactoring.safeDelete.usageInfo; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.psi.PsiAnnotation; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.util.PsiUtil; @@ -25,20 +23,13 @@ import com.intellij.util.IncorrectOperationException; /** * @author dsl */ -public class SafeDeletePrivatizeMethod extends SafeDeleteUsageInfo implements SafeDeleteCustomUsageInfo { +public class SafeDeletePrivatizeMethod extends SafeDeleteOverrideAnnotation { public SafeDeletePrivatizeMethod(PsiMethod method, PsiMethod overridenMethod) { super(method, overridenMethod); } - public PsiMethod getMethod() { - return (PsiMethod) getElement(); - } - public void performRefactoring() throws IncorrectOperationException { PsiUtil.setModifierProperty(getMethod(), PsiModifier.PRIVATE, true); - final PsiAnnotation annotation = AnnotationUtil.findAnnotation(getMethod(), true, Override.class.getName()); - if (annotation != null) { - annotation.delete(); - } + super.performRefactoring(); } } diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index ca905b0f252d..abf333ce4f1e 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -1137,7 +1137,7 @@ public class RefactoringUtil { paramTag.delete(); } for (PsiDocTag psiDocTag : newTags) { - anchor = docComment.addAfter(psiDocTag, anchor); + anchor = anchor != null && anchor.isValid() ? docComment.addAfter(psiDocTag, anchor) : docComment.add(psiDocTag); } } diff --git a/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java b/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java new file mode 100644 index 000000000000..94fa4f24575b --- /dev/null +++ b/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2013 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.unscramble; + +import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.project.Project; + +import javax.swing.*; +import java.util.List; + +/** +* Created by Irina.Chernushina on 7/13/13. +*/ +public class ThreadDumpConsoleFactory implements AnalyzeStacktraceUtil.ConsoleFactory { + private final Project myProject; + private final List<ThreadState> myThreadDump; + + public ThreadDumpConsoleFactory(Project project, List<ThreadState> threadDump) { + myProject = project; + myThreadDump = threadDump; + } + + public JComponent createConsoleComponent(ConsoleView consoleView, DefaultActionGroup toolbarActions) { + return new ThreadDumpPanel(myProject, consoleView, toolbarActions, myThreadDump); + } +} diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java index 2627fd298b4e..37311251a2c0 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java @@ -15,12 +15,10 @@ */ package com.intellij.unscramble; -import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -410,11 +408,7 @@ public class UnscrambleDialog extends DialogWrapper { message = IdeBundle.message("unscramble.unscrambled.deadlock.tab"); icon = AllIcons.Debugger.KillProcess; } - return AnalyzeStacktraceUtil.addConsole(project, threadDump.size() > 1 ? new AnalyzeStacktraceUtil.ConsoleFactory() { - public JComponent createConsoleComponent(ConsoleView consoleView, DefaultActionGroup toolbarActions) { - return new ThreadDumpPanel(project, consoleView, toolbarActions, threadDump); - } - } : null, message, unscrambledTrace, icon); + return AnalyzeStacktraceUtil.addConsole(project, threadDump.size() > 1 ? new ThreadDumpConsoleFactory(project, threadDump) : null, message, unscrambledTrace, icon); } protected String getDimensionServiceKey(){ diff --git a/java/java-impl/src/com/intellij/usages/impl/rules/ClassGroupingRule.java b/java/java-impl/src/com/intellij/usages/impl/rules/ClassGroupingRule.java index 3878aaaca0a3..8cd847129573 100644 --- a/java/java-impl/src/com/intellij/usages/impl/rules/ClassGroupingRule.java +++ b/java/java-impl/src/com/intellij/usages/impl/rules/ClassGroupingRule.java @@ -48,6 +48,8 @@ public class ClassGroupingRule implements UsageGroupingRule { } final PsiElement psiElement = ((PsiElementUsage)usage).getElement(); final PsiFile containingFile = psiElement.getContainingFile(); + if (containingFile == null) return null; + PsiFile topLevelFile = InjectedLanguageManager.getInstance(containingFile.getProject()).getTopLevelFile(containingFile); if (!(topLevelFile instanceof PsiJavaFile) || topLevelFile instanceof JspFile) { diff --git a/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java b/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java index 152e51aad40b..88ccc0a629ef 100644 --- a/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java +++ b/java/java-impl/src/com/intellij/util/xml/CanonicalPsiTypeConverterImpl.java @@ -91,7 +91,7 @@ public class CanonicalPsiTypeConverterImpl extends CanonicalPsiTypeConverter imp return super.advancedResolve(incompleteCode); } - public void processVariants(final PsiScopeProcessor processor) { + public void processVariants(@NotNull final PsiScopeProcessor processor) { if (processor instanceof JavaCompletionProcessor) { ((JavaCompletionProcessor)processor).setCompletionElements(getVariants()); } else { |