From 53e76d1f85f92814945464cd72a766793046297a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 6 Feb 2017 15:36:46 +0300 Subject: [PATCH 1/7] [groovy] more @NotNull/@Nullable, cleanup, fix some constant conditions warnings, get rid of wilcards in Iterable generics --- .../psi/controlFlow/AfterCallInstruction.java | 10 +++++-- .../lang/psi/controlFlow/CallEnvironment.java | 13 +++++---- .../lang/psi/controlFlow/CallInstruction.java | 10 +++++-- .../lang/psi/controlFlow/GotoInstruction.java | 3 +- .../controlFlow/InstanceOfInstruction.java | 17 +++++++++-- .../lang/psi/controlFlow/Instruction.java | 18 ++++++++---- .../controlFlow/NegatingGotoInstruction.java | 3 +- .../ReadWriteVariableInstruction.java | 3 +- .../psi/controlFlow/ReturnInstruction.java | 9 ++++-- .../controlFlow/impl/ArgumentInstruction.java | 19 +++++++----- .../impl/ConditionInstruction.java | 3 +- .../psi/controlFlow/impl/FakeInstruction.java | 27 ----------------- .../controlFlow/impl/IfEndInstruction.java | 6 +++- .../psi/controlFlow/impl/InstructionImpl.java | 29 ++++++++++--------- .../groovy/lang/psi/dataFlow/DFAEngine.java | 14 +++++---- 15 files changed, 104 insertions(+), 80 deletions(-) delete mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/FakeInstruction.java diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/AfterCallInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/AfterCallInstruction.java index 994762cea169..13c418b3b21e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/AfterCallInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/AfterCallInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; import java.util.Collections; @@ -35,17 +36,20 @@ public class AfterCallInstruction extends InstructionImpl { return super.toString() + "AFTER CALL " + myCall.num(); } + @NotNull @Override - public Iterable allPredecessors() { + public Iterable allPredecessors() { return Collections.singletonList(myReturnInstruction); } + @NotNull @Override - public Iterable predecessors(CallEnvironment environment) { + public Iterable predecessors(@NotNull CallEnvironment environment) { environment.callStack(myReturnInstruction).push(myCall); return Collections.singletonList(myReturnInstruction); } + @NotNull @Override protected String getElementPresentation() { return ""; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallEnvironment.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallEnvironment.java index 3766b9eefa50..9742a1dd919b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallEnvironment.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,18 +15,21 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; +import org.jetbrains.annotations.NotNull; + import java.util.Deque; /** + * @author ven * @see org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder#visitTryStatement(org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTryCatchStatement) * @see ReturnInstruction#successors(CallEnvironment) * @see CallInstruction#successors(CallEnvironment) * @see AfterCallInstruction#predecessors(CallEnvironment) - * - * @author ven */ public interface CallEnvironment { - Deque callStack(Instruction instruction); - void update(Deque callStack, Instruction instruction); + @NotNull + Deque callStack(@NotNull Instruction instruction); + + void update(@NotNull Deque callStack, @NotNull Instruction instruction); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallInstruction.java index 141db913bc27..2fd4151dafec 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/CallInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; import java.util.Collections; @@ -34,17 +35,20 @@ public class CallInstruction extends InstructionImpl { return super.toString() + " CALL " + myCallee.num(); } + @NotNull @Override - public Iterable successors(CallEnvironment environment) { + public Iterable successors(@NotNull CallEnvironment environment) { environment.callStack(myCallee).push(this); return Collections.singletonList(myCallee); } + @NotNull @Override - public Iterable allSuccessors() { + public Iterable allSuccessors() { return Collections.singletonList(myCallee); } + @NotNull @Override protected String getElementPresentation() { return ""; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java index 885ccc0cb14a..dfbd64788c12 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -37,6 +37,7 @@ public abstract class GotoInstruction extends InstructionImpl { return myCondition; } + @NotNull @Override protected String getElementPresentation() { return " Positive goto instruction, condition=" + myCondition.num() + getElement(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/InstanceOfInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/InstanceOfInstruction.java index b4076800587e..3c9b2548d4c3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/InstanceOfInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/InstanceOfInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -28,17 +29,26 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ConditionInstruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; +import java.util.Objects; + /** * @author peter */ public class InstanceOfInstruction extends InstructionImpl implements MixinTypeInstruction { private final ConditionInstruction myCondition; - public InstanceOfInstruction(GrExpression assertion, ConditionInstruction cond) { + public InstanceOfInstruction(@NotNull GrExpression assertion, ConditionInstruction cond) { super(assertion); myCondition = cond; } + @NotNull + @Override + public PsiElement getElement() { + return Objects.requireNonNull(super.getElement()); + } + + @NotNull @Override protected String getElementPresentation() { return "instanceof: " + getElement().getText(); @@ -57,6 +67,7 @@ public class InstanceOfInstruction extends InstructionImpl implements MixinTypeI else if (element instanceof GrBinaryExpression && ControlFlowBuilderUtil.isInstanceOfBinary((GrBinaryExpression)element)) { GrExpression left = ((GrBinaryExpression)element).getLeftOperand(); GrExpression right = ((GrBinaryExpression)element).getRightOperand(); + if (right == null) return null; GroovyResolveResult result = ((GrReferenceExpression)right).advancedResolve(); final PsiElement resolved = result.getElement(); if (resolved instanceof PsiClass) { @@ -76,6 +87,7 @@ public class InstanceOfInstruction extends InstructionImpl implements MixinTypeI return instanceOf.getSecond(); } + @Nullable @Override public ReadWriteVariableInstruction getInstructionToMixin(Instruction[] flow) { Pair instanceOf = getInstanceof(); @@ -97,6 +109,7 @@ public class InstanceOfInstruction extends InstructionImpl implements MixinTypeI return instanceOf.getFirst().getText(); } + @Nullable @Override public ConditionInstruction getConditionInstruction() { return myCondition; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java index 80b164256d89..d67595e7e773 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -23,11 +23,18 @@ import org.jetbrains.annotations.Nullable; * @author ven */ public interface Instruction { - Iterable successors(CallEnvironment environment); - Iterable predecessors(CallEnvironment environment); - Iterable allSuccessors(); - Iterable allPredecessors(); + @NotNull + Iterable successors(@NotNull CallEnvironment environment); + + @NotNull + Iterable predecessors(@NotNull CallEnvironment environment); + + @NotNull + Iterable allSuccessors(); + + @NotNull + Iterable allPredecessors(); int num(); @@ -36,5 +43,4 @@ public interface Instruction { @Nullable PsiElement getElement(); - } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java index bfed190e9aab..cc50ee71d8b6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -28,6 +28,7 @@ public class NegatingGotoInstruction extends GotoInstruction { super(element, condition); } + @NotNull @Override protected String getElementPresentation() { return " Negating goto instruction, condition=" + getCondition().num() + getElement(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java index 50be5b1b81f8..9456443b1851 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -45,6 +45,7 @@ public class ReadWriteVariableInstruction extends InstructionImpl { return myIsWrite; } + @NotNull @Override protected String getElementPresentation() { return (isWrite() ? "WRITE " : "READ ") + myName; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReturnInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReturnInstruction.java index c03c580882e1..9ffb8053cb5a 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReturnInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReturnInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrFinallyClause; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; @@ -34,18 +35,20 @@ public class ReturnInstruction extends InstructionImpl { return super.toString() + " RETURN"; } + @NotNull @Override protected String getElementPresentation() { return ""; } + @NotNull @Override - public Iterable successors(CallEnvironment environment) { + public Iterable successors(@NotNull CallEnvironment environment) { final Deque callStack = environment.callStack(this); if (callStack.isEmpty()) return Collections.emptyList(); //can be true in case env was not populated (e.g. by DFA) final CallInstruction callInstruction = callStack.peek(); - final Iterable successors = callInstruction.allSuccessors(); + final Iterable successors = callInstruction.allSuccessors(); final Deque copy = new ArrayDeque<>(callStack); copy.pop(); for (Instruction instruction : successors) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ArgumentInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ArgumentInstruction.java index 9d7215e5593a..76dfc126c94e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ArgumentInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ArgumentInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -81,17 +81,19 @@ public class ArgumentInstruction extends InstructionImpl implements MixinTypeIns return false; } - private static GrCall findCall(PsiElement element) { - PsiElement parent = element.getParent().getParent(); - if (!(parent instanceof GrCall)) { + private static GrCall findCall(@NotNull PsiElement element) { + PsiElement parent = element.getParent(); + PsiElement pParent = parent == null ? null : parent.getParent(); + if (!(pParent instanceof GrCall)) { LOG.error("elemText: " + element.getText() + "\nisValid = " + element.isValid() + - "\nParent = " + (element.getParent() == null ? "null" : element.getParent().getClass()) + - "\nPParent = " + (parent == null ? "null" : parent.getClass())); + "\nParent = " + (parent == null ? "null" : parent.getClass()) + + "\nPParent = " + (pParent == null ? "null" : pParent.getClass())); } - return (GrCall)parent; + return (GrCall)pParent; } + @Nullable @Override public ReadWriteVariableInstruction getInstructionToMixin(Instruction[] flow) { Instruction instruction = ControlFlowUtils.findInstruction(getElement(), flow); @@ -103,17 +105,20 @@ public class ArgumentInstruction extends InstructionImpl implements MixinTypeIns } } + @Nullable @Override public String getVariableName() { //noinspection ConstantConditions return ((GrReferenceExpression)getElement()).getReferenceName(); } + @Nullable @Override public ConditionInstruction getConditionInstruction() { return null; } + @NotNull @Override protected String getElementPresentation() { return "ARGUMENT " + super.getElementPresentation(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java index fa0b5798b040..ad24d98541ce 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -38,6 +38,7 @@ public class ConditionInstruction extends InstructionImpl implements Instruction myDependent.add(this); } + @NotNull @Override protected String getElementPresentation() { StringBuilder builder = new StringBuilder(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/FakeInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/FakeInstruction.java deleted file mode 100644 index 31c8622b31a5..000000000000 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/FakeInstruction.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2000-2014 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.controlFlow.impl; - -import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; - -/** - * @author Max Medvedev - */ -public class FakeInstruction extends InstructionImpl implements Instruction { - public FakeInstruction(int num) { - super(null); - } -} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/IfEndInstruction.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/IfEndInstruction.java index cbd6159f3036..77e87e4a3845 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/IfEndInstruction.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/IfEndInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,8 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement; /** @@ -25,11 +27,13 @@ public class IfEndInstruction extends InstructionImpl{ super(ifStatement); } + @Nullable @Override public GrIfStatement getElement() { return (GrIfStatement)super.getElement(); } + @NotNull @Override protected String getElementPresentation() { return "End element: " + myPsiElement; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java index 82e30f21d329..88b2d401bc22 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -31,8 +31,8 @@ import java.util.LinkedHashSet; * @author ven */ public class InstructionImpl implements Instruction { - private final LinkedHashSet myPredecessors = new LinkedHashSet<>(1); - private final LinkedHashSet mySuccessors = new LinkedHashSet<>(1); + private final LinkedHashSet myPredecessors = new LinkedHashSet<>(1); + private final LinkedHashSet mySuccessors = new LinkedHashSet<>(1); private LinkedHashSet myNegations; protected final PsiElement myPsiElement; @@ -48,33 +48,35 @@ public class InstructionImpl implements Instruction { myPsiElement = element; } + @NotNull @Override - public Iterable successors(CallEnvironment environment) { + public Iterable successors(@NotNull CallEnvironment environment) { final Deque stack = environment.callStack(this); - for (InstructionImpl instruction : mySuccessors) { + for (Instruction instruction : mySuccessors) { environment.update(stack, instruction); } - return mySuccessors; } + @NotNull @Override - public Iterable predecessors(CallEnvironment environment) { + public Iterable predecessors(@NotNull CallEnvironment environment) { final Deque stack = environment.callStack(this); - for (InstructionImpl instruction : myPredecessors) { + for (Instruction instruction : myPredecessors) { environment.update(stack, instruction); } - return myPredecessors; } + @NotNull @Override - public Iterable allSuccessors() { + public Iterable allSuccessors() { return mySuccessors; } + @NotNull @Override - public Iterable allPredecessors() { + public Iterable allPredecessors() { return myPredecessors; } @@ -82,8 +84,8 @@ public class InstructionImpl implements Instruction { final StringBuilder builder = new StringBuilder(); builder.append(myNumber); builder.append("("); - for (InstructionImpl successor : mySuccessors) { - builder.append(successor.myNumber); + for (Instruction successor : mySuccessors) { + builder.append(successor.num()); builder.append(','); } if (!mySuccessors.isEmpty()) builder.delete(builder.length() - 1, builder.length()); @@ -91,6 +93,7 @@ public class InstructionImpl implements Instruction { return builder.toString(); } + @NotNull protected String getElementPresentation() { //return "element: " + (myPsiElement != null ? myPsiElement.getText() : null); return "element: " + myPsiElement; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java index d32e53f53cb7..0f3711014b89 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -37,7 +37,7 @@ public class DFAEngine { private final DfaInstance myDfa; private final Semilattice mySemilattice; - public DFAEngine(Instruction[] flow, DfaInstance dfa, Semilattice semilattice) { + public DFAEngine(@NotNull Instruction[] flow, @NotNull DfaInstance dfa, @NotNull Semilattice semilattice) { myFlow = flow; myDfa = dfa; mySemilattice = semilattice; @@ -53,13 +53,14 @@ public class DFAEngine { } } + @NotNull @Override - public Deque callStack(Instruction instruction) { + public Deque callStack(@NotNull Instruction instruction) { return myEnv.get(instruction.num()); } @Override - public void update(Deque callStack, Instruction instruction) { + public void update(@NotNull Deque callStack, @NotNull Instruction instruction) { myEnv.set(instruction.num(), callStack); } } @@ -136,7 +137,7 @@ public class DFAEngine { @NotNull private E join(@NotNull Instruction instruction, @NotNull List info, @NotNull CallEnvironment env) { - final Iterable prev = myDfa.isForward() ? instruction.predecessors(env) : instruction.successors(env); + final Iterable prev = myDfa.isForward() ? instruction.predecessors(env) : instruction.successors(env); ArrayList prevInfos = new ArrayList<>(); for (Instruction i : prev) { prevInfos.add(info.get(i.num())); @@ -144,7 +145,8 @@ public class DFAEngine { return mySemilattice.join(prevInfos); } - private Iterable getNext(Instruction curr, CallEnvironment env) { + @NotNull + private Iterable getNext(@NotNull Instruction curr, @NotNull CallEnvironment env) { return myDfa.isForward() ? curr.successors(env) : curr.predecessors(env); } } From 56402cc02d0570000e86ecc4b3ebac72bc60eb77 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 6 Feb 2017 16:02:22 +0300 Subject: [PATCH 2/7] test removed --- .../com/intellij/roots/JdkComboBoxTest.java | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 java/java-tests/testSrc/com/intellij/roots/JdkComboBoxTest.java diff --git a/java/java-tests/testSrc/com/intellij/roots/JdkComboBoxTest.java b/java/java-tests/testSrc/com/intellij/roots/JdkComboBoxTest.java deleted file mode 100644 index cd11d857fe4e..000000000000 --- a/java/java-tests/testSrc/com/intellij/roots/JdkComboBoxTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2000-2017 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.roots; - -import com.intellij.openapi.roots.ui.configuration.JdkComboBox; -import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; -import com.intellij.testFramework.LightPlatformTestCase; - -/** - * @author Dmitry Avdeev - */ -public class JdkComboBoxTest extends LightPlatformTestCase { - - public void testSuggestedSdks() throws Exception { - JdkComboBox comboBox = new JdkComboBox(new ProjectSdksModel(), null, null, null, true); - Object itemAt = comboBox.getItemAt(0); - System.out.println(itemAt); - } -} From 4376688de4aed3c3f377de8c9be011bdc57b5afc Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 6 Feb 2017 16:14:25 +0300 Subject: [PATCH 3/7] [groovy] refactor DFAEngine, extract methods & classes --- .../groovy/lang/psi/dataFlow/DFAEngine.java | 104 +++++++++--------- .../groovy/lang/psi/dataFlow/WorkCounter.kt | 36 ++++++ .../groovy/lang/psi/dataFlow/WorkList.kt | 47 ++++++++ 3 files changed, 133 insertions(+), 54 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkCounter.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkList.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java index 0f3711014b89..26c109b9a7fd 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java @@ -15,9 +15,8 @@ */ package org.jetbrains.plugins.groovy.lang.psi.dataFlow; -import com.intellij.codeInspection.dataFlow.WorkingTimeMeasurer; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.util.registry.Registry; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallEnvironment; @@ -33,10 +32,11 @@ import java.util.*; public class DFAEngine { private final Instruction[] myFlow; - private final DfaInstance myDfa; private final Semilattice mySemilattice; + private WorkCounter myCounter = null; + public DFAEngine(@NotNull Instruction[] flow, @NotNull DfaInstance dfa, @NotNull Semilattice semilattice) { myFlow = flow; myDfa = dfa; @@ -79,74 +79,70 @@ public class DFAEngine { @Nullable private List performDFA(boolean timeout) { - WorkingTimeMeasurer measurer = null; + final int n = myFlow.length; + final List info = new ArrayList<>(Collections.nCopies(n, myDfa.initial())); + final CallEnvironment env = new MyCallEnvironment(n); - ArrayList info = new ArrayList<>(Collections.nCopies(myFlow.length, myDfa.initial())); - CallEnvironment env = new MyCallEnvironment(myFlow.length); - - boolean[] visited = new boolean[myFlow.length]; + final WorkList workList = new WorkList(n); - final boolean forward = myDfa.isForward(); - int[] order = ControlFlowBuilderUtil.postorder(myFlow); //todo for backward? - int count = 0; - for (int i = forward ? 0 : myFlow.length - 1; forward ? i < myFlow.length : i >= 0;) { - Instruction instr = myFlow[order[i]]; + final int[] flowOrder = getFlowOrder(); + for (int i : flowOrder) { + if (!workList.offer(myFlow[i])) continue; - if (!visited[instr.num()]) { - Queue workList = new LinkedList<>(); - - workList.add(instr); - visited[instr.num()] = true; - - while (!workList.isEmpty()) { - count++; - if (timeout && count % 512 == 0) { - if (measurer == null) { - long msLimit = Registry.intValue("ide.dfa.time.limit.online"); - - measurer = new WorkingTimeMeasurer(msLimit * 1000 * 1000); - } - else if (measurer.isTimeOver()) { - return null; - } - } - - ProgressManager.checkCanceled(); - final Instruction curr = workList.remove(); - final int num = curr.num(); - final E oldE = info.get(num); - E newE = join(curr, info, env); - myDfa.fun(newE, curr); - if (!mySemilattice.eq(newE, oldE)) { - info.set(num, newE); - for (Instruction next : getNext(curr, env)) { - workList.add(next); - visited[next.num()] = true; - } + while (!workList.isEmpty()) { + ProgressManager.checkCanceled(); + if (timeout && checkCounter()) return null; + final Instruction curr = workList.remove(); + final int num = curr.num(); + final E oldE = info.get(num); // saved outbound state + final E newE = getInboundState(curr, info, env); // inbound state + myDfa.fun(newE, curr); // newly modified outbound state + if (!mySemilattice.eq(newE, oldE)) { // if outbound state changed + info.set(num, newE); // save new state + for (Instruction next : getNext(curr, env)) { + workList.offerUnconditionally(next); } } } - - if (forward) i++; - else i--; } - return info; } + private int[] getFlowOrder() { + int[] order = ControlFlowBuilderUtil.postorder(myFlow); + if (myDfa.isForward()) { + return order; + } + else { + return ArrayUtil.reverseArray(order); + } + } + @NotNull - private E join(@NotNull Instruction instruction, @NotNull List info, @NotNull CallEnvironment env) { - final Iterable prev = myDfa.isForward() ? instruction.predecessors(env) : instruction.successors(env); - ArrayList prevInfos = new ArrayList<>(); - for (Instruction i : prev) { + private E getInboundState(@NotNull Instruction instruction, @NotNull List info, @NotNull CallEnvironment env) { + List prevInfos = new ArrayList<>(); + for (Instruction i : getPrevious(instruction, env)) { prevInfos.add(info.get(i.num())); } return mySemilattice.join(prevInfos); } @NotNull - private Iterable getNext(@NotNull Instruction curr, @NotNull CallEnvironment env) { - return myDfa.isForward() ? curr.successors(env) : curr.predecessors(env); + private Iterable getPrevious(@NotNull Instruction instruction, @NotNull CallEnvironment env) { + return myDfa.isForward() ? instruction.predecessors(env) : instruction.successors(env); + } + + @NotNull + private Iterable getNext(@NotNull Instruction instruction, @NotNull CallEnvironment env) { + return myDfa.isForward() ? instruction.successors(env) : instruction.predecessors(env); + } + + private boolean checkCounter() { + if (myCounter == null) { + myCounter = new WorkCounter(); + return false; + } + return myCounter.isTimeOver(); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkCounter.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkCounter.kt new file mode 100644 index 000000000000..11c6df9f8baa --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkCounter.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2017 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.dataFlow + +import com.intellij.codeInspection.dataFlow.WorkingTimeMeasurer +import com.intellij.openapi.util.registry.Registry + +internal class WorkCounter { + + private val myMeasurer by lazy(LazyThreadSafetyMode.NONE) { + val msLimit = Registry.intValue("ide.dfa.time.limit.online").toLong() + WorkingTimeMeasurer(msLimit * 1000 * 1000) + } + private var myCount: Int = 0 + + /** + * Checks [WorkingTimeMeasurer.isTimeOver] every 512 invocations + * @return `true` if time is over + */ + fun isTimeOver(): Boolean = ++myCount % 512 == 0 && myMeasurer.isTimeOver +} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkList.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkList.kt new file mode 100644 index 000000000000..405b73a041b4 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkList.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2017 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.dataFlow + +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction +import java.util.* + +internal class WorkList(size: Int) { + + private val myQueue: Queue = LinkedList() + private val myVisited: BooleanArray = BooleanArray(size) + + fun remove(): Instruction = myQueue.remove() + + val isEmpty: Boolean get() = myQueue.isEmpty() + + /** + * Adds element to the queue and marks it as visited + */ + fun offerUnconditionally(instruction: Instruction) { + myQueue.add(instruction) + myVisited[instruction.num()] = true + } + + /** + * Adds element to the queue and marks it as visited if it wasn't visited before + * @return `true` if element was added to the queue + */ + fun offer(instruction: Instruction): Boolean { + if (myVisited[instruction.num()]) return false + offerUnconditionally(instruction) + return true + } +} From e2d7ea5f4f3bbf39835c5ec0bc6264fa617e4708 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 6 Feb 2017 16:24:30 +0300 Subject: [PATCH 4/7] IDEA-167667 Unexpected substitution during block selection paste in java --- .../editorActions/CopyPasteReferenceProcessor.java | 10 ++++++---- .../editorActions/CopyPasteFoldingProcessor.java | 10 +++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java index 66056e42797b..a05a9999cdc1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -57,11 +57,13 @@ public abstract class CopyPasteReferenceProcessor exten } final ArrayList array = new ArrayList<>(); + int refOffset = 0; // this is an offset delta for conversion from absolute offset to an offset inside clipboard contents for (int j = 0; j < startOffsets.length; j++) { - final int startOffset = startOffsets[j]; - for (final PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) { - addReferenceData(file, startOffset, element, array); + refOffset += startOffsets[j]; + for (final PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffsets[j], endOffsets[j])) { + addReferenceData(file, refOffset, element, array); } + refOffset -= endOffsets[j] + 1; // 1 accounts for line break inserted between contents corresponding to different carets } if (array.isEmpty()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java index 80fa399a5fca..6164efb982a0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -46,16 +46,20 @@ public class CopyPasteFoldingProcessor extends CopyPastePostProcessor Date: Mon, 6 Feb 2017 16:20:09 +0300 Subject: [PATCH 5/7] Kill the hack --- .../codeStyle/arrangement/ArrangementSettingsPanel.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java index b0d795d4b570..d34d6005ff35 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java @@ -39,7 +39,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -123,8 +122,6 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { @Override public void apply(CodeStyleSettings settings) { - myMatchingRulesPanel.hideEditor(); - CommonCodeStyleSettings commonSettings = settings.getCommonSettings(myLanguage); commonSettings.setArrangementSettings(createSettings()); if (myForceArrangementPanel != null) { From 409ce19b540369f36cf4e1a4ca2455579cf12318 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 6 Feb 2017 16:28:45 +0300 Subject: [PATCH 6/7] switch pycharm edu to webhelp --- .../build/pycharm/edu/PyCharmEduProperties.groovy | 13 ------------- .../resources/idea/PyCharmEduApplicationInfo.xml | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy b/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy index d9d7f4121347..e4c07d2a23ec 100644 --- a/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy +++ b/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy @@ -62,13 +62,6 @@ class PyCharmEduProperties extends PyCharmPropertiesBase { "PyCharm Edu" } - @Override - void copyAdditionalFiles(BuildContext context, String targetDirectory) { - super.copyAdditionalFiles(context, targetDirectory) - context.ant.copy(file: "$context.paths.projectHome/help/pycharm-eduhelp.jar", todir: "$targetDirectory/help", - failonerror: false, quiet: true) - } - @Override String getBaseDownloadUrlForJre() { "https://download.jetbrains.com/python" } } @@ -86,11 +79,6 @@ class PyCharmEduProperties extends PyCharmPropertiesBase { "pycharm-edu-${applicationInfo.isEAP ? buildNumber : applicationInfo.fullVersion}" } - @Override - void copyAdditionalFiles(BuildContext context, String targetDirectory) { - context.ant.copy(file: "$context.paths.projectHome/help/pycharm-eduhelp.jar", todir: "$targetDirectory/help", - failonerror: false, quiet: true) - } } } @@ -100,7 +88,6 @@ class PyCharmEduProperties extends PyCharmPropertiesBase { { icnsPath = "$pythonCommunityPath/educational-python/resources/PyCharmEdu.icns" bundleIdentifier = "com.jetbrains.pycharm" - helpId = "PE" dmgImagePath = "$pythonCommunityPath/educational-python/build/DMG_background.png" } } diff --git a/python/educational-python/resources/idea/PyCharmEduApplicationInfo.xml b/python/educational-python/resources/idea/PyCharmEduApplicationInfo.xml index 28aa98381b47..4c4fdb4ce2d1 100644 --- a/python/educational-python/resources/idea/PyCharmEduApplicationInfo.xml +++ b/python/educational-python/resources/idea/PyCharmEduApplicationInfo.xml @@ -17,7 +17,7 @@ - + Date: Mon, 6 Feb 2017 13:22:45 +0100 Subject: [PATCH 7/7] move freemarker java type check into util, and reuse in velocity (IDEA-167581) --- .../impl/analysis/JavaHighlightUtil.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaHighlightUtil.java index b2d7a57c6f58..4ac7d8a69183 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaHighlightUtil.java @@ -15,8 +15,11 @@ */ package com.intellij.codeInsight.daemon.impl.analysis; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -178,6 +181,33 @@ public class JavaHighlightUtil { } } + @Nullable + public static String checkPsiTypeUseInContext(@Nullable PsiType type, @NotNull PsiElement context) { + if (type instanceof PsiPrimitiveType) return null; + if (type instanceof PsiArrayType) return checkPsiTypeUseInContext(((PsiArrayType) type).getComponentType(), context); + if (PsiUtil.resolveClassInType(type) != null) return null; + if (type instanceof PsiClassType) return checkClassType((PsiClassType)type, context); + return "Invalid Java type"; + } + + private static String checkClassType(@NotNull PsiClassType type, @NotNull PsiElement context) { + String className = PsiNameHelper.getQualifiedClassName(type.getCanonicalText(false), true); + if (classExists(context, className)) { + return getClassInaccessibleMessage(context, className); + } + return "Invalid Java type"; + } + + private static boolean classExists(@NotNull PsiElement context, String className) { + return JavaPsiFacade.getInstance(context.getProject()).findClass(className, GlobalSearchScope.allScope(context.getProject())) != null; + } + + @NotNull + private static String getClassInaccessibleMessage(@NotNull PsiElement context, String className) { + Module module = ModuleUtilCore.findModuleForPsiElement(context); + return "Class '" + className + "' is not accessible " + (module == null ? "here" : "from module '" + module.getName() + "'"); + } + static class ConstructorVisitorInfo { List visitedConstructors; PsiMethod recursivelyCalledConstructor;