From b0d7d7a624a46bf8c7a55ce91ab5eadb6c4c0f31 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 19:02:35 +0100 Subject: [PATCH 01/13] insert paired brace before the closing brace or punctuation in the custom file type --- .../psi/CustomHighlighterTokenType.java | 1 + .../custom/CustomFileTypeLexer.java | 1 + .../impl/CustomFileTypeBraceMatcher.java | 8 +++- .../custom/tokens/PunctuationParser.java | 39 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java diff --git a/platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java b/platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java index 505b52cbeaa2..41ae1093e409 100644 --- a/platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java +++ b/platform/lang-api/src/com/intellij/psi/CustomHighlighterTokenType.java @@ -45,6 +45,7 @@ public interface CustomHighlighterTokenType { IElementType MULTI_LINE_COMMENT = new CustomElementType("MULTI_LINE_COMMENT"); IElementType WHITESPACE = new CustomElementType("WHITESPACE"); IElementType CHARACTER = new CustomElementType("CHARACTER"); + IElementType PUNCTUATION = new CustomElementType("PUNCTUATION"); IElementType L_BRACE = new CustomElementType("L_BRACE"); IElementType R_BRACE = new CustomElementType("R_BRACE"); diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java index c31f41735c91..6506934c0c73 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java @@ -65,6 +65,7 @@ public final class CustomFileTypeLexer extends AbstractCustomLexer { tokenParsers.add(multilineCommentParser); } tokenParsers.add(numberParser); + tokenParsers.add(new PunctuationParser()); if (hexNumberParser != null) { tokenParsers.add(hexNumberParser); } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeBraceMatcher.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeBraceMatcher.java index 1c099650b269..684ab7972e54 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeBraceMatcher.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeBraceMatcher.java @@ -42,8 +42,10 @@ class CustomFileTypeBraceMatcher implements BraceMatcher { } public boolean isRBraceToken(HighlighterIterator iterator, CharSequence fileText, FileType fileType) { - final IElementType tokenType = iterator.getTokenType(); + return isRBraceToken(iterator.getTokenType()); + } + private static boolean isRBraceToken(IElementType tokenType) { return tokenType == CustomHighlighterTokenType.R_BRACKET || tokenType == CustomHighlighterTokenType.R_PARENTH || tokenType == CustomHighlighterTokenType.R_BRACE; @@ -80,7 +82,9 @@ class CustomFileTypeBraceMatcher implements BraceMatcher { } public boolean isPairedBracesAllowedBeforeType(@NotNull final IElementType lbraceType, @Nullable final IElementType contextType) { - return contextType == CustomHighlighterTokenType.WHITESPACE; + return contextType == CustomHighlighterTokenType.PUNCTUATION || + contextType == CustomHighlighterTokenType.WHITESPACE || + isRBraceToken(contextType); } public int getCodeConstructStart(final PsiFile file, final int openingBraceOffset) { diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java new file mode 100644 index 000000000000..e097e4df887b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java @@ -0,0 +1,39 @@ +/* + * 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.ide.highlighter.custom.tokens; + +import com.intellij.psi.CustomHighlighterTokenType; + +/** + * @author peter + */ +public class PunctuationParser extends BaseTokenParser { + @Override + public boolean hasToken(int position) { + final char c = myBuffer.charAt(position); + if (".,:;".indexOf(c) >= 0) { + myTokenInfo.updateData(position, position+1, CustomHighlighterTokenType.PUNCTUATION); + return true; + } + return false; + } + + @Override + public int getSmartUpdateShift() { + return 0; + } +} From 4710c4d8e55a33d2fed2a05d60cd876c2a58e7f5 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 20:29:44 +0100 Subject: [PATCH 02/13] move the groovy constructor-resolving method to a more appropriate place --- .../gpp/GppClosureParameterTypeProvider.java | 3 ++- .../gpp/GppExpectedTypesContributor.java | 3 ++- .../plugins/groovy/gpp/GppTypeConverter.java | 18 +----------------- .../plugins/groovy/lang/psi/util/PsiUtil.java | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java index 452a310bdead..47e863de80d6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java @@ -19,6 +19,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.*; @@ -49,7 +50,7 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh if (listType instanceof GrTupleType) { for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(list)) { if (type instanceof PsiClassType) { - for (GroovyResolveResult resolveResult : GppTypeConverter + for (GroovyResolveResult resolveResult : PsiUtil .getConstructorCandidates((PsiClassType)type, ((GrTupleType)listType).getComponentTypes(), closure)) { final PsiElement method = resolveResult.getElement(); if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java index 6266d2b15af1..5937224292b1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java @@ -10,6 +10,7 @@ import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesPr import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint; import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.ArrayList; import java.util.Arrays; @@ -48,7 +49,7 @@ public class GppExpectedTypesContributor extends GroovyExpectedTypesContributor final ArrayList result = new ArrayList(); for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(expression)) { if (type instanceof PsiClassType) { - for (GroovyResolveResult resolveResult : GppTypeConverter.getConstructorCandidates((PsiClassType)type, argTypes, expression)) { + for (GroovyResolveResult resolveResult : PsiUtil.getConstructorCandidates((PsiClassType)type, argTypes, expression)) { final PsiElement method = resolveResult.getElement(); if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) { final PsiParameter[] constructorParameters = ((PsiMethod)method).getParameterList().getParameters(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index a41d82ebd46e..3a4ea0680f77 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -7,12 +7,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.dsl.toplevel.AnnotatedContextFilter; import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; @@ -93,21 +91,7 @@ public class GppTypeConverter extends GrTypeConverter { } private static boolean hasConstructor(PsiClassType lType, PsiType[] argTypes, GroovyPsiElement context) { - return getConstructorCandidates(lType, argTypes, context).length == 1; - } - - public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) { - final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); - final PsiClass psiClass = resolveResult.getElement(); - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - if (psiClass == null) { - return GroovyResolveResult.EMPTY_ARRAY; - } - - final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult - ? (GroovyResolveResult)resolveResult - : new GroovyResolveResultImpl(psiClass, context, substitutor, true, true); - return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes); + return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(lType, argTypes, context).length == 1; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index d1981723e78c..628b7350ce25 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -66,6 +66,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier; @@ -939,4 +940,18 @@ public class PsiUtil { } return (GrReferenceExpression)replaced; } + + public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) { + final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); + final PsiClass psiClass = resolveResult.getElement(); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + if (psiClass == null) { + return GroovyResolveResult.EMPTY_ARRAY; + } + + final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult + ? (GroovyResolveResult)resolveResult + : new GroovyResolveResultImpl(psiClass, context, substitutor, true, true); + return getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes); + } } From 2b4f33a1b8786c87defe36634d9fdbfd488cf971 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 20:29:53 +0100 Subject: [PATCH 03/13] then- and else branches of groovy if may return a value from function: support this in control flow (IDEA-56628) --- .../GroovyAssignabilityCheckInspection.java | 9 ++++--- .../MissingReturnInspection.java | 7 +++-- .../utils/ControlFlowUtils.java | 13 ++++++--- .../controlFlow/impl/ControlFlowBuilder.java | 17 +++++++----- .../testdata/groovy/controlFlow/if1.test | 5 ++-- .../groovy/controlFlow/ifInstanceofElse.test | 27 ++++++++++--------- 6 files changed, 48 insertions(+), 30 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 44b23e2aae38..f2be2a783d20 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -21,6 +21,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; @@ -94,10 +95,10 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (expectedType == null || PsiType.VOID.equals(expectedType)) return; ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() { - public boolean visit(Instruction instruction) { - final PsiElement psiElement = instruction.getElement(); - if (psiElement instanceof GrExpression) { - checkAssignability(expectedType, (GrExpression)psiElement, (GrExpression)psiElement); + @Override + public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { + if (returnValue != null && !(returnValue.getParent() instanceof GrReturnStatement)) { + checkAssignability(expectedType, returnValue, returnValue); } return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java index 684dbfe780ac..a39ba6cc3fee 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java @@ -24,6 +24,7 @@ import com.intellij.psi.PsiType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; @@ -35,6 +36,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.MaybeReturnInstruction; @@ -86,7 +88,8 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool { final Ref hasExplicitReturn = new Ref(false); final Ref sometimes = new Ref(false); ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() { - public boolean visit(Instruction instruction) { + @Override + public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { if (instruction instanceof MaybeReturnInstruction) { if (((MaybeReturnInstruction)instruction).mayReturnValue()) { sometimes.set(true); @@ -99,7 +102,7 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool { final PsiElement element = instruction.getElement(); if (element instanceof GrReturnStatement) { sometimes.set(true); - if (((GrReturnStatement)element).getReturnValue() != null) { + if (returnValue != null) { hasExplicitReturn.set(true); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java index 86aa6c0503e4..995b0302494d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java @@ -543,7 +543,7 @@ public class ControlFlowUtils { public interface ExitPointVisitor { - boolean visit(Instruction instruction); + boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue); } public static void visitAllExitPoints(@Nullable GrCodeBlock block, ExitPointVisitor visitor) { @@ -556,12 +556,16 @@ public class ControlFlowUtils { private static boolean visitAllExitPointsInner(Instruction last, Instruction first, boolean[] visited, ExitPointVisitor visitor) { if (first == last) return true; if (last instanceof MaybeReturnInstruction) { - return visitor.visit(last); + return visitor.visitExitPoint(last, (GrExpression)last.getElement()); } - final PsiElement element = last.getElement(); + PsiElement element = last.getElement(); if (element != null) { - return visitor.visit(last); + if (element instanceof GrReturnStatement) { + element = ((GrReturnStatement)element).getReturnValue(); + } + + return visitor.visitExitPoint(last, element instanceof GrExpression ? (GrExpression)element : null); } visited[last.num()] = true; for (Instruction pred : last.allPred()) { @@ -571,4 +575,5 @@ public class ControlFlowUtils { } return true; } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index ea85bc7a40b1..174ac80aa94e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -107,16 +107,19 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { if (!(block.getParent() instanceof GrBlockStatement && block.getParent().getParent() instanceof GrLoopStatement)) { final GrStatement[] statements = block.getStatements(); if (statements.length > 0) { - final GrStatement last = statements[statements.length - 1]; - if (last instanceof GrExpression) { - final MaybeReturnInstruction instruction = new MaybeReturnInstruction((GrExpression)last, myInstructionNumber++); - checkPending(instruction); - addNode(instruction); - } + handlePossibleReturn(statements[statements.length - 1]); } } } + private void handlePossibleReturn(GrStatement last) { + if (last instanceof GrExpression) { + final MaybeReturnInstruction instruction = new MaybeReturnInstruction((GrExpression)last, myInstructionNumber++); + checkPending(instruction); + addNode(instruction); + } + } + public Instruction[] buildControlFlow(GroovyPsiElement scope, GroovyPsiElement startInScope, GroovyPsiElement endInScope) { myInstructions = new ArrayList(); myProcessingStack = new Stack(); @@ -386,6 +389,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { condition.accept(this); } thenBranch.accept(this); + handlePossibleReturn(thenBranch); addPendingEdge(ifStatement, myHead); } @@ -402,6 +406,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { final GrStatement elseBranch = ifStatement.getElseBranch(); if (elseBranch != null) { elseBranch.accept(this); + handlePossibleReturn(elseBranch); addPendingEdge(ifStatement, myHead); } diff --git a/plugins/groovy/testdata/groovy/controlFlow/if1.test b/plugins/groovy/testdata/groovy/controlFlow/if1.test index a88e8969eb44..f4dc6626de6c 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/if1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/if1.test @@ -7,6 +7,7 @@ if (true) { 0(1) element: null 1(2,4) element: IF statement 2(3) WRITE a -3(5) element: Assignment expression MAYBE_RETURN +3(6) element: Assignment expression MAYBE_RETURN 4(5) WRITE a -5() element: null \ No newline at end of file +5(6) element: Assignment expression MAYBE_RETURN +6() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test b/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test index 7851696d58a6..e1f89d70302f 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test +++ b/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test @@ -3,17 +3,20 @@ else if (!(o instanceof Integer)) b = 2 else b = 3 ----- 0(1) element: null -1(2,5) element: IF statement +1(2,6) element: IF statement 2(3) READ o 3(4) assertion: o instanceof String -4(14) WRITE b -5(6) READ o -6(7) assertion: ! o instanceof String -7(8,11) element: IF statement -8(9) READ o -9(10) assertion: ! o instanceof Integer -10(14) WRITE b -11(12) READ o -12(13) assertion: o instanceof Integer -13(14) WRITE b -14() element: null \ No newline at end of file +4(5) WRITE b +5(17) element: Assignment expression MAYBE_RETURN +6(7) READ o +7(8) assertion: ! o instanceof String +8(9,13) element: IF statement +9(10) READ o +10(11) assertion: ! o instanceof Integer +11(12) WRITE b +12(17) element: Assignment expression MAYBE_RETURN +13(14) READ o +14(15) assertion: o instanceof Integer +15(16) WRITE b +16(17) element: Assignment expression MAYBE_RETURN +17() element: null \ No newline at end of file From 97e94473315954c3f84fc9434466c8ba7f3acc40 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 20:30:17 +0100 Subject: [PATCH 04/13] PsiReferenceBase.createSelfReference(PsiElement, PsiElement, TextRange) --- .../com/intellij/psi/PsiReferenceBase.java | 59 ++++++++++++++----- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/platform/lang-api/src/com/intellij/psi/PsiReferenceBase.java b/platform/lang-api/src/com/intellij/psi/PsiReferenceBase.java index 4e527134996f..a2840604b3c3 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiReferenceBase.java +++ b/platform/lang-api/src/com/intellij/psi/PsiReferenceBase.java @@ -107,23 +107,11 @@ public abstract class PsiReferenceBase implements PsiRefer } public static PsiReferenceBase createSelfReference(T element, final PsiElement resolveTo) { + return new Immediate(element, true, resolveTo); + } - return new PsiReferenceBase(element,true) { - //do nothing. the element will be renamed via PsiMetaData (com.intellij.refactoring.rename.RenameUtil.doRenameGenericNamedElement()) - public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException { - return getElement(); - } - - @Nullable - public PsiElement resolve() { - return resolveTo; - } - - @NotNull - public Object[] getVariants() { - return EMPTY_ARRAY; - } - }; + public static PsiReferenceBase createSelfReference(T element, TextRange range, final PsiElement resolveTo) { + return new Immediate(element, range, resolveTo); } @Nullable @@ -165,4 +153,43 @@ public abstract class PsiReferenceBase implements PsiRefer return resolveResults.length == 1 ? resolveResults[0].getElement() : null; } } + + public static class Immediate extends PsiReferenceBase { + private final PsiElement myResolveTo; + + public Immediate(T element, TextRange range, boolean soft, PsiElement resolveTo) { + super(element, range, soft); + myResolveTo = resolveTo; + } + + public Immediate(T element, TextRange range, PsiElement resolveTo) { + super(element, range); + myResolveTo = resolveTo; + } + + public Immediate(T element, boolean soft, PsiElement resolveTo) { + super(element, soft); + myResolveTo = resolveTo; + } + + public Immediate(@NotNull T element, PsiElement resolveTo) { + super(element); + myResolveTo = resolveTo; + } + + //do nothing. the element will be renamed via PsiMetaData (com.intellij.refactoring.rename.RenameUtil.doRenameGenericNamedElement()) + public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException { + return getElement(); + } + + @Nullable + public PsiElement resolve() { + return myResolveTo; + } + + @NotNull + public Object[] getVariants() { + return EMPTY_ARRAY; + } + } } From a7a5dbaa7a236482700cb5c9a9ae87a60f5658f7 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 20:31:05 +0100 Subject: [PATCH 05/13] find Groovy list2object conversions as constructor usages --- .../GroovyConstructorUsagesSearchHelper.java | 110 +++++++++++++++--- .../lang/LiteralConstructorUsagesTest.groovy | 47 ++++++++ 2 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java index d3ea103a2b8e..9a46dcfc2899 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java @@ -28,18 +28,30 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.util.Processor; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrTypeCastExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; /** * @author Maxim.Medvedev @@ -88,22 +100,7 @@ public class GroovyConstructorUsagesSearchHelper { ReferencesSearch.search(clazz, searchScope, true).forEach(new ReadActionProcessor() { @Override public boolean processInReadAction(PsiReference ref) { - final PsiElement element = ref.getElement(); - if (element instanceof GrCodeReferenceElement) { - GrNewExpression newExpression = null; - if (element.getParent() instanceof GrNewExpression) { - newExpression = (GrNewExpression)element.getParent(); - } - else if (element.getParent() instanceof GrAnonymousClassDefinition) { - newExpression = (GrNewExpression)element.getParent().getParent(); - } - if (newExpression != null) { - final PsiMethod resolvedConstructor = newExpression.resolveConstructor(); - final PsiManager manager = constructor.getManager(); - if (manager.areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) return false; - } - } - return true; + return processClassReference(ref, constructor, consumer); } }); @@ -128,6 +125,85 @@ public class GroovyConstructorUsagesSearchHelper { return true; } + private static boolean processClassReference(PsiReference ref, final PsiMethod constructor, final Processor consumer) { + final PsiElement element = ref.getElement(); + if (!(element instanceof GrCodeReferenceElement)) { + return true; + } + + final PsiElement parent = element.getParent(); + if (parent instanceof GrNewExpression) { + final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor(); + if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) { + return false; + } + } + else if (parent instanceof GrTypeElement) { + final GrTypeElement typeElement = (GrTypeElement)parent; + + final PsiElement grandpa = typeElement.getParent(); + if (grandpa instanceof GrVariableDeclaration) { + final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables(); + if (vars.length == 1) { + final GrVariable variable = vars[0]; + if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) { + return false; + } + } + } + else if (grandpa instanceof GrMethod) { + final GrMethod method = (GrMethod)grandpa; + if (typeElement == method.getReturnTypeElementGroovy()) { + ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() { + @Override + public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { + if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) { + return false; + } + return true; + } + }); + } + } + else if (grandpa instanceof GrTypeCastExpression) { + final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa; + if (cast.getCastTypeElement() == typeElement && !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + return false; + } + } + else if (grandpa instanceof GrSafeCastExpression) { + final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa; + if (cast.getCastTypeElement() == typeElement && !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + return false; + } + } + } + return true; + } + + private static boolean checkListInstantiation(PsiMethod constructor, + Processor consumer, + GrExpression expression, final GrTypeElement typeElement) { + if (expression instanceof GrListOrMap) { + final GrListOrMap list = (GrListOrMap)expression; + if (!list.isMap()) { + final PsiType expectedType = typeElement.getType(); + final PsiType listType = list.getType(); + if (listType instanceof GrTupleType && expectedType instanceof PsiClassType) { + final GroovyResolveResult[] candidates = PsiUtil.getConstructorCandidates((PsiClassType)expectedType, ((GrTupleType)listType).getComponentTypes(), list); + for (GroovyResolveResult candidate : candidates) { + if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { + if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { + return false; + } + } + } + } + } + } + return true; + } + private static boolean processConstructors(final PsiMethod constructor, final Processor consumer, final PsiClass clazz, final boolean processThisRefs) { return ApplicationManager.getApplication().runReadAction(new Computable() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy new file mode 100644 index 000000000000..f6e6df14f708 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy @@ -0,0 +1,47 @@ +package org.jetbrains.plugins.groovy.lang + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.psi.search.searches.ReferencesSearch + +/** + * @author peter + */ +class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { + + public void testListVariable() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo() {} + } +""") + myFixture.addFileToProject "a.groovy", "Foo x = []" + assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) + } + + public void testListReturnValue() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo() {} + } +""") + myFixture.addFileToProject "a.groovy", "Foo foo() { if (true) [] else return [] }" + assertEquals(2, ReferencesSearch.search(foo.constructors[0]).findAll().size()) + } + + public void testListCast() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo() {} + } +""") + myFixture.addFileToProject "a.groovy", "def x = (Foo) []" + assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) + } + + public void testListAsCast() throws Exception { + def foo = myFixture.addClass("""class Foo { + Foo() {} + } +""") + myFixture.addFileToProject "a.groovy", "def x = [] as Foo" + assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) + } + +} From e9f04b058455c78adccfab5c9b941f975a568b89 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 23:17:13 +0100 Subject: [PATCH 06/13] index groovy package annotations --- .../findUsages/AnnotatedMembersSearcher.java | 56 ++++++++++----- .../packaging/GrPackageDefinition.java | 10 ++- .../impl/GroovyDirectInheritorsSearcher.java | 35 +++++++++- .../packaging/GrPackageDefinitionImpl.java | 14 ++++ .../groovy/lang/psi/stubs/GrFileStub.java | 56 +++++++++++++-- .../groovy/lang/psi/stubs/GrStubUtils.java | 18 ++++- .../lang/psi/stubs/GroovyFileStubBuilder.java | 3 +- .../stubs/elements/GrFieldElementType.java | 23 +----- .../stubs/elements/GrMethodElementType.java | 40 +++-------- .../stubs/elements/GrStubFileElementType.java | 12 +++- .../elements/GrTypeDefinitionElementType.java | 3 +- .../lang/psi/stubs/impl/GrFileStubImpl.java | 63 ----------------- .../stubs/index/GrAnnotatedMemberIndex.java | 8 +-- .../groovy/lang/stubs/GroovyCacheUtil.java | 70 ------------------- 14 files changed, 182 insertions(+), 229 deletions(-) delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/impl/GrFileStubImpl.java delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java index 3a4b9ecfc1d0..ead9e3f235d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java @@ -21,25 +21,49 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.AnnotatedElementsSearch; +import com.intellij.psi.stubs.StubIndex; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; -import org.jetbrains.plugins.groovy.lang.stubs.GroovyCacheUtil; +import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; /** * @author ven */ -public class AnnotatedMembersSearcher implements QueryExecutor { +public class AnnotatedMembersSearcher implements QueryExecutor { - public boolean execute(final AnnotatedElementsSearch.Parameters p, final Processor consumer) { + @NotNull + private static List getAnnotatedMemberCandidates(PsiClass clazz, GlobalSearchScope scope) { + final String name = clazz.getName(); + if (name == null) return Collections.emptyList(); + final Collection members = StubIndex.getInstance().get(GrAnnotatedMemberIndex.KEY, name, clazz.getProject(), scope); + if (members.isEmpty()) { + return Collections.emptyList(); + } + + final ArrayList result = new ArrayList(); + for (PsiElement element : members) { + if (element instanceof GroovyFile) { + element = ((GroovyFile)element).getPackageDefinition(); + } + if (element instanceof PsiModifierListOwner) { + result.add((PsiModifierListOwner)element); + } + } + return result; + } + + public boolean execute(final AnnotatedElementsSearch.Parameters p, final Processor consumer) { final PsiClass annClass = p.getAnnotationClass(); assert annClass.isAnnotationType() : "Annotation type should be passed to annotated members search"; @@ -48,29 +72,27 @@ public class AnnotatedMembersSearcher implements QueryExecutor candidates; if (scope instanceof GlobalSearchScope) { - candidates = GroovyCacheUtil.getAnnotatedMemberCandidates(annClass, ((GlobalSearchScope)scope)); + candidates = getAnnotatedMemberCandidates(annClass, ((GlobalSearchScope)scope)); } else { - PsiElement[] elements = ((LocalSearchScope)scope).getScope(); - final List collector = new ArrayList(); - for (PsiElement element : elements) { + candidates = new ArrayList(); + for (PsiElement element : ((LocalSearchScope)scope).getScope()) { if (element instanceof GroovyPsiElement) { ((GroovyPsiElement)element).accept(new GroovyRecursiveElementVisitor() { public void visitMethod(GrMethod method) { - collector.add(method); + candidates.add(method); } public void visitField(GrField field) { - collector.add(field); + candidates.add(field); } }); } } - candidates = collector.toArray(new PsiMember[collector.size()]); } - for (PsiMember candidate : candidates) { + for (PsiModifierListOwner candidate : candidates) { if (!AnnotatedElementsSearcher.isInstanceof(candidate, p.getTypes())) { continue; } @@ -78,10 +100,8 @@ public class AnnotatedMembersSearcher implements QueryExecutor inheritors = new ArrayList(); + final Collection refLists = StubIndex.getInstance().get(GrDirectInheritorsIndex.KEY, name, clazz.getProject(), scope); + for (GrReferenceList list : refLists) { + final PsiElement parent = list.getParent(); + if (parent instanceof GrTypeDefinition) { + inheritors.add(GrClassSubstitutor.getSubstitutedClass(((GrTypeDefinition)parent))); + } + } + final Collection classes = + StubIndex.getInstance().get(GrAnonymousClassIndex.KEY, name, clazz.getProject(), scope); + for (GrAnonymousClassDefinition aClass : classes) { + inheritors.add(aClass); + } + return inheritors.toArray(new PsiClass[inheritors.size()]); + } + public boolean execute(DirectClassInheritorsSearch.SearchParameters queryParameters, final Processor consumer) { final PsiClass clazz = queryParameters.getClassToProcess(); final SearchScope scope = queryParameters.getScope(); @@ -39,7 +70,7 @@ class GroovyDirectInheritorsSearcher implements QueryExecutor() { public PsiClass[] compute() { if (!clazz.isValid()) return PsiClass.EMPTY_ARRAY; - return GroovyCacheUtil.getDeriverCandidates(clazz, (GlobalSearchScope)scope); + return getDeriverCandidates(clazz, (GlobalSearchScope)scope); } }); for (final PsiClass candidate : candidates) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/packaging/GrPackageDefinitionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/packaging/GrPackageDefinitionImpl.java index 55acc71f0f34..3041aa24363c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/packaging/GrPackageDefinitionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/packaging/GrPackageDefinitionImpl.java @@ -17,6 +17,9 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.toplevel.packaging; import com.intellij.lang.ASTNode; +import com.intellij.psi.Modifier; +import com.intellij.psi.PsiModifierList; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; @@ -56,4 +59,15 @@ public class GrPackageDefinitionImpl extends GroovyPsiElementImpl implements GrP public GrModifierList getAnnotationList() { return (GrModifierList)findChildByType(GroovyElementTypes.MODIFIERS); } + + @Override + public PsiModifierList getModifierList() { + return getAnnotationList(); + } + + @Override + public boolean hasModifierProperty(@Modifier @NonNls @NotNull String name) { + final PsiModifierList list = getModifierList(); + return list != null && list.hasExplicitModifier(name); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java index 0cf2e750f5aa..454c280d7bdc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java @@ -15,17 +15,63 @@ */ package org.jetbrains.plugins.groovy.lang.psi.stubs; -import com.intellij.psi.stubs.PsiFileStub; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.stubs.PsiFileStubImpl; +import com.intellij.psi.tree.IStubFileElementType; +import com.intellij.util.ArrayUtil; import com.intellij.util.io.StringRef; +import org.jetbrains.plugins.groovy.lang.parser.GroovyParserDefinition; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; +import org.jetbrains.plugins.groovy.lang.psi.stubs.elements.GrTypeDefinitionElementType; /** * @author ilyas */ -public interface GrFileStub extends PsiFileStub { - StringRef getPackageName(); +public class GrFileStub extends PsiFileStubImpl { + private final String[] myAnnotations; + private final StringRef myPackageName; + private final StringRef myName; + private final boolean isScript; - StringRef getName(); + public GrFileStub(GroovyFile file) { + super(file); + myPackageName = StringRef.fromString(file.getPackageName()); + myName = StringRef.fromString(StringUtil.trimEnd(file.getName(), ".groovy")); + isScript = file.isScript(); + final GrPackageDefinition definition = file.getPackageDefinition(); + if (definition != null) { + myAnnotations = GrTypeDefinitionElementType.getAnnotationNames(definition); + } else { + myAnnotations = ArrayUtil.EMPTY_STRING_ARRAY; + } + } - boolean isScript(); + public GrFileStub(StringRef packName, StringRef name, boolean isScript, String[] annotations) { + super(null); + myPackageName = packName; + myName = name; + this.isScript = isScript; + myAnnotations = annotations; + } + + public IStubFileElementType getType() { + return GroovyParserDefinition.GROOVY_FILE; + } + + public StringRef getPackageName() { + return myPackageName; + } + + public StringRef getName() { + return myName; + } + + public boolean isScript() { + return isScript; + } + + public String[] getAnnotations() { + return myAnnotations; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrStubUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrStubUtils.java index 7a5d0c4fb816..9ecbce673657 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrStubUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrStubUtils.java @@ -58,5 +58,21 @@ public class GrStubUtils { dataStream.writeUTF(namepParameter); } } - } + } + + public static void writeStringArray(StubOutputStream dataStream, String[] array) throws IOException { + dataStream.writeByte(array.length); + for (String s : array) { + dataStream.writeName(s); + } + } + + public static String[] readStringArray(StubInputStream dataStream) throws IOException { + final byte b = dataStream.readByte(); + final String[] annNames = new String[b]; + for (int i = 0; i < b; i++) { + annNames[i] = dataStream.readName().toString(); + } + return annNames; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GroovyFileStubBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GroovyFileStubBuilder.java index 902f4b0cef96..53aa5f33101a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GroovyFileStubBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GroovyFileStubBuilder.java @@ -19,7 +19,6 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.stubs.DefaultStubBuilder; import com.intellij.psi.stubs.StubElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl; /** * @author ilyas @@ -27,7 +26,7 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl; public class GroovyFileStubBuilder extends DefaultStubBuilder { protected StubElement createStubForFile(final PsiFile file) { if (file instanceof GroovyFile && ((GroovyFile) file).isScript()) { - return new GrFileStubImpl((GroovyFile)file); + return new GrFileStub((GroovyFile)file); } return super.createStubForFile(file); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrFieldElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrFieldElementType.java index b909c710c179..1fe39965b9f0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrFieldElementType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrFieldElementType.java @@ -21,16 +21,10 @@ import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubInputStream; import com.intellij.psi.stubs.StubOutputStream; -import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.StringRef; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrStubElementType; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrFieldImpl; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFieldStub; import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFieldStubImpl; @@ -64,22 +58,7 @@ public class GrFieldElementType extends GrStubElementType } public GrFieldStub createStub(GrField psi, StubElement parentStub) { - final GrModifierList modifiers = psi.getModifierList(); - String[] annNames; - if (modifiers == null) { - annNames = ArrayUtil.EMPTY_STRING_ARRAY; - } - else { - final GrAnnotation[] annotations = modifiers.getAnnotations(); - annNames = ContainerUtil.map(annotations, new Function() { - @Nullable - public String fun(final GrAnnotation grAnnotation) { - final GrCodeReferenceElement element = grAnnotation.getClassReference(); - if (element == null) return null; - return element.getReferenceName(); - } - }, new String[annotations.length]); - } + String[] annNames = GrTypeDefinitionElementType.getAnnotationNames(psi); Set[] namedParametersArray = new Set[0]; if (psi instanceof GrFieldImpl){ diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrMethodElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrMethodElementType.java index 94504b059250..c242f4fe2245 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrMethodElementType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrMethodElementType.java @@ -20,15 +20,9 @@ import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubInputStream; import com.intellij.psi.stubs.StubOutputStream; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.StringRef; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrStubElementType; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members.GrMethodImpl; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrMethodStub; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrStubUtils; @@ -37,7 +31,9 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex; import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrMethodNameIndex; import java.io.IOException; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author ilyas @@ -57,42 +53,22 @@ public class GrMethodElementType extends GrStubElementType() { - @Nullable - public String fun(final GrAnnotation grAnnotation) { - final GrCodeReferenceElement element = grAnnotation.getClassReference(); - if (element == null) return null; - return element.getReferenceName(); - } - }, new String[annotations.length]); - Set[] namedParametersArray; - namedParametersArray = psi.getNamedParametersArray(); - - return new GrMethodStubImpl(parentStub, StringRef.fromString(psi.getName()), annNames, namedParametersArray); + return new GrMethodStubImpl(parentStub, StringRef.fromString(psi.getName()), GrTypeDefinitionElementType.getAnnotationNames(psi), + psi.getNamedParametersArray()); } public void serialize(GrMethodStub stub, StubOutputStream dataStream) throws IOException { dataStream.writeName(stub.getName()); - final String[] annotations = stub.getAnnotations(); - dataStream.writeByte(annotations.length); - for (String s : annotations) { - dataStream.writeName(s); - } + GrStubUtils.writeStringArray(dataStream, stub.getAnnotations()); final Set[] namedParameters = stub.getNamedParameters(); GrStubUtils.serializeCollectionsArray(dataStream, namedParameters); } - + public GrMethodStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException { StringRef ref = dataStream.readName(); - final byte b = dataStream.readByte(); - final String[] annNames = new String[b]; - for (int i = 0; i < b; i++) { - annNames[i] = dataStream.readName().toString(); - } + final String[] annNames = GrStubUtils.readStringArray(dataStream); final List> namedParametersSets = GrStubUtils.deserializeCollectionsArray(dataStream); return new GrMethodStubImpl(parentStub, ref, annNames, namedParametersSets.toArray(new HashSet[0])); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index 70a7da0e41a1..3dd1dec6fc2e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -21,8 +21,9 @@ import com.intellij.psi.stubs.*; import com.intellij.psi.tree.IStubFileElementType; import com.intellij.util.io.StringRef; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFileStub; +import org.jetbrains.plugins.groovy.lang.psi.stubs.GrStubUtils; import org.jetbrains.plugins.groovy.lang.psi.stubs.GroovyFileStubBuilder; -import org.jetbrains.plugins.groovy.lang.psi.stubs.impl.GrFileStubImpl; +import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex; import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrFullScriptNameIndex; import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrScriptClassNameIndex; @@ -43,7 +44,7 @@ public class GrStubFileElementType extends IStubFileElementType { @Override public int getStubVersion() { - return super.getStubVersion() + 5; + return super.getStubVersion() + 6; } public String getExternalId() { @@ -60,6 +61,7 @@ public class GrStubFileElementType extends IStubFileElementType { dataStream.writeName(stub.getPackageName().toString()); dataStream.writeName(stub.getName().toString()); dataStream.writeBoolean(stub.isScript()); + GrStubUtils.writeStringArray(dataStream, stub.getAnnotations()); } @Override @@ -67,7 +69,7 @@ public class GrStubFileElementType extends IStubFileElementType { StringRef packName = dataStream.readName(); StringRef name = dataStream.readName(); boolean isScript = dataStream.readBoolean(); - return new GrFileStubImpl(packName, name, isScript); + return new GrFileStub(packName, name, isScript, GrStubUtils.readStringArray(dataStream)); } public void indexStub(GrFileStub stub, IndexSink sink) { @@ -78,6 +80,10 @@ public class GrStubFileElementType extends IStubFileElementType { final String fqn = pName == null || pName.length() == 0 ? name : pName + "." + name; sink.occurrence(GrFullScriptNameIndex.KEY, fqn.hashCode()); } + + for (String anno : stub.getAnnotations()) { + sink.occurrence(GrAnnotatedMemberIndex.KEY, anno); + } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrTypeDefinitionElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrTypeDefinitionElementType.java index 5cb77de6737b..3caa45dfa5f4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrTypeDefinitionElementType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrTypeDefinitionElementType.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.stubs.elements; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex; import com.intellij.psi.impl.java.stubs.index.JavaShortClassNameIndex; @@ -59,7 +60,7 @@ public abstract class GrTypeDefinitionElementType annoNames = CollectionFactory.arrayList(); final PsiModifierList modifierList = psi.getModifierList(); if (modifierList instanceof GrModifierList) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/impl/GrFileStubImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/impl/GrFileStubImpl.java deleted file mode 100644 index 6a810c1247ec..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/impl/GrFileStubImpl.java +++ /dev/null @@ -1,63 +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 org.jetbrains.plugins.groovy.lang.psi.stubs.impl; - -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.stubs.PsiFileStubImpl; -import com.intellij.psi.tree.IStubFileElementType; -import com.intellij.util.io.StringRef; -import org.jetbrains.plugins.groovy.lang.parser.GroovyParserDefinition; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFileStub; - -/** - * @author ilyas - */ -public class GrFileStubImpl extends PsiFileStubImpl implements GrFileStub { - private final StringRef myPackageName; - private final StringRef myName; - private final boolean isScript; - - public GrFileStubImpl(GroovyFile file) { - super(file); - myPackageName = StringRef.fromString(file.getPackageName()); - myName = StringRef.fromString(StringUtil.trimEnd(file.getName(), ".groovy")); - isScript = file.isScript(); - } - - public GrFileStubImpl(StringRef packName, StringRef name, boolean isScript) { - super(null); - myPackageName = packName; - myName = name; - this.isScript = isScript; - } - - public IStubFileElementType getType() { - return GroovyParserDefinition.GROOVY_FILE; - } - - public StringRef getPackageName() { - return myPackageName; - } - - public StringRef getName() { - return myName; - } - - public boolean isScript() { - return isScript; - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/index/GrAnnotatedMemberIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/index/GrAnnotatedMemberIndex.java index 1b8a5368bd1f..ec2e377773aa 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/index/GrAnnotatedMemberIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/index/GrAnnotatedMemberIndex.java @@ -15,17 +15,17 @@ */ package org.jetbrains.plugins.groovy.lang.psi.stubs.index; -import com.intellij.psi.PsiMember; +import com.intellij.psi.PsiElement; import com.intellij.psi.stubs.StringStubIndexExtension; import com.intellij.psi.stubs.StubIndexKey; /** * @author ilyas */ -public class GrAnnotatedMemberIndex extends StringStubIndexExtension { - public static final StubIndexKey KEY = StubIndexKey.createIndexKey("gr.annot.members"); +public class GrAnnotatedMemberIndex extends StringStubIndexExtension { + public static final StubIndexKey KEY = StubIndexKey.createIndexKey("gr.annot.members"); - public StubIndexKey getKey() { + public StubIndexKey getKey() { return KEY; } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java deleted file mode 100644 index 90484d43d8a9..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyCacheUtil.java +++ /dev/null @@ -1,70 +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 org.jetbrains.plugins.groovy.lang.stubs; - -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMember; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.stubs.StubIndex; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; -import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnnotatedMemberIndex; -import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnonymousClassIndex; -import org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrDirectInheritorsIndex; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * @author ilyas - */ -public abstract class GroovyCacheUtil { - - @NotNull - public static PsiMember[] getAnnotatedMemberCandidates(PsiClass clazz, GlobalSearchScope scope) { - final String name = clazz.getName(); - if (name == null) return GrMember.EMPTY_ARRAY; - final Collection members = StubIndex.getInstance().get(GrAnnotatedMemberIndex.KEY, name, clazz.getProject(), scope); - return members.toArray(new PsiMember[members.size()]); - } - - @NotNull - public static PsiClass[] getDeriverCandidates(PsiClass clazz, GlobalSearchScope scope) { - final String name = clazz.getName(); - if (name == null) return GrTypeDefinition.EMPTY_ARRAY; - final ArrayList inheritors = new ArrayList(); - final Collection refLists = StubIndex.getInstance().get(GrDirectInheritorsIndex.KEY, name, clazz.getProject(), scope); - for (GrReferenceList list : refLists) { - final PsiElement parent = list.getParent(); - if (parent instanceof GrTypeDefinition) { - inheritors.add(GrClassSubstitutor.getSubstitutedClass(((GrTypeDefinition)parent))); - } - } - final Collection classes = - StubIndex.getInstance().get(GrAnonymousClassIndex.KEY, name, clazz.getProject(), scope); - for (GrAnonymousClassDefinition aClass : classes) { - inheritors.add(aClass); - } - return inheritors.toArray(new PsiClass[inheritors.size()]); - } - - -} From 2e71d015b43912e9b7d8dd8ca0dd1e97964879d5 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 26 Jul 2010 23:17:54 +0100 Subject: [PATCH 07/13] find list literal constructor call usages in Groovy++ method calls --- .../GroovyConstructorUsagesSearchHelper.java | 194 +++++++++++++++--- .../plugins/groovy/gpp/GppTypeConverter.java | 15 +- .../lang/LiteralConstructorUsagesTest.groovy | 66 +++++- 3 files changed, 239 insertions(+), 36 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java index 9a46dcfc2899..30c2c35a4c67 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java @@ -18,19 +18,33 @@ package org.jetbrains.plugins.groovy.findUsages; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadActionProcessor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMemberReference; +import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.AnnotatedElementsSearch; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; +import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; +import com.intellij.util.containers.ConcurrentHashSet; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; @@ -38,11 +52,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocat import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrTypeCastExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; @@ -50,9 +62,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + /** * @author Maxim.Medvedev * Date: May 2, 2009 3:48:53 PM @@ -61,11 +78,12 @@ public class GroovyConstructorUsagesSearchHelper { private GroovyConstructorUsagesSearchHelper() { } - public static boolean execute(final PsiMethod constructor, SearchScope searchScope, final Processor consumer) { + public static boolean execute(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer) { if (!constructor.isConstructor()) return true; - if (searchScope instanceof GlobalSearchScope) { - searchScope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)searchScope, GroovyFileType.GROOVY_FILE_TYPE); + SearchScope onlyGroovy = searchScope; + if (onlyGroovy instanceof GlobalSearchScope) { + onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE); } final PsiClass clazz = ApplicationManager.getApplication().runReadAction(new NullableComputable() { @@ -97,10 +115,11 @@ public class GroovyConstructorUsagesSearchHelper { } - ReferencesSearch.search(clazz, searchScope, true).forEach(new ReadActionProcessor() { + final Set processedMethods = new ConcurrentHashSet(); + ReferencesSearch.search(clazz, searchScope, true).forEach(new Processor() { @Override - public boolean processInReadAction(PsiReference ref) { - return processClassReference(ref, constructor, consumer); + public boolean process(PsiReference ref) { + return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope); } }); @@ -111,7 +130,7 @@ public class GroovyConstructorUsagesSearchHelper { } } //super : does not work now, need to invent a way for it to work without repository - if (!DirectClassInheritorsSearch.search(clazz, searchScope).forEach(new Processor() { + if (!DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor() { public boolean process(PsiClass inheritor) { if (inheritor instanceof GrTypeDefinition) { if (!processConstructors(constructor, consumer, inheritor, false)) return false; @@ -125,12 +144,99 @@ public class GroovyConstructorUsagesSearchHelper { return true; } - private static boolean processClassReference(PsiReference ref, final PsiMethod constructor, final Processor consumer) { + @Nullable + private static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass clazz, Set processedMethods) { + final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class); + if (parameter != null) { + final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); + if (method != null && processedMethods.add(method) && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) { + final PsiType parameterType = parameter.getType(); + if (parameterType instanceof PsiClassType) { + if (method.getManager().areElementsEquivalent(clazz, ((PsiClassType)parameterType).resolve())) { + return method; + } + } + } + } + return null; + } + + private static boolean processClassReference(final PsiReference ref, + final PsiClass clazz, + final PsiMethod constructor, + final Processor consumer, + final Set processedMethods, SearchScope scope) { final PsiElement element = ref.getElement(); - if (!(element instanceof GrCodeReferenceElement)) { - return true; + if (element instanceof GrCodeReferenceElement) { + if (!ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref); + } + })) { + return false; + } + } + final PsiMethod method = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiMethod compute() { + return getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); + } + }); + if (method != null) { + return MethodReferencesSearch.search(method, getGppScope(clazz.getProject()).intersectWith(scope), true).forEach(new ReadActionProcessor() { + @Override + public boolean processInReadAction(PsiReference psiReference) { + if (psiReference instanceof GrReferenceElement) { + final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); + if (parent instanceof GrCall) { + final GrArgumentList argList = ((GrCall)parent).getArgumentList(); + if (argList != null) { + boolean checkedTypedContext = false; + + for (GrExpression argument : argList.getExpressionArguments()) { + if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) { + if (!checkedTypedContext) { + if (!GppTypeConverter.hasTypedContext(parent)) { + return true; + } + checkedTypedContext = true; + } + + for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) { + if (psiType instanceof PsiClassType && + clazz.getManager().areElementsEquivalent(clazz,((PsiClassType)psiType).resolve()) && + !checkListInstantiation(constructor, consumer, (GrListOrMap)argument, (PsiClassType)psiType)) { + return false; + } + } + } + } + } + } + } + return true; + } + }); + } + + return true; + } + + private static GlobalSearchScope getGppScope(final Project project) { + return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider() { + @Override + public Result compute() { + return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project)); + } + }); + } + + private static boolean processGroovyConstructorUsages(GrCodeReferenceElement element, + final PsiMethod constructor, + final Processor consumer, + PsiReference ref) { final PsiElement parent = element.getParent(); if (parent instanceof GrNewExpression) { final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor(); @@ -167,13 +273,15 @@ public class GroovyConstructorUsagesSearchHelper { } else if (grandpa instanceof GrTypeCastExpression) { final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa; - if (cast.getCastTypeElement() == typeElement && !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + if (cast.getCastTypeElement() == typeElement && + !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { return false; } } else if (grandpa instanceof GrSafeCastExpression) { final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa; - if (cast.getCastTypeElement() == typeElement && !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + if (cast.getCastTypeElement() == typeElement && + !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { return false; } } @@ -181,6 +289,33 @@ public class GroovyConstructorUsagesSearchHelper { return true; } + private static GlobalSearchScope calcGppScope(Project project) { + final GlobalSearchScope allScope = GlobalSearchScope.allScope(project); + final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE); + GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) { + @Override + public boolean contains(VirtualFile file) { + return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension()); + } + }; + final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope); + if (typed != null) { + final Set files = new HashSet(); + AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor() { + @Override + public boolean process(PsiModifierListOwner occurrence) { + ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files); + return true; + } + }); + + GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files); + return withTypedAnno.union(gppExtensions); + } + + return gppExtensions; + } + private static boolean checkListInstantiation(PsiMethod constructor, Processor consumer, GrExpression expression, final GrTypeElement typeElement) { @@ -188,15 +323,24 @@ public class GroovyConstructorUsagesSearchHelper { final GrListOrMap list = (GrListOrMap)expression; if (!list.isMap()) { final PsiType expectedType = typeElement.getType(); - final PsiType listType = list.getType(); - if (listType instanceof GrTupleType && expectedType instanceof PsiClassType) { - final GroovyResolveResult[] candidates = PsiUtil.getConstructorCandidates((PsiClassType)expectedType, ((GrTupleType)listType).getComponentTypes(), list); - for (GroovyResolveResult candidate : candidates) { - if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { - if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { - return false; - } - } + if (expectedType instanceof PsiClassType) { + return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType); + } + } + } + return true; + } + + private static boolean checkListInstantiation(PsiMethod constructor, + Processor consumer, + GrListOrMap list, + PsiClassType expectedType) { + final PsiType listType = list.getType(); + if (listType instanceof GrTupleType) { + for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) { + if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { + if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { + return false; } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index 3a4ea0680f77..ab44998ef803 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -19,26 +19,29 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; */ public class GppTypeConverter extends GrTypeConverter { + public static final String GROOVY_LANG_TYPED = "groovy.lang.Typed"; + public static boolean hasTypedContext(PsiElement context) { if (context == null) { return false; } - if (AnnotatedContextFilter.hasAnnotatedContext(context, "groovy.lang.Typed")) { + if (AnnotatedContextFilter.hasAnnotatedContext(context, GROOVY_LANG_TYPED)) { return true; } final VirtualFile vfile = context.getContainingFile().getOriginalFile().getVirtualFile(); - if (vfile != null) { - final String extension = vfile.getExtension(); - if ("gpp".equals(extension) || "grunit".equals(vfile.getExtension())) { - return true; - } + if (vfile != null && isGppExtension(vfile.getExtension())) { + return true; } return false; } + public static boolean isGppExtension(String extension) { + return "gpp".equals(extension) || "grunit".equals(extension); + } + @Override public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { if (rType instanceof GrTupleType) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy index f6e6df14f708..00432a8cb4d0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/LiteralConstructorUsagesTest.groovy @@ -7,8 +7,12 @@ import com.intellij.psi.search.searches.ReferencesSearch * @author peter */ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { + @Override protected void setUp() { + super.setUp(); + myFixture.addClass("package groovy.lang; public @interface Typed {}"); + } - public void testListVariable() throws Exception { + public void testList_Variable() throws Exception { def foo = myFixture.addClass("""class Foo { Foo() {} } @@ -17,7 +21,7 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) } - public void testListReturnValue() throws Exception { + public void testList_ReturnValue() throws Exception { def foo = myFixture.addClass("""class Foo { Foo() {} } @@ -26,7 +30,7 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertEquals(2, ReferencesSearch.search(foo.constructors[0]).findAll().size()) } - public void testListCast() throws Exception { + public void testList_Cast() throws Exception { def foo = myFixture.addClass("""class Foo { Foo() {} } @@ -35,13 +39,65 @@ class LiteralConstructorUsagesTest extends LightCodeInsightFixtureTestCase { assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) } - public void testListAsCast() throws Exception { + public void testList_AsCast() throws Exception { def foo = myFixture.addClass("""class Foo { Foo() {} } -""") +}""") myFixture.addFileToProject "a.groovy", "def x = [] as Foo" assertOneElement(ReferencesSearch.search(foo.constructors[0]).findAll()) } + public void testList_GppMethodCall() throws Exception { + //------------------------declarations + def foo = myFixture.addClass(""" + package z; + class Foo { + public Foo() {} + } + """) + + myFixture.addClass(""" + package z; + public class Bar { + public static void giveMeFoo(int a, Foo f) {} + } +""") + myFixture.addFileToProject("Decl.groovy", "static def giveMeFooAsWell(z.Foo f) {}") + + //----------------------usages + myFixture.addFileToProject "a.gpp", "z.Bar.giveMeFoo(2, []) //usage" + myFixture.addFileToProject "b.groovy", """ + @Typed package aa; + z.Bar.giveMeFoo(3, []) //usage + """ + myFixture.addFileToProject "c.groovy", """ + @Typed def someMethod() { + z.Bar.giveMeFoo 4, [] //usage + Decl.giveMeFooAsWell([]) //usage + } + z.Bar.giveMeFoo 5, [] //non-typed context + Decl.giveMeFooAsWell([]) + """ + myFixture.addFileToProject "invalid.gpp", "z.Bar.giveMeFoo 42, 239, []" + myFixture.addFileToProject "nonGpp.groovy", "z.Bar.giveMeFoo(6, [])" + assertEquals(4, ReferencesSearch.search(foo.constructors[0]).findAll().size()) + } + + public void testList_GppConstructorCallWithSeveralParameters() throws Exception { + def foo = myFixture.addClass(""" + class Foo { + Foo() {} + } + """) + + myFixture.addClass(""" + class Bar { + Bar(Foo f1, Foo f2, Foo f3) {} + } + """) + myFixture.addFileToProject "a.gpp", "new Bar([],[],[])" + assertEquals(3, ReferencesSearch.search(foo.constructors[0]).findAll().size()) + } + } From 7a0fad2ea3c2d3d6594469b3172220141725adc2 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 27 Jul 2010 20:55:24 +0100 Subject: [PATCH 08/13] merge with maxim's changes --- .../findUsages/GroovyConstructorUsagesSearchHelper.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java index 30c2c35a4c67..e44211b20192 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java @@ -56,6 +56,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -237,7 +238,11 @@ public class GroovyConstructorUsagesSearchHelper { final PsiMethod constructor, final Processor consumer, PsiReference ref) { - final PsiElement parent = element.getParent(); + PsiElement parent = element.getParent(); + + if (parent instanceof GrAnonymousClassDefinition) { + parent = parent.getParent(); + } if (parent instanceof GrNewExpression) { final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor(); if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) { From 9eb2032dab4f90c996dec692cce470bd55f9ac8e Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 27 Jul 2010 23:33:28 +0100 Subject: [PATCH 09/13] optimized find usages for nested searches; groovy/++ constructor usages using that API --- .../searches/MethodReferencesSearch.java | 12 +- .../intellij/psi/search/PsiSearchRequest.java | 4 + .../psi/search/QuerySearchRequest.java | 43 +++++ .../psi/search/SearchRequestCollector.java | 49 +++++- .../psi/search/searches/ReferencesSearch.java | 13 +- .../psi/impl/search/PsiSearchHelperImpl.java | 155 +++++++++++------- .../ConstructorReferencesSearcher.java | 2 +- .../GroovyConstructorUsagesSearchHelper.java | 35 ++-- .../GroovyConstructorUsagesSearcher.java | 6 +- 9 files changed, 219 insertions(+), 100 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/psi/search/QuerySearchRequest.java diff --git a/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java b/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java index 93bfe3cb66c3..a29b98613b42 100644 --- a/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java +++ b/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java @@ -17,11 +17,9 @@ package com.intellij.psi.search.searches; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchRequestCollector; -import com.intellij.psi.search.SearchRequestQuery; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.*; import com.intellij.util.MergeQuery; +import com.intellij.util.PairProcessor; import com.intellij.util.Query; import com.intellij.util.UniqueResultsQuery; import gnu.trove.TObjectHashingStrategy; @@ -75,6 +73,12 @@ public class MethodReferencesSearch extends ExtensibleQueryFactory processor) { + final SearchRequestCollector nested = new SearchRequestCollector(); + collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(method, scope, strictSignatureSearch, nested)), nested, + inReadAction, processor)); + } + public static Query search(final SearchParameters parameters) { final Query result = INSTANCE.createQuery(parameters); if (parameters.isSharedOptimizer) { diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java b/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java index 5e16c40b8c91..b2a61d521ae7 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java +++ b/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java @@ -25,4 +25,8 @@ public class PsiSearchRequest { this.processor = processor; } + @Override + public String toString() { + return "PsiSearchRequest: " + word + "; " + processor; + } } diff --git a/platform/lang-api/src/com/intellij/psi/search/QuerySearchRequest.java b/platform/lang-api/src/com/intellij/psi/search/QuerySearchRequest.java new file mode 100644 index 000000000000..158ee91dc151 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/search/QuerySearchRequest.java @@ -0,0 +1,43 @@ +package com.intellij.psi.search; + +import com.intellij.openapi.application.ReadActionProcessor; +import com.intellij.psi.PsiReference; +import com.intellij.util.PairProcessor; +import com.intellij.util.Processor; +import com.intellij.util.Query; + +/** + * @author peter + */ +public class QuerySearchRequest { + public final Query query; + public final SearchRequestCollector collector; + public final Processor processor; + + public QuerySearchRequest(Query query, + final SearchRequestCollector collector, + boolean inReadAction, final PairProcessor processor) { + this.query = query; + this.collector = collector; + if (inReadAction) { + this.processor = new ReadActionProcessor() { + @Override + public boolean processInReadAction(PsiReference psiReference) { + return processor.process(psiReference, collector); + } + }; + } else { + this.processor = new Processor() { + @Override + public boolean process(PsiReference psiReference) { + return processor.process(psiReference, collector); + } + }; + } + + } + + public void runQuery() { + query.forEach(processor); + } +} diff --git a/platform/lang-api/src/com/intellij/psi/search/SearchRequestCollector.java b/platform/lang-api/src/com/intellij/psi/search/SearchRequestCollector.java index b4e434ebcf6f..596282772625 100644 --- a/platform/lang-api/src/com/intellij/psi/search/SearchRequestCollector.java +++ b/platform/lang-api/src/com/intellij/psi/search/SearchRequestCollector.java @@ -3,6 +3,7 @@ package com.intellij.psi.search; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.util.Processor; +import com.intellij.util.containers.CollectionFactory; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -12,8 +13,10 @@ import java.util.List; * @author peter */ public class SearchRequestCollector { - private final List myRequests = new ArrayList(); - private final List>> myCustomSearchActions = new ArrayList>>(); + private final Object lock = new Object(); + private final List myWordRequests = CollectionFactory.arrayList(); + private final List myQueryRequests = CollectionFactory.arrayList(); + private final List>> myCustomSearchActions = CollectionFactory.arrayList(); public void searchWord(@NotNull String word, @NotNull SearchScope searchScope, boolean caseSensitive, @NotNull PsiElement searchTarget) { final short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_FOREIGN_LANGUAGES | UsageSearchContext.IN_COMMENTS; @@ -29,18 +32,48 @@ public class SearchRequestCollector { return; } - myRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor)); + synchronized (lock) { + myWordRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor)); + } + } + + public void searchQuery(QuerySearchRequest request) { + assert request.collector != this; + synchronized (lock) { + myQueryRequests.add(request); + } } public void searchCustom(Processor> searchAction) { - myCustomSearchActions.add(searchAction); + synchronized (lock) { + myCustomSearchActions.add(searchAction); + } } - public List getSearchRequests() { - return myRequests; + public boolean hasRequests() { + synchronized (lock) { + return !myWordRequests.isEmpty() || !myCustomSearchActions.isEmpty() || !myQueryRequests.isEmpty(); + } } - public List>> getCustomSearchActions() { - return myCustomSearchActions; + public List takeQueryRequests() { + return takeRequests(myQueryRequests); + } + + private List takeRequests(List list) { + synchronized (lock) { + final List requests = new ArrayList(list); + requests.addAll(list); + list.clear(); + return requests; + } + } + + public List takeSearchRequests() { + return takeRequests(myWordRequests); + } + + public List>> takeCustomSearchActions() { + return takeRequests(myCustomSearchActions); } } diff --git a/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java b/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java index c43a8875a6f5..e2dc5c6ff22f 100644 --- a/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java +++ b/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java @@ -17,10 +17,7 @@ package com.intellij.psi.search.searches; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchRequestCollector; -import com.intellij.psi.search.SearchRequestQuery; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.*; import com.intellij.util.*; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; @@ -111,4 +108,12 @@ public class ReferencesSearch extends ExtensibleQueryFactory processor) { + final SearchRequestCollector nested = new SearchRequestCollector(); + collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(element, searchScope, ignoreAccessScope, nested)), nested, + inReadAction, processor)); + } + + } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 425e5c86fd81..24e17f5319c4 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -487,34 +488,62 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { myManager.getCacheManager().processFilesWithWord(processor, word, UsageSearchContext.IN_STRINGS, scope, true); } - public boolean processRequests(@NotNull SearchRequestCollector request, Processor processor) { - final MultiMap, PsiSearchRequest> singles = new MultiMap, PsiSearchRequest>(); - final List>> customs = new ArrayList>>(); - distributePrimitives(request, singles, customs); - - if (!processRequestsOptimized(singles, processor)) { - return false; + private static class RequestWithProcessor extends Pair> { + private RequestWithProcessor(PsiSearchRequest first, Processor second) { + super(first, second); } - - for (Processor> custom : customs) { - if (!custom.process(processor)) { - return false; - } - } - - return true; - } - private boolean processRequestsOptimized(MultiMap, PsiSearchRequest> singles, final Processor consumer) { + public boolean processRequests(@NotNull SearchRequestCollector collector, Processor processor) { + Map> collectors = new HashMap>(); + collectors.put(collector, processor); + + appendCollectorsFromQueryRequests(collectors); + + do { + final MultiMap, RequestWithProcessor> singles = new MultiMap, RequestWithProcessor>(); + final List> customs = new ArrayList>(); + distributePrimitives(collectors, singles, customs); + + if (!processRequestsOptimized(singles)) { + return false; + } + + for (Computable custom : customs) { + if (!custom.compute()) { + return false; + } + } + } while (appendCollectorsFromQueryRequests(collectors)); + + return true; + } + + private static boolean appendCollectorsFromQueryRequests(Map> collectors) { + boolean changed = false; + LinkedList queue = new LinkedList(collectors.keySet()); + while (!queue.isEmpty()) { + final SearchRequestCollector each = queue.removeFirst(); + for (QuerySearchRequest request : each.takeQueryRequests()) { + request.runQuery(); + collectors.put(request.collector, request.processor); + queue.addLast(request.collector); + changed = true; + } + } + return changed; + } + + private boolean processRequestsOptimized(MultiMap, RequestWithProcessor> singles) { if (singles.isEmpty()) { return true; } if (singles.size() == 1) { - final Collection requests = singles.get(singles.keySet().iterator().next()); + final Collection requests = singles.get(singles.keySet().iterator().next()); if (requests.size() == 1) { - return processSingleRequest(requests.iterator().next(), consumer); + final RequestWithProcessor theOnly = requests.iterator().next(); + return processSingleRequest(theOnly.first, theOnly.second); } } @@ -524,13 +553,13 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { progress.setText(PsiBundle.message("psi.scanning.files.progress")); } - final MultiMap candidateFiles = collectFiles(singles); + final MultiMap candidateFiles = collectFiles(singles); - final Map searchers = new HashMap(); + final Map searchers = new HashMap(); final Set allWords = new TreeSet(); - for (PsiSearchRequest singleRequest : candidateFiles.values()) { - searchers.put(singleRequest, new StringSearcher(singleRequest.word, singleRequest.caseSensitive, true)); - allWords.add(singleRequest.word); + for (RequestWithProcessor singleRequest : candidateFiles.values()) { + searchers.put(singleRequest, new StringSearcher(singleRequest.first.word, singleRequest.first.caseSensitive, true)); + allWords.add(singleRequest.first.word); } if (progress != null) { @@ -540,9 +569,9 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return processPsiFileRoots(progress, new ArrayList(candidateFiles.keySet()), new Processor() { public boolean process(PsiElement psiRoot) { final VirtualFile vfile = psiRoot.getContainingFile().getVirtualFile(); - for (final PsiSearchRequest singleRequest : candidateFiles.get(vfile)) { + for (final RequestWithProcessor singleRequest : candidateFiles.get(vfile)) { StringSearcher searcher = searchers.get(singleRequest); - if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest, consumer), psiRoot, searcher, false, progress)) { + if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest.first, singleRequest.second), psiRoot, searcher, false, progress)) { return false; } } @@ -565,18 +594,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { }; } - private MultiMap collectFiles(MultiMap, PsiSearchRequest> singles) { + private MultiMap collectFiles(MultiMap, RequestWithProcessor> singles) { final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex(); - final MultiMap result = new MultiMap(); + final MultiMap result = new MultiMap(); for (Set key : singles.keySet()) { - final Collection data = singles.get(key); + final Collection data = singles.get(key); GlobalSearchScope commonScope = uniteScopes(data); - MultiMap intersection = null; + MultiMap intersection = null; boolean first = true; for (IdIndexEntry entry : key) { - final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope); + final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope); if (first) { intersection = local; first = false; @@ -593,31 +622,34 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return result; } - private static GlobalSearchScope uniteScopes(Collection requests) { + private static GlobalSearchScope uniteScopes(Collection requests) { GlobalSearchScope commonScope = null; - for (PsiSearchRequest r : requests) { - final GlobalSearchScope scope = (GlobalSearchScope)r.searchScope; + for (RequestWithProcessor r : requests) { + final GlobalSearchScope scope = (GlobalSearchScope)r.first.searchScope; commonScope = commonScope == null ? scope : commonScope.uniteWith(scope); } assert commonScope != null; return commonScope; } - private static MultiMap findFilesWithIndexEntry(final IdIndexEntry entry, + private static MultiMap findFilesWithIndexEntry(final IdIndexEntry entry, final ProjectFileIndex index, - final Collection data, + final Collection data, final GlobalSearchScope commonScope) { - final MultiMap local = new MultiMap(); + final MultiMap local = new MultiMap(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { + ProgressManager.checkCanceled(); FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor() { public boolean process(VirtualFile file, Integer value) { + ProgressManager.checkCanceled(); if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { return true; } int mask = value.intValue(); - for (PsiSearchRequest single : data) { - if ((mask & single.searchContext) != 0 && ((GlobalSearchScope)single.searchScope).contains(file)) { + for (RequestWithProcessor single : data) { + final PsiSearchRequest request = single.first; + if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) { local.putValue(file, single); } } @@ -630,27 +662,38 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return local; } - private void distributePrimitives(SearchRequestCollector request, - MultiMap, PsiSearchRequest> singles, - List>> customs) { - for (final PsiSearchRequest primitive : request.getSearchRequests()) { - final SearchScope scope = primitive.searchScope; - if (scope instanceof LocalSearchScope) { - customs.add(new Processor>() { - public boolean process(Processor processor) { - return processSingleRequest(primitive, processor); + private void distributePrimitives(final Map> collectors, + MultiMap, RequestWithProcessor> singles, + List> customs) { + for (final SearchRequestCollector collector : collectors.keySet()) { + final Processor processor = collectors.get(collector); + for (final PsiSearchRequest primitive : collector.takeSearchRequests()) { + final SearchScope scope = primitive.searchScope; + if (scope instanceof LocalSearchScope) { + customs.add(new Computable() { + @Override + public Boolean compute() { + return processSingleRequest(primitive, processor); + } + }); + } else { + final List words = StringUtil.getWordsIn(primitive.word); + final Set key = new HashSet(words.size() * 2); + for (String word : words) { + key.add(new IdIndexEntry(word, primitive.caseSensitive)); + } + singles.putValue(key, new RequestWithProcessor(primitive, processor)); + } + } + for (final Processor> customAction : collector.takeCustomSearchActions()) { + customs.add(new Computable() { + @Override + public Boolean compute() { + return customAction.process(processor); } }); - } else { - final List words = StringUtil.getWordsIn(primitive.word); - final Set key = new HashSet(words.size() * 2); - for (String word : words) { - key.add(new IdIndexEntry(word, primitive.caseSensitive)); - } - singles.putValue(key, primitive); } } - customs.addAll(request.getCustomSearchActions()); } private boolean processSingleRequest(PsiSearchRequest single, Processor consumer) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java index 138a9034642a..6af2559d1122 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java @@ -31,7 +31,7 @@ public class ConstructorReferencesSearcher implements QueryExecutor consumer) { + public static boolean processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector) { if (!constructor.isConstructor()) return true; SearchScope onlyGroovy = searchScope; @@ -117,10 +115,11 @@ public class GroovyConstructorUsagesSearchHelper { final Set processedMethods = new ConcurrentHashSet(); - ReferencesSearch.search(clazz, searchScope, true).forEach(new Processor() { + + ReferencesSearch.searchOptimized(clazz, searchScope, true, collector, true, new PairProcessor() { @Override - public boolean process(PsiReference ref) { - return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope); + public boolean process(PsiReference ref, SearchRequestCollector collector) { + return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope, collector); } }); @@ -166,29 +165,21 @@ public class GroovyConstructorUsagesSearchHelper { final PsiClass clazz, final PsiMethod constructor, final Processor consumer, - final Set processedMethods, SearchScope scope) { + final Set processedMethods, SearchScope scope, SearchRequestCollector collector) { final PsiElement element = ref.getElement(); if (element instanceof GrCodeReferenceElement) { - if (!ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref); - } - })) { + if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref)) { return false; } } - final PsiMethod method = ApplicationManager.getApplication().runReadAction(new Computable() { - public PsiMethod compute() { - return getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); - } - }); + final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); if (method != null) { - return MethodReferencesSearch.search(method, getGppScope(clazz.getProject()).intersectWith(scope), true).forEach(new ReadActionProcessor() { + final GlobalSearchScope gppScope = getGppScope(clazz.getProject()); + MethodReferencesSearch.searchOptimized(method, gppScope.intersectWith(scope), true, collector, true, new PairProcessor() { @Override - public boolean processInReadAction(PsiReference psiReference) { + public boolean process(PsiReference psiReference, SearchRequestCollector collector) { if (psiReference instanceof GrReferenceElement) { final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); if (parent instanceof GrCall) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java index da1ef93bd10f..8a2a8ebbfa36 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java @@ -16,9 +16,7 @@ package org.jetbrains.plugins.groovy.findUsages; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; -import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; @@ -28,8 +26,6 @@ import com.intellij.util.QueryExecutor; */ public class GroovyConstructorUsagesSearcher implements QueryExecutor { public boolean execute(MethodReferencesSearch.SearchParameters p, final Processor consumer) { - final PsiMethod method = p.getMethod(); - final SearchScope searchScope = p.getScope(); - return GroovyConstructorUsagesSearchHelper.execute(method, searchScope, consumer); + return GroovyConstructorUsagesSearchHelper.processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer()); } } From 080ab7ce655e6eaf4becfa8539ebbb57266a1ebe Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 28 Jul 2010 00:04:21 +0100 Subject: [PATCH 10/13] optimized java constructor usage searcher --- .../ConstructorReferencesSearchHelper.java | 68 ++++++------------- .../search/ConstructorReferencesSearcher.java | 16 +++-- .../psi/impl/search/MethodUsagesSearcher.java | 57 ++++++---------- .../psi/search/searches/ReferencesSearch.java | 9 +++ 4 files changed, 60 insertions(+), 90 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java b/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java index 3d9715e89932..bbad1ed8e70a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java @@ -3,17 +3,15 @@ */ package com.intellij.psi.impl.search; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadActionProcessor; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMemberReference; import com.intellij.psi.search.PsiSearchScopeUtil; +import com.intellij.psi.search.SearchRequestCollector; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.util.PairProcessor; import com.intellij.util.Processor; /** @@ -30,38 +28,29 @@ public class ConstructorReferencesSearchHelper { final PsiMethod constructor, final SearchScope searchScope, boolean ignoreAccessScope, - final boolean isStrictSignatureSearch) { - final Ref result = new Ref(); - PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable() { - public PsiClass compute() { - PsiClass aClass = constructor.getContainingClass(); - if (aClass == null) { - result.set(true); - return null; - } + final boolean isStrictSignatureSearch, SearchRequestCollector collector) { + PsiClass aClass = constructor.getContainingClass(); + if (aClass == null) { + return true; + } - if (aClass.isEnum()) { - PsiField[] fields = aClass.getFields(); - for (PsiField field : fields) { - if (field instanceof PsiEnumConstant) { - PsiReference reference = field.getReference(); - if (reference != null && reference.isReferenceTo(constructor)) { - if (!processor.process(reference)) { - result.set(false); - return null; - } - } + if (aClass.isEnum()) { + for (PsiField field : aClass.getFields()) { + if (field instanceof PsiEnumConstant) { + PsiReference reference = field.getReference(); + if (reference != null && reference.isReferenceTo(constructor)) { + if (!processor.process(reference)) { + return false; } } } - return aClass; } - }); - if (!result.isNull()) return result.get(); + } // search usages like "new XXX(..)" - Processor processor1 = new ReadActionProcessor() { - public boolean processInReadAction(final PsiReference reference) { + PairProcessor processor1 = new PairProcessor() { + @Override + public boolean process(PsiReference reference, SearchRequestCollector collector) { PsiElement parent = reference.getElement().getParent(); if (parent instanceof PsiAnonymousClass) { parent = parent.getParent(); @@ -85,12 +74,12 @@ public class ConstructorReferencesSearchHelper { } }; - if (!ReferencesSearch.search(aClass, searchScope, ignoreAccessScope).forEach(processor1)) return false; + ReferencesSearch.searchOptimized(aClass, searchScope, ignoreAccessScope, collector, true, processor1); final boolean constructorCanBeCalledImplicitly = constructor.getParameterList().getParametersCount() == 0; // search usages like "this(..)" if (!processSuperOrThis(processor, aClass, constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch, - PsiKeyword.THIS)) { + PsiKeyword.THIS)) { return false; } @@ -98,7 +87,7 @@ public class ConstructorReferencesSearchHelper { Processor processor2 = new Processor() { public boolean process(PsiClass inheritor) { return processSuperOrThis(processor, (PsiClass)inheritor.getNavigationElement(), constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch, - PsiKeyword.SUPER); + PsiKeyword.SUPER); } }; @@ -110,21 +99,6 @@ public class ConstructorReferencesSearchHelper { final PsiMethod constructor, final boolean constructorCanBeCalledImplicitly, final SearchScope searchScope, final boolean isStrictSignatureSearch, final String superOrThisKeyword) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - public Boolean compute() { - return processSuperOrThisInReadAction(inheritor, searchScope, superOrThisKeyword, isStrictSignatureSearch, constructor, - constructorCanBeCalledImplicitly, processor); - } - }); - } - - private boolean processSuperOrThisInReadAction(final PsiClass inheritor, - final SearchScope searchScope, - final String superOrThisKeyword, - final boolean isStrictSignatureSearch, - final PsiMethod constructor, - final boolean constructorCanBeCalledImplicitly, - final Processor processor) { PsiMethod[] constructors = inheritor.getConstructors(); if (constructors.length == 0 && constructorCanBeCalledImplicitly) { processImplicitConstructorCall(inheritor, processor, constructor, inheritor); diff --git a/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearcher.java b/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearcher.java index acb87007dc39..85382259fdb0 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearcher.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearcher.java @@ -3,24 +3,28 @@ */ package com.intellij.psi.impl.search; +import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.util.Processor; -import com.intellij.util.QueryExecutor; /** * @author max */ -public class ConstructorReferencesSearcher implements QueryExecutor { - public boolean execute(final ReferencesSearch.SearchParameters p, final Processor consumer) { +public class ConstructorReferencesSearcher extends QueryExecutorBase { + protected ConstructorReferencesSearcher() { + super(true); + } + + @Override + public void processQuery(ReferencesSearch.SearchParameters p, Processor consumer) { final PsiElement element = p.getElementToSearch(); if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) { - return new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject())) - .processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true); + new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject())) + .processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true, p.getOptimizer()); } - return true; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java b/java/java-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java index a09f590f3c08..2e51faa888d2 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/MethodUsagesSearcher.java @@ -3,9 +3,7 @@ */ package com.intellij.psi.impl.search; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.QueryExecutorBase; -import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.search.SearchRequestCollector; import com.intellij.psi.search.SearchScope; @@ -18,6 +16,9 @@ import com.intellij.util.Processor; * @author max */ public class MethodUsagesSearcher extends QueryExecutorBase { + protected MethodUsagesSearcher() { + super(true); + } @Override public void processQuery(MethodReferencesSearch.SearchParameters p, Processor consumer) { @@ -28,60 +29,42 @@ public class MethodUsagesSearcher extends QueryExecutorBase() { - public PsiClass compute() { - return method.isValid() ? method.getContainingClass() : null; - } - }); + final PsiClass aClass = method.getContainingClass(); if (aClass == null) return; final boolean strictSignatureSearch = p.isStrictSignatureSearch(); if (method.isConstructor()) { - collector.searchCustom(new Processor>() { - public boolean process(Processor consumer) { - return new ConstructorReferencesSearchHelper(psiManager). - processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch); - } - }); + new ConstructorReferencesSearchHelper(psiManager). + processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch, collector); } - boolean needStrictSignatureSearch = ApplicationManager.getApplication().runReadAction(new Computable() { - public Boolean compute() { - return method.isValid() && strictSignatureSearch && (aClass instanceof PsiAnonymousClass + boolean needStrictSignatureSearch = strictSignatureSearch && (aClass instanceof PsiAnonymousClass || aClass.hasModifierProperty(PsiModifier.FINAL) || method.hasModifierProperty(PsiModifier.STATIC) || method.hasModifierProperty(PsiModifier.FINAL) || method.hasModifierProperty(PsiModifier.PRIVATE)); - } - }); if (needStrictSignatureSearch) { - ReferencesSearch.search(new ReferencesSearch.SearchParameters(method, searchScope, false, collector)).forEach(consumer); + ReferencesSearch.searchOptimized(method, searchScope, false, collector, consumer); return; } - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (!method.isValid()) return; + final String textToSearch = method.getName(); + final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false); - final String textToSearch = method.getName(); - final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false); + SearchScope accessScope = methods[0].getUseScope(); + for (int i = 1; i < methods.length; i++) { + PsiMethod method1 = methods[i]; + accessScope = accessScope.union(method1.getUseScope()); + } - SearchScope accessScope = methods[0].getUseScope(); - for (int i = 1; i < methods.length; i++) { - PsiMethod method1 = methods[i]; - accessScope = accessScope.union(method1.getUseScope()); - } + final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope); - final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope); + short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES; + collector.searchWord(textToSearch, restrictedByAccess, searchContext, true, + new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods)); - short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES; - collector.searchWord(textToSearch, restrictedByAccess, searchContext, true, - new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods)); - - SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector); - } - }); + SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector); } diff --git a/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java b/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java index e2dc5c6ff22f..aa869f7b507c 100644 --- a/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java +++ b/platform/lang-api/src/com/intellij/psi/search/searches/ReferencesSearch.java @@ -108,6 +108,15 @@ public class ReferencesSearch extends ExtensibleQueryFactory processor) { + searchOptimized(element, searchScope, ignoreAccessScope, collector, false, new PairProcessor() { + @Override + public boolean process(PsiReference psiReference, SearchRequestCollector collector) { + return processor.process(psiReference); + } + }); + } public static void searchOptimized(@NotNull PsiElement element, @NotNull SearchScope searchScope, boolean ignoreAccessScope, @NotNull SearchRequestCollector collector, final boolean inReadAction, PairProcessor processor) { final SearchRequestCollector nested = new SearchRequestCollector(); From eec6830c3fb2da2b2e1dda738ef1be0065a548b3 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 28 Jul 2010 00:29:39 +0100 Subject: [PATCH 11/13] if there are no files containing a word, don't change the find usages progress indicator text --- .../src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 24e17f5319c4..878523e34bd8 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -555,6 +555,10 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { final MultiMap candidateFiles = collectFiles(singles); + if (candidateFiles.isEmpty()) { + return true; + } + final Map searchers = new HashMap(); final Set allWords = new TreeSet(); for (RequestWithProcessor singleRequest : candidateFiles.values()) { From 27e3ada8a0f47f83e13b0db3e7223d43c74fbc71 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 28 Jul 2010 23:16:03 +0100 Subject: [PATCH 12/13] remove GroovyConstructorUsagesSearchHelper, move logic to the searcher, read-action it --- .../ConstructorReferencesSearcher.java | 14 +- .../GroovyConstructorUsagesSearchHelper.java | 415 ------------------ .../GroovyConstructorUsagesSearcher.java | 385 +++++++++++++++- 3 files changed, 389 insertions(+), 425 deletions(-) delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java index 6af2559d1122..1774fa1970d4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java @@ -15,26 +15,30 @@ */ package org.jetbrains.plugins.groovy.findUsages; +import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.util.Processor; -import com.intellij.util.QueryExecutor; /** * @author ven */ -public class ConstructorReferencesSearcher implements QueryExecutor { - public boolean execute(ReferencesSearch.SearchParameters queryParameters, final Processor consumer) { +public class ConstructorReferencesSearcher extends QueryExecutorBase { + protected ConstructorReferencesSearcher() { + super(true); + } + + @Override + public void processQuery(ReferencesSearch.SearchParameters queryParameters, Processor consumer) { final PsiElement element = queryParameters.getElementToSearch(); if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod)element; if (method.isConstructor()) { - return GroovyConstructorUsagesSearchHelper.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer()); + GroovyConstructorUsagesSearcher.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer()); } } - return true; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java deleted file mode 100644 index 8b5765b7a1cd..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearchHelper.java +++ /dev/null @@ -1,415 +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 org.jetbrains.plugins.groovy.findUsages; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.NullableComputable; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.impl.light.LightMemberReference; -import com.intellij.psi.search.*; -import com.intellij.psi.search.searches.AnnotatedElementsSearch; -import com.intellij.psi.search.searches.DirectClassInheritorsSearch; -import com.intellij.psi.search.searches.MethodReferencesSearch; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.PairProcessor; -import com.intellij.util.Processor; -import com.intellij.util.containers.ConcurrentHashSet; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; -import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; -import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; -import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; -import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Maxim.Medvedev - * Date: May 2, 2009 3:48:53 PM - */ -public class GroovyConstructorUsagesSearchHelper { - private GroovyConstructorUsagesSearchHelper() { - } - - public static boolean processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector) { - if (!constructor.isConstructor()) return true; - - SearchScope onlyGroovy = searchScope; - if (onlyGroovy instanceof GlobalSearchScope) { - onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE); - } - - final PsiClass clazz = ApplicationManager.getApplication().runReadAction(new NullableComputable() { - public PsiClass compute() { - return constructor.getContainingClass(); - } - }); - if (clazz == null) return true; - - - //enum constants - if (!ApplicationManager.getApplication().runReadAction(new Computable() { - public Boolean compute() { - if (!clazz.isEnum()) return true; - if (!(clazz instanceof GroovyPsiElement)) return true; - final PsiField[] fields = clazz.getFields(); - for (PsiField field : fields) { - if (field instanceof GrEnumConstant) { - final PsiReference ref = field.getReference(); - if (ref.isReferenceTo(constructor)) { - if (!consumer.process(ref)) return false; - } - } - } - return true; - } - })) { - return false; - } - - - final Set processedMethods = new ConcurrentHashSet(); - - ReferencesSearch.searchOptimized(clazz, searchScope, true, collector, true, new PairProcessor() { - @Override - public boolean process(PsiReference ref, SearchRequestCollector collector) { - return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope, collector); - } - }); - - //this() - if (clazz instanceof GrTypeDefinition) { - if (!processConstructors(constructor, consumer, clazz, true)) { - return false; - } - } - //super : does not work now, need to invent a way for it to work without repository - if (!DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor() { - public boolean process(PsiClass inheritor) { - if (inheritor instanceof GrTypeDefinition) { - if (!processConstructors(constructor, consumer, inheritor, false)) return false; - } - return true; - } - })) { - return false; - } - - return true; - } - - @Nullable - private static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass clazz, Set processedMethods) { - final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class); - if (parameter != null) { - final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); - if (method != null && processedMethods.add(method) && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) { - final PsiType parameterType = parameter.getType(); - if (parameterType instanceof PsiClassType) { - if (method.getManager().areElementsEquivalent(clazz, ((PsiClassType)parameterType).resolve())) { - return method; - } - } - } - } - return null; - } - - private static boolean processClassReference(final PsiReference ref, - final PsiClass clazz, - final PsiMethod constructor, - final Processor consumer, - final Set processedMethods, SearchScope scope, SearchRequestCollector collector) { - final PsiElement element = ref.getElement(); - if (element instanceof GrCodeReferenceElement) { - if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref)) { - return false; - } - - } - - final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); - if (method != null) { - final GlobalSearchScope gppScope = getGppScope(clazz.getProject()); - MethodReferencesSearch.searchOptimized(method, gppScope.intersectWith(scope), true, collector, true, new PairProcessor() { - @Override - public boolean process(PsiReference psiReference, SearchRequestCollector collector) { - if (psiReference instanceof GrReferenceElement) { - final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); - if (parent instanceof GrCall) { - final GrArgumentList argList = ((GrCall)parent).getArgumentList(); - if (argList != null) { - boolean checkedTypedContext = false; - - for (GrExpression argument : argList.getExpressionArguments()) { - if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) { - if (!checkedTypedContext) { - if (!GppTypeConverter.hasTypedContext(parent)) { - return true; - } - checkedTypedContext = true; - } - - for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) { - if (psiType instanceof PsiClassType && - clazz.getManager().areElementsEquivalent(clazz,((PsiClassType)psiType).resolve()) && - !checkListInstantiation(constructor, consumer, (GrListOrMap)argument, (PsiClassType)psiType)) { - return false; - } - } - } - } - } - } - } - return true; - } - }); - } - - return true; - } - - private static GlobalSearchScope getGppScope(final Project project) { - return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider() { - @Override - public Result compute() { - return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project)); - } - }); - } - - private static boolean processGroovyConstructorUsages(GrCodeReferenceElement element, - final PsiMethod constructor, - final Processor consumer, - PsiReference ref) { - PsiElement parent = element.getParent(); - - if (parent instanceof GrAnonymousClassDefinition) { - parent = parent.getParent(); - } - if (parent instanceof GrNewExpression) { - final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor(); - if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) { - return false; - } - } - else if (parent instanceof GrTypeElement) { - final GrTypeElement typeElement = (GrTypeElement)parent; - - final PsiElement grandpa = typeElement.getParent(); - if (grandpa instanceof GrVariableDeclaration) { - final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables(); - if (vars.length == 1) { - final GrVariable variable = vars[0]; - if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) { - return false; - } - } - } - else if (grandpa instanceof GrMethod) { - final GrMethod method = (GrMethod)grandpa; - if (typeElement == method.getReturnTypeElementGroovy()) { - ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() { - @Override - public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { - if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) { - return false; - } - return true; - } - }); - } - } - else if (grandpa instanceof GrTypeCastExpression) { - final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa; - if (cast.getCastTypeElement() == typeElement && - !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { - return false; - } - } - else if (grandpa instanceof GrSafeCastExpression) { - final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa; - if (cast.getCastTypeElement() == typeElement && - !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { - return false; - } - } - } - return true; - } - - private static GlobalSearchScope calcGppScope(Project project) { - final GlobalSearchScope allScope = GlobalSearchScope.allScope(project); - final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE); - GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) { - @Override - public boolean contains(VirtualFile file) { - return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension()); - } - }; - final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope); - if (typed != null) { - final Set files = new HashSet(); - AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor() { - @Override - public boolean process(PsiModifierListOwner occurrence) { - ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files); - return true; - } - }); - - GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files); - return withTypedAnno.union(gppExtensions); - } - - return gppExtensions; - } - - private static boolean checkListInstantiation(PsiMethod constructor, - Processor consumer, - GrExpression expression, final GrTypeElement typeElement) { - if (expression instanceof GrListOrMap) { - final GrListOrMap list = (GrListOrMap)expression; - if (!list.isMap()) { - final PsiType expectedType = typeElement.getType(); - if (expectedType instanceof PsiClassType) { - return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType); - } - } - } - return true; - } - - private static boolean checkListInstantiation(PsiMethod constructor, - Processor consumer, - GrListOrMap list, - PsiClassType expectedType) { - final PsiType listType = list.getType(); - if (listType instanceof GrTupleType) { - for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) { - if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { - if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { - return false; - } - } - } - } - return true; - } - - private static boolean processConstructors(final PsiMethod constructor, final Processor consumer, final PsiClass clazz, - final boolean processThisRefs) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - public Boolean compute() { - return processClassConstructors(clazz, constructor, consumer, processThisRefs); - } - }); - } - - private static boolean processClassConstructors(PsiClass clazz, - PsiMethod searchedConstructor, - Processor consumer, - boolean processThisRefs) { - final PsiMethod[] constructors = clazz.getConstructors(); - if (constructors.length == 0) { - processImplicitConstructorCall(clazz, consumer, searchedConstructor); - } - for (PsiMethod constructor : constructors) { - final GrOpenBlock block = ((GrMethod)constructor).getBlock(); - if (block != null) { - final GrStatement[] statements = block.getStatements(); - if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) { - final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0]; - if (invocation.isThisCall() == processThisRefs && - invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) && - !consumer.process(invocation)) { - return false; - } - } - else { - processImplicitConstructorCall(constructor, consumer, searchedConstructor); - } - } - } - return true; - } - - private static void processImplicitConstructorCall(final PsiMember usage, - final Processor processor, - final PsiMethod constructor) { - if (constructor instanceof GrMethod) { - GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters(); - if (grParameters.length > 0 && !grParameters[0].isOptional()) return; - } - else if (constructor.getParameterList().getParameters().length > 0) return; - - - PsiManager manager = constructor.getManager(); - if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return; - processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) { - public PsiElement getElement() { - return usage; - } - - public TextRange getRangeInElement() { - if (usage instanceof PsiClass) { - PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier(); - if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength()); - } - else if (usage instanceof PsiMethod) { - PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier(); - if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength()); - } - return super.getRangeInElement(); - } - }); - - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java index 8a2a8ebbfa36..4b1c7a9515fc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyConstructorUsagesSearcher.java @@ -16,16 +16,391 @@ package org.jetbrains.plugins.groovy.findUsages; -import com.intellij.psi.PsiReference; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.QueryExecutorBase; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightMemberReference; +import com.intellij.psi.search.DelegatingGlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.SearchRequestCollector; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.searches.AnnotatedElementsSearch; +import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.PairProcessor; import com.intellij.util.Processor; -import com.intellij.util.QueryExecutor; +import com.intellij.util.containers.ConcurrentHashSet; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** * @author Maxim.Medvedev */ -public class GroovyConstructorUsagesSearcher implements QueryExecutor { - public boolean execute(MethodReferencesSearch.SearchParameters p, final Processor consumer) { - return GroovyConstructorUsagesSearchHelper.processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer()); +public class GroovyConstructorUsagesSearcher extends QueryExecutorBase { + public GroovyConstructorUsagesSearcher() { + super(true); } + + @Override + public void processQuery(MethodReferencesSearch.SearchParameters p, Processor consumer) { + processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer()); + } + + static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector) { + if (!constructor.isConstructor()) return; + + SearchScope onlyGroovy = searchScope; + if (onlyGroovy instanceof GlobalSearchScope) { + onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE); + } + + final PsiClass clazz = constructor.getContainingClass(); + if (clazz == null) return; + + + if (clazz.isEnum() && clazz instanceof GroovyPsiElement) { + for (PsiField field : clazz.getFields()) { + if (field instanceof GrEnumConstant) { + final PsiReference ref = field.getReference(); + if (ref != null && ref.isReferenceTo(constructor)) { + if (!consumer.process(ref)) return; + } + } + } + } + + final Set processedMethods = new ConcurrentHashSet(); + + ReferencesSearch.searchOptimized(clazz, searchScope, true, collector, true, new PairProcessor() { + @Override + public boolean process(PsiReference ref, SearchRequestCollector collector) { + return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope, collector); + } + }); + + //this() + if (clazz instanceof GrTypeDefinition) { + if (!processConstructors(constructor, consumer, clazz, true)) { + return; + } + } + //super() + DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor() { + public boolean process(PsiClass inheritor) { + if (inheritor instanceof GrTypeDefinition) { + if (!processConstructors(constructor, consumer, inheritor, false)) return false; + } + return true; + } + }); + } + + @Nullable + static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass clazz, Set processedMethods) { + final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class); + if (parameter != null) { + final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); + if (method != null && processedMethods.add(method) && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) { + final PsiType parameterType = parameter.getType(); + if (parameterType instanceof PsiClassType) { + if (method.getManager().areElementsEquivalent(clazz, ((PsiClassType)parameterType).resolve())) { + return method; + } + } + } + } + return null; + } + + static boolean processClassReference(final PsiReference ref, + final PsiClass clazz, + final PsiMethod constructor, + final Processor consumer, + final Set processedMethods, SearchScope scope, SearchRequestCollector collector) { + final PsiElement element = ref.getElement(); + if (element instanceof GrCodeReferenceElement) { + if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref)) { + return false; + } + + } + + final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); + if (method != null) { + final GlobalSearchScope gppScope = getGppScope(clazz.getProject()); + MethodReferencesSearch.searchOptimized(method, gppScope.intersectWith(scope), true, collector, true, new PairProcessor() { + @Override + public boolean process(PsiReference psiReference, SearchRequestCollector collector) { + if (psiReference instanceof GrReferenceElement) { + final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); + if (parent instanceof GrCall) { + final GrArgumentList argList = ((GrCall)parent).getArgumentList(); + if (argList != null) { + boolean checkedTypedContext = false; + + for (GrExpression argument : argList.getExpressionArguments()) { + if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) { + if (!checkedTypedContext) { + if (!GppTypeConverter.hasTypedContext(parent)) { + return true; + } + checkedTypedContext = true; + } + + for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) { + if (psiType instanceof PsiClassType && + clazz.getManager().areElementsEquivalent(clazz,((PsiClassType)psiType).resolve()) && + !checkListInstantiation(constructor, consumer, (GrListOrMap)argument, (PsiClassType)psiType)) { + return false; + } + } + } + } + } + } + } + return true; + } + }); + } + + return true; + } + + static GlobalSearchScope getGppScope(final Project project) { + return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider() { + @Override + public Result compute() { + return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project)); + } + }); + } + + static boolean processGroovyConstructorUsages(GrCodeReferenceElement element, + final PsiMethod constructor, + final Processor consumer, + PsiReference ref) { + PsiElement parent = element.getParent(); + + if (parent instanceof GrAnonymousClassDefinition) { + parent = parent.getParent(); + } + if (parent instanceof GrNewExpression) { + final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor(); + if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) { + return false; + } + } + else if (parent instanceof GrTypeElement) { + final GrTypeElement typeElement = (GrTypeElement)parent; + + final PsiElement grandpa = typeElement.getParent(); + if (grandpa instanceof GrVariableDeclaration) { + final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables(); + if (vars.length == 1) { + final GrVariable variable = vars[0]; + if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) { + return false; + } + } + } + else if (grandpa instanceof GrMethod) { + final GrMethod method = (GrMethod)grandpa; + if (typeElement == method.getReturnTypeElementGroovy()) { + ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() { + @Override + public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { + if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) { + return false; + } + return true; + } + }); + } + } + else if (grandpa instanceof GrTypeCastExpression) { + final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa; + if (cast.getCastTypeElement() == typeElement && + !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + return false; + } + } + else if (grandpa instanceof GrSafeCastExpression) { + final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa; + if (cast.getCastTypeElement() == typeElement && + !checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) { + return false; + } + } + } + return true; + } + + static GlobalSearchScope calcGppScope(Project project) { + final GlobalSearchScope allScope = GlobalSearchScope.allScope(project); + final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE); + GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) { + @Override + public boolean contains(VirtualFile file) { + return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension()); + } + }; + final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope); + if (typed != null) { + final Set files = new HashSet(); + AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor() { + @Override + public boolean process(PsiModifierListOwner occurrence) { + ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files); + return true; + } + }); + + GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files); + return withTypedAnno.union(gppExtensions); + } + + return gppExtensions; + } + + static boolean checkListInstantiation(PsiMethod constructor, + Processor consumer, + GrExpression expression, final GrTypeElement typeElement) { + if (expression instanceof GrListOrMap) { + final GrListOrMap list = (GrListOrMap)expression; + if (!list.isMap()) { + final PsiType expectedType = typeElement.getType(); + if (expectedType instanceof PsiClassType) { + return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType); + } + } + } + return true; + } + + static boolean checkListInstantiation(PsiMethod constructor, + Processor consumer, + GrListOrMap list, + PsiClassType expectedType) { + final PsiType listType = list.getType(); + if (listType instanceof GrTupleType) { + for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) { + if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) { + if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) { + return false; + } + } + } + } + return true; + } + + static boolean processConstructors(final PsiMethod constructor, final Processor consumer, final PsiClass clazz, + final boolean processThisRefs) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + public Boolean compute() { + return processClassConstructors(clazz, constructor, consumer, processThisRefs); + } + }); + } + + static boolean processClassConstructors(PsiClass clazz, + PsiMethod searchedConstructor, + Processor consumer, + boolean processThisRefs) { + final PsiMethod[] constructors = clazz.getConstructors(); + if (constructors.length == 0) { + processImplicitConstructorCall(clazz, consumer, searchedConstructor); + } + for (PsiMethod constructor : constructors) { + final GrOpenBlock block = ((GrMethod)constructor).getBlock(); + if (block != null) { + final GrStatement[] statements = block.getStatements(); + if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) { + final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0]; + if (invocation.isThisCall() == processThisRefs && + invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) && + !consumer.process(invocation)) { + return false; + } + } + else { + processImplicitConstructorCall(constructor, consumer, searchedConstructor); + } + } + } + return true; + } + + static void processImplicitConstructorCall(final PsiMember usage, + final Processor processor, + final PsiMethod constructor) { + if (constructor instanceof GrMethod) { + GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters(); + if (grParameters.length > 0 && !grParameters[0].isOptional()) return; + } + else if (constructor.getParameterList().getParameters().length > 0) return; + + + PsiManager manager = constructor.getManager(); + if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return; + processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) { + public PsiElement getElement() { + return usage; + } + + public TextRange getRangeInElement() { + if (usage instanceof PsiClass) { + PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier(); + if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength()); + } + else if (usage instanceof PsiMethod) { + PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier(); + if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength()); + } + return super.getRangeInElement(); + } + }); + + } + } From 0130db72e18dcc5a8d0466e3ea0902d8b83d5961 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 28 Jul 2010 23:47:44 +0100 Subject: [PATCH 13/13] more efficient literals in g++ calls search --- .../searches/MethodReferencesSearch.java | 17 ++- .../ConstructorReferencesSearcher.java | 2 +- .../GroovyConstructorUsagesSearcher.java | 108 ++++++++++-------- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java b/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java index a29b98613b42..dfa15c5399c4 100644 --- a/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java +++ b/java/openapi/src/com/intellij/psi/search/searches/MethodReferencesSearch.java @@ -18,11 +18,9 @@ package com.intellij.psi.search.searches; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; import com.intellij.psi.search.*; -import com.intellij.util.MergeQuery; -import com.intellij.util.PairProcessor; -import com.intellij.util.Query; -import com.intellij.util.UniqueResultsQuery; +import com.intellij.util.*; import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -73,7 +71,16 @@ public class MethodReferencesSearch extends ExtensibleQueryFactory processor) { + public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch, + @NotNull SearchRequestCollector collector, final Processor processor) { + searchOptimized(method, scope, strictSignatureSearch, collector, false, new PairProcessor() { + @Override + public boolean process(PsiReference psiReference, SearchRequestCollector collector) { + return processor.process(psiReference); + } + }); + } +public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch, SearchRequestCollector collector, final boolean inReadAction, PairProcessor processor) { final SearchRequestCollector nested = new SearchRequestCollector(); collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(method, scope, strictSignatureSearch, nested)), nested, inReadAction, processor)); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java index 1774fa1970d4..1e8ee89c70ff 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/ConstructorReferencesSearcher.java @@ -36,7 +36,7 @@ public class ConstructorReferencesSearcher extends QueryExecutorBase consumer) { - processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer()); + processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer(), true); } - static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector) { + static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor consumer, final SearchRequestCollector collector, final boolean searchGppCalls) { if (!constructor.isConstructor()) return; SearchScope onlyGroovy = searchScope; @@ -113,7 +115,20 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase() { @Override public boolean process(PsiReference ref, SearchRequestCollector collector) { - return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope, collector); + final PsiElement element = ref.getElement(); + if (element instanceof GrCodeReferenceElement) { + if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref, !searchGppCalls)) { + return false; + } + } + + if (searchGppCalls) { + final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz); + if (method != null && processedMethods.add(method)) { + processGppMethodCalls(clazz, constructor, consumer, searchScope, collector, method); + } + } + return true; } }); @@ -135,14 +150,14 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase processedMethods) { + static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass targetClass) { final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class); if (parameter != null) { final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); - if (method != null && processedMethods.add(method) && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) { + if (method != null && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) { final PsiType parameterType = parameter.getType(); if (parameterType instanceof PsiClassType) { - if (method.getManager().areElementsEquivalent(clazz, ((PsiClassType)parameterType).resolve())) { + if (method.getManager().areElementsEquivalent(targetClass, ((PsiClassType)parameterType).resolve())) { return method; } } @@ -151,59 +166,52 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase consumer, - final Set processedMethods, SearchScope scope, SearchRequestCollector collector) { - final PsiElement element = ref.getElement(); - if (element instanceof GrCodeReferenceElement) { - if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref)) { - return false; - } + private static void processGppMethodCalls(final PsiClass targetClass, + final PsiMethod originalTarget, + final Processor originalProcessor, + SearchScope scope, + SearchRequestCollector originalCollector, @NotNull PsiMethod currentTarget) { + final SearchScope gppScope = getGppScope(targetClass.getProject()).intersectWith(scope); + final ReadActionProcessor gppCallProcessor = new ReadActionProcessor() { + @Override + public boolean processInReadAction(PsiReference psiReference) { + if (psiReference instanceof GrReferenceElement) { + final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); + if (parent instanceof GrCall) { + final GrArgumentList argList = ((GrCall)parent).getArgumentList(); + if (argList != null) { + boolean checkedTypedContext = false; - } - - final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods); - if (method != null) { - final GlobalSearchScope gppScope = getGppScope(clazz.getProject()); - MethodReferencesSearch.searchOptimized(method, gppScope.intersectWith(scope), true, collector, true, new PairProcessor() { - @Override - public boolean process(PsiReference psiReference, SearchRequestCollector collector) { - if (psiReference instanceof GrReferenceElement) { - final PsiElement parent = ((GrReferenceElement)psiReference).getParent(); - if (parent instanceof GrCall) { - final GrArgumentList argList = ((GrCall)parent).getArgumentList(); - if (argList != null) { - boolean checkedTypedContext = false; - - for (GrExpression argument : argList.getExpressionArguments()) { - if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) { - if (!checkedTypedContext) { - if (!GppTypeConverter.hasTypedContext(parent)) { - return true; - } - checkedTypedContext = true; + for (GrExpression argument : argList.getExpressionArguments()) { + if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) { + if (!checkedTypedContext) { + if (!GppTypeConverter.hasTypedContext(parent)) { + return true; } + checkedTypedContext = true; + } - for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) { - if (psiType instanceof PsiClassType && - clazz.getManager().areElementsEquivalent(clazz,((PsiClassType)psiType).resolve()) && - !checkListInstantiation(constructor, consumer, (GrListOrMap)argument, (PsiClassType)psiType)) { - return false; - } + for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) { + if (psiType instanceof PsiClassType && + targetClass.getManager().areElementsEquivalent(targetClass, ((PsiClassType)psiType).resolve()) && + !checkListInstantiation(originalTarget, originalProcessor, (GrListOrMap)argument, (PsiClassType)psiType)) { + return false; } } } } } } - return true; } - }); + return true; + } + }; + if (currentTarget.isConstructor()) { + processConstructorUsages(currentTarget, gppScope, gppCallProcessor, originalCollector, false); + } + else { + MethodReferencesSearch.searchOptimized(currentTarget, gppScope, true, originalCollector, gppCallProcessor); } - - return true; } static GlobalSearchScope getGppScope(final Project project) { @@ -218,7 +226,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase consumer, - PsiReference ref) { + PsiReference ref, boolean usualCallsOnly) { PsiElement parent = element.getParent(); if (parent instanceof GrAnonymousClassDefinition) { @@ -230,7 +238,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase